From: Richard Smith Date: Wed, 10 Apr 2013 06:11:48 +0000 (+0000) Subject: Add support for computing the exception specification for an inheriting X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0b0ca4724d1c05dc0dd1d6e5aff4c8a439cbb1a2;p=clang Add support for computing the exception specification for an inheriting 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 --- 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