]> granicus.if.org Git - clang/commitdiff
Add support for computing the exception specification for an inheriting
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 10 Apr 2013 06:11:48 +0000 (06:11 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 10 Apr 2013 06:11:48 +0000 (06:11 +0000)
constructor. This isn't quite perfect (as usual, we don't handle default
arguments correctly yet, and we don't deal with copy/move constructors for
arguments correctly either, but this will be fixed when we implement core issue
1351.

This completes our support for inheriting constructors.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@179154 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/Sema.h
lib/Sema/SemaDeclCXX.cpp
test/CXX/except/except.spec/p14.cpp
www/cxx_status.html

index 5b93e513eafe076228b9d2bca5177c1500b697f3..9e9fda791fd613cff69ab12b4d2cbe921c075b5e 100644 (file)
@@ -3542,7 +3542,7 @@ public:
     const QualType *data() const { return Exceptions.data(); }
 
     /// \brief Integrate another called method into the collected data.
-    void CalledDecl(SourceLocation CallLoc, CXXMethodDecl *Method);
+    void CalledDecl(SourceLocation CallLoc, const CXXMethodDecl *Method);
 
     /// \brief Integrate an invoked expression into the collected data.
     void CalledExpr(Expr *E);
@@ -3606,7 +3606,7 @@ public:
   /// \brief Determine what sort of exception specification an inheriting
   /// constructor of a class will have.
   ImplicitExceptionSpecification
-  ComputeInheritingCtorExceptionSpec(CXXMethodDecl *MD);
+  ComputeInheritingCtorExceptionSpec(CXXConstructorDecl *CD);
 
   /// \brief Evaluate the implicit exception specification for a defaulted
   /// special member function.
index 5666c0a8d33e13fb15ae140404001778bfd899cf..0bea565f937b26acb93ad59692a6d311d5c01918 100644 (file)
@@ -145,8 +145,9 @@ namespace {
   }
 }
 
-void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc,
-                                                      CXXMethodDecl *Method) {
+void
+Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc,
+                                                 const CXXMethodDecl *Method) {
   // If we have an MSAny spec already, don't bother.
   if (!Method || ComputedEST == EST_MSAny)
     return;
@@ -7522,9 +7523,73 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc,
 }
 
 Sema::ImplicitExceptionSpecification
-Sema::ComputeInheritingCtorExceptionSpec(CXXMethodDecl *MD) {
+Sema::ComputeInheritingCtorExceptionSpec(CXXConstructorDecl *CD) {
+  CXXRecordDecl *ClassDecl = CD->getParent();
+
+  // C++ [except.spec]p14:
+  //   An inheriting constructor [...] shall have an exception-specification. [...]
   ImplicitExceptionSpecification ExceptSpec(*this);
-  // FIXME: Compute the exception spec.
+  if (ClassDecl->isInvalidDecl())
+    return ExceptSpec;
+
+  // Inherited constructor.
+  const CXXConstructorDecl *InheritedCD = CD->getInheritedConstructor();
+  const CXXRecordDecl *InheritedDecl = InheritedCD->getParent();
+  // FIXME: Copying or moving the parameters could add extra exceptions to the
+  // set, as could the default arguments for the inherited constructor. This
+  // will be addressed when we implement the resolution of core issue 1351.
+  ExceptSpec.CalledDecl(CD->getLocStart(), InheritedCD);
+
+  // Direct base-class constructors.
+  for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(),
+                                       BEnd = ClassDecl->bases_end();
+       B != BEnd; ++B) {
+    if (B->isVirtual()) // Handled below.
+      continue;
+
+    if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
+      CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
+      if (BaseClassDecl == InheritedDecl)
+        continue;
+      CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
+      if (Constructor)
+        ExceptSpec.CalledDecl(B->getLocStart(), Constructor);
+    }
+  }
+
+  // Virtual base-class constructors.
+  for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(),
+                                       BEnd = ClassDecl->vbases_end();
+       B != BEnd; ++B) {
+    if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
+      CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
+      if (BaseClassDecl == InheritedDecl)
+        continue;
+      CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
+      if (Constructor)
+        ExceptSpec.CalledDecl(B->getLocStart(), Constructor);
+    }
+  }
+
+  // Field constructors.
+  for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
+                               FEnd = ClassDecl->field_end();
+       F != FEnd; ++F) {
+    if (F->hasInClassInitializer()) {
+      if (Expr *E = F->getInClassInitializer())
+        ExceptSpec.CalledExpr(E);
+      else if (!F->isInvalidDecl())
+        Diag(CD->getLocation(),
+             diag::err_in_class_initializer_references_def_ctor) << CD;
+    } else if (const RecordType *RecordTy
+              = Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
+      CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
+      CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl);
+      if (Constructor)
+        ExceptSpec.CalledDecl(F->getLocation(), Constructor);
+    }
+  }
+
   return ExceptSpec;
 }
 
index 99ed2fdee19d9f54f126ca09aa1c98122cb7500a..dda69e9aad60dc48582e4489404d1609fa3f28ed 100644 (file)
@@ -112,3 +112,26 @@ namespace rdar13017229 {
     Typo foo(); // expected-error{{unknown type name 'Typo'}}
   };
 }
+
+namespace InhCtor {
+  template<int> struct X {};
+  struct Base {
+    Base(X<0>) noexcept(true);
+    Base(X<1>) noexcept(false);
+    Base(X<2>) throw(X<2>);
+    template<typename T> Base(T) throw(T);
+  };
+  template<typename T> struct Throw {
+    Throw() throw(T);
+  };
+  struct Derived : Base, Throw<X<3>> {
+    using Base::Base;
+    Throw<X<4>> x;
+  };
+  struct Test {
+    friend Derived::Derived(X<0>) throw(X<3>, X<4>);
+    friend Derived::Derived(X<1>) noexcept(false);
+    friend Derived::Derived(X<2>) throw(X<2>, X<3>, X<4>);
+  };
+  static_assert(!noexcept(Derived{X<5>{}}), "");
+}
index 21e337f8371a5691f37ebfdf0d858eaed5ce3574..715efda47e748736f551df5012ba840258656405 100644 (file)
@@ -196,7 +196,7 @@ releases prior to version 3.2 in C++11 mode.</p>
     <tr>
       <td>Inheriting constructors</td>
       <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2540.htm">N2540</a></td>
-      <td class="none" align="center">No</td>
+      <td class="svn" align="center">SVN</td>
     </tr>
     <tr>
       <td>Explicit conversion operators</td>