@@ -60,31 +60,13 @@ bool pointsToUserType(clang::QualType type) {
6060 return tag && IsUserDefinedDecl (tag);
6161}
6262
63+ constexpr llvm::StringLiteral kInitAliasPrefix = " cpp2rust_init_" ;
64+
6365bool isRuleName (llvm::StringRef name) {
6466 return name.size () > 1 && (name[0 ] == ' f' || name[0 ] == ' t' ) &&
6567 llvm::all_of (name.drop_front (), llvm::isDigit);
6668}
6769
68- // The T of a rule's trailing `Init<T, Args> &&...args` pack.
69- clang::QualType getInitPattern (const clang::FunctionDecl *rule) {
70- if (rule->param_empty ()) {
71- return {};
72- }
73- auto expansion =
74- rule->parameters ().back ()->getType ()->getAs <clang::PackExpansionType>();
75- if (!expansion) {
76- return {};
77- }
78- auto alias = expansion->getPattern ()
79- .getNonReferenceType ()
80- ->getAs <clang::TemplateSpecializationType>();
81- if (!alias || !alias->isTypeAlias () ||
82- alias->getTemplateName ().getAsTemplateDecl ()->getName () != " Init" ) {
83- return {};
84- }
85- return alias->template_arguments ()[0 ].getAsType ();
86- }
87-
8870void collectGenerics (const std::vector<TranslationRule::BodyFragment> &body,
8971 std::unordered_set<unsigned > &used) {
9072 TranslationRule::AnyFragment (body, [&](const TranslationRule::BodyFragment
@@ -158,6 +140,7 @@ void checkGenerics(const std::string &dir, const std::string &name,
158140 for (const auto ¶m : rule.params ) {
159141 collectGenerics (param.type , used);
160142 }
143+ collectGenerics (rule.init .type , used);
161144 for (unsigned i : used) {
162145 if (!declared.contains (std::format (" T{}" , i)) &&
163146 !isBoundArgument (rule, i)) {
@@ -166,10 +149,14 @@ void checkGenerics(const std::string &dir, const std::string &name,
166149 llvm::report_fatal_error (" Absent generic from src" );
167150 }
168151 }
169- if (rule.usesInit () && getInitPattern (decl).isNull ()) {
152+ if (rule.usesInit () &&
153+ (decl->param_empty () || !decl->parameters ()
154+ .back ()
155+ ->getType ()
156+ ->getAs <clang::PackExpansionType>())) {
170157 llvm::errs () << dir << " ::" << name << ' \n ' ;
171- llvm::report_fatal_error (" Expr rule uses init but its src pack is not "
172- " declared as Init<T, Args> " );
158+ llvm::report_fatal_error (
159+ " Expr rule uses init but its src does not end in a pack " );
173160 }
174161}
175162
@@ -219,6 +206,10 @@ void addCxxRules(clang::ASTContext &ctx, const clang::NamespaceDecl *rules) {
219206 }
220207 for (auto decl : ns->decls ()) {
221208 auto named = llvm::cast<clang::NamedDecl>(decl);
209+ if (llvm::isa<clang::TypeAliasTemplateDecl>(named) &&
210+ named->getName ().starts_with (kInitAliasPrefix )) {
211+ continue ;
212+ }
222213 if (!isRuleName (named->getName ())) {
223214 llvm::report_fatal_error (" declaration is not a rule" );
224215 }
@@ -451,18 +442,58 @@ clang::QualType GetConversionSourceType(clang::ASTContext &ctx,
451442 llvm::report_fatal_error (" converted generic has no CppFrom bound" );
452443}
453444
454- clang::QualType GetInitType (const clang::Expr *expr) {
445+ clang::QualType GetInitType (clang::ASTContext &ctx, const clang::Expr *expr) {
455446 auto match = findExpr (expr);
456447 assert (match.rule_decl && " expression must have a translation rule" );
448+ const auto &rule = match.rule_decl ->rule ;
449+ if (rule.init .cpp_type .empty ()) {
450+ llvm::StringRef type = rule.init .type ;
451+ unsigned n = 0 ;
452+ [[maybe_unused]] bool bad =
453+ !type.consume_front (" T" ) || type.getAsInteger (10 , n);
454+ assert (!bad && " init type must be a bare generic or a cpp_type!" );
455+ return GetGenericType (ctx, expr, n);
456+ }
457457 auto function = match.rule_decl ->decl ->getAsFunction ();
458- auto pattern = getInitPattern (function);
459- assert (!pattern.isNull () && " rule has no Init<T, Args> pack" );
460- clang::MultiLevelTemplateArgumentList args (
461- function->getDescribedFunctionTemplate (), match.args , /* Final=*/ false );
458+ auto tmpl = function->getDescribedFunctionTemplate ();
459+ assert (tmpl && " cpp_type! init in a non-template rule" );
460+ clang::TypeAliasTemplateDecl *alias = nullptr ;
461+ for (auto decl : function->getDeclContext ()->lookup (
462+ &ctx.Idents .get (InitAliasName (model_, function->getName ().str ())))) {
463+ if ((alias = llvm::dyn_cast<clang::TypeAliasTemplateDecl>(decl))) {
464+ break ;
465+ }
466+ }
467+ assert (alias && " cpp_type! init has no alias next to its rule" );
468+ clang::MultiLevelTemplateArgumentList args (tmpl, match.args ,
469+ /* Final=*/ false );
462470 clang::Sema::InstantiatingTemplate inst (
463471 *sema_, expr->getBeginLoc (), const_cast <clang::FunctionDecl *>(function));
464- return sema_->SubstType (pattern, args, expr->getBeginLoc (),
465- clang::DeclarationName ());
472+ auto type =
473+ sema_->SubstType (alias->getTemplatedDecl ()->getUnderlyingType (), args,
474+ expr->getBeginLoc (), clang::DeclarationName ());
475+ assert (!type.isNull () && " cpp_type! init does not substitute" );
476+ return type;
477+ }
478+
479+ std::string InitCppType (Model model, const std::string &dir,
480+ const std::string &name) {
481+ auto rule = findRule (model, dir, name);
482+ if (!rule) {
483+ rule = findRule (Model::kUnsafe , dir, name);
484+ }
485+ if (!rule) {
486+ return {};
487+ }
488+ auto params = rule->getObject (" params" );
489+ auto init = params ? params->getObject (" init" ) : nullptr ;
490+ auto cpp_type = init ? init->getString (" cpp_type" ) : std::nullopt ;
491+ return cpp_type ? cpp_type->str () : std::string ();
492+ }
493+
494+ std::string InitAliasName (Model model, const std::string &name) {
495+ return std::format (" {}{}_{}" , kInitAliasPrefix .str (),
496+ model == Model::kRefCount ? " refcount" : " unsafe" , name);
466497}
467498
468499bool HasExprRule (const clang::FunctionDecl *decl) {
0 commit comments