diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -499,6 +499,7 @@ ExpectedDecl VisitCXXConstructorDecl(CXXConstructorDecl *D); ExpectedDecl VisitCXXDestructorDecl(CXXDestructorDecl *D); ExpectedDecl VisitCXXConversionDecl(CXXConversionDecl *D); + ExpectedDecl VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D); ExpectedDecl VisitFieldDecl(FieldDecl *D); ExpectedDecl VisitIndirectFieldDecl(IndirectFieldDecl *D); ExpectedDecl VisitFriendDecl(FriendDecl *D); @@ -3328,6 +3329,17 @@ return ToPOrErr.takeError(); } + // Common code to import an explicit specifier of different kind of functions. + auto ImportExplicitExpr = [this, &Err](auto *Fun) -> ExpectedExpr { + Expr *ExplicitExpr = nullptr; + if (Fun->getExplicitSpecifier().getExpr()) { + ExplicitExpr = importChecked(Err, Fun->getExplicitSpecifier().getExpr()); + if (Err) + return std::move(Err); + } + return ExplicitExpr; + }; + // Create the imported function. FunctionDecl *ToFunction = nullptr; if (auto *FromConstructor = dyn_cast(D)) { @@ -3369,17 +3381,13 @@ ToDtor->setOperatorDelete(ToOperatorDelete, ToThisArg); } else if (CXXConversionDecl *FromConversion = dyn_cast(D)) { - Expr *ExplicitExpr = nullptr; - if (FromConversion->getExplicitSpecifier().getExpr()) { - auto Imp = import(FromConversion->getExplicitSpecifier().getExpr()); - if (!Imp) - return Imp.takeError(); - ExplicitExpr = *Imp; - } + ExpectedExpr ExplicitExpr = ImportExplicitExpr(FromConversion); + if (!ExplicitExpr) + return ExplicitExpr.takeError(); if (GetImportedOrCreateDecl( ToFunction, D, Importer.getToContext(), cast(DC), ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(), - ExplicitSpecifier(ExplicitExpr, + ExplicitSpecifier(*ExplicitExpr, FromConversion->getExplicitSpecifier().getKind()), D->getConstexprKind(), SourceLocation(), TrailingRequiresClause)) return ToFunction; @@ -3390,6 +3398,18 @@ Method->isInlineSpecified(), D->getConstexprKind(), SourceLocation(), TrailingRequiresClause)) return ToFunction; + } else if (auto *Guide = dyn_cast(D)) { + ExpectedExpr ExplicitExpr = ImportExplicitExpr(Guide); + if (!ExplicitExpr) + return ExplicitExpr.takeError(); + if (GetImportedOrCreateDecl( + ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart, + ExplicitSpecifier(*ExplicitExpr, + Guide->getExplicitSpecifier().getKind()), + NameInfo, T, TInfo, ToEndLoc)) + return ToFunction; + cast(ToFunction) + ->setIsCopyDeductionCandidate(Guide->isCopyDeductionCandidate()); } else { if (GetImportedOrCreateDecl( ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart, @@ -3517,6 +3537,11 @@ return VisitCXXMethodDecl(D); } +ExpectedDecl +ASTNodeImporter::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) { + return VisitFunctionDecl(D); +} + ExpectedDecl ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { // Import the major distinguishing characteristics of a variable. DeclContext *DC, *LexicalDC; 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 @@ -5957,6 +5957,47 @@ EXPECT_EQ(Record, CompletedTags.front()); } +TEST_P(ImportFunctions, CTADImplicit) { + Decl *FromTU = getTuDecl( + R"( + template struct A { + A(T); + }; + A a{(int)0}; + )", + Lang_CXX17, "input.cc"); + auto *FromD = FirstDeclMatcher().match( + FromTU, + cxxDeductionGuideDecl(hasParameter(0, hasType(asString("A"))))); + auto *ToD = Import(FromD, Lang_CXX17); + ASSERT_TRUE(ToD); + EXPECT_TRUE(ToD->isCopyDeductionCandidate()); + // Check that the deduced class template is also imported. + EXPECT_TRUE(findFromTU(FromD)->Importer->GetAlreadyImportedOrNull( + FromD->getDeducedTemplate())); +} + +TEST_P(ImportFunctions, CTADUserDefinedExplicit) { + Decl *FromTU = getTuDecl( + R"( + template struct A { + A(T); + }; + template explicit A(T) -> A; + A a{(int)0}; // calls A::A(float) + )", + Lang_CXX17, "input.cc"); + auto *FromD = FirstDeclMatcher().match( + FromTU, cxxDeductionGuideDecl(unless(isImplicit()))); + // Not-implicit: i.e. not compiler-generated, user defined. + ASSERT_FALSE(FromD->isImplicit()); + ASSERT_TRUE(FromD->isExplicit()); // Has the explicit keyword. + auto *ToD = Import(FromD, Lang_CXX17); + ASSERT_TRUE(ToD); + EXPECT_FALSE(FromD->isImplicit()); + EXPECT_TRUE(ToD->isExplicit()); +} + INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterLookupTableTest, DefaultTestValuesForRunOptions, );