diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 5086a56eb496a5e8bff3c86613e2338c852004eb..05dad41c07faf0cae49dfb7fb0459e130edfb9a3 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -860,6 +860,10 @@ Bug Fixes to C++ Support (`#64172 `_) and (`#64723 `_). +- Clang now defers the instantiation of explicit specifier until constraint checking + completes (except deduction guides). Fixes: + (`#59827 `_) + Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 3752a23faa85cb5fd2b1868fda35fc98165a427b..b2ab6d0f8445728489e4c6423440a256d4e2b3f6 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10293,6 +10293,9 @@ public: const CXXConstructorDecl *Tmpl, const MultiLevelTemplateArgumentList &TemplateArgs); + ExplicitSpecifier instantiateExplicitSpecifier( + const MultiLevelTemplateArgumentList &TemplateArgs, ExplicitSpecifier ES); + NamedDecl *FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs, bool FindingInstantiatedContext = false); diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 31ea7be2975e49616d2a2cefbe10c35497907cb5..58dd1b783bacd8a7cf75b3475be94b761518e69e 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -3546,6 +3546,48 @@ static unsigned getPackIndexForParam(Sema &S, llvm_unreachable("parameter index would not be produced from template"); } +// if `Specialization` is a `CXXConstructorDecl` or `CXXConversionDecl`, +// we'll try to instantiate and update its explicit specifier after constraint +// checking. +static Sema::TemplateDeductionResult instantiateExplicitSpecifierDeferred( + Sema &S, FunctionDecl *Specialization, + const MultiLevelTemplateArgumentList &SubstArgs, + TemplateDeductionInfo &Info, FunctionTemplateDecl *FunctionTemplate, + ArrayRef DeducedArgs) { + auto GetExplicitSpecifier = [](FunctionDecl *D) { + return isa(D) + ? cast(D)->getExplicitSpecifier() + : cast(D)->getExplicitSpecifier(); + }; + auto SetExplicitSpecifier = [](FunctionDecl *D, ExplicitSpecifier ES) { + isa(D) + ? cast(D)->setExplicitSpecifier(ES) + : cast(D)->setExplicitSpecifier(ES); + }; + + ExplicitSpecifier ES = GetExplicitSpecifier(Specialization); + Expr *ExplicitExpr = ES.getExpr(); + if (!ExplicitExpr) + return Sema::TDK_Success; + if (!ExplicitExpr->isValueDependent()) + return Sema::TDK_Success; + + Sema::InstantiatingTemplate Inst( + S, Info.getLocation(), FunctionTemplate, DeducedArgs, + Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution, Info); + if (Inst.isInvalid()) + return Sema::TDK_InstantiationDepth; + Sema::SFINAETrap Trap(S); + const ExplicitSpecifier InstantiatedES = + S.instantiateExplicitSpecifier(SubstArgs, ES); + if (InstantiatedES.isInvalid() || Trap.hasErrorOccurred()) { + Specialization->setInvalidDecl(true); + return Sema::TDK_SubstitutionFailure; + } + SetExplicitSpecifier(Specialization, InstantiatedES); + return Sema::TDK_Success; +} + /// Finish template argument deduction for a function template, /// checking the deduced template arguments for completeness and forming /// the function template specialization. @@ -3675,6 +3717,17 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( } } + // We skipped the instantiation of the explicit-specifier during the + // substitution of `FD` before. So, we try to instantiate it back if + // `Specialization` is either a constructor or a conversion function. + if (isa(Specialization)) { + if (TDK_Success != instantiateExplicitSpecifierDeferred( + *this, Specialization, SubstArgs, Info, + FunctionTemplate, DeducedArgs)) { + return TDK_SubstitutionFailure; + } + } + if (OriginalCallArgs) { // C++ [temp.deduct.call]p4: // In general, the deduction process attempts to find template argument diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index f78d46f5950360b3deaae7959600870e10eedd17..a40510ce5f2cf274b6a228e707dbdda4803bf0a2 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -555,18 +555,16 @@ static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr( S.addAMDGPUFlatWorkGroupSizeAttr(New, Attr, MinExpr, MaxExpr); } -static ExplicitSpecifier -instantiateExplicitSpecifier(Sema &S, - const MultiLevelTemplateArgumentList &TemplateArgs, - ExplicitSpecifier ES, FunctionDecl *New) { +ExplicitSpecifier Sema::instantiateExplicitSpecifier( + const MultiLevelTemplateArgumentList &TemplateArgs, ExplicitSpecifier ES) { if (!ES.getExpr()) return ES; Expr *OldCond = ES.getExpr(); Expr *Cond = nullptr; { EnterExpressionEvaluationContext Unevaluated( - S, Sema::ExpressionEvaluationContext::ConstantEvaluated); - ExprResult SubstResult = S.SubstExpr(OldCond, TemplateArgs); + *this, Sema::ExpressionEvaluationContext::ConstantEvaluated); + ExprResult SubstResult = SubstExpr(OldCond, TemplateArgs); if (SubstResult.isInvalid()) { return ExplicitSpecifier::Invalid(); } @@ -574,7 +572,7 @@ instantiateExplicitSpecifier(Sema &S, } ExplicitSpecifier Result(Cond, ES.getKind()); if (!Cond->isTypeDependent()) - S.tryResolveExplicitSpecifier(Result); + tryResolveExplicitSpecifier(Result); return Result; } @@ -2065,8 +2063,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( ExplicitSpecifier InstantiatedExplicitSpecifier; if (auto *DGuide = dyn_cast(D)) { - InstantiatedExplicitSpecifier = instantiateExplicitSpecifier( - SemaRef, TemplateArgs, DGuide->getExplicitSpecifier(), DGuide); + InstantiatedExplicitSpecifier = SemaRef.instantiateExplicitSpecifier( + TemplateArgs, DGuide->getExplicitSpecifier()); if (InstantiatedExplicitSpecifier.isInvalid()) return nullptr; } @@ -2440,11 +2438,25 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( } } - ExplicitSpecifier InstantiatedExplicitSpecifier = - instantiateExplicitSpecifier(SemaRef, TemplateArgs, - ExplicitSpecifier::getFromDecl(D), D); - if (InstantiatedExplicitSpecifier.isInvalid()) - return nullptr; + auto InstantiatedExplicitSpecifier = ExplicitSpecifier::getFromDecl(D); + // deduction guides need this + const bool CouldInstantiate = + InstantiatedExplicitSpecifier.getExpr() == nullptr || + !InstantiatedExplicitSpecifier.getExpr()->isValueDependent(); + + // Delay the instantiation of the explicit-specifier until after the + // constraints are checked during template argument deduction. + if (CouldInstantiate || + SemaRef.CodeSynthesisContexts.back().Kind != + Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution) { + InstantiatedExplicitSpecifier = SemaRef.instantiateExplicitSpecifier( + TemplateArgs, InstantiatedExplicitSpecifier); + + if (InstantiatedExplicitSpecifier.isInvalid()) + return nullptr; + } else { + InstantiatedExplicitSpecifier.setKind(ExplicitSpecKind::Unresolved); + } // Implicit destructors/constructors created for local classes in // DeclareImplicit* (see SemaDeclCXX.cpp) might not have an associated TSI. diff --git a/clang/test/SemaCXX/cxx2a-explicit-bool-deferred.cpp b/clang/test/SemaCXX/cxx2a-explicit-bool-deferred.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4d667008f2e2763b2b68457f3c214f6045be292a --- /dev/null +++ b/clang/test/SemaCXX/cxx2a-explicit-bool-deferred.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2a %s + +template struct is_same { + static constexpr bool value = false; +}; + +template struct is_same { + static constexpr bool value = true; +}; + +template +concept SameHelper = is_same::value; +template +concept same_as = SameHelper && SameHelper; + +namespace deferred_instantiation { +template constexpr X do_not_instantiate() { return nullptr; } + +struct T { + template X> explicit(do_not_instantiate()) T(X) {} + + T(int) {} +}; + +T t(5); +// expected-error@17{{cannot initialize}} +// expected-note@20{{in instantiation of function template specialization}} +// expected-note@30{{while substituting deduced template arguments}} +// expected-note@30{{in instantiation of function template specialization}} +T t2(5.0f); +} // namespace deferred_instantiation