forked from OSchip/llvm-project
PR14558: Compute triviality of special members (etc) at the end of the class
definition, rather than at the end of the definition of the set of nested classes. We still defer checking of the user-specified exception specification to the end of the nesting -- we can't check that until we've parsed the in-class initializers for non-static data members. llvm-svn: 169805
This commit is contained in:
parent
d4c0c6cb22
commit
bd3051272c
|
@ -366,6 +366,16 @@ public:
|
|||
const CXXDestructorDecl*>, 2>
|
||||
DelayedDestructorExceptionSpecChecks;
|
||||
|
||||
/// \brief All the members seen during a class definition which were both
|
||||
/// explicitly defaulted and had explicitly-specified exception
|
||||
/// specifications, along with the function type containing their
|
||||
/// user-specified exception specification. Those exception specifications
|
||||
/// were overridden with the default specifications, but we still need to
|
||||
/// check whether they are compatible with the default specification, and
|
||||
/// we can't do that until the nesting set of class definitions is complete.
|
||||
SmallVector<std::pair<CXXMethodDecl*, const FunctionProtoType*>, 2>
|
||||
DelayedDefaultedMemberExceptionSpecs;
|
||||
|
||||
/// \brief Callback to the parser to parse templated functions when needed.
|
||||
typedef void LateTemplateParserCB(void *P, const FunctionDecl *FD);
|
||||
LateTemplateParserCB *LateTemplateParser;
|
||||
|
@ -4441,8 +4451,10 @@ public:
|
|||
StorageClass& SC);
|
||||
Decl *ActOnConversionDeclarator(CXXConversionDecl *Conversion);
|
||||
|
||||
void CheckExplicitlyDefaultedAndDeletedMethods(CXXRecordDecl *Record);
|
||||
void CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD);
|
||||
void CheckExplicitlyDefaultedMemberExceptionSpec(CXXMethodDecl *MD,
|
||||
const FunctionProtoType *T);
|
||||
void CheckDelayedExplicitlyDefaultedMemberExceptionSpecs();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ Derived Classes
|
||||
|
|
|
@ -3981,14 +3981,69 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
|
|||
DiagnoseAbstractType(Record);
|
||||
}
|
||||
|
||||
// See if a method overloads virtual methods in a base
|
||||
/// class without overriding any.
|
||||
if (!Record->isDependentType()) {
|
||||
for (CXXRecordDecl::method_iterator M = Record->method_begin(),
|
||||
MEnd = Record->method_end();
|
||||
M != MEnd; ++M) {
|
||||
// See if a method overloads virtual methods in a base
|
||||
// class without overriding any.
|
||||
if (!M->isStatic())
|
||||
DiagnoseHiddenVirtualMethods(Record, *M);
|
||||
|
||||
// Check whether the explicitly-defaulted special members are valid.
|
||||
if (!M->isInvalidDecl() && M->isExplicitlyDefaulted())
|
||||
CheckExplicitlyDefaultedSpecialMember(*M);
|
||||
|
||||
// For an explicitly defaulted or deleted special member, we defer
|
||||
// determining triviality until the class is complete. That time is now!
|
||||
if (!M->isImplicit() && !M->isUserProvided()) {
|
||||
CXXSpecialMember CSM = getSpecialMember(*M);
|
||||
if (CSM != CXXInvalid) {
|
||||
M->setTrivial(SpecialMemberIsTrivial(*M, CSM));
|
||||
|
||||
// Inform the class that we've finished declaring this member.
|
||||
Record->finishedDefaultedOrDeletedMember(*M);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// C++11 [dcl.constexpr]p8: A constexpr specifier for a non-static member
|
||||
// function that is not a constructor declares that member function to be
|
||||
// const. [...] The class of which that function is a member shall be
|
||||
// a literal type.
|
||||
//
|
||||
// If the class has virtual bases, any constexpr members will already have
|
||||
// been diagnosed by the checks performed on the member declaration, so
|
||||
// suppress this (less useful) diagnostic.
|
||||
//
|
||||
// We delay this until we know whether an explicitly-defaulted (or deleted)
|
||||
// destructor for the class is trivial.
|
||||
if (LangOpts.CPlusPlus0x && !Record->isDependentType() &&
|
||||
!Record->isLiteral() && !Record->getNumVBases()) {
|
||||
for (CXXRecordDecl::method_iterator M = Record->method_begin(),
|
||||
MEnd = Record->method_end();
|
||||
M != MEnd; ++M) {
|
||||
if (M->isConstexpr() && M->isInstance() && !isa<CXXConstructorDecl>(*M)) {
|
||||
switch (Record->getTemplateSpecializationKind()) {
|
||||
case TSK_ImplicitInstantiation:
|
||||
case TSK_ExplicitInstantiationDeclaration:
|
||||
case TSK_ExplicitInstantiationDefinition:
|
||||
// If a template instantiates to a non-literal type, but its members
|
||||
// instantiate to constexpr functions, the template is technically
|
||||
// ill-formed, but we allow it for sanity.
|
||||
continue;
|
||||
|
||||
case TSK_Undeclared:
|
||||
case TSK_ExplicitSpecialization:
|
||||
RequireLiteralType(M->getLocation(), Context.getRecordType(Record),
|
||||
diag::err_constexpr_method_non_literal);
|
||||
break;
|
||||
}
|
||||
|
||||
// Only produce one error per class.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4002,27 +4057,6 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
|
|||
DeclareInheritedConstructors(Record);
|
||||
}
|
||||
|
||||
void Sema::CheckExplicitlyDefaultedAndDeletedMethods(CXXRecordDecl *Record) {
|
||||
for (CXXRecordDecl::method_iterator MI = Record->method_begin(),
|
||||
ME = Record->method_end();
|
||||
MI != ME; ++MI) {
|
||||
if (!MI->isInvalidDecl() && MI->isExplicitlyDefaulted())
|
||||
CheckExplicitlyDefaultedSpecialMember(*MI);
|
||||
|
||||
if (!MI->isImplicit() && !MI->isUserProvided()) {
|
||||
// For an explicitly defaulted or deleted special member, we defer
|
||||
// determining triviality until the class is complete. That time is now!
|
||||
CXXSpecialMember CSM = getSpecialMember(*MI);
|
||||
if (CSM != CXXInvalid) {
|
||||
MI->setTrivial(SpecialMemberIsTrivial(*MI, CSM));
|
||||
|
||||
// Inform the class that we've finished declaring this member.
|
||||
Record->finishedDefaultedOrDeletedMember(*MI);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the special member function which would be selected to perform the
|
||||
/// specified operation on the specified class type a constexpr constructor?
|
||||
static bool specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
|
||||
|
@ -4271,16 +4305,6 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
|
|||
HadError = true;
|
||||
}
|
||||
|
||||
// Rebuild the type with the implicit exception specification added, if we
|
||||
// are going to need it.
|
||||
const FunctionProtoType *ImplicitType = 0;
|
||||
if (First || Type->hasExceptionSpec()) {
|
||||
FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo();
|
||||
computeImplicitExceptionSpec(*this, MD->getLocation(), MD).getEPI(EPI);
|
||||
ImplicitType = cast<FunctionProtoType>(
|
||||
Context.getFunctionType(ReturnType, &ArgType, ExpectedParams, EPI));
|
||||
}
|
||||
|
||||
// C++11 [dcl.fct.def.default]p2:
|
||||
// An explicitly-defaulted function may be declared constexpr only if it
|
||||
// would have been implicitly declared as constexpr,
|
||||
|
@ -4295,13 +4319,17 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
|
|||
// FIXME: Explain why the constructor can't be constexpr.
|
||||
HadError = true;
|
||||
}
|
||||
|
||||
// and may have an explicit exception-specification only if it is compatible
|
||||
// with the exception-specification on the implicit declaration.
|
||||
if (Type->hasExceptionSpec() &&
|
||||
CheckEquivalentExceptionSpec(
|
||||
PDiag(diag::err_incorrect_defaulted_exception_spec) << CSM,
|
||||
PDiag(), ImplicitType, SourceLocation(), Type, MD->getLocation()))
|
||||
HadError = true;
|
||||
if (Type->hasExceptionSpec()) {
|
||||
// Delay the check if this is the first declaration of the special member,
|
||||
// since we may not have parsed some necessary in-class initializers yet.
|
||||
if (First)
|
||||
DelayedDefaultedMemberExceptionSpecs.push_back(std::make_pair(MD, Type));
|
||||
else
|
||||
CheckExplicitlyDefaultedMemberExceptionSpec(MD, Type);
|
||||
}
|
||||
|
||||
// If a function is explicitly defaulted on its first declaration,
|
||||
if (First) {
|
||||
|
@ -4311,7 +4339,11 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
|
|||
|
||||
// -- it is implicitly considered to have the same exception-specification
|
||||
// as if it had been implicitly declared,
|
||||
MD->setType(QualType(ImplicitType, 0));
|
||||
FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo();
|
||||
EPI.ExceptionSpecType = EST_Unevaluated;
|
||||
EPI.ExceptionSpecDecl = MD;
|
||||
MD->setType(Context.getFunctionType(ReturnType, &ArgType,
|
||||
ExpectedParams, EPI));
|
||||
}
|
||||
|
||||
if (ShouldDeleteSpecialMember(MD, CSM)) {
|
||||
|
@ -4330,6 +4362,36 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
|
|||
MD->setInvalidDecl();
|
||||
}
|
||||
|
||||
/// Check whether the exception specification provided for an
|
||||
/// explicitly-defaulted special member matches the exception specification
|
||||
/// that would have been generated for an implicit special member, per
|
||||
/// C++11 [dcl.fct.def.default]p2.
|
||||
void Sema::CheckExplicitlyDefaultedMemberExceptionSpec(
|
||||
CXXMethodDecl *MD, const FunctionProtoType *SpecifiedType) {
|
||||
// Compute the implicit exception specification.
|
||||
FunctionProtoType::ExtProtoInfo EPI;
|
||||
computeImplicitExceptionSpec(*this, MD->getLocation(), MD).getEPI(EPI);
|
||||
const FunctionProtoType *ImplicitType = cast<FunctionProtoType>(
|
||||
Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
|
||||
|
||||
// Ensure that it matches.
|
||||
CheckEquivalentExceptionSpec(
|
||||
PDiag(diag::err_incorrect_defaulted_exception_spec)
|
||||
<< getSpecialMember(MD), PDiag(),
|
||||
ImplicitType, SourceLocation(),
|
||||
SpecifiedType, MD->getLocation());
|
||||
}
|
||||
|
||||
void Sema::CheckDelayedExplicitlyDefaultedMemberExceptionSpecs() {
|
||||
for (unsigned I = 0, N = DelayedDefaultedMemberExceptionSpecs.size();
|
||||
I != N; ++I)
|
||||
CheckExplicitlyDefaultedMemberExceptionSpec(
|
||||
DelayedDefaultedMemberExceptionSpecs[I].first,
|
||||
DelayedDefaultedMemberExceptionSpecs[I].second);
|
||||
|
||||
DelayedDefaultedMemberExceptionSpecs.clear();
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct SpecialMemberDeletionInfo {
|
||||
Sema &S;
|
||||
|
@ -7500,52 +7562,9 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
|
|||
}
|
||||
|
||||
void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) {
|
||||
if (!D) return;
|
||||
AdjustDeclIfTemplate(D);
|
||||
|
||||
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D);
|
||||
|
||||
if (!ClassDecl->isDependentType())
|
||||
CheckExplicitlyDefaultedAndDeletedMethods(ClassDecl);
|
||||
|
||||
// C++11 [dcl.constexpr]p8: A constexpr specifier for a non-static member
|
||||
// function that is not a constructor declares that member function to be
|
||||
// const. [...] The class of which that function is a member shall be
|
||||
// a literal type.
|
||||
//
|
||||
// If the class has virtual bases, any constexpr members will already have
|
||||
// been diagnosed by the checks performed on the member declaration, so
|
||||
// suppress this (less useful) diagnostic.
|
||||
//
|
||||
// We delay this until we know whether an explicitly-defaulted (or deleted)
|
||||
// destructor for the class is trivial.
|
||||
if (LangOpts.CPlusPlus0x && !ClassDecl->isDependentType() &&
|
||||
!ClassDecl->isLiteral() && !ClassDecl->getNumVBases()) {
|
||||
for (CXXRecordDecl::method_iterator M = ClassDecl->method_begin(),
|
||||
MEnd = ClassDecl->method_end();
|
||||
M != MEnd; ++M) {
|
||||
if (M->isConstexpr() && M->isInstance() && !isa<CXXConstructorDecl>(*M)) {
|
||||
switch (ClassDecl->getTemplateSpecializationKind()) {
|
||||
case TSK_ImplicitInstantiation:
|
||||
case TSK_ExplicitInstantiationDeclaration:
|
||||
case TSK_ExplicitInstantiationDefinition:
|
||||
// If a template instantiates to a non-literal type, but its members
|
||||
// instantiate to constexpr functions, the template is technically
|
||||
// ill-formed, but we allow it for sanity.
|
||||
continue;
|
||||
|
||||
case TSK_Undeclared:
|
||||
case TSK_ExplicitSpecialization:
|
||||
RequireLiteralType(M->getLocation(), Context.getRecordType(ClassDecl),
|
||||
diag::err_constexpr_method_non_literal);
|
||||
break;
|
||||
}
|
||||
|
||||
// Only produce one error per class.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check that any explicitly-defaulted methods have exception specifications
|
||||
// compatible with their implicit exception specifications.
|
||||
CheckDelayedExplicitlyDefaultedMemberExceptionSpecs();
|
||||
}
|
||||
|
||||
void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
|
||||
|
@ -10882,6 +10901,11 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
|
|||
|
||||
CheckExplicitlyDefaultedSpecialMember(MD);
|
||||
|
||||
// The exception specification is needed because we are defining the
|
||||
// function.
|
||||
ResolveExceptionSpec(DefaultLoc,
|
||||
MD->getType()->castAs<FunctionProtoType>());
|
||||
|
||||
switch (Member) {
|
||||
case CXXDefaultConstructor: {
|
||||
CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
|
||||
|
|
|
@ -2782,7 +2782,6 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
|
|||
|
||||
EnterExpressionEvaluationContext EvalContext(*this,
|
||||
Sema::PotentiallyEvaluated);
|
||||
ActOnStartOfFunctionDef(0, Function);
|
||||
|
||||
// Introduce a new scope where local variable instantiations will be
|
||||
// recorded, unless we're actually a member function within a local
|
||||
|
@ -2794,21 +2793,21 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
|
|||
|
||||
LocalInstantiationScope Scope(*this, MergeWithParentScope);
|
||||
|
||||
// Enter the scope of this instantiation. We don't use
|
||||
// PushDeclContext because we don't have a scope.
|
||||
Sema::ContextRAII savedContext(*this, Function);
|
||||
|
||||
MultiLevelTemplateArgumentList TemplateArgs =
|
||||
getTemplateInstantiationArgs(Function, 0, false, PatternDecl);
|
||||
|
||||
addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope,
|
||||
TemplateArgs);
|
||||
|
||||
if (PatternDecl->isDefaulted()) {
|
||||
ActOnFinishFunctionBody(Function, 0, /*IsInstantiation=*/true);
|
||||
|
||||
if (PatternDecl->isDefaulted())
|
||||
SetDeclDefaulted(Function, PatternDecl->getLocation());
|
||||
} else {
|
||||
else {
|
||||
ActOnStartOfFunctionDef(0, Function);
|
||||
|
||||
// Enter the scope of this instantiation. We don't use
|
||||
// PushDeclContext because we don't have a scope.
|
||||
Sema::ContextRAII savedContext(*this, Function);
|
||||
|
||||
MultiLevelTemplateArgumentList TemplateArgs =
|
||||
getTemplateInstantiationArgs(Function, 0, false, PatternDecl);
|
||||
|
||||
addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope,
|
||||
TemplateArgs);
|
||||
|
||||
// If this is a constructor, instantiate the member initializers.
|
||||
if (const CXXConstructorDecl *Ctor =
|
||||
dyn_cast<CXXConstructorDecl>(PatternDecl)) {
|
||||
|
@ -2824,12 +2823,12 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
|
|||
|
||||
ActOnFinishFunctionBody(Function, Body.get(),
|
||||
/*IsInstantiation=*/true);
|
||||
|
||||
PerformDependentDiagnostics(PatternDecl, TemplateArgs);
|
||||
|
||||
savedContext.pop();
|
||||
}
|
||||
|
||||
PerformDependentDiagnostics(PatternDecl, TemplateArgs);
|
||||
|
||||
savedContext.pop();
|
||||
|
||||
DeclGroupRef DG(Function);
|
||||
Consumer.HandleTopLevelDecl(DG);
|
||||
|
||||
|
|
|
@ -195,3 +195,15 @@ static_assert(__has_trivial_constructor(Trivial4<int>), "Trivial4 is trivial");
|
|||
|
||||
template<typename T> class Trivial5 { Trivial5() = delete; };
|
||||
static_assert(__has_trivial_constructor(Trivial5<int>), "Trivial5 is trivial");
|
||||
|
||||
namespace PR14558 {
|
||||
// Ensure we determine whether an explicitly-defaulted or deleted special
|
||||
// member is trivial before we return to parsing the containing class.
|
||||
struct A {
|
||||
struct B { B() = default; } b;
|
||||
struct C { C() = delete; } c;
|
||||
};
|
||||
|
||||
static_assert(__has_trivial_constructor(A), "");
|
||||
static_assert(__has_trivial_constructor(A::B), "");
|
||||
}
|
||||
|
|
|
@ -476,8 +476,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl8) {
|
|||
" A() = default;"
|
||||
"};",
|
||||
constructorDecl(ofClass(hasName("A"))).bind("id"),
|
||||
"A() noexcept = default"));
|
||||
// Should be: "A() = default;" if we care about noexcept as written
|
||||
"A() = default"));
|
||||
}
|
||||
|
||||
TEST(DeclPrinter, TestCXXConstructorDecl9) {
|
||||
|
|
Loading…
Reference in New Issue