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 @@ -2350,6 +2350,15 @@ ParmVarDecl *OldParam, MultiLevelTemplateArgumentList &Args, llvm::SmallVectorImpl &MaterializedTypedefs) { TypeSourceInfo *OldDI = OldParam->getTypeSourceInfo(); + + if (auto *OldTypedefT = OldParam->getType()->getAs()) { + TypedefNameDecl *OldTypedefDecl = OldTypedefT->getDecl(); + auto *CD = cast(OldParam->getDeclContext()); + // If the typedef is not a local typedef, then skip the transform. + if (OldTypedefDecl->getDeclContext() != CD->getDeclContext()) + return OldParam; + } + TypeSourceInfo *NewDI; if (auto PackTL = OldDI->getTypeLoc().getAs()) { // Expand out the one and only element in each inner pack. 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 @@ -5865,6 +5865,56 @@ 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"); + TU->dump(); + 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, DeductionGuideShouldCopyALocalTypedef) { + Decl *TU = getTuDecl( + R"( + template struct A { + typedef T U; + A(U, T); + }; + A a{(int)0, (int)0}; + )", + Lang_CXX17, "input.cc"); + TU->dump(); + 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, );