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);
/// \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.
}
}
-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;
}
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;
}
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>{}}), "");
+}