diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2011-08-15 21:04:07 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2011-08-15 21:04:07 +0000 |
commit | af1fc7af351758b0ea0d285bdfe5640128109a4e (patch) | |
tree | 22b6d9705984486730bbe86f9827df5e3b5f85e9 /lib/Sema | |
parent | faef9fcb41cff7c2cbafb86d3af47c422ddf3010 (diff) |
Track in the AST whether a function is constexpr.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@137653 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 56 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 17 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 15 |
3 files changed, 75 insertions, 13 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index c1a6c60d28..67493c7716 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2229,6 +2229,20 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, << DS.getSourceRange(); } + if (DS.isConstexprSpecified()) { + // C++0x [dcl.constexpr]p1: constexpr can only be applied to declarations + // and definitions of functions and variables. + if (Tag) + Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_tag) + << (DS.getTypeSpecType() == DeclSpec::TST_class ? 0 : + DS.getTypeSpecType() == DeclSpec::TST_struct ? 1 : + DS.getTypeSpecType() == DeclSpec::TST_union ? 2 : 3); + else + Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_no_declarators); + // Don't emit warnings after this error. + return TagD; + } + if (DS.isFriendSpecified()) { // If we're dealing with a decl but not a TagDecl, assume that // whatever routines created it handled the friendship aspect. @@ -3434,6 +3448,9 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + if (D.getDeclSpec().isConstexprSpecified()) + Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) + << 1; if (D.getName().Kind != UnqualifiedId::IK_Identifier) { Diag(D.getName().StartLocation, diag::err_typedef_not_identifier) @@ -3767,6 +3784,11 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, TemplateParamLists.size(), TemplateParamLists.release()); } + + if (D.getDeclSpec().isConstexprSpecified()) { + // FIXME: check this is a valid use of constexpr. + NewVD->setConstexpr(true); + } } if (D.getDeclSpec().isThreadSpecified()) { @@ -4304,6 +4326,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, isFriend = D.getDeclSpec().isFriendSpecified(); bool isVirtual = D.getDeclSpec().isVirtualSpecified(); bool isExplicit = D.getDeclSpec().isExplicitSpecified(); + bool isConstexpr = D.getDeclSpec().isConstexprSpecified(); bool isVirtualOkay = false; // Check that the return type is not an abstract class type. @@ -4330,7 +4353,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, D.getSourceRange().getBegin(), NameInfo, R, TInfo, isExplicit, isInline, - /*isImplicitlyDeclared=*/false); + /*isImplicitlyDeclared=*/false, + isConstexpr); NewFD = NewCD; } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { @@ -4364,7 +4388,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD = FunctionDecl::Create(Context, DC, D.getSourceRange().getBegin(), D.getIdentifierLoc(), Name, R, TInfo, SC, SCAsWritten, isInline, - /*hasPrototype=*/true); + /*hasPrototype=*/true, isConstexpr); D.setInvalidType(); } } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { @@ -4378,7 +4402,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC), D.getSourceRange().getBegin(), NameInfo, R, TInfo, - isInline, isExplicit, + isInline, isExplicit, isConstexpr, SourceLocation()); isVirtualOkay = true; @@ -4416,6 +4440,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, D.getSourceRange().getBegin(), NameInfo, R, TInfo, isStatic, SCAsWritten, isInline, + isConstexpr, SourceLocation()); NewFD = NewMD; @@ -4426,7 +4451,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // - we're in C++ (where every function has a prototype), NewFD = FunctionDecl::Create(Context, DC, D.getSourceRange().getBegin(), NameInfo, R, TInfo, SC, SCAsWritten, isInline, - true/*HasPrototype*/); + true/*HasPrototype*/, isConstexpr); } if (isFriend && !isInline && IsFunctionDefinition) { @@ -4590,6 +4615,23 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } + if (isConstexpr) { + // C++0x [dcl.constexpr]p2: constexpr functions and constexpr constructors + // are implicitly inline. + NewFD->setImplicitlyInline(); + + // FIXME: If this is a redeclaration, check the original declaration was + // marked constepr. + + // C++0x [dcl.constexpr]p3: functions declared constexpr are required to + // be either constructors or to return a literal type. Therefore, + // destructors cannot be declared constexpr. + if (isa<CXXDestructorDecl>(NewFD)) + Diag(D.getDeclSpec().getConstexprSpecLoc(), + diag::err_constexpr_dtor); + } + + // Filter out previous declarations that don't match the scope. FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(), isExplicitSpecialization || @@ -6105,6 +6147,9 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + if (D.getDeclSpec().isConstexprSpecified()) + Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) + << 0; DiagnoseFunctionSpecifiers(D); @@ -7813,6 +7858,9 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + if (D.getDeclSpec().isConstexprSpecified()) + Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) + << 2; // Check to see if this name was declared as a member previously LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 76461a0ca6..428316297c 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -6012,7 +6012,9 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, - /*isImplicitlyDeclared=*/true); + /*isImplicitlyDeclared=*/true, + // FIXME: apply the rules for definitions here + /*isConstexpr=*/false); DefaultCon->setAccess(AS_public); DefaultCon->setDefaulted(); DefaultCon->setImplicit(); @@ -6263,12 +6265,15 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { // OK, we're there, now add the constructor. // C++0x [class.inhctor]p8: [...] that would be performed by a - // user-writtern inline constructor [...] + // user-written inline constructor [...] DeclarationNameInfo DNI(CreatedCtorName, UsingLoc); CXXConstructorDecl *NewCtor = CXXConstructorDecl::Create( Context, ClassDecl, UsingLoc, DNI, QualType(NewCtorType, 0), /*TInfo=*/0, BaseCtor->isExplicit(), /*Inline=*/true, - /*ImplicitlyDeclared=*/true); + /*ImplicitlyDeclared=*/true, + // FIXME: Due to a defect in the standard, we treat inherited + // constructors as constexpr even if that makes them ill-formed. + /*Constexpr=*/BaseCtor->isConstexpr()); NewCtor->setAccess(BaseCtor->getAccess()); // Build up the parameter decls and add them. @@ -6777,7 +6782,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { Context.getFunctionType(RetType, &ArgType, 1, EPI), /*TInfo=*/0, /*isStatic=*/false, /*StorageClassAsWritten=*/SC_None, - /*isInline=*/true, + /*isInline=*/true, /*isConstexpr=*/false, SourceLocation()); CopyAssignment->setAccess(AS_public); CopyAssignment->setDefaulted(); @@ -7249,7 +7254,9 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, - /*isImplicitlyDeclared=*/true); + /*isImplicitlyDeclared=*/true, + // FIXME: apply the rules for definitions here + /*isConstexpr=*/false); CopyConstructor->setAccess(AS_public); CopyConstructor->setDefaulted(); CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor()); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 2554b82d97..812482e436 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1070,11 +1070,15 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, TemplateArgs); } + bool isConstexpr = D->isConstexpr(); + // FIXME: check whether the instantiation produces a constexpr function. + FunctionDecl *Function = FunctionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(), D->getLocation(), D->getDeclName(), T, TInfo, D->getStorageClass(), D->getStorageClassAsWritten(), - D->isInlineSpecified(), D->hasWrittenPrototype()); + D->isInlineSpecified(), D->hasWrittenPrototype(), + isConstexpr); if (QualifierLoc) Function->setQualifierInfo(QualifierLoc); @@ -1383,6 +1387,9 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, if (!DC) return 0; } + bool isConstexpr = D->isConstexpr(); + // FIXME: check whether the instantiation produces a constexpr function. + // Build the instantiated method declaration. CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); CXXMethodDecl *Method = 0; @@ -1395,7 +1402,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, StartLoc, NameInfo, T, TInfo, Constructor->isExplicit(), Constructor->isInlineSpecified(), - false); + false, isConstexpr); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { Method = CXXDestructorDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, @@ -1406,14 +1413,14 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, StartLoc, NameInfo, T, TInfo, Conversion->isInlineSpecified(), Conversion->isExplicit(), - Conversion->getLocEnd()); + isConstexpr, Conversion->getLocEnd()); } else { Method = CXXMethodDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, D->isStatic(), D->getStorageClassAsWritten(), D->isInlineSpecified(), - D->getLocEnd()); + isConstexpr, D->getLocEnd()); } if (QualifierLoc) |