diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2077,23 +2077,28 @@ QualType TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) { ASTContext &Context = SemaRef.getASTContext(); TypedefNameDecl *OrigDecl = TL.getTypedefNameDecl(); + TypeLocBuilder InnerTLB; QualType Transformed = TransformType(InnerTLB, OrigDecl->getTypeSourceInfo()->getTypeLoc()); TypeSourceInfo *TSI = TransformType(InnerTLB.getTypeSourceInfo(Context, Transformed)); - TypedefNameDecl *Decl = nullptr; - if (isa(OrigDecl)) - Decl = TypeAliasDecl::Create( - Context, Context.getTranslationUnitDecl(), OrigDecl->getBeginLoc(), - OrigDecl->getLocation(), OrigDecl->getIdentifier(), TSI); - else { - assert(isa(OrigDecl) && "Not a Type alias or typedef"); - Decl = TypedefDecl::Create( - Context, Context.getTranslationUnitDecl(), OrigDecl->getBeginLoc(), - OrigDecl->getLocation(), OrigDecl->getIdentifier(), TSI); + TypedefNameDecl *Decl = OrigDecl; + + // Create a new Decl only if the typedef has a dependent context. + if (OrigDecl->getDeclContext()->isDependentContext()) { + if (isa(OrigDecl)) + Decl = TypeAliasDecl::Create( + Context, Context.getTranslationUnitDecl(), OrigDecl->getBeginLoc(), + OrigDecl->getLocation(), OrigDecl->getIdentifier(), TSI); + else { + assert(isa(OrigDecl) && "Not a Type alias or typedef"); + Decl = TypedefDecl::Create( + Context, Context.getTranslationUnitDecl(), OrigDecl->getBeginLoc(), + OrigDecl->getLocation(), OrigDecl->getIdentifier(), TSI); + } } MaterializedTypedefs.push_back(Decl); diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -5884,6 +5884,77 @@ EXPECT_EQ(Record, CompletedTags.front()); } +// FIXME Move these tests out of ASTImporterTest. For that we need to factor +// out the ASTImporter specific pars from ASTImporterOptionSpecificTestBase +// into a new test Fixture. Then we should lift up this Fixture to its own +// implementation file and only then could we reuse the Fixture in other AST +// unitttests. +struct CTAD : ASTImporterOptionSpecificTestBase {}; + +TEST_P(CTAD, DeductionGuideShouldReferToANonLocalTypedef) { + Decl *TU = getTuDecl( + R"( + typedef int U; + template struct A { + A(U, T); + }; + A a{(int)0, (int)0}; + )", + Lang_CXX17, "input.cc"); + auto *Guide = FirstDeclMatcher().match( + TU, cxxDeductionGuideDecl()); + auto *Typedef = FirstDeclMatcher().match( + TU, typedefNameDecl(hasName("U"))); + ParmVarDecl *Param = Guide->getParamDecl(0); + // The type of the first param (which is a typedef) should match the typedef + // in the global scope. + EXPECT_EQ(Param->getType()->getAs()->getDecl(), Typedef); +} + +TEST_P(CTAD, DeductionGuideShouldReferToANonLocalTypedefInParamPtr) { + Decl *TU = getTuDecl( + R"( + typedef int U; + template struct A { + A(U*, T); + }; + A a{(int*)0, (int)0}; + )", + Lang_CXX17, "input.cc"); + auto *Guide = FirstDeclMatcher().match( + TU, cxxDeductionGuideDecl()); + auto *Typedef = FirstDeclMatcher().match( + TU, typedefNameDecl(hasName("U"))); + ParmVarDecl *Param = Guide->getParamDecl(0); + EXPECT_EQ(Param->getType() + ->getAs() + ->getPointeeType() + ->getAs() + ->getDecl(), + Typedef); +} + +TEST_P(CTAD, DeductionGuideShouldCopyALocalTypedef) { + Decl *TU = getTuDecl( + R"( + template struct A { + typedef T U; + A(U, T); + }; + A a{(int)0, (int)0}; + )", + Lang_CXX17, "input.cc"); + auto *Guide = FirstDeclMatcher().match( + TU, cxxDeductionGuideDecl()); + auto *Typedef = FirstDeclMatcher().match( + TU, typedefNameDecl(hasName("U"))); + ParmVarDecl *Param = Guide->getParamDecl(0); + EXPECT_NE(Param->getType()->getAs()->getDecl(), Typedef); +} + +INSTANTIATE_TEST_CASE_P(ParameterizedTests, CTAD, + DefaultTestValuesForRunOptions, ); + INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterLookupTableTest, DefaultTestValuesForRunOptions, );