33
44#include " converter/rules/decls.h"
55
6- #include < clang/AST/DeclCXX.h>
76#include < clang/AST/DeclTemplate.h>
87#include < clang/AST/ExprCXX.h>
9- #include < clang/Basic/OperatorKinds.h>
10- #include < clang/Basic/SourceManager.h>
11- #include < clang/Lex/Lexer.h>
12- #include < llvm/ADT/STLExtras.h>
8+ #include < clang/Sema/TemplateDeduction.h>
9+ #include < llvm/ADT/SmallVector.h>
1310
1411#include < cassert>
12+ #include < optional>
1513#include < vector>
1614
1715namespace cpp2rust ::RuleDecls {
1816
19- namespace {
20-
21- const clang::Decl *getScope (clang::QualType type) {
22- type = type.getNonReferenceType ();
23- if (type->isPointerType ()) {
24- type = type->getPointeeType ();
25- }
26- if (auto spec = type->getAs <clang::TemplateSpecializationType>()) {
27- if (auto tmpl = llvm::dyn_cast_or_null<clang::ClassTemplateDecl>(
28- spec->getTemplateName ().getAsTemplateDecl ())) {
29- return tmpl->getCanonicalDecl ();
30- }
31- return nullptr ;
32- }
33- auto record = type->getAsCXXRecordDecl ();
34- if (!record) {
35- return nullptr ;
36- }
37- if (auto spec =
38- llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(record)) {
39- return spec->getSpecializedTemplate ()->getCanonicalDecl ();
40- }
41- return record->getCanonicalDecl ();
42- }
43-
44- const clang::Decl *getScope (const clang::Decl *decl) {
45- if (auto record =
46- llvm::dyn_cast<clang::CXXRecordDecl>(decl->getDeclContext ())) {
47- return getScope (decl->getASTContext ().getCanonicalTagType (record));
48- }
49- return nullptr ;
50- }
51-
52- std::vector<clang::QualType> resolveMemberType (clang::QualType type) {
53- auto member = type->getAs <clang::DependentNameType>();
54- if (!member) {
55- return {type};
56- }
57- auto qualifier = member->getQualifier ().getAsType ();
58- assert (qualifier && " member type is not qualified by a type" );
59- std::vector<clang::QualType> resolved;
60- for (auto owner : resolveMemberType (clang::QualType (qualifier, 0 ))) {
61- auto spec = owner->getAs <clang::TemplateSpecializationType>();
62- auto tmpl = spec ? llvm::dyn_cast_or_null<clang::ClassTemplateDecl>(
63- spec->getTemplateName ().getAsTemplateDecl ())
64- : nullptr ;
65- assert (tmpl && " member type is not qualified by a class template" );
66- llvm::SmallVector<clang::ClassTemplatePartialSpecializationDecl *> partials;
67- tmpl->getPartialSpecializations (partials);
68- llvm::SmallVector<clang::CXXRecordDecl *> records{tmpl->getTemplatedDecl ()};
69- records.append (partials.begin (), partials.end ());
70- for (auto record : records) {
71- if (!record->hasDefinition ()) {
72- continue ;
73- }
74- for (auto decl :
75- record->getDefinition ()->lookup (member->getIdentifier ())) {
76- if (auto alias = llvm::dyn_cast<clang::TypedefNameDecl>(decl)) {
77- auto types = resolveMemberType (alias->getUnderlyingType ());
78- resolved.insert (resolved.end (), types.begin (), types.end ());
79- }
80- }
81- }
82- }
83- return resolved;
84- }
85-
86- ExprKey getOperatorKey (clang::ASTContext &ctx,
87- clang::OverloadedOperatorKind op) {
88- return {nullptr , ctx.DeclarationNames .getCXXOperatorName (op)};
89- }
90-
91- clang::DeclarationName getKeyName (clang::DeclarationName name) {
92- if (name.getNameKind () == clang::DeclarationName::CXXConversionFunctionName) {
93- return {};
94- }
95- return name;
96- }
97-
98- ExprKey getDeclKey (const clang::NamedDecl *decl) {
99- if (auto ctor = llvm::dyn_cast<clang::CXXConstructorDecl>(decl)) {
100- return {getScope (ctor), clang::DeclarationName ()};
101- }
102- return {getScope (decl), getKeyName (decl->getDeclName ())};
103- }
104-
105- ExprKey getExprKey (clang::ASTContext &ctx, const clang::Expr *expr) {
106- expr = SkipImplicit (expr);
107- if (llvm::isa<clang::IntegerLiteral>(expr) &&
108- expr->getBeginLoc ().isMacroID ()) {
109- auto macro = clang::Lexer::getImmediateMacroName (
110- expr->getBeginLoc (), ctx.getSourceManager (), ctx.getLangOpts ());
111- return {nullptr , clang::DeclarationName (&ctx.Idents .get (macro))};
112- }
113- if (auto rewritten =
114- llvm::dyn_cast<clang::CXXRewrittenBinaryOperator>(expr)) {
115- return getOperatorKey (ctx, clang::BinaryOperator::getOverloadedOperator (
116- rewritten->getOperator ()));
117- }
118- if (auto cast = llvm::dyn_cast<clang::ExplicitCastExpr>(expr)) {
119- return getExprKey (ctx, cast->getSubExpr ());
120- }
121- if (auto construct = llvm::dyn_cast<clang::CXXConstructExpr>(expr)) {
122- return getDeclKey (construct->getConstructor ());
123- }
124- if (auto construct =
125- llvm::dyn_cast<clang::CXXUnresolvedConstructExpr>(expr)) {
126- return {getScope (construct->getTypeAsWritten ()), clang::DeclarationName ()};
127- }
128- if (auto call = llvm::dyn_cast<clang::CallExpr>(expr)) {
129- if (auto callee = call->getDirectCallee ()) {
130- return getDeclKey (callee);
131- }
132- return getExprKey (ctx, call->getCallee ());
133- }
134- if (auto member = llvm::dyn_cast<clang::UnresolvedMemberExpr>(expr)) {
135- return {getScope (member->getBaseType ()),
136- getKeyName (member->getMemberName ())};
137- }
138- if (auto member = llvm::dyn_cast<clang::CXXDependentScopeMemberExpr>(expr)) {
139- return {getScope (member->getBaseType ()), getKeyName (member->getMember ())};
140- }
141- if (auto lookup = llvm::dyn_cast<clang::UnresolvedLookupExpr>(expr)) {
142- return {nullptr , lookup->getName ()};
143- }
144- if (auto ref = llvm::dyn_cast<clang::DependentScopeDeclRefExpr>(expr)) {
145- return {nullptr , ref->getDeclName ()};
146- }
147- if (auto member = llvm::dyn_cast<clang::MemberExpr>(expr)) {
148- return getDeclKey (member->getMemberDecl ());
149- }
150- if (auto ref = llvm::dyn_cast<clang::DeclRefExpr>(expr)) {
151- return getDeclKey (ref->getDecl ());
152- }
153- if (auto binary = llvm::dyn_cast<clang::BinaryOperator>(expr)) {
154- return getOperatorKey (
155- ctx, clang::BinaryOperator::getOverloadedOperator (binary->getOpcode ()));
156- }
157- if (auto unary = llvm::dyn_cast<clang::UnaryOperator>(expr)) {
158- return getOperatorKey (
159- ctx, clang::UnaryOperator::getOverloadedOperator (unary->getOpcode ()));
160- }
161- if (llvm::isa<clang::ArraySubscriptExpr>(expr)) {
162- return getOperatorKey (ctx, clang::OO_Subscript);
163- }
164- return {};
165- }
166-
167- } // namespace
168-
16917const clang::Expr *SkipImplicit (const clang::Expr *expr) {
17018 while (true ) {
17119 expr = expr->IgnoreParens ();
@@ -201,94 +49,6 @@ const clang::Expr *GetReturned(const clang::FunctionDecl *rule) {
20149 return returned;
20250}
20351
204- ExprKey GetExprKey (clang::ASTContext &ctx, const clang::Expr *use) {
205- return getExprKey (ctx, use);
206- }
207-
208- std::vector<ExprKey> GetExprKeys (clang::ASTContext &ctx,
209- const clang::NamedDecl *rule) {
210- if (auto var = llvm::dyn_cast<clang::VarDecl>(rule)) {
211- return {getExprKey (ctx, var->getInit ())};
212- }
213- auto returned = SkipImplicit (GetReturned (rule->getAsFunction ()));
214- if (auto construct =
215- llvm::dyn_cast<clang::CXXUnresolvedConstructExpr>(returned)) {
216- std::vector<ExprKey> keys;
217- for (auto type : resolveMemberType (construct->getTypeAsWritten ())) {
218- ExprKey key{getScope (type), clang::DeclarationName ()};
219- if (!llvm::is_contained (keys, key)) {
220- keys.push_back (key);
221- }
222- }
223- return keys;
224- }
225- return {getExprKey (ctx, returned)};
226- }
227-
228- const void *GetTypeKey (clang::QualType type) {
229- type = type.getCanonicalType ().getUnqualifiedType ();
230- if (auto scope = getScope (type)) {
231- return scope;
232- }
233- if (auto tag = type->getAsTagDecl ()) {
234- return tag->getCanonicalDecl ();
235- }
236- if (type->isDependentType ()) {
237- return nullptr ;
238- }
239- return type.getTypePtr ();
240- }
241-
242- std::vector<const void *> GetTypeKeys (const clang::NamedDecl *rule) {
243- auto alias = llvm::dyn_cast<clang::TypedefNameDecl>(rule);
244- if (auto tmpl = llvm::dyn_cast<clang::TypeAliasTemplateDecl>(rule)) {
245- alias = tmpl->getTemplatedDecl ();
246- }
247- assert (alias && " type rule is not an alias" );
248- auto pattern = alias->getUnderlyingType ();
249- if (pattern->getAs <clang::TemplateTypeParmType>()) {
250- pattern = EnableIfSameType (rule);
251- assert (!pattern.isNull () &&
252- " type rule matching any type must be constrained by enable_if" );
253- std::vector<const void *> keys;
254- for (auto type : resolveMemberType (pattern)) {
255- auto key = GetTypeKey (type);
256- if (!llvm::is_contained (keys, key)) {
257- keys.push_back (key);
258- }
259- }
260- return keys;
261- }
262- if (auto member = pattern->getAs <clang::DependentNameType>()) {
263- auto qualifier = member->getQualifier ().getAsType ();
264- assert (qualifier && " member type is not qualified by a type" );
265- return {getScope (clang::QualType (qualifier, 0 ))};
266- }
267- return {GetTypeKey (pattern)};
268- }
269-
270- std::vector<const void *> GetTypeKeys (clang::ASTContext &ctx,
271- clang::QualType use) {
272- std::vector<const void *> keys{GetTypeKey (use)};
273- for (auto type = use;; type = type.getSingleStepDesugaredType (ctx)) {
274- if (auto typedef_type =
275- llvm::dyn_cast<clang::TypedefType>(type.getTypePtr ())) {
276- if (auto owner = llvm::dyn_cast<clang::CXXRecordDecl>(
277- typedef_type->getDecl ()->getDeclContext ())) {
278- auto key = GetTypeKey (ctx.getCanonicalTagType (owner));
279- if (!llvm::is_contained (keys, key)) {
280- keys.push_back (key);
281- }
282- }
283- }
284- if (type.getSingleStepDesugaredType (ctx) == type) {
285- return keys;
286- }
287- }
288- }
289-
290- ExprKey GetDeclKey (const clang::NamedDecl *decl) { return getDeclKey (decl); }
291-
29252clang::QualType EnableIfSameType (const clang::Decl *rule) {
29353 auto tmpl = llvm::dyn_cast<clang::TemplateDecl>(rule);
29454 if (!tmpl) {
@@ -313,4 +73,21 @@ clang::QualType EnableIfSameType(const clang::Decl *rule) {
31373 return {};
31474}
31575
76+ std::optional<std::vector<clang::TemplateArgument>>
77+ DeduceFromType (clang::Sema &sema, clang::TemplateParameterList *params,
78+ clang::QualType pattern, clang::QualType actual) {
79+ Trial trial (sema);
80+ llvm::SmallVector<clang::DeducedTemplateArgument, 4 > deduced (params->size ());
81+ clang::sema::TemplateDeductionInfo info (params->getTemplateLoc ());
82+ if (sema.DeduceTemplateArguments (params, clang::TemplateArgument (pattern),
83+ clang::TemplateArgument (actual), info,
84+ deduced, /* NumberOfArgumentsMustMatch=*/
85+ true ) !=
86+ clang::TemplateDeductionResult::Success ||
87+ trial.failed ()) {
88+ return std::nullopt ;
89+ }
90+ return std::vector<clang::TemplateArgument>(deduced.begin (), deduced.end ());
91+ }
92+
31693} // namespace cpp2rust::RuleDecls
0 commit comments