diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 6c3b418ee8cc..46136c3babea 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -469,7 +469,8 @@ class CXXRecordDecl : public RecordDecl { bool HasTrivialDestructor : 1; /// HasNonLiteralTypeFieldsOrBases - True when this class contains at least - /// one non-static data member or base class of non literal type. + /// one non-static data member or base class of non-literal or volatile + /// type. bool HasNonLiteralTypeFieldsOrBases : 1; /// ComputedVisibleConversions - True when visible conversion functions are @@ -1095,8 +1096,8 @@ public: // (C++ [class.dtor]p3) bool hasTrivialDestructor() const { return data().HasTrivialDestructor; } - // hasNonLiteralTypeFieldsOrBases - Whether this class has a non-literal type - // non-static data member or base class. + // hasNonLiteralTypeFieldsOrBases - Whether this class has a non-literal or + // volatile type non-static data member or base class. bool hasNonLiteralTypeFieldsOrBases() const { return data().HasNonLiteralTypeFieldsOrBases; } @@ -1116,20 +1117,23 @@ public: // isLiteral - Whether this class is a literal type. // - // C++0x [basic.types]p10 + // C++11 [basic.types]p10 // A class type that has all the following properties: - // -- a trivial destructor + // -- it has a trivial destructor // -- every constructor call and full-expression in the // brace-or-equal-intializers for non-static data members (if any) is // a constant expression. // -- it is an aggregate type or has at least one constexpr constructor or // constructor template that is not a copy or move constructor, and - // -- all non-static data members and base classes of literal types + // -- all of its non-static data members and base classes are of literal + // types // - // We resolve DR1361 by ignoring the second bullet. + // We resolve DR1361 by ignoring the second bullet. We resolve DR1452 by + // treating types with trivial default constructors as literal types. bool isLiteral() const { return hasTrivialDestructor() && - (isAggregate() || hasConstexprNonCopyMoveConstructor()) && + (isAggregate() || hasConstexprNonCopyMoveConstructor() || + hasTrivialDefaultConstructor()) && !hasNonLiteralTypeFieldsOrBases(); } diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index fb6e73090e2f..0f1a05d16f2e 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -28,6 +28,11 @@ def note_constexpr_lshift_discards : Note<"signed left shift discards bits">; def note_constexpr_invalid_function : Note< "%select{non-constexpr|undefined}0 %select{function|constructor}1 %2 cannot " "be used in a constant expression">; +def note_constexpr_virtual_call : Note< + "cannot evaluate virtual function call in a constant expression">; +def note_constexpr_virtual_base : Note< + "cannot construct object of type %0 with virtual base class " + "in a constant expression">; def note_constexpr_nonliteral : Note< "non-literal type %0 cannot be used in a constant expression">; def note_constexpr_non_global : Note< diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index dbc8aa2ecad1..3e6c190343bd 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1361,6 +1361,8 @@ def err_invalid_constexpr_var_decl : Error< "constexpr variable declaration must be a definition">; def err_constexpr_static_mem_var_requires_init : Error< "declaration of constexpr static data member %0 requires an initializer">; +def err_constexpr_var_non_literal : Error< + "constexpr variable cannot have non-literal type %0">; def err_constexpr_var_requires_const_init : Error< "constexpr variable %0 must be initialized by a constant expression">; def err_constexpr_redecl_mismatch : Error< @@ -1369,29 +1371,17 @@ def err_constexpr_redecl_mismatch : Error< def note_constexpr_redecl_mismatch : Note< "previous declaration was %select{not |}0marked constexpr">; def err_constexpr_virtual : Error<"virtual function cannot be constexpr">; -def note_constexpr_tmpl_virtual : Note<"function template instantiation is not " - "constexpr because it is virtual">; def err_constexpr_virtual_base : Error< "constexpr %select{member function|constructor}0 not allowed in " "%select{class|struct}1 with virtual base %plural{1:class|:classes}2">; -def note_constexpr_tmpl_virtual_base : Note< - "%select{function|constructor}0 template instantiation is " - "not constexpr because %select{class|struct}1 has virtual base " - "%plural{1:class|:classes}2">; def note_non_literal_virtual_base : Note<"%select{class|struct}0 with virtual " "base %plural{1:class|:classes}1 is not a literal type">; def note_constexpr_virtual_base_here : Note<"virtual base class declared here">; def err_constexpr_non_literal_return : Error< "constexpr function's return type %0 is not a literal type">; -def note_constexpr_tmpl_non_literal_return : Note< - "function template instantiation is not constexpr because return type %0 is " - "not a literal type">; def err_constexpr_non_literal_param : Error< "constexpr %select{function|constructor}1's %ordinal0 parameter type %2 is " "not a literal type">; -def note_constexpr_tmpl_non_literal_param : Note< - "%select{function|constructor}1 template instantiation is not constexpr " - "because %ordinal0 parameter type %2 is not a literal type">; def err_constexpr_body_invalid_stmt : Error< "statement not allowed in constexpr %select{function|constructor}0">; def err_constexpr_type_definition : Error< @@ -1426,7 +1416,8 @@ def note_non_literal_no_constexpr_ctors : Note< def note_non_literal_base_class : Note< "%0 is not literal because it has base class %1 of non-literal type">; def note_non_literal_field : Note< - "%0 is not literal because it has data member %1 of non-literal type %2">; + "%0 is not literal because it has data member %1 of " + "%select{non-literal|volatile}3 type %2">; def note_non_literal_user_provided_dtor : Note< "%0 is not literal because it has a user-provided destructor">; def note_non_literal_nontrivial_dtor : Note< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 3333e56e7142..2e5f8750dbd9 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -835,8 +835,7 @@ public: PartialDiagnostic> Note); bool RequireLiteralType(SourceLocation Loc, QualType T, - const PartialDiagnostic &PD, - bool AllowIncompleteType = false); + const PartialDiagnostic &PD); QualType getElaboratedType(ElaboratedTypeKeyword Keyword, const CXXScopeSpec &SS, QualType T); @@ -1004,23 +1003,8 @@ public: bool &AddToScope); bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); - /// \brief The kind of constexpr declaration checking we are performing. - /// - /// The kind affects which diagnostics (if any) are emitted if the function - /// does not satisfy the requirements of a constexpr function declaration. - enum CheckConstexprKind { - /// \brief Check a constexpr function declaration, and produce errors if it - /// does not satisfy the requirements. - CCK_Declaration, - /// \brief Check a constexpr function template instantiation. - CCK_Instantiation, - /// \brief Produce notes explaining why an instantiation was not constexpr. - CCK_NoteNonConstexprInstantiation - }; - bool CheckConstexprFunctionDecl(const FunctionDecl *FD, - CheckConstexprKind CCK); - bool CheckConstexprFunctionBody(const FunctionDecl *FD, Stmt *Body, - bool IsInstantiation); + bool CheckConstexprFunctionDecl(const FunctionDecl *FD); + bool CheckConstexprFunctionBody(const FunctionDecl *FD, Stmt *Body); void DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); // Returns true if the function declaration is a redeclaration diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 22a9eadaad93..f9d95b121a13 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -799,8 +799,8 @@ NotASpecialMember:; data().IsStandardLayout = false; } - // Record if this field is the first non-literal field or base. - if (!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType()) + // Record if this field is the first non-literal or volatile field or base. + if (!T->isLiteralType() || T.isVolatileQualified()) data().HasNonLiteralTypeFieldsOrBases = true; if (Field->hasInClassInitializer()) { diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 998bb705f9dd..520e3cbbafea 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2033,6 +2033,12 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, if (!Info.CheckCallLimit(CallLoc)) return false; + const CXXRecordDecl *RD = Definition->getParent(); + if (RD->getNumVBases()) { + Info.Diag(CallLoc, diag::note_constexpr_virtual_base) << RD; + return false; + } + CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues.data()); // If it's a delegating constructor, just delegate. @@ -2044,7 +2050,6 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, // For a trivial copy or move constructor, perform an APValue copy. This is // essential for unions, where the operations performed by the constructor // cannot be represented by ctor-initializers. - const CXXRecordDecl *RD = Definition->getParent(); if (Definition->isDefaulted() && ((Definition->isCopyConstructor() && RD->hasTrivialCopyConstructor()) || (Definition->isMoveConstructor() && RD->hasTrivialMoveConstructor()))) { @@ -2083,7 +2088,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, QualType BaseType((*I)->getBaseClass(), 0); #ifndef NDEBUG // Non-virtual base classes are initialized in the order in the class - // definition. We cannot have a virtual base class for a literal type. + // definition. We have already checked for virtual base classes. assert(!BaseIt->isVirtual() && "virtual base for literal type"); assert(Info.Ctx.hasSameType(BaseIt->getType(), BaseType) && "base class initializers not in expected order"); @@ -2414,6 +2419,7 @@ public: const FunctionDecl *FD = 0; LValue *This = 0, ThisVal; llvm::ArrayRef Args(E->getArgs(), E->getNumArgs()); + bool HasQualifier = false; // Extract function decl and 'this' pointer from the callee. if (CalleeType->isSpecificBuiltinType(BuiltinType::BoundMember)) { @@ -2424,6 +2430,7 @@ public: return false; Member = ME->getMemberDecl(); This = &ThisVal; + HasQualifier = ME->hasQualifier(); } else if (const BinaryOperator *BE = dyn_cast(Callee)) { // Indirect bound member calls ('.*' or '->*'). Member = HandleMemberPointerAccess(Info, BE, ThisVal, false); @@ -2472,6 +2479,12 @@ public: if (This && !This->checkSubobject(Info, E, CSK_This)) return false; + // DR1358 allows virtual constexpr functions in some cases. Don't allow + // calls to such functions in constant expressions. + if (This && !HasQualifier && + isa(FD) && cast(FD)->isVirtual()) + return Error(E, diag::note_constexpr_virtual_call); + const FunctionDecl *Definition = 0; Stmt *Body = FD->getBody(Definition); APValue Result; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 52789c781cde..3c73f689e71c 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3991,8 +3991,15 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, TemplateParamLists.release()); } - if (D.getDeclSpec().isConstexprSpecified()) + if (D.getDeclSpec().isConstexprSpecified()) { NewVD->setConstexpr(true); + SourceLocation ConstexprLoc = D.getDeclSpec().getConstexprSpecLoc(); + if (!NewVD->isInvalidDecl() && !R->isDependentType() && + RequireLiteralType(NewVD->getLocation(), R, + PDiag(diag::err_constexpr_var_non_literal) + << SourceRange(ConstexprLoc))) + NewVD->setInvalidDecl(); + } } // Set the lexical context. If the declarator has a C++ scope specifier, the @@ -5347,10 +5354,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); - if (NewFD->isConstexpr() && !NewFD->isInvalidDecl() && - !CheckConstexprFunctionDecl(NewFD, CCK_Declaration)) - NewFD->setInvalidDecl(); - NamedDecl *PrincipalDecl = (FunctionTemplate ? cast(FunctionTemplate) : NewFD); @@ -6223,8 +6226,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, if (DclT->isDependentType()) { // Allow any 'static constexpr' members, whether or not they are of literal - // type. We separately check that the initializer is a constant expression, - // which implicitly requires the member to be of literal type. + // type. We separately check that every constexpr variable is of literal + // type. } else if (VDecl->isConstexpr()) { // Require constness. @@ -7350,8 +7353,9 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, ActivePolicy = &WP; } - if (FD && FD->isConstexpr() && !FD->isInvalidDecl() && - !CheckConstexprFunctionBody(FD, Body, IsInstantiation)) + if (!IsInstantiation && FD && FD->isConstexpr() && !FD->isInvalidDecl() && + (!CheckConstexprFunctionDecl(FD) || + !CheckConstexprFunctionBody(FD, Body))) FD->setInvalidDecl(); assert(ExprCleanupObjects.empty() && "Leftover temporaries in function"); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index b8ea85bea961..66f045ea8e24 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -632,9 +632,9 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { // CheckConstexprParameterTypes - Check whether a function's parameter types // are all literal types. If so, return true. If not, produce a suitable -// diagnostic depending on @p CCK and return false. -static bool CheckConstexprParameterTypes(Sema &SemaRef, const FunctionDecl *FD, - Sema::CheckConstexprKind CCK) { +// diagnostic and return false. +static bool CheckConstexprParameterTypes(Sema &SemaRef, + const FunctionDecl *FD) { unsigned ArgIndex = 0; const FunctionProtoType *FT = FD->getType()->getAs(); for (FunctionProtoType::arg_type_iterator i = FT->arg_type_begin(), @@ -642,63 +642,37 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef, const FunctionDecl *FD, const ParmVarDecl *PD = FD->getParamDecl(ArgIndex); SourceLocation ParamLoc = PD->getLocation(); if (!(*i)->isDependentType() && - SemaRef.RequireLiteralType(ParamLoc, *i, CCK == Sema::CCK_Declaration ? + SemaRef.RequireLiteralType(ParamLoc, *i, SemaRef.PDiag(diag::err_constexpr_non_literal_param) << ArgIndex+1 << PD->getSourceRange() - << isa(FD) : - SemaRef.PDiag(), - /*AllowIncompleteType*/ true)) { - if (CCK == Sema::CCK_NoteNonConstexprInstantiation) - SemaRef.Diag(ParamLoc, diag::note_constexpr_tmpl_non_literal_param) - << ArgIndex+1 << PD->getSourceRange() - << isa(FD) << *i; + << isa(FD))) return false; - } } return true; } // CheckConstexprFunctionDecl - Check whether a function declaration satisfies -// the requirements of a constexpr function declaration or a constexpr -// constructor declaration. Return true if it does, false if not. +// the requirements of a constexpr function definition or a constexpr +// constructor definition. If so, return true. If not, produce appropriate +// diagnostics and return false. // -// This implements C++11 [dcl.constexpr]p3,4, as amended by N3308. -// -// \param CCK Specifies whether to produce diagnostics if the function does not -// satisfy the requirements. -bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD, - CheckConstexprKind CCK) { - assert((CCK != CCK_NoteNonConstexprInstantiation || - (NewFD->getTemplateInstantiationPattern() && - NewFD->getTemplateInstantiationPattern()->isConstexpr())) && - "only constexpr templates can be instantiated non-constexpr"); - +// This implements C++11 [dcl.constexpr]p3,4, as amended by DR1360. +bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) { const CXXMethodDecl *MD = dyn_cast(NewFD); if (MD && MD->isInstance()) { - // C++11 [dcl.constexpr]p4: In the definition of a constexpr constructor... - // In addition, either its function-body shall be = delete or = default or - // it shall satisfy the following constraints: + // C++11 [dcl.constexpr]p4: + // The definition of a constexpr constructor shall satisfy the following + // constraints: // - the class shall not have any virtual base classes; - // - // We apply this to constexpr member functions too: the class cannot be a - // literal type, so the members are not permitted to be constexpr. const CXXRecordDecl *RD = MD->getParent(); if (RD->getNumVBases()) { - // Note, this is still illegal if the body is = default, since the - // implicit body does not satisfy the requirements of a constexpr - // constructor. We also reject cases where the body is = delete, as - // required by N3308. - if (CCK != CCK_Instantiation) { - Diag(NewFD->getLocation(), - CCK == CCK_Declaration ? diag::err_constexpr_virtual_base - : diag::note_constexpr_tmpl_virtual_base) - << isa(NewFD) << RD->isStruct() - << RD->getNumVBases(); - for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), - E = RD->vbases_end(); I != E; ++I) - Diag(I->getSourceRange().getBegin(), - diag::note_constexpr_virtual_base_here) << I->getSourceRange(); - } + Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base) + << isa(NewFD) << RD->isStruct() + << RD->getNumVBases(); + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) + Diag(I->getSourceRange().getBegin(), + diag::note_constexpr_virtual_base_here) << I->getSourceRange(); return false; } } @@ -710,39 +684,29 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD, // - it shall not be virtual; const CXXMethodDecl *Method = dyn_cast(NewFD); if (Method && Method->isVirtual()) { - if (CCK != CCK_Instantiation) { - Diag(NewFD->getLocation(), - CCK == CCK_Declaration ? diag::err_constexpr_virtual - : diag::note_constexpr_tmpl_virtual); + Diag(NewFD->getLocation(), diag::err_constexpr_virtual); - // If it's not obvious why this function is virtual, find an overridden - // function which uses the 'virtual' keyword. - const CXXMethodDecl *WrittenVirtual = Method; - while (!WrittenVirtual->isVirtualAsWritten()) - WrittenVirtual = *WrittenVirtual->begin_overridden_methods(); - if (WrittenVirtual != Method) - Diag(WrittenVirtual->getLocation(), - diag::note_overridden_virtual_function); - } + // If it's not obvious why this function is virtual, find an overridden + // function which uses the 'virtual' keyword. + const CXXMethodDecl *WrittenVirtual = Method; + while (!WrittenVirtual->isVirtualAsWritten()) + WrittenVirtual = *WrittenVirtual->begin_overridden_methods(); + if (WrittenVirtual != Method) + Diag(WrittenVirtual->getLocation(), + diag::note_overridden_virtual_function); return false; } // - its return type shall be a literal type; QualType RT = NewFD->getResultType(); if (!RT->isDependentType() && - RequireLiteralType(NewFD->getLocation(), RT, CCK == CCK_Declaration ? - PDiag(diag::err_constexpr_non_literal_return) : - PDiag(), - /*AllowIncompleteType*/ true)) { - if (CCK == CCK_NoteNonConstexprInstantiation) - Diag(NewFD->getLocation(), - diag::note_constexpr_tmpl_non_literal_return) << RT; + RequireLiteralType(NewFD->getLocation(), RT, + PDiag(diag::err_constexpr_non_literal_return))) return false; - } } // - each of its parameter types shall be a literal type; - if (!CheckConstexprParameterTypes(*this, NewFD, CCK)) + if (!CheckConstexprParameterTypes(*this, NewFD)) return false; return true; @@ -854,8 +818,7 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef, /// the permitted types of statement. C++11 [dcl.constexpr]p3,p4. /// /// \return true if the body is OK, false if we have diagnosed a problem. -bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body, - bool IsInstantiation) { +bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { if (isa(Body)) { // C++11 [dcl.constexpr]p3: // The definition of a constexpr function shall satisfy the following @@ -1005,7 +968,7 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body, // - every constructor involved in initializing non-static data members and // base class sub-objects shall be a constexpr constructor. llvm::SmallVector Diags; - if (!IsInstantiation && !Expr::isPotentialConstantExpr(Dcl, Diags)) { + if (!Expr::isPotentialConstantExpr(Dcl, Diags)) { Diag(Dcl->getLocation(), diag::err_constexpr_function_never_constant_expr) << isa(Dcl); for (size_t I = 0, N = Diags.size(); I != N; ++I) @@ -3755,9 +3718,6 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { // const. [...] The class of which that function is a member shall be // a literal type. // - // It's fine to diagnose constructors here too: such constructors cannot - // produce a constant expression, so are ill-formed (no diagnostic required). - // // 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. @@ -3766,16 +3726,14 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { for (CXXRecordDecl::method_iterator M = Record->method_begin(), MEnd = Record->method_end(); M != MEnd; ++M) { - if (M->isConstexpr() && M->isInstance()) { + if (M->isConstexpr() && M->isInstance() && !isa(*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. Such members are treated as - // non-constexpr. - (*M)->setConstexpr(false); + // ill-formed, but we allow it for sanity. continue; case TSK_Undeclared: diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 7449c62fee0b..fb771aa30b99 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1034,7 +1034,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, D->getLocation(), D->getDeclName(), T, TInfo, D->getStorageClass(), D->getStorageClassAsWritten(), D->isInlineSpecified(), D->hasWrittenPrototype(), - /*isConstexpr*/ false); + D->isConstexpr()); if (QualifierLoc) Function->setQualifierInfo(QualifierLoc); @@ -1379,7 +1379,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, StartLoc, NameInfo, T, TInfo, Constructor->isExplicit(), Constructor->isInlineSpecified(), - false, /*isConstexpr*/ false); + false, Constructor->isConstexpr()); } else if (CXXDestructorDecl *Destructor = dyn_cast(D)) { Method = CXXDestructorDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, @@ -1390,7 +1390,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, StartLoc, NameInfo, T, TInfo, Conversion->isInlineSpecified(), Conversion->isExplicit(), - /*isConstexpr*/ false, + Conversion->isConstexpr(), Conversion->getLocEnd()); } else { Method = CXXMethodDecl::Create(SemaRef.Context, Record, @@ -1398,7 +1398,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, D->isStatic(), D->getStorageClassAsWritten(), D->isInlineSpecified(), - /*isConstexpr*/ false, D->getLocEnd()); + D->isConstexpr(), D->getLocEnd()); } if (QualifierLoc) @@ -2305,13 +2305,6 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, EPI)); } - // C++0x [dcl.constexpr]p6: If the instantiated template specialization of - // a constexpr function template satisfies the requirements for a constexpr - // function, then it is a constexpr function. - if (Tmpl->isConstexpr() && - SemaRef.CheckConstexprFunctionDecl(New, Sema::CCK_Instantiation)) - New->setConstexpr(true); - const FunctionDecl* Definition = Tmpl; // Get the definition. Leaves the variable unchanged if undefined. diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 6cc4426e5eda..a4b3d86d10b3 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -4243,19 +4243,14 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, /// @param PD The partial diagnostic that will be printed out if T is not a /// literal type. /// -/// @param AllowIncompleteType If true, an incomplete type will be considered -/// acceptable. -/// /// @returns @c true if @p T is not a literal type and a diagnostic was emitted, /// @c false otherwise. bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, - const PartialDiagnostic &PD, - bool AllowIncompleteType) { + const PartialDiagnostic &PD) { assert(!T->isDependentType() && "type should not be dependent"); - bool Incomplete = RequireCompleteType(Loc, T, 0); - if (T->isLiteralType() || - (AllowIncompleteType && Incomplete && !T->isVoidType())) + RequireCompleteType(Loc, T, 0); + if (T->isLiteralType()) return false; if (PD.getDiagID() == 0) @@ -4273,8 +4268,9 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, const CXXRecordDecl *RD = cast(RT->getDecl()); // If the class has virtual base classes, then it's not an aggregate, and - // cannot have any constexpr constructors, so is non-literal. This is better - // to diagnose than the resulting absence of constexpr constructors. + // cannot have any constexpr constructors or a trivial default constructor, + // so is non-literal. This is better to diagnose than the resulting absence + // of constexpr constructors. if (RD->getNumVBases()) { Diag(RD->getLocation(), diag::note_non_literal_virtual_base) << RD->isStruct() << RD->getNumVBases(); @@ -4282,29 +4278,9 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, E = RD->vbases_end(); I != E; ++I) Diag(I->getSourceRange().getBegin(), diag::note_constexpr_virtual_base_here) << I->getSourceRange(); - } else if (!RD->isAggregate() && !RD->hasConstexprNonCopyMoveConstructor()) { + } else if (!RD->isAggregate() && !RD->hasConstexprNonCopyMoveConstructor() && + !RD->hasTrivialDefaultConstructor()) { Diag(RD->getLocation(), diag::note_non_literal_no_constexpr_ctors) << RD; - - switch (RD->getTemplateSpecializationKind()) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - break; - - case TSK_ImplicitInstantiation: - case TSK_ExplicitInstantiationDeclaration: - case TSK_ExplicitInstantiationDefinition: - // If the base template had constexpr constructors which were - // instantiated as non-constexpr constructors, explain why. - for (CXXRecordDecl::ctor_iterator I = RD->ctor_begin(), - E = RD->ctor_end(); I != E; ++I) { - if ((*I)->isCopyConstructor() || (*I)->isMoveConstructor()) - continue; - - FunctionDecl *Base = (*I)->getInstantiatedFromMemberFunction(); - if (Base && Base->isConstexpr()) - CheckConstexprFunctionDecl(*I, CCK_NoteNonConstexprInstantiation); - } - } } else if (RD->hasNonLiteralTypeFieldsOrBases()) { for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { @@ -4317,9 +4293,11 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, } for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I) { - if (!(*I)->getType()->isLiteralType()) { + if (!(*I)->getType()->isLiteralType() || + (*I)->getType().isVolatileQualified()) { Diag((*I)->getLocation(), diag::note_non_literal_field) - << RD << (*I) << (*I)->getType(); + << RD << (*I) << (*I)->getType() + << (*I)->getType().isVolatileQualified(); return true; } } diff --git a/clang/test/CXX/basic/basic.types/p10.cpp b/clang/test/CXX/basic/basic.types/p10.cpp index def4dc95bb1c..7641e09f61e0 100644 --- a/clang/test/CXX/basic/basic.types/p10.cpp +++ b/clang/test/CXX/basic/basic.types/p10.cpp @@ -5,22 +5,23 @@ struct NonLiteral { NonLiteral(); }; // A type is a literal type if it is: // - a scalar type -constexpr int f1(double); +constexpr int f1(double) { return 0; } // - a reference type struct S { S(); }; -constexpr int f2(S &); +constexpr int f2(S &) { return 0; } // - a class type that has all of the following properties: // - it has a trivial destructor struct UserProvDtor { - constexpr UserProvDtor(); // expected-error {{non-literal type 'UserProvDtor' cannot have constexpr members}} + constexpr int f(); // expected-error {{non-literal type 'UserProvDtor' cannot have constexpr members}} ~UserProvDtor(); // expected-note {{has a user-provided destructor}} }; struct NonTrivDtor { - constexpr NonTrivDtor(); // expected-error {{non-literal type 'NonTrivDtor' cannot have constexpr members}} + constexpr NonTrivDtor(); + constexpr int f(); // expected-error {{non-literal type 'NonTrivDtor' cannot have constexpr members}} virtual ~NonTrivDtor() = default; // expected-note {{has a non-trivial destructor}} }; struct NonTrivDtorBase { @@ -30,16 +31,16 @@ template struct DerivedFromNonTrivDtor : T { // expected-note {{'DerivedFromNonTrivDtor' is not literal because it has base class 'NonTrivDtorBase' of non-literal type}} constexpr DerivedFromNonTrivDtor(); }; -constexpr int f(DerivedFromNonTrivDtor); // expected-error {{constexpr function's 1st parameter type 'DerivedFromNonTrivDtor' is not a literal type}} +constexpr int f(DerivedFromNonTrivDtor) { return 0; } // expected-error {{constexpr function's 1st parameter type 'DerivedFromNonTrivDtor' is not a literal type}} struct TrivDtor { constexpr TrivDtor(); }; -constexpr int f(TrivDtor); +constexpr int f(TrivDtor) { return 0; } struct TrivDefaultedDtor { constexpr TrivDefaultedDtor(); ~TrivDefaultedDtor() = default; }; -constexpr int f(TrivDefaultedDtor); +constexpr int f(TrivDefaultedDtor) { return 0; } // - it is an aggregate type or has at least one constexpr constructor or // constexpr constructor template that is not a copy or move constructor @@ -52,36 +53,41 @@ struct CtorTemplate { template constexpr CtorTemplate(T); }; struct CopyCtorOnly { // expected-note {{'CopyCtorOnly' is not literal because it is not an aggregate and has no constexpr constructors other than copy or move constructors}} - constexpr CopyCtorOnly(CopyCtorOnly&); // expected-error {{non-literal type 'CopyCtorOnly' cannot have constexpr members}} + constexpr CopyCtorOnly(CopyCtorOnly&); + constexpr int f(); // expected-error {{non-literal type 'CopyCtorOnly' cannot have constexpr members}} }; struct MoveCtorOnly { // expected-note {{no constexpr constructors other than copy or move constructors}} - constexpr MoveCtorOnly(MoveCtorOnly&&); // expected-error {{non-literal type 'MoveCtorOnly' cannot have constexpr members}} + constexpr MoveCtorOnly(MoveCtorOnly&&); + constexpr int f(); // expected-error {{non-literal type 'MoveCtorOnly' cannot have constexpr members}} }; template -struct CtorArg { // expected-note {{no constexpr constructors other than copy or move constructors}} - constexpr CtorArg(T); // expected-note {{constructor template instantiation is not constexpr because 1st parameter type 'NonLiteral' is not a literal type}} +struct CtorArg { + constexpr CtorArg(T); }; -constexpr int f(CtorArg); -constexpr int f(CtorArg); // expected-error {{not a literal type}} +constexpr int f(CtorArg) { return 0; } // ok +constexpr int f(CtorArg) { return 0; } // ok, ctor is still constexpr // We have a special-case diagnostic for classes with virtual base classes. struct VBase {}; struct HasVBase : virtual VBase {}; // expected-note 2{{virtual base class declared here}} struct Derived : HasVBase { - constexpr Derived(); // expected-error {{constexpr constructor not allowed in struct with virtual base class}} + constexpr Derived() {} // expected-error {{constexpr constructor not allowed in struct with virtual base class}} }; template struct DerivedFromVBase : T { // expected-note {{struct with virtual base class is not a literal type}} constexpr DerivedFromVBase(); }; -constexpr int f(DerivedFromVBase); // expected-error {{constexpr function's 1st parameter type 'DerivedFromVBase' is not a literal type}} +constexpr int f(DerivedFromVBase) {} // expected-error {{constexpr function's 1st parameter type 'DerivedFromVBase' is not a literal type}} +template constexpr DerivedFromVBase::DerivedFromVBase() : T() {} +constexpr int nVBase = (DerivedFromVBase(), 0); // expected-error {{constant expression}} expected-note {{cannot construct object of type 'DerivedFromVBase' with virtual base class in a constant expression}} // - it has all non-static data members and base classes of literal types struct NonLitMember { S s; // expected-note {{has data member 's' of non-literal type 'S'}} }; -constexpr int f(NonLitMember); // expected-error {{1st parameter type 'NonLitMember' is not a literal type}} +constexpr int f(NonLitMember) {} // expected-error {{1st parameter type 'NonLitMember' is not a literal type}} struct NonLitBase : S { // expected-note {{base class 'S' of non-literal type}} - constexpr NonLitBase(); // expected-error {{non-literal type 'NonLitBase' cannot have constexpr members}} + constexpr NonLitBase(); + constexpr int f() { return 0; } // expected-error {{non-literal type 'NonLitBase' cannot have constexpr members}} }; struct LitMemBase : Agg { Agg agg; @@ -91,8 +97,8 @@ struct MemberType { T t; // expected-note {{'MemberType' is not literal because it has data member 't' of non-literal type 'NonLiteral'}} constexpr MemberType(); }; -constexpr int f(MemberType); -constexpr int f(MemberType); // expected-error {{not a literal type}} +constexpr int f(MemberType) { return 0; } +constexpr int f(MemberType) { return 0; } // expected-error {{not a literal type}} // - an array of literal type struct ArrGood { @@ -101,9 +107,9 @@ struct ArrGood { TrivDtor td[3]; TrivDefaultedDtor tdd[3]; }; -constexpr int f(ArrGood); +constexpr int f(ArrGood) { return 0; } struct ArrBad { S s[3]; // expected-note {{data member 's' of non-literal type 'S [3]'}} }; -constexpr int f(ArrBad); // expected-error {{1st parameter type 'ArrBad' is not a literal type}} +constexpr int f(ArrBad) { return 0; } // expected-error {{1st parameter type 'ArrBad' is not a literal type}} diff --git a/clang/test/CXX/class/class.static/class.static.data/p3.cpp b/clang/test/CXX/class/class.static/class.static.data/p3.cpp index fed715e21909..fef9a7dae162 100644 --- a/clang/test/CXX/class/class.static/class.static.data/p3.cpp +++ b/clang/test/CXX/class/class.static/class.static.data/p3.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -struct NonLit { +struct NonLit { // expected-note {{no constexpr constructors}} NonLit(); }; @@ -29,15 +29,14 @@ template struct U { static constexpr int a = 0; static constexpr int b; // expected-error {{declaration of constexpr static data member 'b' requires an initializer}} - // FIXME: It'd be nice to error on this at template definition time. - static constexpr NonLit h = NonLit(); // expected-error 2{{must be initialized by a constant expression}} expected-note 2{{non-literal type}} + static constexpr NonLit h = NonLit(); // expected-error {{cannot have non-literal type 'const NonLit'}} static constexpr T c = T(); // expected-error {{must be initialized by a constant expression}} expected-note {{non-literal type}} static const T d; }; template constexpr T U::d = T(); // expected-error {{must be initialized by a constant expression}} expected-note {{non-literal type 'const NonLit'}} -U u1; // expected-note {{here}} +U u1; U u2; // expected-note {{here}} static_assert(U::a == 0, ""); diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp index f173748e9675..24e15e3d7880 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -struct notlit { +struct notlit { // expected-note {{not literal because}} notlit() {} }; struct notlit2 { @@ -20,7 +20,7 @@ constexpr int s1::mi2 = 0; // not a definition of an object constexpr extern int i2; // expected-error {{constexpr variable declaration must be a definition}} // not a literal type -constexpr notlit nl1; // expected-error {{constexpr variable 'nl1' must be initialized by a constant expression}} expected-note {{non-literal type 'const notlit' cannot be used in a constant expression}} +constexpr notlit nl1; // expected-error {{constexpr variable cannot have non-literal type 'const notlit'}} // function parameters void f2(constexpr int i) {} // expected-error {{function parameter cannot be constexpr}} // non-static member @@ -77,11 +77,11 @@ struct S { // explicit specialization can differ in constepxr // FIXME: When checking the explicit specialization, we implicitly instantiate // the primary template then claim a constexpr mismatch. -template <> notlit ft(notlit nl) { return nl; } +template <> notlit ft(notlit nl) { return nl; } // unexpected-error {{follows constexpr declaration}} unexpected-note {{here}} template <> char ft(char c) { return c; } // desired-note {{previous}} unexpected-error {{follows constexpr declaration}} unexpected-note {{here}} template <> constexpr char ft(char nl); // desired-error {{constexpr declaration of 'ft' follows non-constexpr declaration}} template <> constexpr int gt(int nl) { return nl; } // unexpected-error {{follows non-constexpr declaration}} unexpected-note {{here}} -template <> notlit S::f() const { return notlit(); } +template <> notlit S::f() const { return notlit(); } // unexpected-error {{follows constexpr declaration}} unexpected-note {{here}} template <> constexpr int S::g() { return 0; } // desired-note {{previous}} unexpected-error {{follows non-constexpr declaration}} unexpected-note {{here}} template <> int S::g() const; // desired-error {{non-constexpr declaration of 'g' follows constexpr declaration}} // specializations can drop the 'constexpr' but not the implied 'const'. diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp index 19bcde66401f..cafdd635518c 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp @@ -8,7 +8,7 @@ namespace M { typedef double D; } -struct NonLiteral { // expected-note 4{{no constexpr constructors}} +struct NonLiteral { // expected-note 2{{no constexpr constructors}} NonLiteral() {} NonLiteral(int) {} }; @@ -24,31 +24,28 @@ struct SS : S { int ImplicitlyVirtual() const; }; -// Note, the wording applies constraints to the definition of constexpr -// functions, but we intentionally apply all that we can to the declaration -// instead. See DR1360. - // The definition of a constexpr function shall satisfy the following // constraints: struct T : SS, NonLiteral { // expected-note {{base class 'NonLiteral' of non-literal type}} - constexpr T(); // expected-error {{non-literal type 'T' cannot have constexpr members}} + constexpr T(); + constexpr int f(); // expected-error {{non-literal type 'T' cannot have constexpr members}} // - it shall not be virtual; - virtual constexpr int ExplicitlyVirtual(); // expected-error {{virtual function cannot be constexpr}} + virtual constexpr int ExplicitlyVirtual() { return 0; } // expected-error {{virtual function cannot be constexpr}} - constexpr int ImplicitlyVirtual(); // expected-error {{virtual function cannot be constexpr}} + constexpr int ImplicitlyVirtual() { return 0; } // expected-error {{virtual function cannot be constexpr}} // - its return type shall be a literal type; - constexpr NonLiteral NonLiteralReturn(); // expected-error {{constexpr function's return type 'NonLiteral' is not a literal type}} - constexpr void VoidReturn(); // expected-error {{constexpr function's return type 'void' is not a literal type}} + constexpr NonLiteral NonLiteralReturn() { return {}; } // expected-error {{constexpr function's return type 'NonLiteral' is not a literal type}} + constexpr void VoidReturn() { return; } // expected-error {{constexpr function's return type 'void' is not a literal type}} constexpr ~T(); // expected-error {{destructor cannot be marked constexpr}} typedef NonLiteral F(); - constexpr F NonLiteralReturn2; // expected-error {{constexpr function's return type 'NonLiteral' is not a literal type}} + constexpr F NonLiteralReturn2; // ok until definition // - each of its parameter types shall be a literal type; - constexpr int NonLiteralParam(NonLiteral); // expected-error {{constexpr function's 1st parameter type 'NonLiteral' is not a literal type}} + constexpr int NonLiteralParam(NonLiteral) { return 0; } // expected-error {{constexpr function's 1st parameter type 'NonLiteral' is not a literal type}} typedef int G(NonLiteral); - constexpr G NonLiteralParam2; // expected-error {{constexpr function's 1st parameter type 'NonLiteral' is not a literal type}} + constexpr G NonLiteralParam2; // ok until definition // - its function-body shall be = delete, = default, constexpr int Deleted() = delete; @@ -65,7 +62,7 @@ struct U { }; struct V : virtual U { // expected-note {{here}} - constexpr int F(); // expected-error {{constexpr member function not allowed in struct with virtual base class}} + constexpr int F() { return 0; } // expected-error {{constexpr member function not allowed in struct with virtual base class}} }; // or a compound-statememt that contains only diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp index 86b7ded95950..65573c753362 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp @@ -18,16 +18,12 @@ struct Literal { operator int() const { return 0; } }; -// Note, the wording applies constraints to the definition of constexpr -// constructors, but we intentionally apply all that we can to the declaration -// instead. See DR1360. - // In the definition of a constexpr constructor, each of the parameter types // shall be a literal type. struct S { - constexpr S(int, N::C); - constexpr S(int, NonLiteral, N::C); // expected-error {{constexpr constructor's 2nd parameter type 'NonLiteral' is not a literal type}} - constexpr S(int, NonLiteral = 42); // expected-error {{constexpr constructor's 2nd parameter type 'NonLiteral' is not a literal type}} + constexpr S(int, N::C) {} + constexpr S(int, NonLiteral, N::C) {} // expected-error {{constexpr constructor's 2nd parameter type 'NonLiteral' is not a literal type}} + constexpr S(int, NonLiteral = 42) {} // expected-error {{constexpr constructor's 2nd parameter type 'NonLiteral' is not a literal type}} // In addition, either its function-body shall be = delete or = default constexpr S() = default; @@ -38,14 +34,14 @@ struct S { // - the class shall not have any virtual base classes; struct T : virtual S { // expected-note {{here}} - constexpr T(); // expected-error {{constexpr constructor not allowed in struct with virtual base class}} + constexpr T() {} // expected-error {{constexpr constructor not allowed in struct with virtual base class}} }; namespace IndirectVBase { struct A {}; struct B : virtual A {}; // expected-note {{here}} class C : public B { public: - constexpr C(); // expected-error {{constexpr constructor not allowed in class with virtual base class}} + constexpr C() {} // expected-error {{constexpr constructor not allowed in class with virtual base class}} }; } diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp index e383bc09226c..1a6dc9ecfb5d 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp @@ -10,7 +10,7 @@ namespace M { struct NonLiteral { NonLiteral() {} - NonLiteral(int) {} + NonLiteral(int) {} // expected-note 2{{here}} operator int() const { return 0; } }; struct Literal { @@ -19,7 +19,7 @@ struct Literal { }; struct S { - virtual int ImplicitlyVirtual(); + virtual int ImplicitlyVirtual() const; }; struct T {}; @@ -27,48 +27,42 @@ template struct ImplicitVirtualFromDependentBase : T { constexpr int ImplicitlyVirtual() { return 0; } }; -// FIXME: Can't test this until we have function invocation substitution -#if 0 -constexpr int a = ImplicitVirtualFromDependentBase().ImplicitlyVirtual(); // desired-error {{not a constant expression}} +constexpr int a = ImplicitVirtualFromDependentBase().ImplicitlyVirtual(); // expected-error {{constant expression}} expected-note {{cannot evaluate virtual function call}} constexpr int b = ImplicitVirtualFromDependentBase().ImplicitlyVirtual(); // ok -#endif +constexpr int c = ImplicitVirtualFromDependentBase().ImplicitVirtualFromDependentBase::ImplicitlyVirtual(); template struct ConstexprMember { constexpr R F() { return 0; } }; -// FIXME: Can't test this until we have function invocation substitution -#if 0 -constexpr int c = ConstexprMember().F(); // ok -constexpr int d = ConstexprMember().F(); // desired-error {{not a constant expression}} -#endif +constexpr int d = ConstexprMember().F(); // ok +constexpr int e = ConstexprMember().F(); // expected-error {{constant expression}} -template struct ConstexprCtor { // expected-note 2{{no constexpr constructors}} - constexpr ConstexprCtor(P...); // expected-note {{constructor template instantiation is not constexpr because 1st parameter type 'NonLiteral' is not a literal type}} \ - expected-note {{constructor template instantiation is not constexpr because 2nd parameter type 'NonLiteral' is not a literal type}} +template struct ConstexprCtor { + constexpr ConstexprCtor(P...) {} }; -constexpr ConstexprCtor<> f1(); // ok -constexpr ConstexprCtor f2(); // ok -constexpr ConstexprCtor f3(); // expected-error {{not a literal type}} -constexpr ConstexprCtor f4(); // expected-error {{not a literal type}} +constexpr ConstexprCtor<> f1() { return {}; } // ok +constexpr ConstexprCtor f2() { return 0; } // ok +constexpr ConstexprCtor f3() { return { 0 }; } // expected-error {{never produces a constant expression}} expected-note {{non-constexpr constructor 'NonLiteral}} +constexpr ConstexprCtor f4() { return { 0, 0 }; } // expected-error {{never produces a constant expression}} expected-note {{non-constexpr constructor 'NonLiteral}} struct VirtBase : virtual S {}; // expected-note {{here}} namespace TemplateVBase { template struct T1 : virtual Literal { // expected-note {{here}} - constexpr T1(); // expected-error {{constexpr constructor not allowed in struct with virtual base class}} + constexpr T1() {} // expected-error {{constexpr constructor not allowed in struct with virtual base class}} }; - template struct T2 : virtual T { // expected-note {{struct with virtual base class is not a literal type}} expected-note {{here}} + template struct T2 : virtual T { // FIXME: This is ill-formed (no diagnostic required). // We should diagnose it now rather than waiting until instantiation. - constexpr T2(); // desired-error {{constexpr constructor not allowed in class with virtual base classes}} + constexpr T2() {} }; - constexpr T2 g2(); // expected-error {{not a literal type}} + constexpr T2 g2() { return {}; } template class T3 : public T { // expected-note {{class with virtual base class is not a literal type}} public: constexpr T3() {} }; - constexpr T3 g3(); // ok - constexpr T3 g4(); // expected-error {{not a literal type}} + constexpr T3 g3() { return {}; } // ok + constexpr T3 g4() { return {}; } // expected-error {{not a literal type}} } diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp index 34114cb07716..2412a145f866 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp @@ -18,15 +18,15 @@ extern int (*const d)(int); // A variable declaration which uses the constexpr specifier shall have an // initializer and shall be initialized by a constant expression. constexpr int ni1; // expected-error {{default initialization of an object of const type 'const int'}} -constexpr struct C { C(); } ni2; // expected-error {{constexpr variable 'ni2' must be initialized by a constant expression}} expected-note {{non-literal type 'const struct C' cannot be used in a constant expression}} +constexpr struct C { C(); } ni2; // expected-error {{cannot have non-literal type 'const struct C'}} expected-note 3{{has no constexpr constructors}} constexpr double &ni3; // expected-error {{declaration of reference variable 'ni3' requires an initializer}} constexpr int nc1 = i; // expected-error {{constexpr variable 'nc1' must be initialized by a constant expression}} expected-note {{read of non-const variable 'i' is not allowed in a constant expression}} -constexpr C nc2 = C(); // expected-error {{constexpr variable 'nc2' must be initialized by a constant expression}} expected-note {{non-literal type}} +constexpr C nc2 = C(); // expected-error {{cannot have non-literal type 'const C'}} int &f(); // expected-note {{declared here}} constexpr int &nc3 = f(); // expected-error {{constexpr variable 'nc3' must be initialized by a constant expression}} expected-note {{non-constexpr function 'f' cannot be used in a constant expression}} constexpr int nc4(i); // expected-error {{constexpr variable 'nc4' must be initialized by a constant expression}} expected-note {{read of non-const variable 'i' is not allowed in a constant expression}} -constexpr C nc5((C())); // expected-error {{constexpr variable 'nc5' must be initialized by a constant expression}} expected-note {{non-literal type 'const C'}} +constexpr C nc5((C())); // expected-error {{cannot have non-literal type 'const C'}} int &f(); // expected-note {{here}} constexpr int &nc6(f()); // expected-error {{constexpr variable 'nc6' must be initialized by a constant expression}} expected-note {{non-constexpr function 'f'}} diff --git a/clang/test/CXX/expr/expr.const/p2-0x.cpp b/clang/test/CXX/expr/expr.const/p2-0x.cpp index 2d4f4fb62e69..a22d1e4e4e31 100644 --- a/clang/test/CXX/expr/expr.const/p2-0x.cpp +++ b/clang/test/CXX/expr/expr.const/p2-0x.cpp @@ -288,7 +288,7 @@ namespace LValueToRValue { // non-volatile const object with a preceding initialization, initialized // with a constant expression [Note: a string literal (2.14.5 [lex.string]) // corresponds to an array of such objects. -end note], or - volatile const int vi = 1; // expected-note {{here}} + volatile const int vi = 1; // expected-note 2{{here}} const int ci = 1; volatile const int &vrci = ci; static_assert(vi, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}} @@ -298,18 +298,23 @@ namespace LValueToRValue { // - a non-volatile glvalue of literal type that refers to a non-volatile // object defined with constexpr, or that refers to a sub-object of such an // object, or - struct S { - constexpr S(int=0) : i(1), v(1) {} - constexpr S(const S &s) : i(2), v(2) {} - int i; - volatile int v; // expected-note {{here}} + struct V { + constexpr V() : v(1) {} + volatile int v; // expected-note {{not literal because}} }; - constexpr S s; + constexpr V v; // expected-error {{non-literal type}} + struct S { + constexpr S(int=0) : i(1), v(const_cast(vi)) {} + constexpr S(const S &s) : i(2), v(const_cast(vi)) {} + int i; + volatile int &v; + }; + constexpr S s; // ok constexpr volatile S vs; // expected-note {{here}} - constexpr const volatile S &vrs = s; + constexpr const volatile S &vrs = s; // ok static_assert(s.i, ""); static_assert(s.v, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}} - static_assert(const_cast(s.v), ""); // expected-error {{constant expression}} expected-note {{read of volatile member 'v'}} + static_assert(const_cast(s.v), ""); // expected-error {{constant expression}} expected-note {{read of volatile object 'vi'}} static_assert(vs.i, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}} static_assert(const_cast(vs.i), ""); // expected-error {{constant expression}} expected-note {{read of volatile object 'vs'}} static_assert(vrs.i, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}} diff --git a/clang/test/CXX/special/class.ctor/p6-0x.cpp b/clang/test/CXX/special/class.ctor/p6-0x.cpp index 71afd244bd09..8c8800f2de45 100644 --- a/clang/test/CXX/special/class.ctor/p6-0x.cpp +++ b/clang/test/CXX/special/class.ctor/p6-0x.cpp @@ -11,7 +11,7 @@ struct NonConstexpr2 { // expected-note {{here}} struct NonConstexpr2a : NonConstexpr1 { }; constexpr NonConstexpr1 nc1 = NonConstexpr1(); // ok, does not call constructor constexpr NonConstexpr2 nc2 = NonConstexpr2(); // ok, does not call constructor -constexpr NonConstexpr2a nc2a = NonConstexpr2a(); // expected-error {{constant expression}} expected-note {{non-literal type 'const NonConstexpr2a'}} +constexpr NonConstexpr2a nc2a = NonConstexpr2a(); // ok, does not call constructor constexpr int nc2_a = NonConstexpr2().nl.a; // ok constexpr int nc2a_a = NonConstexpr2a().a; // ok struct Helper { @@ -21,8 +21,8 @@ struct Helper { struct Constexpr1 {}; constexpr Constexpr1 c1 = Constexpr1(); // ok -struct NonConstexpr3 : virtual Constexpr1 {}; -constexpr NonConstexpr3 nc3 = NonConstexpr3(); // expected-error {{constant expression}} expected-note {{non-literal type 'const NonConstexpr3'}} +struct NonConstexpr3 : virtual Constexpr1 {}; // expected-note {{struct with virtual base}} expected-note {{declared here}} +constexpr NonConstexpr3 nc3 = NonConstexpr3(); // expected-error {{non-literal type 'const NonConstexpr3'}} struct Constexpr2 { int a = 0; diff --git a/clang/test/SemaCXX/constexpr-value-init.cpp b/clang/test/SemaCXX/constexpr-value-init.cpp index efa9e94da12e..db4b68dcc6df 100644 --- a/clang/test/SemaCXX/constexpr-value-init.cpp +++ b/clang/test/SemaCXX/constexpr-value-init.cpp @@ -26,6 +26,6 @@ struct D : C { int d; }; constexpr C c1; // expected-error {{requires a user-provided default constructor}} constexpr C c2 = C(); // ok constexpr D d1; // expected-error {{requires a user-provided default constructor}} -constexpr D d2 = D(); // expected-error {{constant expression}} expected-note {{non-literal type 'const D'}} +constexpr D d2 = D(); // ok with DR1452 static_assert(D().c == 0, ""); static_assert(D().d == 0, ""); diff --git a/clang/test/SemaCXX/literal-type.cpp b/clang/test/SemaCXX/literal-type.cpp index 60bfcf00cf0b..14a4094c45a1 100644 --- a/clang/test/SemaCXX/literal-type.cpp +++ b/clang/test/SemaCXX/literal-type.cpp @@ -23,6 +23,8 @@ static_assert(__is_literal(VectorExt), "fail"); // a constant expression, // -- it is an aggregate type or has at least one constexpr constructor // or constructor template that is not a copy or move constructor, and +// [DR1452 adds class types with trivial default constructors to +// this list] // -- it has all non-static data members and base classes of literal // types struct Empty {}; @@ -36,25 +38,26 @@ struct LiteralType { struct HasDtor { ~HasDtor(); }; class NonAggregate { int x; }; -struct HasNonLiteralBase : NonAggregate {}; +struct NonLiteral { NonLiteral(); }; +struct HasNonLiteralBase : NonLiteral {}; struct HasNonLiteralMember { HasDtor x; }; static_assert(__is_literal(Empty), "fail"); static_assert(__is_literal(LiteralType), "fail"); +static_assert(__is_literal(NonAggregate), "fail"); +static_assert(!__is_literal(NonLiteral), "fail"); static_assert(!__is_literal(HasDtor), "fail"); -static_assert(!__is_literal(NonAggregate), "fail"); static_assert(!__is_literal(HasNonLiteralBase), "fail"); static_assert(!__is_literal(HasNonLiteralMember), "fail"); -// FIXME: Test constexpr constructors and non-static members with initializers -// when Clang supports them: -#if 0 -extern int f(); +// DR1361 removes the brace-or-equal-initializer bullet so that we can allow: +extern int f(); // expected-note {{here}} struct HasNonConstExprMemInit { - int x = f(); - constexpr HasNonConstExprMemInit(int y) {} + int x = f(); // expected-note {{non-constexpr function}} + constexpr HasNonConstExprMemInit() {} // expected-error {{never produces a constant expression}} + constexpr HasNonConstExprMemInit(int y) : x(y) {} // ok }; -static_assert(!__is_literal(HasNonConstExprMemInit), "fail"); +static_assert(__is_literal(HasNonConstExprMemInit), "fail"); class HasConstExprCtor { int x; @@ -66,6 +69,9 @@ template class HasConstExprCtorTemplate { public: template constexpr HasConstExprCtorTemplate(U y) : x(y) {} }; +template class HasConstExprCtorT { + constexpr HasConstExprCtorT(T) {} +}; static_assert(__is_literal(HasConstExprCtor), "fail"); -static_assert(__is_literal(HasConstExprCtorTemplate), "fail"); -#endif +static_assert(__is_literal(HasConstExprCtorTemplate), "fail"); +static_assert(__is_literal(HasConstExprCtorT), "fail");