Skip to content

Commit

Permalink
[Clang][Sema] Defer instantiation of exception specification until af…
Browse files Browse the repository at this point in the history
…ter partial ordering when determining primary template
  • Loading branch information
sdkrystian committed Feb 20, 2024
1 parent fb615cf commit 16b6ce3
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 22 deletions.
10 changes: 9 additions & 1 deletion clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9706,9 +9706,17 @@ bool Sema::CheckFunctionTemplateSpecialization(
if (Result == Candidates.end())
return true;

// Ignore access information; it doesn't figure into redeclaration checking.
FunctionDecl *Specialization = cast<FunctionDecl>(*Result);
auto *SpecializationFPT =
Specialization->getType()->castAs<FunctionProtoType>();
// If the function has a dependent exception specification, resolve it after
// we have selected the primary template so we can check whether it matches.
if (getLangOpts().CPlusPlus17 &&
isUnresolvedExceptionSpec(SpecializationFPT->getExceptionSpecType()) &&
!ResolveExceptionSpec(FD->getLocation(), SpecializationFPT))
return true;

// Ignore access information; it doesn't figure into redeclaration checking.
FunctionTemplateSpecializationInfo *SpecInfo
= Specialization->getTemplateSpecializationInfo();
assert(SpecInfo && "Function template specialization info missing?");
Expand Down
14 changes: 6 additions & 8 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4632,11 +4632,9 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
Info.getLocation()))
return TemplateDeductionResult::MiscellaneousDeductionFailure;

// If the function has a dependent exception specification, resolve it now,
// so we can check that the exception specification matches.
auto *SpecializationFPT =
Specialization->getType()->castAs<FunctionProtoType>();
if (getLangOpts().CPlusPlus17 &&
if (IsAddressOfFunction && getLangOpts().CPlusPlus17 &&
isUnresolvedExceptionSpec(SpecializationFPT->getExceptionSpecType()) &&
!ResolveExceptionSpec(Info.getLocation(), SpecializationFPT))
return TemplateDeductionResult::MiscellaneousDeductionFailure;
Expand All @@ -4662,11 +4660,11 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
// specialization with respect to arguments of compatible pointer to function
// types, template argument deduction fails.
if (!ArgFunctionType.isNull()) {
if (IsAddressOfFunction
? !isSameOrCompatibleFunctionType(
Context.getCanonicalType(SpecializationType),
Context.getCanonicalType(ArgFunctionType))
: !Context.hasSameType(SpecializationType, ArgFunctionType)) {
if (IsAddressOfFunction ? !isSameOrCompatibleFunctionType(
Context.getCanonicalType(SpecializationType),
Context.getCanonicalType(ArgFunctionType))
: !Context.hasSameFunctionTypeIgnoringExceptionSpec(
SpecializationType, ArgFunctionType)) {
Info.FirstArg = TemplateArgument(SpecializationType);
Info.SecondArg = TemplateArgument(ArgFunctionType);
return TemplateDeductionResult::NonDeducedMismatch;
Expand Down
38 changes: 38 additions & 0 deletions clang/test/CXX/except/except.spec/p13.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// RUN: %clang_cc1 -fexceptions -fcxx-exceptions -fsyntax-only -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::x);

template<typename T, typename U>
void f(T, U**) noexcept(T::y); // expected-error {{no member named 'y' in 'A'}}

template<typename T, typename U>
void f(T, U***) noexcept(T::x);

template<>
void f(A, int*) noexcept; // expected-note {{previous declaration is here}}

template<>
void f(A, int*); // expected-error {{'f<A, int>' is missing exception specification 'noexcept'}}

template<>
void f(A, int**) noexcept; // expected-error {{exception specification in declaration does not match previous declaration}}
// expected-note@-1 {{in instantiation of exception specification for 'f<A, int>' requested here}}
// expected-note@-2 {{previous declaration is here}}

// FIXME: Exception specification is currently set to EST_None if instantiation fails.
template<>
void f(A, int**);

template<>
void f(A, int***) noexcept; // expected-note {{previous declaration is here}}

template<>
void f(A, int***); // expected-error {{'f<A, int>' is missing exception specification 'noexcept'}}
14 changes: 1 addition & 13 deletions clang/test/SemaTemplate/class-template-noexcept.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
// RUN: %clang_cc1 -std=c++11 -verify %s
// RUN: %clang_cc1 -std=c++17 -verify %s
// RUN: %clang_cc1 -std=c++1z -verify %s
#if __cplusplus >= 201703
// expected-no-diagnostics
#endif

class A {
public:
static const char X;
Expand All @@ -14,19 +12,9 @@ const char A::X = 0;
template<typename U> void func() noexcept(U::X);

template<class... B, char x>
#if __cplusplus >= 201703
void foo(void(B...) noexcept(x)) {}
#else
void foo(void(B...) noexcept(x)) {} // expected-note{{candidate template ignored}}
#endif

void bar()
{
#if __cplusplus >= 201703
foo(func<A>);
#else
foo(func<A>); // expected-error{{no matching function for call}}
#endif
}


0 comments on commit 16b6ce3

Please sign in to comment.