From 17feca48a8331dd511992e3ef0876486e774deec Mon Sep 17 00:00:00 2001 From: Gauthier Harnisch Date: Fri, 14 Jun 2019 08:56:20 +0000 Subject: [C++20] add Basic consteval specifier Summary: this revision adds Lexing, Parsing and Basic Semantic for the consteval specifier as specified by http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1073r3.html with this patch, the consteval specifier is treated as constexpr but can only be applied to function declaration. Changes: - add the consteval keyword. - add parsing of consteval specifier for normal declarations and lambdas expressions. - add the whether a declaration is constexpr is now represented by and enum everywhere except for variable because they can't be consteval. - adapt diagnostic about constexpr to print constexpr or consteval depending on the case. - add tests for basic semantic. Reviewers: rsmith, martong, shafik Reviewed By: rsmith Subscribers: eraman, efriedma, rnkovacs, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D61790 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@363362 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaDeclCXX.cpp | 68 ++++++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 28 deletions(-) (limited to 'lib/Sema/SemaDeclCXX.cpp') diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 354316a3cc..6686b855c3 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -638,9 +638,9 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, // C++11 [dcl.constexpr]p1: If any declaration of a function or function // template has a constexpr specifier then all its declarations shall // contain the constexpr specifier. - if (New->isConstexpr() != Old->isConstexpr()) { + if (New->getConstexprKind() != Old->getConstexprKind()) { Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch) - << New << New->isConstexpr(); + << New << New->getConstexprKind() << Old->getConstexprKind(); Diag(Old->getLocation(), diag::note_previous_declaration); Invalid = true; } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() && @@ -741,8 +741,9 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, CPlusPlus20Specifiers.push_back(DeclSpec::getSpecifierName(TSCS)); CPlusPlus20SpecifierLocs.push_back(DS.getThreadStorageClassSpecLoc()); } - if (DS.isConstexprSpecified()) { - BadSpecifiers.push_back("constexpr"); + if (DS.hasConstexprSpecifier()) { + BadSpecifiers.push_back( + DeclSpec::getSpecifierName(DS.getConstexprSpecifier())); BadSpecifierLocs.push_back(DS.getConstexprSpecLoc()); } if (DS.isInlineSpecified()) { @@ -1581,10 +1582,10 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef, const ParmVarDecl *PD = FD->getParamDecl(ArgIndex); SourceLocation ParamLoc = PD->getLocation(); if (!(*i)->isDependentType() && - SemaRef.RequireLiteralType(ParamLoc, *i, - diag::err_constexpr_non_literal_param, - ArgIndex+1, PD->getSourceRange(), - isa(FD))) + SemaRef.RequireLiteralType( + ParamLoc, *i, diag::err_constexpr_non_literal_param, ArgIndex + 1, + PD->getSourceRange(), isa(FD), + FD->isConsteval())) return false; } return true; @@ -1661,7 +1662,8 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) { QualType RT = NewFD->getReturnType(); if (!RT->isDependentType() && RequireLiteralType(NewFD->getLocation(), RT, - diag::err_constexpr_non_literal_return)) + diag::err_constexpr_non_literal_return, + NewFD->isConsteval())) return false; } @@ -1775,7 +1777,7 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, default: SemaRef.Diag(DS->getBeginLoc(), diag::err_constexpr_body_invalid_stmt) - << isa(Dcl); + << isa(Dcl) << Dcl->isConsteval(); return false; } } @@ -1960,7 +1962,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, } SemaRef.Diag(S->getBeginLoc(), diag::err_constexpr_body_invalid_stmt) - << isa(Dcl); + << isa(Dcl) << Dcl->isConsteval(); return false; } @@ -2082,7 +2084,8 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { Dcl->getReturnType()->isDependentType()); Diag(Dcl->getLocation(), OK ? diag::warn_cxx11_compat_constexpr_body_no_return - : diag::err_constexpr_body_no_return); + : diag::err_constexpr_body_no_return) + << Dcl->isConsteval(); if (!OK) return false; } else if (ReturnStmts.size() > 1) { @@ -3052,7 +3055,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, DS.getStorageClassSpec() == DeclSpec::SCS_mutable) && !isFunc); - if (DS.isConstexprSpecified() && isInstField) { + if (DS.hasConstexprSpecifier() && isInstField) { SemaDiagnosticBuilder B = Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr_member); SourceLocation ConstexprLoc = DS.getConstexprSpecLoc(); @@ -6688,7 +6691,10 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { : isa(MD)) && MD->isConstexpr() && !Constexpr && MD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) { - Diag(MD->getBeginLoc(), diag::err_incorrect_defaulted_constexpr) << CSM; + Diag(MD->getBeginLoc(), MD->isConsteval() + ? diag::err_incorrect_defaulted_consteval + : diag::err_incorrect_defaulted_constexpr) + << CSM; // FIXME: Explain why the special member can't be constexpr. HadError = true; } @@ -6698,7 +6704,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { // If a function is explicitly defaulted on its first declaration, it is // implicitly considered to be constexpr if the implicit declaration // would be. - MD->setConstexpr(Constexpr); + MD->setConstexprKind(Constexpr ? CSK_constexpr : CSK_unspecified); if (!Type->hasExceptionSpec()) { // C++2a [except.spec]p3: @@ -8744,7 +8750,7 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, // We leave 'friend' and 'virtual' to be rejected in the normal way. if (DS.hasTypeSpecifier() || DS.getTypeQualifiers() || DS.getStorageClassSpecLoc().isValid() || DS.isInlineSpecified() || - DS.isNoreturnSpecified() || DS.isConstexprSpecified()) { + DS.isNoreturnSpecified() || DS.hasConstexprSpecifier()) { BadSpecifierDiagnoser Diagnoser( *this, D.getIdentifierLoc(), diag::err_deduction_guide_invalid_specifier); @@ -11035,7 +11041,8 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create( Context, ClassDecl, ClassLoc, NameInfo, /*Type*/ QualType(), /*TInfo=*/nullptr, ExplicitSpecifier(), - /*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr); + /*isInline=*/true, /*isImplicitlyDeclared=*/true, + Constexpr ? CSK_constexpr : CSK_unspecified); DefaultCon->setAccess(AS_public); DefaultCon->setDefaulted(); @@ -11155,7 +11162,8 @@ Sema::findInheritingConstructor(SourceLocation Loc, CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create( Context, Derived, UsingLoc, NameInfo, TInfo->getType(), TInfo, BaseCtor->getExplicitSpecifier(), /*Inline=*/true, - /*ImplicitlyDeclared=*/true, Constexpr, + /*ImplicitlyDeclared=*/true, + Constexpr ? BaseCtor->getConstexprKind() : CSK_unspecified, InheritedConstructor(Shadow, BaseCtor)); if (Shadow->isInvalidDecl()) DerivedCtor->setInvalidDecl(); @@ -11904,10 +11912,11 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); SourceLocation ClassLoc = ClassDecl->getLocation(); DeclarationNameInfo NameInfo(Name, ClassLoc); - CXXMethodDecl *CopyAssignment = - CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(), - /*TInfo=*/nullptr, /*StorageClass=*/SC_None, - /*isInline=*/true, Constexpr, SourceLocation()); + CXXMethodDecl *CopyAssignment = CXXMethodDecl::Create( + Context, ClassDecl, ClassLoc, NameInfo, QualType(), + /*TInfo=*/nullptr, /*StorageClass=*/SC_None, + /*isInline=*/true, Constexpr ? CSK_constexpr : CSK_unspecified, + SourceLocation()); CopyAssignment->setAccess(AS_public); CopyAssignment->setDefaulted(); CopyAssignment->setImplicit(); @@ -12224,10 +12233,11 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); SourceLocation ClassLoc = ClassDecl->getLocation(); DeclarationNameInfo NameInfo(Name, ClassLoc); - CXXMethodDecl *MoveAssignment = - CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(), - /*TInfo=*/nullptr, /*StorageClass=*/SC_None, - /*isInline=*/true, Constexpr, SourceLocation()); + CXXMethodDecl *MoveAssignment = CXXMethodDecl::Create( + Context, ClassDecl, ClassLoc, NameInfo, QualType(), + /*TInfo=*/nullptr, /*StorageClass=*/SC_None, + /*isInline=*/true, Constexpr ? CSK_constexpr : CSK_unspecified, + SourceLocation()); MoveAssignment->setAccess(AS_public); MoveAssignment->setDefaulted(); MoveAssignment->setImplicit(); @@ -12608,7 +12618,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr, ExplicitSpecifier(), /*isInline=*/true, - /*isImplicitlyDeclared=*/true, Constexpr); + /*isImplicitlyDeclared=*/true, + Constexpr ? CSK_constexpr : CSK_unspecified); CopyConstructor->setAccess(AS_public); CopyConstructor->setDefaulted(); @@ -12739,7 +12750,8 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr, ExplicitSpecifier(), /*isInline=*/true, - /*isImplicitlyDeclared=*/true, Constexpr); + /*isImplicitlyDeclared=*/true, + Constexpr ? CSK_constexpr : CSK_unspecified); MoveConstructor->setAccess(AS_public); MoveConstructor->setDefaulted(); -- cgit v1.2.1