Skip to content

Commit 6a46f88

Browse files
committed
Split matcher into expr matcher and type matcher
1 parent 7852fa7 commit 6a46f88

9 files changed

Lines changed: 563 additions & 490 deletions

File tree

‎cpp2rust/converter/rules/decls.cpp‎

Lines changed: 20 additions & 243 deletions
Original file line numberDiff line numberDiff line change
@@ -3,169 +3,17 @@
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

1715
namespace 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-
16917
const 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-
29252
clang::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

‎cpp2rust/converter/rules/decls.h‎

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,47 +3,45 @@
33
// Copyright (c) 2022-present INESC-ID.
44
// Distributed under the MIT license that can be found in the LICENSE file.
55

6-
#include <clang/AST/ASTContext.h>
76
#include <clang/AST/Decl.h>
8-
#include <clang/AST/DeclarationName.h>
7+
#include <clang/AST/DeclTemplate.h>
98
#include <clang/AST/Expr.h>
9+
#include <clang/AST/TemplateBase.h>
1010
#include <clang/AST/Type.h>
11-
#include <llvm/ADT/Hashing.h>
11+
#include <clang/Basic/Diagnostic.h>
12+
#include <clang/Sema/Sema.h>
1213

14+
#include <optional>
1315
#include <vector>
1416

1517
namespace cpp2rust::RuleDecls {
16-
struct ExprKey {
17-
const clang::Decl *scope = nullptr;
18-
clang::DeclarationName name;
18+
class Trial {
19+
public:
20+
explicit Trial(clang::Sema &sema)
21+
: diagnostics_(sema.getDiagnostics()),
22+
suppressed_(diagnostics_.getSuppressAllDiagnostics()),
23+
trap_(sema, /*ForValidityCheck=*/true) {
24+
diagnostics_.setSuppressAllDiagnostics(true);
25+
}
1926

20-
bool operator==(const ExprKey &) const = default;
21-
};
27+
~Trial() { diagnostics_.setSuppressAllDiagnostics(suppressed_); }
2228

23-
struct ExprKeyHash {
24-
size_t operator()(const ExprKey &key) const {
25-
return llvm::hash_combine(key.scope, key.name.getAsOpaquePtr());
26-
}
29+
bool failed() const { return trap_.hasErrorOccurred(); }
30+
31+
private:
32+
clang::DiagnosticsEngine &diagnostics_;
33+
bool suppressed_;
34+
clang::Sema::SFINAETrap trap_;
2735
};
2836

2937
const clang::Expr *SkipImplicit(const clang::Expr *expr);
3038

3139
const clang::Expr *GetReturned(const clang::FunctionDecl *rule);
3240

33-
ExprKey GetExprKey(clang::ASTContext &ctx, const clang::Expr *use);
34-
35-
std::vector<ExprKey> GetExprKeys(clang::ASTContext &ctx,
36-
const clang::NamedDecl *rule);
37-
38-
ExprKey GetDeclKey(const clang::NamedDecl *decl);
39-
40-
const void *GetTypeKey(clang::QualType type);
41-
42-
std::vector<const void *> GetTypeKeys(const clang::NamedDecl *rule);
43-
44-
std::vector<const void *> GetTypeKeys(clang::ASTContext &ctx,
45-
clang::QualType use);
46-
4741
clang::QualType EnableIfSameType(const clang::Decl *rule);
4842

43+
std::optional<std::vector<clang::TemplateArgument>>
44+
DeduceFromType(clang::Sema &sema, clang::TemplateParameterList *params,
45+
clang::QualType pattern, clang::QualType actual);
46+
4947
} // namespace cpp2rust::RuleDecls

0 commit comments

Comments
 (0)