[cfe-commits] r95969 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExceptionSpec.cpp test/SemaCXX/Inputs/ test/SemaCXX/Inputs/lit.local.cfg test/SemaCXX/Inputs/malloc.h test/SemaCXX/builtin-exception-spec.cpp
Douglas Gregor
dgregor at apple.com
Thu Feb 11 23:32:17 PST 2010
Author: dgregor
Date: Fri Feb 12 01:32:17 2010
New Revision: 95969
URL: http://llvm.org/viewvc/llvm-project?rev=95969&view=rev
Log:
Work around an annoying, non-standard optimization in the glibc
headers, where malloc (and many other libc functions) are declared
with empty throw specifications, e.g.,
extern void *malloc (__SIZE_TYPE__ __size) throw () __attribute__
((__malloc__)) ;
The C++ standard doesn't seem to allow this, and redeclaring malloc as
the standard permits (as follows) resulted in Clang (rightfully!)
complaining about mis-matched exception specifications.
void *malloc(size_t size);
We work around this by silently propagating an empty throw
specification "throw()" from a function with C linkage declared in a
system header to a redeclaration that has no throw specifier.
Ick.
Added:
cfe/trunk/test/SemaCXX/Inputs/
cfe/trunk/test/SemaCXX/Inputs/lit.local.cfg
cfe/trunk/test/SemaCXX/Inputs/malloc.h (with props)
cfe/trunk/test/SemaCXX/builtin-exception-spec.cpp (with props)
Modified:
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=95969&r1=95968&r2=95969&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Feb 12 01:32:17 2010
@@ -657,13 +657,15 @@
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,
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=95969&r1=95968&r2=95969&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Feb 12 01:32:17 2010
@@ -356,9 +356,7 @@
}
}
- if (CheckEquivalentExceptionSpec(
- Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
- New->getType()->getAs<FunctionProtoType>(), New->getLocation()))
+ if (CheckEquivalentExceptionSpec(Old, New))
Invalid = true;
return Invalid;
Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=95969&r1=95968&r2=95969&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Fri Feb 12 01:32:17 2010
@@ -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 @@
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(
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);
Added: cfe/trunk/test/SemaCXX/Inputs/lit.local.cfg
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/Inputs/lit.local.cfg?rev=95969&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/Inputs/lit.local.cfg (added)
+++ cfe/trunk/test/SemaCXX/Inputs/lit.local.cfg Fri Feb 12 01:32:17 2010
@@ -0,0 +1 @@
+config.suffixes = []
Added: cfe/trunk/test/SemaCXX/Inputs/malloc.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/Inputs/malloc.h?rev=95969&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/Inputs/malloc.h (added)
+++ cfe/trunk/test/SemaCXX/Inputs/malloc.h Fri Feb 12 01:32:17 2010
@@ -0,0 +1,3 @@
+extern "C" {
+extern void *malloc (__SIZE_TYPE__ __size) throw () __attribute__ ((__malloc__)) ;
+}
Propchange: cfe/trunk/test/SemaCXX/Inputs/malloc.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/SemaCXX/Inputs/malloc.h
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/SemaCXX/Inputs/malloc.h
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: cfe/trunk/test/SemaCXX/builtin-exception-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/builtin-exception-spec.cpp?rev=95969&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/builtin-exception-spec.cpp (added)
+++ cfe/trunk/test/SemaCXX/builtin-exception-spec.cpp Fri Feb 12 01:32:17 2010
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -isystem %S/Inputs -fsyntax-only -verify %s
+#include <malloc.h>
+
+extern "C" {
+void *malloc(__SIZE_TYPE__);
+}
Propchange: cfe/trunk/test/SemaCXX/builtin-exception-spec.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/SemaCXX/builtin-exception-spec.cpp
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/SemaCXX/builtin-exception-spec.cpp
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the cfe-commits
mailing list