[cfe-commits] r166372 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExceptionSpec.cpp lib/Sema/SemaType.cpp test/CXX/except/except.spec/p15.cpp test/CXX/except/except.spec/p4.cpp test/CXX/special/class.dtor/p3.cpp

Richard Smith richard-llvm at metafoo.co.uk
Sat Oct 20 01:26:51 PDT 2012


Author: rsmith
Date: Sat Oct 20 03:26:51 2012
New Revision: 166372

URL: http://llvm.org/viewvc/llvm-project?rev=166372&view=rev
Log:
Rework implementation of DR1492: Apply the resolution to operator delete too,
since it also has an implicit exception specification. Downgrade the error to
an extwarn, since at least for operator delete, system headers like to declare
it as 'noexcept' whereas the implicit definition does not have an explicit
exception specification. Move the exception specification for user-declared
'operator delete' functions from the type-as-written into the type, to reflect
reality and to allow us to detect whether there was an implicit exception spec
or not.

Added:
    cfe/trunk/test/CXX/except/except.spec/p4.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/CXX/except/except.spec/p15.cpp
    cfe/trunk/test/CXX/special/class.dtor/p3.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=166372&r1=166371&r2=166372&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sat Oct 20 03:26:51 2012
@@ -5425,6 +5425,10 @@
   "defaulting this %select{default constructor|copy constructor|move "
   "constructor|copy assignment operator|move assignment operator|destructor}0 "
   "would delete it after its first declaration">;
+def ext_implicit_exception_spec_mismatch : ExtWarn<
+  "function previously declared with an %select{explicit|implicit}0 exception "
+  "specification redeclared with an %select{implicit|explicit}0 exception "
+  "specification">, InGroup<DiagGroup<"implicit-exception-spec-mismatch">>;
 
 def warn_ptr_arith_precedes_bounds : Warning<
   "the pointer decremented by %0 refers before the beginning of the array">,

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=166372&r1=166371&r2=166372&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sat Oct 20 03:26:51 2012
@@ -5519,6 +5519,20 @@
            diag::err_static_out_of_line)
         << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
     }
+
+    // C++11 [except.spec]p15:
+    //   A deallocation function with no exception-specification is treated
+    //   as if it were specified with noexcept(true).
+    const FunctionProtoType *FPT = R->getAs<FunctionProtoType>();
+    if ((Name.getCXXOverloadedOperator() == OO_Delete ||
+         Name.getCXXOverloadedOperator() == OO_Array_Delete) &&
+        getLangOpts().CPlusPlus0x && FPT && !FPT->hasExceptionSpec()) {
+      FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+      EPI.ExceptionSpecType = EST_BasicNoexcept;
+      NewFD->setType(Context.getFunctionType(FPT->getResultType(),
+                                             FPT->arg_type_begin(),
+                                             FPT->getNumArgs(), EPI));
+    }
   }
 
   // Filter out previous declarations that don't match the scope.

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=166372&r1=166371&r2=166372&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sat Oct 20 03:26:51 2012
@@ -9379,7 +9379,7 @@
 }
 
 static bool
-CheckOperatorDeleteDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) {
+CheckOperatorDeleteDeclaration(Sema &SemaRef, FunctionDecl *FnDecl) {
   // C++ [basic.stc.dynamic.deallocation]p1:
   //   A program is ill-formed if deallocation functions are declared in a
   //   namespace scope other than global scope or declared static in global 

Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=166372&r1=166371&r2=166372&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Sat Oct 20 03:26:51 2012
@@ -120,21 +120,22 @@
   return SourceDecl->getType()->castAs<FunctionProtoType>();
 }
 
-/// Get the type that a function had prior to adjustment of the exception
+/// Determine whether a function has an implicitly-generated exception
 /// specification.
-static const FunctionProtoType *getUnadjustedFunctionType(FunctionDecl *Decl) {
-  if (isa<CXXDestructorDecl>(Decl) && Decl->getTypeSourceInfo()) {
-    const FunctionProtoType *Ty =
-      Decl->getTypeSourceInfo()->getType()->getAs<FunctionProtoType>();
-    if (!Ty->hasExceptionSpec())
-      // The type will be adjusted. Use the EST_None exception specification
-      // from the type as written.
-      return Ty;
-  }
+static bool hasImplicitExceptionSpec(FunctionDecl *Decl) {
+  if (!isa<CXXDestructorDecl>(Decl) &&
+      Decl->getDeclName().getCXXOverloadedOperator() != OO_Delete &&
+      Decl->getDeclName().getCXXOverloadedOperator() != OO_Array_Delete)
+    return false;
+
+  // If the user didn't declare the function, its exception specification must
+  // be implicit.
+  if (!Decl->getTypeSourceInfo())
+    return true;
 
-  // Use whatever type the function now has. The TypeSourceInfo does not contain
-  // an instantiated exception specification for a function template, 
-  return Decl->getType()->getAs<FunctionProtoType>();
+  const FunctionProtoType *Ty =
+    Decl->getTypeSourceInfo()->getType()->getAs<FunctionProtoType>();
+  return !Ty->hasExceptionSpec();
 }
 
 bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
@@ -150,18 +151,31 @@
   // specification adjustment is applied.
   if (!CheckEquivalentExceptionSpec(
         PDiag(DiagID), PDiag(diag::note_previous_declaration),
-        getUnadjustedFunctionType(Old), Old->getLocation(),
-        getUnadjustedFunctionType(New), New->getLocation(),
+        Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
+        New->getType()->getAs<FunctionProtoType>(), New->getLocation(),
         &MissingExceptionSpecification, &MissingEmptyExceptionSpecification,
-        /*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew))
+        /*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew)) {
+    // C++11 [except.spec]p4 [DR1492]:
+    //   If a declaration of a function has an implicit
+    //   exception-specification, other declarations of the function shall
+    //   not specify an exception-specification.
+    if (getLangOpts().CPlusPlus0x &&
+        hasImplicitExceptionSpec(Old) != hasImplicitExceptionSpec(New)) {
+      Diag(New->getLocation(), diag::ext_implicit_exception_spec_mismatch)
+        << hasImplicitExceptionSpec(Old);
+      if (!Old->getLocation().isInvalid())
+        Diag(Old->getLocation(), diag::note_previous_declaration);
+    }
     return false;
+  }
 
   // The failure was something other than an empty exception
   // specification; return an error.
   if (!MissingExceptionSpecification && !MissingEmptyExceptionSpecification)
     return true;
 
-  const FunctionProtoType *NewProto = getUnadjustedFunctionType(New);
+  const FunctionProtoType *NewProto =
+    New->getType()->getAs<FunctionProtoType>();
 
   // The new function declaration is only missing an empty exception
   // specification "throw()". If the throw() specification came from a
@@ -186,7 +200,8 @@
   }
 
   if (MissingExceptionSpecification && NewProto) {
-    const FunctionProtoType *OldProto = getUnadjustedFunctionType(Old);
+    const FunctionProtoType *OldProto =
+      Old->getType()->getAs<FunctionProtoType>();
 
     FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
     EPI.ExceptionSpecType = OldProto->getExceptionSpecType();
@@ -310,6 +325,10 @@
 
 /// CheckEquivalentExceptionSpec - Check if the two types have compatible
 /// exception specifications. See C++ [except.spec]p3.
+///
+/// \return \c false if the exception specifications match, \c true if there is
+/// a problem. If \c true is returned, either a diagnostic has already been
+/// produced or \c *MissingExceptionSpecification is set to \c true.
 bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
                                         const PartialDiagnostic & NoteID,
                                         const FunctionProtoType *Old,

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=166372&r1=166371&r2=166372&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Sat Oct 20 03:26:51 2012
@@ -2169,16 +2169,6 @@
   ASTContext &Context = S.Context;
   const LangOptions &LangOpts = S.getLangOpts();
 
-  bool ImplicitlyNoexcept = false;
-  if (D.getName().getKind() == UnqualifiedId::IK_OperatorFunctionId &&
-      LangOpts.CPlusPlus0x) {
-    OverloadedOperatorKind OO = D.getName().OperatorFunctionId.Operator;
-    /// In C++0x, deallocation functions (normal and array operator delete)
-    /// are implicitly noexcept.
-    if (OO == OO_Delete || OO == OO_Array_Delete)
-      ImplicitlyNoexcept = true;
-  }
-
   // The name we're declaring, if any.
   DeclarationName Name;
   if (D.getIdentifier())
@@ -2578,12 +2568,6 @@
                                       Exceptions,
                                       EPI);
 
-        if (FTI.getExceptionSpecType() == EST_None &&
-            ImplicitlyNoexcept && chunkIndex == 0) {
-          // Only the outermost chunk is marked noexcept, of course.
-          EPI.ExceptionSpecType = EST_BasicNoexcept;
-        }
-
         T = Context.getFunctionType(T, ArgTys.data(), ArgTys.size(), EPI);
       }
 

Modified: cfe/trunk/test/CXX/except/except.spec/p15.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/except/except.spec/p15.cpp?rev=166372&r1=166371&r2=166372&view=diff
==============================================================================
--- cfe/trunk/test/CXX/except/except.spec/p15.cpp (original)
+++ cfe/trunk/test/CXX/except/except.spec/p15.cpp Sat Oct 20 03:26:51 2012
@@ -9,16 +9,20 @@
   delete[] new int[1];
 }
 
-void operator delete(void*) noexcept;
-void operator delete[](void*) noexcept;
+void operator delete(void*);
+void operator delete[](void*);
+
+static_assert(noexcept(operator delete(0)), "");
+static_assert(noexcept(operator delete[](0)), "");
 
 // Same goes for explicit declarations.
 void operator delete(void*, float);
-void operator delete(void*, float) noexcept;
-
 void operator delete[](void*, float);
-void operator delete[](void*, float) noexcept;
+
+static_assert(noexcept(operator delete(0, 0.f)), "");
+static_assert(noexcept(operator delete[](0, 0.f)), "");
 
 // But explicit specs stay.
 void operator delete(void*, double) throw(int); // expected-note {{previous}}
+static_assert(!noexcept(operator delete(0, 0.)), "");
 void operator delete(void*, double) noexcept; // expected-error {{does not match}}

Added: cfe/trunk/test/CXX/except/except.spec/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/except/except.spec/p4.cpp?rev=166372&view=auto
==============================================================================
--- cfe/trunk/test/CXX/except/except.spec/p4.cpp (added)
+++ cfe/trunk/test/CXX/except/except.spec/p4.cpp Sat Oct 20 03:26:51 2012
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -std=c++11 %s -verify -fcxx-exceptions
+
+// We permit overriding an implicit exception specification with an explicit one
+// as an extension, for compatibility with existing code.
+
+struct S {
+  void a(); // expected-note {{here}}
+  ~S(); // expected-note {{here}}
+  void operator delete(void*); // expected-note {{here}}
+};
+
+void S::a() noexcept {} // expected-error {{does not match previous}}
+S::~S() noexcept {} // expected-warning {{function previously declared with an implicit exception specification redeclared with an explicit exception specification}}
+void S::operator delete(void*) noexcept {} // expected-warning {{function previously declared with an implicit exception specification redeclared with an explicit exception specification}}
+
+struct T {
+  void a() noexcept; // expected-note {{here}}
+  ~T() noexcept; // expected-note {{here}}
+  void operator delete(void*) noexcept; // expected-note {{here}}
+};
+
+void T::a() {} // expected-warning {{missing exception specification 'noexcept'}}
+T::~T() {} // expected-warning {{function previously declared with an explicit exception specification redeclared with an implicit exception specification}}
+void T::operator delete(void*) {} // expected-warning {{function previously declared with an explicit exception specification redeclared with an implicit exception specification}}
+
+
+// The extension does not extend to function templates.
+
+template<typename T> struct U {
+  T t;
+  ~U(); // expected-note {{here}}
+  void operator delete(void*); // expected-note {{here}}
+};
+
+template<typename T> U<T>::~U() noexcept(true) {} // expected-error {{exception specification in declaration does not match previous declaration}}
+template<typename T> void U<T>::operator delete(void*) noexcept(false) {} // expected-error {{exception specification in declaration does not match previous declaration}}

Modified: cfe/trunk/test/CXX/special/class.dtor/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.dtor/p3.cpp?rev=166372&r1=166371&r2=166372&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.dtor/p3.cpp (original)
+++ cfe/trunk/test/CXX/special/class.dtor/p3.cpp Sat Oct 20 03:26:51 2012
@@ -4,10 +4,10 @@
 // the exception specification adjustment occurs.
 namespace DR1492 {
   struct A { ~A(); }; // expected-note {{here}}
-  A::~A() noexcept {} // expected-error {{does not match previous declaration}}
+  A::~A() noexcept {} // expected-warning {{previously declared with an implicit exception specification}}
 
   struct B { ~B() noexcept; }; // expected-note {{here}}
-  B::~B() {} // expected-warning {{~B' is missing exception specification 'noexcept'}}
+  B::~B() {} // expected-warning {{previously declared with an explicit exception specification}}
 
   template<typename T> struct C {
     T t;





More information about the cfe-commits mailing list