Skip to content

Commit 61abccd

Browse files
committed
Shadow self-referencial member typedefs, required for c++ < 20
1 parent dbcb065 commit 61abccd

1 file changed

Lines changed: 80 additions & 32 deletions

File tree

cpp2rust/cpp_rule_preprocessor.cpp

Lines changed: 80 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -344,43 +344,61 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
344344
}
345345
}
346346

347-
clang::QualType createMirrorType(llvm::StringRef name, clang::QualType hint) {
348-
clang::ASTContext &ctx = sema_->Context;
349-
forceCompleteDefinition(hint);
347+
clang::QualType
348+
getTemplateIdType(clang::ClassTemplateDecl *decl,
349+
llvm::ArrayRef<clang::TemplateArgument> args) {
350+
clang::TemplateArgumentListInfo info(loc_, loc_);
351+
for (const clang::TemplateArgument &arg : args) {
352+
info.addArgument(
353+
sema_->getTrivialTemplateArgumentLoc(arg, getNTTPType(arg), loc_));
354+
}
355+
return sema_->CheckTemplateIdType(clang::ElaboratedTypeKeyword::None,
356+
clang::TemplateName(decl), loc_, info,
357+
sema_->getCurScope(),
358+
/*ForNestedNameSpecifier=*/false);
359+
}
350360

351-
const auto *hdecl = hint->getAsCXXRecordDecl();
352-
assert(hdecl && "Failed resolving hint record declaration");
353-
assert(hdecl->isCompleteDefinition() && "Incomplete hint");
361+
using MirrorMap = llvm::SmallDenseMap<const clang::ClassTemplateDecl *,
362+
clang::ClassTemplateDecl *>;
354363

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);
364+
clang::TypeSourceInfo *findMatch(MirrorMap &substs, clang::QualType type) {
365+
const auto *tst = type->getAs<clang::TemplateSpecializationType>();
366+
if (!tst) {
367+
return nullptr;
368+
}
369+
370+
const auto *tdecl = llvm::dyn_cast_or_null<clang::ClassTemplateDecl>(
371+
tst->getTemplateName().getAsTemplateDecl());
372+
if (!tdecl) {
373+
return nullptr;
374+
}
375+
376+
if (auto it = substs.find(tdecl->getCanonicalDecl()); it != substs.end()) {
377+
auto match = getTemplateIdType(it->second, tst->template_arguments());
378+
assert(!match.isNull());
379+
return sema_->Context.getTrivialTypeSourceInfo(match, loc_);
362380
}
381+
return nullptr;
382+
}
363383

384+
clang::ClassTemplateDecl *
385+
createInheritingTemplate(llvm::StringRef name, clang::ClassTemplateDecl *decl,
386+
MirrorMap &substs) {
387+
clang::ASTContext &ctx = sema_->Context;
364388
auto *pattern = clang::CXXRecordDecl::Create(
365389
ctx, clang::TagTypeKind::Struct, sema_->CurContext, loc_, loc_,
366390
&ctx.Idents.get(name));
367391

368-
auto *htdecl = hspec->getSpecializedTemplate();
369392
auto *mirror = clang::ClassTemplateDecl::Create(
370393
ctx, sema_->CurContext, loc_,
371394
clang::DeclarationName(&ctx.Idents.get(name)),
372-
htdecl->getTemplateParameters(), pattern);
395+
decl->getTemplateParameters(), pattern);
373396
pattern->setDescribedClassTemplate(mirror);
397+
mirror->setAccess(clang::AS_public);
398+
substs.try_emplace(decl->getCanonicalDecl(), mirror);
374399

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);
400+
clang::QualType base_t = getTemplateIdType(
401+
decl, decl->getTemplateParameters()->getInjectedTemplateArgs(ctx));
384402
assert(!base_t.isNull() && "Failed building mirror base");
385403

386404
pattern->startDefinition();
@@ -390,19 +408,49 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
390408
/*EllipsisLoc=*/clang::SourceLocation());
391409
const clang::CXXBaseSpecifier *bases[] = {&base};
392410
pattern->setBases(bases, 1);
411+
412+
for (auto *member : decl->getTemplatedDecl()->decls()) {
413+
if (const auto *td = llvm::dyn_cast<clang::TypedefNameDecl>(member)) {
414+
if (auto *replacement = findMatch(substs, td->getUnderlyingType())) {
415+
auto *copy = clang::TypedefDecl::Create(
416+
ctx, pattern, loc_, loc_, td->getIdentifier(), replacement);
417+
copy->setAccess(clang::AS_public);
418+
pattern->addDecl(copy);
419+
}
420+
} else if (auto *tdecl =
421+
llvm::dyn_cast<clang::ClassTemplateDecl>(member)) {
422+
clang::Sema::ContextRAII savedContext(*sema_, pattern);
423+
createInheritingTemplate(tdecl->getName(), tdecl, substs);
424+
}
425+
}
426+
393427
pattern->completeDefinition();
394428
sema_->CurContext->addDecl(mirror);
429+
return mirror;
430+
}
395431

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_));
432+
clang::QualType createMirrorType(llvm::StringRef name, clang::QualType hint) {
433+
clang::ASTContext &ctx = sema_->Context;
434+
forceCompleteDefinition(hint);
435+
436+
const auto *hdecl = hint->getAsCXXRecordDecl();
437+
assert(hdecl && "Failed resolving hint record declaration");
438+
assert(hdecl->isCompleteDefinition() && "Incomplete hint");
439+
440+
const auto *hspec =
441+
llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(hdecl);
442+
if (!hspec) {
443+
// if it is not a template specialization inheriting from it suffices
444+
clang::RecordDecl *rdecl = createRecordDecl(name, hint);
445+
return ctx.getTagType(clang::ElaboratedTypeKeyword::None,
446+
rdecl->getQualifier(), rdecl, false);
401447
}
402448

403-
clang::QualType spec = sema_->CheckTemplateIdType(
404-
clang::ElaboratedTypeKeyword::None, clang::TemplateName(mirror), loc_,
405-
args, sema_->getCurScope(), /*ForNestedNameSpecifier=*/false);
449+
MirrorMap substs;
450+
auto *mirror =
451+
createInheritingTemplate(name, hspec->getSpecializedTemplate(), substs);
452+
clang::QualType spec =
453+
getTemplateIdType(mirror, hspec->getTemplateArgs().asArray());
406454
assert(!spec.isNull() && spec->getAsCXXRecordDecl());
407455

408456
// required to print Tn instead of Tn<arg1, arg2, ...>

0 commit comments

Comments
 (0)