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
This commit is contained in:
Richard Smith 2013-04-10 06:11:48 +00:00
Родитель 0baaabb717
Коммит 0b0ca4724d
4 изменённых файлов: 95 добавлений и 7 удалений

Просмотреть файл

@ -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.

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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>{}}), "");
}

Просмотреть файл

@ -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>