Skip to content

Commit 93e8653

Browse files
committed
Extend cpp-rule-preprocessor supported C++ rules
1 parent 7ee4a56 commit 93e8653

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>
@@ -54,10 +55,15 @@ struct LookupInfo {
5455
name = dm->getMember();
5556
kind = LookupKind::CXXMethodName;
5657
explicitArgs = dm->template_arguments();
58+
} else if (const auto *um =
59+
llvm::dyn_cast<clang::UnresolvedMemberExpr>(expr)) {
60+
name = um->getMemberName();
61+
kind = LookupKind::CXXMethodName;
62+
explicitArgs = um->template_arguments();
5763
} else if (const auto *dref =
5864
llvm::dyn_cast<clang::DependentScopeDeclRefExpr>(expr)) {
5965
clang::DeclarationName dname = dref->getDeclName();
60-
if (name.getNameKind() ==
66+
if (dname.getNameKind() ==
6167
clang::DeclarationName::NameKind::CXXConstructorName) {
6268
name = dname;
6369
kind = LookupKind::CXXConstructorName;
@@ -255,7 +261,8 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
255261
return spec;
256262
}
257263

258-
if (result == clang::TemplateDeductionResult::SubstitutionFailure) {
264+
if (result == clang::TemplateDeductionResult::SubstitutionFailure ||
265+
result == clang::TemplateDeductionResult::ConstraintsNotSatisfied) {
259266
if (const auto *deduced = info.takeCanonical()) {
260267
clang::TemplateArgumentListInfo targsInfo;
261268
for (const auto &arg : deduced->asArray()) {
@@ -287,7 +294,9 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
287294
return ns;
288295
}
289296

290-
clang::RecordDecl *createRecordDecl(llvm::StringRef name) {
297+
clang::RecordDecl *
298+
createRecordDecl(llvm::StringRef name,
299+
clang::QualType base = clang::QualType()) {
291300
bool owned = true;
292301
bool dependent = false;
293302
clang::CXXScopeSpec scope;
@@ -300,11 +309,135 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
300309
clang::TypeResult(), false, false, clang::OffsetOfKind::Outside);
301310
assert(decl.isUsable() && "Record decl creation failed");
302311
auto *rdecl = decl.getAs<clang::RecordDecl>();
312+
303313
rdecl->startDefinition();
314+
if (!base.isNull()) {
315+
clang::CXXBaseSpecifier baseSpec(
316+
clang::SourceRange(loc_, loc_), false, true, clang::AS_public,
317+
sema_->Context.getTrivialTypeSourceInfo(base, loc_),
318+
/*EllipsisLoc=*/clang::SourceLocation());
319+
const clang::CXXBaseSpecifier *bases[] = {&baseSpec};
320+
llvm::cast<clang::CXXRecordDecl>(rdecl)->setBases(bases, 1);
321+
}
304322
rdecl->completeDefinition();
305323
return rdecl;
306324
}
307325

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

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

0 commit comments

Comments
 (0)