diff options
-rw-r--r-- | clang/include/clang/AST/DeclCXX.h | 2 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 1 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExceptionSpec.cpp | 129 | ||||
-rw-r--r-- | clang/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-noexceptions.cpp | 13 | ||||
-rw-r--r-- | clang/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp | 9 | ||||
-rw-r--r-- | clang/test/FixIt/fixit.cpp | 3 | ||||
-rw-r--r-- | clang/test/SemaCXX/exception-spec.cpp | 6 |
8 files changed, 144 insertions, 21 deletions
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 4e273d1dae9..1a1bf4e4818 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -941,7 +941,7 @@ public: return (CD->begin_overridden_methods() != CD->end_overridden_methods()); } - + /// \brief Determine whether this is a usual deallocation function /// (C++ [basic.stc.dynamic.deallocation]p2), which is an overloaded /// delete or delete[] operator with a particular signature. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index c0e497a6b1a..efe75e9b080 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -434,6 +434,8 @@ 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< + "%0 is missing exception specification '%1'">; // C++ access checking def err_class_redeclared_with_different_access : Error< diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 85fa4f1742a..ba6d38f849a 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -728,6 +728,7 @@ public: const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc, + bool *MissingExceptionSpecification = 0, bool *MissingEmptyExceptionSpecification = 0); bool CheckExceptionSpecSubset( const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 4ce1ce9b019..5767551c53b 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -15,6 +15,8 @@ #include "clang/AST/CXXInheritance.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallPtrSet.h" @@ -94,6 +96,7 @@ bool Sema::CheckDistantExceptionSpec(QualType T) { } bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { + bool MissingExceptionSpecification = false; bool MissingEmptyExceptionSpecification = false; if (!CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec, diag::note_previous_declaration, @@ -101,12 +104,13 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { Old->getLocation(), New->getType()->getAs<FunctionProtoType>(), New->getLocation(), + &MissingExceptionSpecification, &MissingEmptyExceptionSpecification)) return false; // The failure was something other than an empty exception // specification; return an error. - if (!MissingEmptyExceptionSpecification) + if (!MissingExceptionSpecification && !MissingEmptyExceptionSpecification) return true; // The new function declaration is only missing an empty exception @@ -117,8 +121,10 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { // to many libc functions as an optimization. Unfortunately, that // optimization isn't permitted by the C++ standard, so we're forced // to work around it here. - if (isa<FunctionProtoType>(New->getType()) && - Context.getSourceManager().isInSystemHeader(Old->getLocation()) && + if (MissingEmptyExceptionSpecification && + isa<FunctionProtoType>(New->getType()) && + (Old->getLocation().isInvalid() || + Context.getSourceManager().isInSystemHeader(Old->getLocation())) && Old->isExternC()) { const FunctionProtoType *NewProto = cast<FunctionProtoType>(New->getType()); @@ -134,6 +140,88 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { return false; } + if (MissingExceptionSpecification && isa<FunctionProtoType>(New->getType())) { + const FunctionProtoType *NewProto + = cast<FunctionProtoType>(New->getType()); + const FunctionProtoType *OldProto + = Old->getType()->getAs<FunctionProtoType>(); + + // Update the type of the function with the appropriate exception + // specification. + QualType NewType = Context.getFunctionType(NewProto->getResultType(), + NewProto->arg_type_begin(), + NewProto->getNumArgs(), + NewProto->isVariadic(), + NewProto->getTypeQuals(), + OldProto->hasExceptionSpec(), + OldProto->hasAnyExceptionSpec(), + OldProto->getNumExceptions(), + OldProto->exception_begin(), + NewProto->getNoReturnAttr(), + NewProto->getCallConv()); + New->setType(NewType); + + // If exceptions are disabled, suppress the warning about missing + // exception specifications for new and delete operators. + if (!getLangOptions().Exceptions) { + switch (New->getDeclName().getCXXOverloadedOperator()) { + case OO_New: + case OO_Array_New: + case OO_Delete: + case OO_Array_Delete: + if (New->getDeclContext()->isTranslationUnit()) + return false; + break; + + default: + break; + } + } + + // Warn about the lack of exception specification. + llvm::SmallString<128> ExceptionSpecString; + llvm::raw_svector_ostream OS(ExceptionSpecString); + OS << "throw("; + bool OnFirstException = true; + for (FunctionProtoType::exception_iterator E = OldProto->exception_begin(), + EEnd = OldProto->exception_end(); + E != EEnd; + ++E) { + if (OnFirstException) + OnFirstException = false; + else + OS << ", "; + + OS << E->getAsString(Context.PrintingPolicy); + } + OS << ")"; + OS.flush(); + + SourceLocation AfterParenLoc; + if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) { + TypeLoc TL = TSInfo->getTypeLoc(); + if (const FunctionTypeLoc *FTLoc = dyn_cast<FunctionTypeLoc>(&TL)) + AfterParenLoc = PP.getLocForEndOfToken(FTLoc->getRParenLoc()); + } + + if (AfterParenLoc.isInvalid()) + Diag(New->getLocation(), diag::warn_missing_exception_specification) + << 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) + << New << OS.str() + << CodeModificationHint::CreateInsertion(AfterParenLoc, + " " + OS.str().str()); + } + + if (!Old->getLocation().isInvalid()) + Diag(Old->getLocation(), diag::note_previous_declaration); + + return false; + } + Diag(New->getLocation(), diag::err_mismatched_exception_spec); Diag(Old->getLocation(), diag::note_previous_declaration); return true; @@ -155,11 +243,17 @@ bool Sema::CheckEquivalentExceptionSpec( /// exception specifications. Exception specifications are equivalent if /// they allow exactly the same set of exception types. It does not matter how /// that is achieved. See C++ [except.spec]p2. -bool Sema::CheckEquivalentExceptionSpec( - const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, - const FunctionProtoType *Old, SourceLocation OldLoc, - const FunctionProtoType *New, SourceLocation NewLoc, - bool *MissingEmptyExceptionSpecification) { +bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, + const PartialDiagnostic & NoteID, + const FunctionProtoType *Old, + SourceLocation OldLoc, + const FunctionProtoType *New, + SourceLocation NewLoc, + bool *MissingExceptionSpecification, + bool *MissingEmptyExceptionSpecification) { + if (MissingExceptionSpecification) + *MissingExceptionSpecification = false; + if (MissingEmptyExceptionSpecification) *MissingEmptyExceptionSpecification = false; @@ -168,13 +262,20 @@ bool Sema::CheckEquivalentExceptionSpec( if (OldAny && NewAny) return false; if (OldAny || NewAny) { - if (MissingEmptyExceptionSpecification && Old->hasExceptionSpec() && - !Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0 && + if (MissingExceptionSpecification && Old->hasExceptionSpec() && !New->hasExceptionSpec()) { - // The old type has a throw() exception specification and the - // new type has no exception specification, and the caller asked - // to handle this itself. - *MissingEmptyExceptionSpecification = true; + // The old type has an exception specification of some sort, but + // the new type does not. + *MissingExceptionSpecification = true; + + if (MissingEmptyExceptionSpecification && + !Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0) { + // The old type has a throw() exception specification and the + // new type has no exception specification, and the caller asked + // to handle this itself. + *MissingEmptyExceptionSpecification = true; + } + return true; } diff --git a/clang/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-noexceptions.cpp b/clang/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-noexceptions.cpp new file mode 100644 index 00000000000..4567c469e81 --- /dev/null +++ b/clang/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-noexceptions.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +namespace std { + class bad_alloc { }; + + typedef __SIZE_TYPE__ size_t; +} + +class foo { virtual ~foo(); }; + +void* operator new(std::size_t); +void* operator new[](std::size_t); +void operator delete(void*); +void operator delete[](void*); diff --git a/clang/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp b/clang/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp index f4860bb9bab..37a4f976bad 100644 --- a/clang/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp +++ b/clang/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -fexceptions -verify %s int *use_new(int N) { if (N == 1) return new int; @@ -19,7 +19,10 @@ namespace std { typedef __SIZE_TYPE__ size_t; } -void* operator new(std::size_t) throw(std::bad_alloc); +void* operator new(std::size_t) throw(std::bad_alloc); // expected-note{{previous declaration}} void* operator new[](std::size_t) throw(std::bad_alloc); -void operator delete(void*) throw(); +void operator delete(void*) throw(); // expected-note{{previous declaration}} void operator delete[](void*) throw(); + +void* operator new(std::size_t); // expected-warning{{'operator new' is missing exception specification 'throw(std::bad_alloc)'}} +void operator delete(void*); // expected-warning{{'operator delete' is missing exception specification 'throw()'}} diff --git a/clang/test/FixIt/fixit.cpp b/clang/test/FixIt/fixit.cpp index ee93755775e..79c294b1d92 100644 --- a/clang/test/FixIt/fixit.cpp +++ b/clang/test/FixIt/fixit.cpp @@ -37,3 +37,6 @@ protected: class B : public A { A::foo; // expected-warning{{access declarations are deprecated}} }; + +void f() throw(); +void f(); // expected-warning{{missing exception specification}} diff --git a/clang/test/SemaCXX/exception-spec.cpp b/clang/test/SemaCXX/exception-spec.cpp index 782cf838569..498611ee859 100644 --- a/clang/test/SemaCXX/exception-spec.cpp +++ b/clang/test/SemaCXX/exception-spec.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s +// RUN: %clang_cc1 -fsyntax-only -verify -fexceptions -fms-extensions %s // Straight from the standard: // Plain function with spec @@ -50,7 +50,7 @@ void r4() throw(int, float); void r4() throw(float, int); void r5() throw(int); // expected-note {{previous declaration}} -void r5(); // expected-error {{exception specification in declaration does not match}} +void r5(); // expected-warning {{missing exception specification}} void r6() throw(...); // expected-note {{previous declaration}} void r6() throw(int); // expected-error {{exception specification in declaration does not match}} @@ -170,7 +170,7 @@ void fnptrs() // Member function stuff struct Str1 { void f() throw(int); }; // expected-note {{previous declaration}} -void Str1::f() // expected-error {{does not match previous declaration}} +void Str1::f() // expected-warning {{missing exception specification}} { } |