[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