diff options
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 5 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExceptionSpec.cpp | 46 | ||||
-rw-r--r-- | clang/test/CXX/drs/dr1xx.cpp | 2 | ||||
-rw-r--r-- | clang/test/CXX/drs/dr5xx.cpp | 2 | ||||
-rw-r--r-- | clang/test/CXX/except/except.spec/p3.cpp | 4 | ||||
-rw-r--r-- | clang/test/CXX/except/except.spec/p4.cpp | 2 | ||||
-rw-r--r-- | clang/test/CXX/except/except.spec/p5-pointers.cpp | 2 | ||||
-rw-r--r-- | clang/test/FixIt/fixit.cpp | 2 | ||||
-rw-r--r-- | clang/test/Misc/warning-flags.c | 3 | ||||
-rw-r--r-- | clang/test/SemaCXX/exception-spec.cpp | 7 |
10 files changed, 50 insertions, 25 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 162f6998093..63343b0382d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1153,7 +1153,10 @@ def err_incompatible_exception_specs : Error< "target exception specification is not superset of source">; def err_deep_exception_specs_differ : Error< "exception specifications of %select{return|argument}0 types differ">; -def warn_missing_exception_specification : Warning< +def ext_missing_exception_specification : ExtWarn< + "%0 is missing exception specification '%1'">, + InGroup<DiagGroup<"missing-exception-spec">>; +def err_missing_exception_specification : Error< "%0 is missing exception specification '%1'">; def err_noexcept_needs_constant_expression : Error< "argument to noexcept specifier must be a constant expression">; diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 6182ad934e8..8e1c88458e3 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -270,16 +270,31 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { FunctionProtoType::ExceptionSpecInfo ESI = OldProto->getExceptionSpecType(); if (ESI.Type == EST_Dynamic) { ESI.Exceptions = OldProto->exceptions(); - } else if (ESI.Type == EST_ComputedNoexcept) { - // FIXME: We can't just take the expression from the old prototype. It - // likely contains references to the old prototype's parameters. } - // Update the type of the function with the appropriate exception - // specification. - New->setType(Context.getFunctionType( - NewProto->getReturnType(), NewProto->getParamTypes(), - NewProto->getExtProtoInfo().withExceptionSpec(ESI))); + if (ESI.Type == EST_ComputedNoexcept) { + // For computed noexcept, we can't just take the expression from the old + // prototype. It likely contains references to the old prototype's + // parameters. + New->setInvalidDecl(); + } else { + // Update the type of the function with the appropriate exception + // specification. + New->setType(Context.getFunctionType( + NewProto->getReturnType(), NewProto->getParamTypes(), + NewProto->getExtProtoInfo().withExceptionSpec(ESI))); + } + + // Allow missing exception specifications in redeclarations as an extension, + // when declaring a replaceable global allocation function. + if (New->isReplaceableGlobalAllocationFunction() && + ESI.Type != EST_ComputedNoexcept) { + DiagID = diag::ext_missing_exception_specification; + ReturnValueOnError = false; + } else { + DiagID = diag::err_missing_exception_specification; + ReturnValueOnError = true; + } // Warn about the lack of exception specification. SmallString<128> ExceptionSpecString; @@ -322,17 +337,18 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { SourceLocation FixItLoc; if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) { TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens(); - if (FunctionTypeLoc FTLoc = TL.getAs<FunctionTypeLoc>()) - FixItLoc = getLocForEndOfToken(FTLoc.getLocalRangeEnd()); + // FIXME: Preserve enough information so that we can produce a correct fixit + // location when there is a trailing return type. + if (auto FTLoc = TL.getAs<FunctionProtoTypeLoc>()) + if (!FTLoc.getTypePtr()->hasTrailingReturn()) + FixItLoc = getLocForEndOfToken(FTLoc.getLocalRangeEnd()); } if (FixItLoc.isInvalid()) - Diag(New->getLocation(), diag::warn_missing_exception_specification) + Diag(New->getLocation(), DiagID) << New << OS.str(); else { - // FIXME: This will get more complicated with C++0x - // late-specified return types. - Diag(New->getLocation(), diag::warn_missing_exception_specification) + Diag(New->getLocation(), DiagID) << New << OS.str() << FixItHint::CreateInsertion(FixItLoc, " " + OS.str().str()); } @@ -340,7 +356,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { if (!Old->getLocation().isInvalid()) Diag(Old->getLocation(), diag::note_previous_declaration); - return false; + return ReturnValueOnError; } /// CheckEquivalentExceptionSpec - Check if the two types have equivalent diff --git a/clang/test/CXX/drs/dr1xx.cpp b/clang/test/CXX/drs/dr1xx.cpp index d8d9307a5eb..377bfc94ffa 100644 --- a/clang/test/CXX/drs/dr1xx.cpp +++ b/clang/test/CXX/drs/dr1xx.cpp @@ -234,7 +234,7 @@ namespace dr125 { friend dr125_A::dr125_B (::dr125_C)(); // ok friend dr125_A (::dr125_B::dr125_C)(); // ok friend dr125_A::dr125_B::dr125_C(); // expected-error {{did you mean the constructor name 'dr125_B'?}} - // expected-warning@-1 {{missing exception specification}} + // expected-error@-1 {{missing exception specification}} #if __cplusplus >= 201103L // expected-error@-3 {{follows constexpr declaration}} expected-note@-10 {{here}} #endif diff --git a/clang/test/CXX/drs/dr5xx.cpp b/clang/test/CXX/drs/dr5xx.cpp index 5bf085f5220..0cf67e6b8c2 100644 --- a/clang/test/CXX/drs/dr5xx.cpp +++ b/clang/test/CXX/drs/dr5xx.cpp @@ -7,7 +7,7 @@ // pointing at the implicit operator new. We can't match such a diagnostic // with -verify. __extension__ typedef __SIZE_TYPE__ size_t; -void *operator new(size_t); // expected-warning 0-1{{missing exception spec}} expected-note{{candidate}} +void *operator new(size_t); // expected-error 0-1{{missing exception spec}} expected-note{{candidate}} namespace dr500 { // dr500: dup 372 class D; diff --git a/clang/test/CXX/except/except.spec/p3.cpp b/clang/test/CXX/except/except.spec/p3.cpp index d77aea40602..03f1d7626c0 100644 --- a/clang/test/CXX/except/except.spec/p3.cpp +++ b/clang/test/CXX/except/except.spec/p3.cpp @@ -24,9 +24,9 @@ extern void (*r4)() throw(...); extern void (*r5)() throw(int); // expected-note {{previous declaration}} extern void (*r5)(); // expected-error {{exception specification in declaration does not match}} -// For functions, we accept this with a warning. +// throw(int) and no spec are not compatible extern void f5() throw(int); // expected-note {{previous declaration}} -extern void f5(); // expected-warning {{missing exception specification}} +extern void f5(); // expected-error {{missing exception specification}} // Different types are not compatible. extern void (*r7)() throw(int); // expected-note {{previous declaration}} diff --git a/clang/test/CXX/except/except.spec/p4.cpp b/clang/test/CXX/except/except.spec/p4.cpp index 8d1b75fbdd6..04b2bd9bf28 100644 --- a/clang/test/CXX/except/except.spec/p4.cpp +++ b/clang/test/CXX/except/except.spec/p4.cpp @@ -19,7 +19,7 @@ struct T { void operator delete(void*) noexcept; // expected-note {{here}} }; -void T::a() {} // expected-warning {{missing exception specification 'noexcept'}} +void T::a() {} // expected-error {{missing exception specification 'noexcept'}} T::~T() {} // expected-warning {{function previously declared with an explicit exception specification redeclared with an implicit exception specification}} void T::operator delete(void*) {} // expected-warning {{function previously declared with an explicit exception specification redeclared with an implicit exception specification}} diff --git a/clang/test/CXX/except/except.spec/p5-pointers.cpp b/clang/test/CXX/except/except.spec/p5-pointers.cpp index f855520aa24..fe4a264587f 100644 --- a/clang/test/CXX/except/except.spec/p5-pointers.cpp +++ b/clang/test/CXX/except/except.spec/p5-pointers.cpp @@ -73,7 +73,7 @@ void fnptrs() // Member function stuff struct Str1 { void f() throw(int); }; // expected-note {{previous declaration}} -void Str1::f() // expected-warning {{missing exception specification}} +void Str1::f() // expected-error {{missing exception specification}} { } diff --git a/clang/test/FixIt/fixit.cpp b/clang/test/FixIt/fixit.cpp index 512713aa529..686cc23d635 100644 --- a/clang/test/FixIt/fixit.cpp +++ b/clang/test/FixIt/fixit.cpp @@ -45,7 +45,7 @@ class B : public A { }; void f() throw(); // expected-note{{previous}} -void f(); // expected-warning{{missing exception specification}} +void f(); // expected-error{{missing exception specification}} namespace rdar7853795 { struct A { diff --git a/clang/test/Misc/warning-flags.c b/clang/test/Misc/warning-flags.c index f61e966612b..bd97c4ae808 100644 --- a/clang/test/Misc/warning-flags.c +++ b/clang/test/Misc/warning-flags.c @@ -18,7 +18,7 @@ This test serves two purposes: The list of warnings below should NEVER grow. It should gradually shrink to 0. -CHECK: Warnings without flags (90): +CHECK: Warnings without flags (89): CHECK-NEXT: ext_excess_initializers CHECK-NEXT: ext_excess_initializers_in_char_array_initializer CHECK-NEXT: ext_expected_semi_decl_list @@ -80,7 +80,6 @@ CHECK-NEXT: warn_maynot_respond CHECK-NEXT: warn_method_param_redefinition CHECK-NEXT: warn_missing_case_for_condition CHECK-NEXT: warn_missing_dependent_template_keyword -CHECK-NEXT: warn_missing_exception_specification CHECK-NEXT: warn_missing_whitespace_after_macro_name CHECK-NEXT: warn_mt_message CHECK-NEXT: warn_no_constructor_for_refconst diff --git a/clang/test/SemaCXX/exception-spec.cpp b/clang/test/SemaCXX/exception-spec.cpp new file mode 100644 index 00000000000..f301a63503d --- /dev/null +++ b/clang/test/SemaCXX/exception-spec.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -fcxx-exceptions -std=c++11 %s + +namespace MissingOnTemplate { + template<typename T> void foo(T) noexcept(true); // expected-note {{previous}} + template<typename T> void foo(T); // expected-error {{missing exception specification 'noexcept(true)'}} + void test() { foo(0); } +} |