Skip to content

Commit 81d131d

Browse files
committed
Extend cpp-rule-preprocessor supported C++ rules
1 parent 6849e2c commit 81d131d

1 file changed

Lines changed: 152 additions & 8 deletions

File tree

cpp2rust/cpp_rule_preprocessor.cpp

Lines changed: 152 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Distributed under the MIT license that can be found in the LICENSE file.
33

44
#include <clang/AST/ASTContext.h>
5+
#include <clang/AST/Attr.h>
56
#include <clang/AST/Decl.h>
67
#include <clang/AST/Expr.h>
78
#include <clang/AST/PrettyPrinter.h>
@@ -58,10 +59,15 @@ struct LookupInfo {
5859
name = dm->getMember();
5960
kind = LookupKind::CXXMethodName;
6061
explicitArgs = dm->template_arguments();
62+
} else if (const auto *um =
63+
llvm::dyn_cast<clang::UnresolvedMemberExpr>(expr)) {
64+
name = um->getMemberName();
65+
kind = LookupKind::CXXMethodName;
66+
explicitArgs = um->template_arguments();
6167
} else if (const auto *dref =
6268
llvm::dyn_cast<clang::DependentScopeDeclRefExpr>(expr)) {
6369
clang::DeclarationName dname = dref->getDeclName();
64-
if (name.getNameKind() ==
70+
if (dname.getNameKind() ==
6571
clang::DeclarationName::NameKind::CXXConstructorName) {
6672
name = dname;
6773
kind = LookupKind::CXXConstructorName;
@@ -260,7 +266,8 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
260266
return spec;
261267
}
262268

263-
if (result == clang::TemplateDeductionResult::SubstitutionFailure) {
269+
if (result == clang::TemplateDeductionResult::SubstitutionFailure ||
270+
result == clang::TemplateDeductionResult::ConstraintsNotSatisfied) {
264271
if (const auto *deduced = info.takeCanonical()) {
265272
clang::TemplateArgumentListInfo targsInfo;
266273
for (const auto &arg : deduced->asArray()) {
@@ -292,7 +299,9 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
292299
return ns;
293300
}
294301

295-
clang::RecordDecl *createRecordDecl(llvm::StringRef name) {
302+
clang::RecordDecl *
303+
createRecordDecl(llvm::StringRef name,
304+
clang::QualType base = clang::QualType()) {
296305
bool owned = true;
297306
bool dependent = false;
298307
clang::CXXScopeSpec scope;
@@ -305,11 +314,135 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
305314
clang::TypeResult(), false, false, clang::OffsetOfKind::Outside);
306315
assert(decl.isUsable() && "Record decl creation failed");
307316
auto *rdecl = decl.getAs<clang::RecordDecl>();
317+
308318
rdecl->startDefinition();
319+
if (!base.isNull()) {
320+
clang::CXXBaseSpecifier baseSpec(
321+
clang::SourceRange(loc_, loc_), false, true, clang::AS_public,
322+
sema_->Context.getTrivialTypeSourceInfo(base, loc_),
323+
/*EllipsisLoc=*/clang::SourceLocation());
324+
const clang::CXXBaseSpecifier *bases[] = {&baseSpec};
325+
llvm::cast<clang::CXXRecordDecl>(rdecl)->setBases(bases, 1);
326+
}
309327
rdecl->completeDefinition();
310328
return rdecl;
311329
}
312330

331+
static clang::QualType getNTTPType(const clang::TemplateArgument &arg) {
332+
switch (arg.getKind()) {
333+
case clang::TemplateArgument::Integral:
334+
return arg.getIntegralType();
335+
case clang::TemplateArgument::Declaration:
336+
return arg.getParamTypeForDecl();
337+
case clang::TemplateArgument::NullPtr:
338+
return arg.getNullPtrType();
339+
case clang::TemplateArgument::StructuralValue:
340+
return arg.getStructuralValueType();
341+
default:
342+
return clang::QualType();
343+
}
344+
}
345+
346+
clang::QualType createMirrorType(llvm::StringRef name, clang::QualType hint) {
347+
clang::ASTContext &ctx = sema_->Context;
348+
forceCompleteDefinition(hint);
349+
350+
const auto *hdecl = hint->getAsCXXRecordDecl();
351+
assert(hdecl && "Failed resolving hint record declaration");
352+
assert(hdecl->isCompleteDefinition() && "Incomplete hint");
353+
354+
const auto *hspec =
355+
llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(hdecl);
356+
if (!hspec) {
357+
// if it is not a template specialization inheriting from it suffices
358+
clang::RecordDecl *rdecl = createRecordDecl(name, hint);
359+
return ctx.getTagType(clang::ElaboratedTypeKeyword::None,
360+
rdecl->getQualifier(), rdecl, false);
361+
}
362+
363+
auto *pattern = clang::CXXRecordDecl::Create(
364+
ctx, clang::TagTypeKind::Struct, sema_->CurContext, loc_, loc_,
365+
&ctx.Idents.get(name));
366+
367+
auto *htdecl = hspec->getSpecializedTemplate();
368+
auto *mirror = clang::ClassTemplateDecl::Create(
369+
ctx, sema_->CurContext, loc_,
370+
clang::DeclarationName(&ctx.Idents.get(name)),
371+
htdecl->getTemplateParameters(), pattern);
372+
pattern->setDescribedClassTemplate(mirror);
373+
374+
clang::TemplateArgumentListInfo bargs(loc_, loc_);
375+
for (const clang::TemplateArgument &arg :
376+
htdecl->getTemplateParameters()->getInjectedTemplateArgs(ctx)) {
377+
bargs.addArgument(
378+
sema_->getTrivialTemplateArgumentLoc(arg, getNTTPType(arg), loc_));
379+
}
380+
clang::QualType base_t = sema_->CheckTemplateIdType(
381+
clang::ElaboratedTypeKeyword::None, clang::TemplateName(htdecl), loc_,
382+
bargs, sema_->getCurScope(), /*ForNestedNameSpecifier=*/false);
383+
assert(!base_t.isNull() && "Failed building mirror base");
384+
385+
pattern->startDefinition();
386+
clang::CXXBaseSpecifier base(clang::SourceRange(loc_, loc_), false, true,
387+
clang::AS_public,
388+
ctx.getTrivialTypeSourceInfo(base_t, loc_),
389+
/*EllipsisLoc=*/clang::SourceLocation());
390+
const clang::CXXBaseSpecifier *bases[] = {&base};
391+
pattern->setBases(bases, 1);
392+
pattern->completeDefinition();
393+
sema_->CurContext->addDecl(mirror);
394+
395+
clang::TemplateArgumentListInfo args(loc_, loc_);
396+
for (const clang::TemplateArgument &arg :
397+
hspec->getTemplateArgs().asArray()) {
398+
args.addArgument(
399+
sema_->getTrivialTemplateArgumentLoc(arg, getNTTPType(arg), loc_));
400+
}
401+
402+
clang::QualType spec = sema_->CheckTemplateIdType(
403+
clang::ElaboratedTypeKeyword::None, clang::TemplateName(mirror), loc_,
404+
args, sema_->getCurScope(), /*ForNestedNameSpecifier=*/false);
405+
assert(!spec.isNull() && spec->getAsCXXRecordDecl());
406+
407+
// required to print Tn instead of Tn<arg1, arg2, ...>
408+
clang::NamespaceDecl *ns = createNamespaceDecl();
409+
auto *alias =
410+
clang::TypeAliasDecl::Create(ctx, ns, loc_, loc_, &ctx.Idents.get(name),
411+
ctx.getTrivialTypeSourceInfo(spec, loc_));
412+
ns->addDecl(alias);
413+
414+
clang::QualType alias_t = ctx.getTypedefType(
415+
clang::ElaboratedTypeKeyword::None, std::nullopt, alias);
416+
spec->getAsCXXRecordDecl()->addAttr(
417+
clang::PreferredNameAttr::CreateImplicit(
418+
ctx, ctx.getTrivialTypeSourceInfo(alias_t, loc_)));
419+
420+
return ctx.getCanonicalType(spec);
421+
}
422+
423+
clang::QualType
424+
getDefaultArg(clang::TemplateDecl *decl,
425+
const clang::TemplateTypeParmDecl *parm,
426+
llvm::ArrayRef<clang::TemplateArgument> currentArgs) {
427+
clang::QualType type = parm->getDefaultArgument().getArgument().getAsType();
428+
if (!type->isDependentType()) {
429+
return type;
430+
}
431+
432+
clang::Sema::InstantiatingTemplate Inst(*sema_, loc_, decl);
433+
assert(!Inst.isInvalid() && "Invalid instantiation context");
434+
435+
clang::MultiLevelTemplateArgumentList mtal;
436+
mtal.setKind(clang::TemplateSubstitutionKind::Rewrite);
437+
mtal.addOuterTemplateArguments(currentArgs);
438+
439+
clang::TypeSourceInfo *tsi =
440+
sema_->SubstType(sema_->Context.getTrivialTypeSourceInfo(type), mtal,
441+
loc_, clang::DeclarationName());
442+
assert(tsi && "Template argument type instantiation failed");
443+
return tsi->getType();
444+
}
445+
313446
clang::VarDecl *createVarDecl(clang::QualType type, llvm::StringRef name,
314447
clang::StorageClass sclass = clang::SC_None) {
315448
clang::ASTContext &ctx = sema_->Context;
@@ -354,11 +487,19 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
354487
createTemplateArguments(clang::TemplateDecl *decl,
355488
llvm::SmallVectorImpl<clang::TemplateArgument> &out) {
356489
for (clang::NamedDecl *param : *decl->getTemplateParameters()) {
357-
if (llvm::isa<clang::TemplateTypeParmDecl>(param)) {
358-
clang::RecordDecl *rdecl = createRecordDecl(param->getName());
359-
clang::QualType type =
360-
sema_->Context.getTagType(clang::ElaboratedTypeKeyword::None,
361-
rdecl->getQualifier(), rdecl, false);
490+
if (const auto *ttp =
491+
llvm::dyn_cast<clang::TemplateTypeParmDecl>(param)) {
492+
clang::QualType type;
493+
if (ttp->hasDefaultArgument()) {
494+
clang::QualType hint = getDefaultArg(decl, ttp, out);
495+
assert(!hint.isNull() && "Failed retrieving type hint");
496+
type = createMirrorType(param->getName(), hint);
497+
} else {
498+
clang::RecordDecl *rdecl = createRecordDecl(param->getName());
499+
type = sema_->Context.getTagType(clang::ElaboratedTypeKeyword::None,
500+
rdecl->getQualifier(), rdecl, false);
501+
}
502+
assert(!type.isNull() && "Template type argument creation failed");
362503
out.emplace_back(type);
363504
} else if (const auto *nttp =
364505
llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(param)) {
@@ -504,6 +645,7 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
504645
clang::NamespaceDecl *ns = createNamespaceDecl();
505646
clang::Sema::ContextRAII savedContext(*sema_, ns);
506647
clang::FunctionDecl *rule = instantiateRuleDecl(decl);
648+
assert(rule && "Rule instantiation failed");
507649
llvm::ArrayRef<clang::ParmVarDecl *> parms = rule->parameters();
508650
auto csk = lookup.name.getNameKind() ==
509651
clang::DeclarationName::NameKind::CXXOperatorName
@@ -610,6 +752,7 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
610752
clang::NamespaceDecl *ns = createNamespaceDecl();
611753
clang::Sema::ContextRAII savedContext(*sema_, ns);
612754
clang::FunctionDecl *rule = instantiateRuleDecl(decl);
755+
assert(rule && "Rule instantiation failed");
613756
clang::CXXRecordDecl *rdecl =
614757
resolveCXXRecordDecl(rule->getParamDecl(0)->getType());
615758
assert(rdecl && "Failed fetching record decl");
@@ -627,6 +770,7 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
627770
clang::NamespaceDecl *ns = createNamespaceDecl();
628771
clang::Sema::ContextRAII savedContext(*sema_, ns);
629772
clang::FunctionDecl *rule = instantiateRuleDecl(decl);
773+
assert(rule && "Rule instantiation failed");
630774

631775
clang::Expr *obj = createOpaqueValueExpr(
632776
rule->getParamDecl(0)->getType().getNonReferenceType());

0 commit comments

Comments
 (0)