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
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index c1a6c60..67493c7 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2229,6 +2229,20 @@
<< 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
D.getSourceRange().getBegin(),
NameInfo, R, TInfo,
isStatic, SCAsWritten, isInline,
+ isConstexpr,
SourceLocation());
NewFD = NewMD;
@@ -4426,7 +4451,7 @@
// - 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 @@
}
}
+ 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 @@
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 @@
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 76461a0..4283162 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -6012,7 +6012,9 @@
/*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 @@
// 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 @@
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 @@
/*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 2554b82..812482e 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1070,11 +1070,15 @@
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 @@
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 @@
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 @@
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)