Skip to content

Commit 1e14588

Browse files
author
Gabor Marton
committed
[Clang][Sema] Attempt to fix CTAD faulty copy of non-local typedefs
http://lists.llvm.org/pipermail/cfe-dev/2020-November/067252.html Differential Revision: https://reviews.llvm.org/D92101
1 parent 7ec6188 commit 1e14588

File tree

2 files changed

+91
-19
lines changed

2 files changed

+91
-19
lines changed

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2077,27 +2077,28 @@ class ExtractTypeForDeductionGuide
20772077
QualType TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) {
20782078
ASTContext &Context = SemaRef.getASTContext();
20792079
TypedefNameDecl *OrigDecl = TL.getTypedefNameDecl();
2080-
TypeLocBuilder InnerTLB;
2081-
QualType Transformed =
2082-
TransformType(InnerTLB, OrigDecl->getTypeSourceInfo()->getTypeLoc());
2083-
TypeSourceInfo *TSI =
2084-
TransformType(InnerTLB.getTypeSourceInfo(Context, Transformed));
2085-
2086-
TypedefNameDecl *Decl = nullptr;
2087-
2088-
if (isa<TypeAliasDecl>(OrigDecl))
2089-
Decl = TypeAliasDecl::Create(
2090-
Context, Context.getTranslationUnitDecl(), OrigDecl->getBeginLoc(),
2091-
OrigDecl->getLocation(), OrigDecl->getIdentifier(), TSI);
2092-
else {
2093-
assert(isa<TypedefDecl>(OrigDecl) && "Not a Type alias or typedef");
2094-
Decl = TypedefDecl::Create(
2095-
Context, Context.getTranslationUnitDecl(), OrigDecl->getBeginLoc(),
2096-
OrigDecl->getLocation(), OrigDecl->getIdentifier(), TSI);
2080+
TypedefNameDecl *Decl = OrigDecl;
2081+
// Transform the underlying type of the typedef and clone the Decl only if
2082+
// the typedef has a dependent context.
2083+
if (OrigDecl->getDeclContext()->isDependentContext()) {
2084+
TypeLocBuilder InnerTLB;
2085+
QualType Transformed =
2086+
TransformType(InnerTLB, OrigDecl->getTypeSourceInfo()->getTypeLoc());
2087+
TypeSourceInfo *TSI =
2088+
TransformType(InnerTLB.getTypeSourceInfo(Context, Transformed));
2089+
if (isa<TypeAliasDecl>(OrigDecl))
2090+
Decl = TypeAliasDecl::Create(
2091+
Context, Context.getTranslationUnitDecl(), OrigDecl->getBeginLoc(),
2092+
OrigDecl->getLocation(), OrigDecl->getIdentifier(), TSI);
2093+
else {
2094+
assert(isa<TypedefDecl>(OrigDecl) && "Not a Type alias or typedef");
2095+
Decl = TypedefDecl::Create(
2096+
Context, Context.getTranslationUnitDecl(), OrigDecl->getBeginLoc(),
2097+
OrigDecl->getLocation(), OrigDecl->getIdentifier(), TSI);
2098+
}
2099+
MaterializedTypedefs.push_back(Decl);
20972100
}
20982101

2099-
MaterializedTypedefs.push_back(Decl);
2100-
21012102
QualType TDTy = Context.getTypedefType(Decl);
21022103
TypedefTypeLoc TypedefTL = TLB.push<TypedefTypeLoc>(TDTy);
21032104
TypedefTL.setNameLoc(TL.getNameLoc());

clang/unittests/AST/ASTImporterTest.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5998,6 +5998,77 @@ TEST_P(ImportFunctions, CTADUserDefinedExplicit) {
59985998
EXPECT_TRUE(ToD->isExplicit());
59995999
}
60006000

6001+
// FIXME Move these tests out of ASTImporterTest. For that we need to factor
6002+
// out the ASTImporter specific pars from ASTImporterOptionSpecificTestBase
6003+
// into a new test Fixture. Then we should lift up this Fixture to its own
6004+
// implementation file and only then could we reuse the Fixture in other AST
6005+
// unitttests.
6006+
struct CTAD : ASTImporterOptionSpecificTestBase {};
6007+
6008+
TEST_P(CTAD, DeductionGuideShouldReferToANonLocalTypedef) {
6009+
Decl *TU = getTuDecl(
6010+
R"(
6011+
typedef int U;
6012+
template <typename T> struct A {
6013+
A(U, T);
6014+
};
6015+
A a{(int)0, (int)0};
6016+
)",
6017+
Lang_CXX17, "input.cc");
6018+
auto *Guide = FirstDeclMatcher<CXXDeductionGuideDecl>().match(
6019+
TU, cxxDeductionGuideDecl());
6020+
auto *Typedef = FirstDeclMatcher<TypedefNameDecl>().match(
6021+
TU, typedefNameDecl(hasName("U")));
6022+
ParmVarDecl *Param = Guide->getParamDecl(0);
6023+
// The type of the first param (which is a typedef) should match the typedef
6024+
// in the global scope.
6025+
EXPECT_EQ(Param->getType()->getAs<TypedefType>()->getDecl(), Typedef);
6026+
}
6027+
6028+
TEST_P(CTAD, DeductionGuideShouldReferToANonLocalTypedefInParamPtr) {
6029+
Decl *TU = getTuDecl(
6030+
R"(
6031+
typedef int U;
6032+
template <typename T> struct A {
6033+
A(U*, T);
6034+
};
6035+
A a{(int*)0, (int)0};
6036+
)",
6037+
Lang_CXX17, "input.cc");
6038+
auto *Guide = FirstDeclMatcher<CXXDeductionGuideDecl>().match(
6039+
TU, cxxDeductionGuideDecl());
6040+
auto *Typedef = FirstDeclMatcher<TypedefNameDecl>().match(
6041+
TU, typedefNameDecl(hasName("U")));
6042+
ParmVarDecl *Param = Guide->getParamDecl(0);
6043+
EXPECT_EQ(Param->getType()
6044+
->getAs<PointerType>()
6045+
->getPointeeType()
6046+
->getAs<TypedefType>()
6047+
->getDecl(),
6048+
Typedef);
6049+
}
6050+
6051+
TEST_P(CTAD, DeductionGuideShouldCopyALocalTypedef) {
6052+
Decl *TU = getTuDecl(
6053+
R"(
6054+
template <typename T> struct A {
6055+
typedef T U;
6056+
A(U, T);
6057+
};
6058+
A a{(int)0, (int)0};
6059+
)",
6060+
Lang_CXX17, "input.cc");
6061+
auto *Guide = FirstDeclMatcher<CXXDeductionGuideDecl>().match(
6062+
TU, cxxDeductionGuideDecl());
6063+
auto *Typedef = FirstDeclMatcher<TypedefNameDecl>().match(
6064+
TU, typedefNameDecl(hasName("U")));
6065+
ParmVarDecl *Param = Guide->getParamDecl(0);
6066+
EXPECT_NE(Param->getType()->getAs<TypedefType>()->getDecl(), Typedef);
6067+
}
6068+
6069+
INSTANTIATE_TEST_CASE_P(ParameterizedTests, CTAD,
6070+
DefaultTestValuesForRunOptions, );
6071+
60016072
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterLookupTableTest,
60026073
DefaultTestValuesForRunOptions, );
60036074

0 commit comments

Comments
 (0)