diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 5b93e513ea..9e9fda791f 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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. diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 5666c0a8d3..0bea565f93 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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()) { + CXXRecordDecl *BaseClassDecl = cast(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()) { + CXXRecordDecl *BaseClassDecl = cast(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()) { + CXXRecordDecl *FieldRecDecl = cast(RecordTy->getDecl()); + CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl); + if (Constructor) + ExceptSpec.CalledDecl(F->getLocation(), Constructor); + } + } + return ExceptSpec; } diff --git a/test/CXX/except/except.spec/p14.cpp b/test/CXX/except/except.spec/p14.cpp index 99ed2fdee1..dda69e9aad 100644 --- a/test/CXX/except/except.spec/p14.cpp +++ b/test/CXX/except/except.spec/p14.cpp @@ -112,3 +112,26 @@ namespace rdar13017229 { Typo foo(); // expected-error{{unknown type name 'Typo'}} }; } + +namespace InhCtor { + template struct X {}; + struct Base { + Base(X<0>) noexcept(true); + Base(X<1>) noexcept(false); + Base(X<2>) throw(X<2>); + template Base(T) throw(T); + }; + template struct Throw { + Throw() throw(T); + }; + struct Derived : Base, Throw> { + using Base::Base; + Throw> 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>{}}), ""); +} diff --git a/www/cxx_status.html b/www/cxx_status.html index 21e337f837..715efda47e 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -196,7 +196,7 @@ releases prior to version 3.2 in C++11 mode.

Inheriting constructors N2540 - No + SVN Explicit conversion operators