]> granicus.if.org Git - clang/commitdiff
Implement a hack to work around the changing exception specification of operator...
authorSebastian Redl <sebastian.redl@getdesigned.at>
Tue, 15 Mar 2011 19:52:30 +0000 (19:52 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Tue, 15 Mar 2011 19:52:30 +0000 (19:52 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@127688 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/Sema.h
lib/Sema/SemaExceptionSpec.cpp
test/CXX/except/except.spec/p3.cpp

index 51cff569605dcdb81828c6af39a452691a7fb479..394a57ae258f2c6ce31ea0fe5866a715f543391b 100644 (file)
@@ -758,7 +758,8 @@ public:
       const FunctionProtoType *New, SourceLocation NewLoc,
       bool *MissingExceptionSpecification = 0,
       bool *MissingEmptyExceptionSpecification = 0,
-      bool AllowNoexceptAllMatchWithNoSpec = false);
+      bool AllowNoexceptAllMatchWithNoSpec = false,
+      bool IsOperatorNew = false);
   bool CheckExceptionSpecSubset(
       const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
       const FunctionProtoType *Superset, SourceLocation SuperLoc,
index 285f400b07b3a6a378f0402bbd4c82944e9073cc..1d21b9760c78a4c10d5f78c62298ed67c578922c 100644 (file)
@@ -96,6 +96,8 @@ bool Sema::CheckDistantExceptionSpec(QualType T) {
 }
 
 bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
+  OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator();
+  bool IsOperatorNew = OO == OO_New || OO == OO_Array_New;
   bool MissingExceptionSpecification = false;
   bool MissingEmptyExceptionSpecification = false;
   if (!CheckEquivalentExceptionSpec(PDiag(diag::err_mismatched_exception_spec),
@@ -106,7 +108,8 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
                                     New->getLocation(),
                                     &MissingExceptionSpecification,
                                     &MissingEmptyExceptionSpecification,
-                                    /*AllowNoexceptAllMatchWithNoSpec=*/true))
+                                    /*AllowNoexceptAllMatchWithNoSpec=*/true,
+                                    IsOperatorNew))
     return false;
 
   // The failure was something other than an empty exception
@@ -272,7 +275,8 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
                                         SourceLocation NewLoc,
                                         bool *MissingExceptionSpecification,
                                         bool*MissingEmptyExceptionSpecification,
-                                        bool AllowNoexceptAllMatchWithNoSpec) {
+                                        bool AllowNoexceptAllMatchWithNoSpec,
+                                        bool IsOperatorNew) {
   // Just completely ignore this under -fno-exceptions.
   if (!getLangOptions().CXXExceptions)
     return false;
@@ -374,6 +378,38 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
   if (OldNonThrowing && NewNonThrowing)
     return false;
 
+  // As a special compatibility feature, under C++0x we accept no spec and
+  // throw(std::bad_alloc) as equivalent for operator new and operator new[].
+  // This is because the implicit declaration changed, but old code would break.
+  if (getLangOptions().CPlusPlus0x && IsOperatorNew) {
+    const FunctionProtoType *WithExceptions = 0;
+    if (OldEST == EST_None && NewEST == EST_Dynamic)
+      WithExceptions = New;
+    else if (OldEST == EST_Dynamic && NewEST == EST_None)
+      WithExceptions = Old;
+    if (WithExceptions && WithExceptions->getNumExceptions() == 1) {
+      // One has no spec, the other throw(something). If that something is
+      // std::bad_alloc, all conditions are met.
+      QualType Exception = *WithExceptions->exception_begin();
+      if (CXXRecordDecl *ExRecord = Exception->getAsCXXRecordDecl()) {
+        IdentifierInfo* Name = ExRecord->getIdentifier();
+        if (Name && Name->getName() == "bad_alloc") {
+          // It's called bad_alloc, but is it in std?
+          DeclContext* DC = ExRecord->getDeclContext();
+          while (DC && !isa<NamespaceDecl>(DC))
+            DC = DC->getParent();
+          if (DC) {
+            NamespaceDecl* NS = cast<NamespaceDecl>(DC);
+            IdentifierInfo* NSName = NS->getIdentifier();
+            if (NSName && NSName->getName() == "std" &&
+                isa<TranslationUnitDecl>(NS->getParent()))
+              return false;
+          }
+        }
+      }
+    }
+  }
+
   // At this point, the only remaining valid case is two matching dynamic
   // specifications. We return here unless both specifications are dynamic.
   if (OldEST != EST_Dynamic || NewEST != EST_Dynamic) {
index e751f55ec3bf682ab7de010b58978636ff9d05e0..10e027b719a749daecaf04ef546018de1f518d1f 100644 (file)
@@ -92,3 +92,14 @@ extern void (*r20)() noexcept(false); // expected-error {{does not match}}
 
 extern void (*r21)() throw(int); // expected-note {{previous declaration}}
 extern void (*r21)() noexcept(true); // expected-error {{does not match}}
+
+
+// As a very special workaround, we allow operator new to match no spec
+// with a throw(bad_alloc) spec, because C++0x makes an incompatible change
+// here.
+namespace std { class bad_alloc {}; }
+void* operator new(unsigned long) throw(std::bad_alloc);
+void* operator new(unsigned long);
+void* operator new[](unsigned long) throw(std::bad_alloc);
+void* operator new[](unsigned long);
+