https://github.com/sdkrystian updated https://github.com/llvm/llvm-project/pull/90760
>From a30530b4de31fab70911cb7b51e7a7e274fd2a38 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Wed, 1 May 2024 10:54:12 -0400 Subject: [PATCH 1/4] [Clang][Sema] Explicit template arguments are not substituted into the exception specification of a function --- clang/lib/Sema/SemaTemplateDeduction.cpp | 17 ----------------- clang/test/CXX/temp/temp.deduct/p7.cpp | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 17 deletions(-) create mode 100644 clang/test/CXX/temp/temp.deduct/p7.cpp diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 9f9e4422827173..026ce6db1c8eb9 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -3509,23 +3509,6 @@ TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( if (FunctionType) { auto EPI = Proto->getExtProtoInfo(); EPI.ExtParameterInfos = ExtParamInfos.getPointerOrNull(ParamTypes.size()); - - // In C++1z onwards, exception specifications are part of the function type, - // so substitution into the type must also substitute into the exception - // specification. - SmallVector<QualType, 4> ExceptionStorage; - if (getLangOpts().CPlusPlus17 && - SubstExceptionSpec( - Function->getLocation(), EPI.ExceptionSpec, ExceptionStorage, - getTemplateInstantiationArgs( - FunctionTemplate, nullptr, /*Final=*/true, - /*Innermost=*/SugaredExplicitArgumentList->asArray(), - /*RelativeToPrimary=*/false, - /*Pattern=*/nullptr, - /*ForConstraintInstantiation=*/false, - /*SkipForSpecialization=*/true))) - return TemplateDeductionResult::SubstitutionFailure; - *FunctionType = BuildFunctionType(ResultType, ParamTypes, Function->getLocation(), Function->getDeclName(), diff --git a/clang/test/CXX/temp/temp.deduct/p7.cpp b/clang/test/CXX/temp/temp.deduct/p7.cpp new file mode 100644 index 00000000000000..cf6d17fc51ac95 --- /dev/null +++ b/clang/test/CXX/temp/temp.deduct/p7.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -verify %s + +struct A { + static constexpr bool x = true; +}; + +template<typename T, typename U> +void f(T, U) noexcept(T::x); + +template<typename T, typename U> +void f(T, U*) noexcept(T::y); // expected-error {{no member named 'y' in 'A'}} + +template<> +void f<A>(A, int*); // expected-note {{in instantiation of exception specification}} >From 9172000c589d7235e0e93d22b10017d25b3df1fd Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Wed, 1 May 2024 14:14:28 -0400 Subject: [PATCH 2/4] [FOLD] --- clang/lib/Sema/SemaInit.cpp | 24 ++++++++++++++----- clang/lib/Sema/SemaTemplateDeduction.cpp | 11 ++------- clang/test/CXX/drs/dr13xx.cpp | 13 ++++------ .../SemaCXX/cxx1z-noexcept-function-type.cpp | 4 ++-- clang/test/SemaTemplate/temp_arg_type.cpp | 10 ++++---- 5 files changed, 31 insertions(+), 31 deletions(-) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 7d9eaf6720461d..c8049ae581f843 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -6576,12 +6576,12 @@ void InitializationSequence::InitializeFrom(Sema &S, AddPassByIndirectCopyRestoreStep(DestType, ShouldCopy); } else if (ICS.isBad()) { - DeclAccessPair dap; - if (isLibstdcxxPointerReturnFalseHack(S, Entity, Initializer)) { + if (isLibstdcxxPointerReturnFalseHack(S, Entity, Initializer)) AddZeroInitializationStep(Entity.getType()); - } else if (Initializer->getType() == Context.OverloadTy && - !S.ResolveAddressOfOverloadedFunction(Initializer, DestType, - false, dap)) + else if (DeclAccessPair Found; + Initializer->getType() == Context.OverloadTy && + !S.ResolveAddressOfOverloadedFunction(Initializer, DestType, + /*Complain=*/false, Found)) SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); else if (Initializer->getType()->isFunctionType() && isExprAnUnaddressableFunction(S, Initializer)) @@ -9641,6 +9641,8 @@ bool InitializationSequence::Diagnose(Sema &S, if (!Failed()) return false; + QualType DestType = Entity.getType(); + // When we want to diagnose only one element of a braced-init-list, // we need to factor it out. Expr *OnlyArg; @@ -9650,11 +9652,21 @@ bool InitializationSequence::Diagnose(Sema &S, OnlyArg = List->getInit(0); else OnlyArg = Args[0]; + + if (OnlyArg->getType() == S.Context.OverloadTy) { + DeclAccessPair Found; + if (FunctionDecl *FD = S.ResolveAddressOfOverloadedFunction( + OnlyArg, DestType.getNonReferenceType(), /*Complain=*/false, + Found)) { + if (Expr *Resolved = + S.FixOverloadedFunctionReference(OnlyArg, Found, FD).get()) + OnlyArg = Resolved; + } + } } else OnlyArg = nullptr; - QualType DestType = Entity.getType(); switch (Failure) { case FK_TooManyInitsForReference: // FIXME: Customize for the initialized entity? diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 026ce6db1c8eb9..942b84488004fd 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -1325,11 +1325,11 @@ bool Sema::isSameOrCompatibleFunctionType(QualType P, QualType A) { // Noreturn and noexcept adjustment. QualType AdjustedParam; if (IsFunctionConversion(P, A, AdjustedParam)) - return Context.hasSameType(AdjustedParam, A); + return Context.hasSameFunctionTypeIgnoringExceptionSpec(AdjustedParam, A); // FIXME: Compatible calling conventions. - return Context.hasSameType(P, A); + return Context.hasSameFunctionTypeIgnoringExceptionSpec(P, A); } /// Get the index of the first template parameter that was originally from the @@ -4688,13 +4688,6 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( Info.getLocation())) return TemplateDeductionResult::MiscellaneousDeductionFailure; - auto *SpecializationFPT = - Specialization->getType()->castAs<FunctionProtoType>(); - if (IsAddressOfFunction && getLangOpts().CPlusPlus17 && - isUnresolvedExceptionSpec(SpecializationFPT->getExceptionSpecType()) && - !ResolveExceptionSpec(Info.getLocation(), SpecializationFPT)) - return TemplateDeductionResult::MiscellaneousDeductionFailure; - // Adjust the exception specification of the argument to match the // substituted and resolved type we just formed. (Calling convention and // noreturn can't be dependent, so we don't actually need this for them diff --git a/clang/test/CXX/drs/dr13xx.cpp b/clang/test/CXX/drs/dr13xx.cpp index dad82c4e2829f0..a334b6d01acf51 100644 --- a/clang/test/CXX/drs/dr13xx.cpp +++ b/clang/test/CXX/drs/dr13xx.cpp @@ -281,13 +281,10 @@ namespace cwg1330 { // cwg1330: 4 c++11 decltype(f<char>()) f2; // #cwg1330-f-char bool f3 = noexcept(f<float>()); /// #cwg1330-f-float #endif - // In C++17 onwards, substituting explicit template arguments into the - // function type substitutes into the exception specification (because it's - // part of the type). In earlier languages, we don't notice there's a problem - // until we've already started to instantiate. template int f<short>(); // #cwg1330-f-short - // since-cxx17-error@-1 {{explicit instantiation of 'f' does not refer to a function template, variable template, member function, member class, or static data member}} - // since-cxx17-note@#cwg1330-f {{candidate template ignored: substitution failure [with T = short]: type 'short' cannot be used prior to '::' because it has no members}} + // since-cxx17-error@#cwg1330-f {{type 'short' cannot be used prior to '::' because it has no members}} + // since-cxx17-note@#cwg1330-f {{in instantiation of exception specification for 'f<short>' requested here}} + // since-cxx17-note@#cwg1330-f-short {{in instantiation of function template specialization 'cwg1330::f<short>' requested here}} template<typename T> struct C { C() throw(typename T::type); // #cwg1330-C @@ -500,7 +497,7 @@ namespace cwg1359 { // cwg1359: 3.5 union B { constexpr B() = default; int a; }; // #cwg1359-B // cxx11-17-error@-1 {{defaulted definition of default constructor cannot be marked constexpr before C++23}} union C { constexpr C() = default; int a, b; }; // #cwg1359-C - // cxx11-17-error@-1 {{defaulted definition of default constructor cannot be marked constexpr}} + // cxx11-17-error@-1 {{defaulted definition of default constructor cannot be marked constexpr}} struct X { constexpr X() = default; union {}; }; // since-cxx11-error@-1 {{declaration does not declare anything}} struct Y { constexpr Y() = default; union { int a; }; }; // #cwg1359-Y @@ -720,7 +717,7 @@ struct A { } // namespace cwg1397 namespace cwg1399 { // cwg1399: dup 1388 - template<typename ...T> void f(T..., int, T...) {} // #cwg1399-f + template<typename ...T> void f(T..., int, T...) {} // #cwg1399-f // cxx98-error@-1 {{variadic templates are a C++11 extension}} void g() { f(0); diff --git a/clang/test/SemaCXX/cxx1z-noexcept-function-type.cpp b/clang/test/SemaCXX/cxx1z-noexcept-function-type.cpp index 5e56f19477d6ca..c8204c21523a37 100644 --- a/clang/test/SemaCXX/cxx1z-noexcept-function-type.cpp +++ b/clang/test/SemaCXX/cxx1z-noexcept-function-type.cpp @@ -18,7 +18,7 @@ template<typename A, typename B> void redecl3() throw(B); // expected-error {{do typedef int I; template<bool B> void redecl4(I) noexcept(B); -template<bool B> void redecl4(I) noexcept(B); // expected-note {{could not match 'void (I) noexcept(false)' (aka 'void (int) noexcept(false)') against 'void (int) noexcept'}} +template<bool B> void redecl4(I) noexcept(B); void (*init_with_exact_type_a)(int) noexcept = redecl4<true>; void (*init_with_mismatched_type_a)(int) = redecl4<true>; @@ -27,7 +27,7 @@ using DeducedType_a = decltype(deduce_auto_from_noexcept_function_ptr_a); using DeducedType_a = void (*)(int) noexcept; void (*init_with_exact_type_b)(int) = redecl4<false>; -void (*init_with_mismatched_type_b)(int) noexcept = redecl4<false>; // expected-error {{does not match required type}} +void (*init_with_mismatched_type_b)(int) noexcept = redecl4<false>; // expected-error {{cannot initialize a variable of type}} auto deduce_auto_from_noexcept_function_ptr_b = redecl4<false>; using DeducedType_b = decltype(deduce_auto_from_noexcept_function_ptr_b); using DeducedType_b = void (*)(int); diff --git a/clang/test/SemaTemplate/temp_arg_type.cpp b/clang/test/SemaTemplate/temp_arg_type.cpp index 9069f63e0224fe..cdbcf281125efd 100644 --- a/clang/test/SemaTemplate/temp_arg_type.cpp +++ b/clang/test/SemaTemplate/temp_arg_type.cpp @@ -11,7 +11,7 @@ A<0> *a1; // expected-error{{template argument for template type parameter must A<A> *a2; // expected-error{{use of class template 'A' requires template arguments}} A<int> *a3; -A<int()> *a4; +A<int()> *a4; A<int(float)> *a5; A<A<int> > *a6; @@ -95,15 +95,13 @@ namespace deduce_noexcept { template void dep() noexcept(true); // expected-error {{does not refer to a function template}} template void dep() noexcept(false); // expected-error {{does not refer to a function template}} - // FIXME: It's also not clear whether this should be valid: do we substitute - // into the function type (including the exception specification) or not? - template<typename T> typename T::type1 f() noexcept(T::a); - template<typename T> typename T::type2 f() noexcept(T::b) {} + template<typename T> typename T::type1 f() noexcept(T::a); // expected-note {{candidate}} + template<typename T> typename T::type2 f() noexcept(T::b) {} // expected-note {{candidate}} struct X { static constexpr bool b = true; using type1 = void; using type2 = void; }; - template void f<X>(); + template void f<X>(); // expected-error {{partial ordering for explicit instantiation of 'f' is ambiguous}} } #endif >From 6815127e8eba99734a1cf88c5a82d82dc0ed7896 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Mon, 6 May 2024 06:40:53 -0400 Subject: [PATCH 3/4] [FOLD] add release note --- clang/docs/ReleaseNotes.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index b146a9b56884ad..52bec6a499abd7 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -683,6 +683,8 @@ Bug Fixes to C++ Support - Fix an assertion failure when parsing an invalid members of an anonymous class. (#GH85447) - Fixed a misuse of ``UnresolvedLookupExpr`` for ill-formed templated expressions. Fixes (#GH48673), (#GH63243) and (#GH88832). +- Clang now defers all substitution into the exception specification of a function template specialization + until the noexcept-specifier is instantiated. Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ >From 196871c57eecdef0134bb5070eb88730a2ca5eee Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Mon, 6 May 2024 12:50:52 -0400 Subject: [PATCH 4/4] [FOLD] refactor isSameOrCompatibleFunctionType --- clang/lib/Sema/SemaTemplateDeduction.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 942b84488004fd..dcaea4a77bffd2 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -1323,12 +1323,10 @@ bool Sema::isSameOrCompatibleFunctionType(QualType P, QualType A) { return Context.hasSameType(P, A); // Noreturn and noexcept adjustment. - QualType AdjustedParam; - if (IsFunctionConversion(P, A, AdjustedParam)) - return Context.hasSameFunctionTypeIgnoringExceptionSpec(AdjustedParam, A); + if (QualType AdjustedParam; IsFunctionConversion(P, A, AdjustedParam)) + P = AdjustedParam; // FIXME: Compatible calling conventions. - return Context.hasSameFunctionTypeIgnoringExceptionSpec(P, A); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits