From f945e9022eef9de82804907e77cc29ccc9e5be1a Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Thu, 6 Nov 2014 10:10:50 +0000 Subject: Fix for exception specification mismatch in explicit instantiation. According to C++ standard if an exception-specification is specified in an explicit instantiation directive, it shall be compatible with the exception-specifications of other declarations of that function. This patch adds checks for this. Differential Revision: http://reviews.llvm.org/D5822 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@221448 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 5 +++++ lib/Sema/SemaTemplate.cpp | 23 +++++++++++++++++++++++ test/SemaTemplate/explicit-instantiation.cpp | 23 +++++++++++++++++++---- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 6503aef324..9f561164c5 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -3658,6 +3658,11 @@ def err_invalid_var_template_spec_type : Error<"type %2 " "of %select{explicit instantiation|explicit specialization|" "partial specialization|redeclaration}0 of %1 does not match" " expected type %3">; +def err_mismatched_exception_spec_explicit_instantiation : Error< + "exception specification in explicit instantiation does not match instantiated one">; +def ext_mismatched_exception_spec_explicit_instantiation : ExtWarn< + "exception specification in explicit instantiation does not match instantiated one">, + InGroup; // C++ typename-specifiers def err_typename_nested_not_found : Error<"no type named %0 in %1">; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 57d1ab8d75..1bddfe2184 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -7627,6 +7627,29 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // Ignore access control bits, we don't need them for redeclaration checking. FunctionDecl *Specialization = cast(*Result); + // C++11 [except.spec]p4 + // In an explicit instantiation an exception-specification may be specified, + // but is not required. + // If an exception-specification is specified in an explicit instantiation + // directive, it shall be compatible with the exception-specifications of + // other declarations of that function. + if (auto *FPT = R->getAs()) + if (FPT->hasExceptionSpec()) { + unsigned DiagID = + diag::err_mismatched_exception_spec_explicit_instantiation; + if (getLangOpts().MicrosoftExt) + DiagID = diag::ext_mismatched_exception_spec_explicit_instantiation; + bool Result = CheckEquivalentExceptionSpec( + PDiag(DiagID) << Specialization->getType(), + PDiag(diag::note_explicit_instantiation_here), + Specialization->getType()->getAs(), + Specialization->getLocation(), FPT, D.getLocStart()); + // In Microsoft mode, mismatching exception specifications just cause a + // warning. + if (!getLangOpts().MicrosoftExt && Result) + return true; + } + if (Specialization->getTemplateSpecializationKind() == TSK_Undeclared) { Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_member_function_not_instantiated) diff --git a/test/SemaTemplate/explicit-instantiation.cpp b/test/SemaTemplate/explicit-instantiation.cpp index c28c5d1831..71121ad2b3 100644 --- a/test/SemaTemplate/explicit-instantiation.cpp +++ b/test/SemaTemplate/explicit-instantiation.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -fexceptions -fcxx-exceptions %s +// RUN: %clang_cc1 -fsyntax-only -verify -fexceptions -fcxx-exceptions -std=c++11 %s template void *; // expected-error{{expected unqualified-id}} @@ -13,8 +14,8 @@ struct X0 { T f0(T x) { return x + 1; // expected-error{{invalid operands}} - } - T* f0(T*, T*) { return T(); } // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int *'}} + } + T *f0(T *, T *) { return T(); } // expected-warning 0-1 {{expression which evaluates to zero treated as a null pointer constant of type 'int *'}} expected-error 0-1 {{cannot initialize return object of type 'int *' with an rvalue of type 'int'}} template T f0(T, U) { return T(); } // expected-note-re {{candidate template ignored: could not match 'int (int, U){{( __attribute__\(\(thiscall\)\))?}}' against 'int (int){{( __attribute__\(\(thiscall\)\))?}} const'}} \ // expected-note {{candidate template ignored: could not match 'int' against 'int *'}} @@ -25,7 +26,7 @@ T X0::value; // expected-error{{no matching constructor}} template int X0::value; -struct NotDefaultConstructible { // expected-note{{candidate constructor (the implicit copy constructor)}} +struct NotDefaultConstructible { // expected-note{{candidate constructor (the implicit copy constructor)}} expected-note 0-1 {{candidate constructor (the implicit move constructor)}} NotDefaultConstructible(int); // expected-note{{candidate constructor}} }; @@ -149,3 +150,17 @@ namespace undefined_static_data_member { template int C::b; template int D::c; } + +// expected-note@+1 3-4 {{explicit instantiation refers here}} +template void Foo(T i) throw(T) { throw i; } +// expected-error@+1 {{exception specification in explicit instantiation does not match instantiated one}} +template void Foo(int a) throw(char); +// expected-error@+1 {{exception specification in explicit instantiation does not match instantiated one}} +template void Foo(double a) throw(); +// expected-error@+1 1 {{exception specification in explicit instantiation does not match instantiated one}} +template void Foo(long a) throw(long, char); +template void Foo(float a); +#if __cplusplus >= 201103L +// expected-error@+1 0-1 {{exception specification in explicit instantiation does not match instantiated one}} +template void Foo(double a) noexcept; +#endif -- cgit v1.2.3