diff options
-rw-r--r-- | include/clang/Sema/Sema.h | 14 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 194 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 29 | ||||
-rw-r--r-- | test/CXX/special/class.ctor/p5-0x.cpp | 12 | ||||
-rw-r--r-- | unittests/AST/DeclPrinterTest.cpp | 3 |
5 files changed, 149 insertions, 103 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 16360e5e8c..047804ae4f 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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 diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 2fae8c9f91..027491cbbe 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 337534eaac..566f6eef7f 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -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); + if (PatternDecl->isDefaulted()) + SetDeclDefaulted(Function, PatternDecl->getLocation()); + else { + ActOnStartOfFunctionDef(0, Function); - MultiLevelTemplateArgumentList TemplateArgs = - getTemplateInstantiationArgs(Function, 0, false, PatternDecl); + // Enter the scope of this instantiation. We don't use + // PushDeclContext because we don't have a scope. + Sema::ContextRAII savedContext(*this, Function); - addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope, - TemplateArgs); + MultiLevelTemplateArgumentList TemplateArgs = + getTemplateInstantiationArgs(Function, 0, false, PatternDecl); - if (PatternDecl->isDefaulted()) { - ActOnFinishFunctionBody(Function, 0, /*IsInstantiation=*/true); + addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope, + TemplateArgs); - SetDeclDefaulted(Function, PatternDecl->getLocation()); - } else { // If this is a constructor, instantiate the member initializers. if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(PatternDecl)) { @@ -2824,11 +2823,11 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, ActOnFinishFunctionBody(Function, Body.get(), /*IsInstantiation=*/true); - } - PerformDependentDiagnostics(PatternDecl, TemplateArgs); + PerformDependentDiagnostics(PatternDecl, TemplateArgs); - savedContext.pop(); + savedContext.pop(); + } DeclGroupRef DG(Function); Consumer.HandleTopLevelDecl(DG); diff --git a/test/CXX/special/class.ctor/p5-0x.cpp b/test/CXX/special/class.ctor/p5-0x.cpp index ab8fdb0f1b..0f4add8c97 100644 --- a/test/CXX/special/class.ctor/p5-0x.cpp +++ b/test/CXX/special/class.ctor/p5-0x.cpp @@ -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), ""); +} diff --git a/unittests/AST/DeclPrinterTest.cpp b/unittests/AST/DeclPrinterTest.cpp index 50aab03212..844b9a49e1 100644 --- a/unittests/AST/DeclPrinterTest.cpp +++ b/unittests/AST/DeclPrinterTest.cpp @@ -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) { |