diff options
-rw-r--r-- | lib/Sema/Sema.h | 4 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaExceptionSpec.cpp | 65 | ||||
-rw-r--r-- | test/SemaCXX/Inputs/lit.local.cfg | 1 | ||||
-rw-r--r-- | test/SemaCXX/Inputs/malloc.h | 3 | ||||
-rw-r--r-- | test/SemaCXX/builtin-exception-spec.cpp | 6 |
6 files changed, 77 insertions, 6 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 02ffb8ccb4..8db3eb1713 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -657,13 +657,15 @@ public: static QualType GetTypeFromParser(TypeTy *Ty, TypeSourceInfo **TInfo = 0); bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range); bool CheckDistantExceptionSpec(QualType T); + bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New); bool CheckEquivalentExceptionSpec( const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc); bool CheckEquivalentExceptionSpec( const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, const FunctionProtoType *Old, SourceLocation OldLoc, - const FunctionProtoType *New, SourceLocation NewLoc); + const FunctionProtoType *New, SourceLocation NewLoc, + bool *MissingEmptyExceptionSpecification = 0); bool CheckExceptionSpecSubset( const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, const FunctionProtoType *Superset, SourceLocation SuperLoc, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 00bc453e84..a062724ee4 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -356,9 +356,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { } } - if (CheckEquivalentExceptionSpec( - Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(), - New->getType()->getAs<FunctionProtoType>(), New->getLocation())) + if (CheckEquivalentExceptionSpec(Old, New)) Invalid = true; return Invalid; diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index d0718d020b..9be411b552 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -12,10 +12,11 @@ //===----------------------------------------------------------------------===// #include "Sema.h" -#include "clang/Basic/Diagnostic.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallPtrSet.h" namespace clang { @@ -92,6 +93,52 @@ bool Sema::CheckDistantExceptionSpec(QualType T) { return FnT->hasExceptionSpec(); } +bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { + bool MissingEmptyExceptionSpecification = false; + if (!CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec, + diag::note_previous_declaration, + Old->getType()->getAs<FunctionProtoType>(), + Old->getLocation(), + New->getType()->getAs<FunctionProtoType>(), + New->getLocation(), + &MissingEmptyExceptionSpecification)) + return false; + + // The failure was something other than an empty exception + // specification; return an error. + if (!MissingEmptyExceptionSpecification) + return true; + + // The new function declaration is only missing an empty exception + // specification "throw()". If the throw() specification came from a + // function in a system header that has C linkage, just add an empty + // exception specification to the "new" declaration. This is an + // egregious workaround for glibc, which adds throw() specifications + // 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()) && + Old->isExternC()) { + const FunctionProtoType *NewProto + = cast<FunctionProtoType>(New->getType()); + QualType NewType = Context.getFunctionType(NewProto->getResultType(), + NewProto->arg_type_begin(), + NewProto->getNumArgs(), + NewProto->isVariadic(), + NewProto->getTypeQuals(), + true, false, 0, 0, + NewProto->getNoReturnAttr(), + NewProto->getCallConv()); + New->setType(NewType); + return false; + } + + Diag(New->getLocation(), diag::err_mismatched_exception_spec); + Diag(Old->getLocation(), diag::note_previous_declaration); + return true; +} + /// CheckEquivalentExceptionSpec - Check if the two types have equivalent /// exception specifications. Exception specifications are equivalent if /// they allow exactly the same set of exception types. It does not matter how @@ -111,12 +158,26 @@ bool Sema::CheckEquivalentExceptionSpec( bool Sema::CheckEquivalentExceptionSpec( const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, const FunctionProtoType *Old, SourceLocation OldLoc, - const FunctionProtoType *New, SourceLocation NewLoc) { + const FunctionProtoType *New, SourceLocation NewLoc, + bool *MissingEmptyExceptionSpecification) { + if (MissingEmptyExceptionSpecification) + *MissingEmptyExceptionSpecification = false; + bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec(); bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec(); if (OldAny && NewAny) return false; if (OldAny || NewAny) { + if (MissingEmptyExceptionSpecification && Old->hasExceptionSpec() && + !Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0 && + !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; + return true; + } + Diag(NewLoc, DiagID); if (NoteID.getDiagID() != 0) Diag(OldLoc, NoteID); diff --git a/test/SemaCXX/Inputs/lit.local.cfg b/test/SemaCXX/Inputs/lit.local.cfg new file mode 100644 index 0000000000..e6f55eef7a --- /dev/null +++ b/test/SemaCXX/Inputs/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = [] diff --git a/test/SemaCXX/Inputs/malloc.h b/test/SemaCXX/Inputs/malloc.h new file mode 100644 index 0000000000..c54d621501 --- /dev/null +++ b/test/SemaCXX/Inputs/malloc.h @@ -0,0 +1,3 @@ +extern "C" { +extern void *malloc (__SIZE_TYPE__ __size) throw () __attribute__ ((__malloc__)) ; +} diff --git a/test/SemaCXX/builtin-exception-spec.cpp b/test/SemaCXX/builtin-exception-spec.cpp new file mode 100644 index 0000000000..324d20ea6a --- /dev/null +++ b/test/SemaCXX/builtin-exception-spec.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -isystem %S/Inputs -fsyntax-only -verify %s +#include <malloc.h> + +extern "C" { +void *malloc(__SIZE_TYPE__); +} |