Skip to content

Commit d23e2d7

Browse files
committed
Extend cpp-rule-preprocessor supported C++ rules
1 parent 4b1deff commit d23e2d7

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()) {
@@ -293,7 +300,9 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
293300
return ns;
294301
}
295302

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

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

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

0 commit comments

Comments
 (0)