aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Sema/Sema.h4
-rw-r--r--lib/Sema/SemaDeclCXX.cpp4
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp65
-rw-r--r--test/SemaCXX/Inputs/lit.local.cfg1
-rw-r--r--test/SemaCXX/Inputs/malloc.h3
-rw-r--r--test/SemaCXX/builtin-exception-spec.cpp6
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__);
+}