forked from OSchip/llvm-project
When determining whether a lambda-expression is implicitly constexpr,
check the formal rules rather than seeing if the normal checks produce a diagnostic. This fixes the handling of C++2a extensions in lambdas in C++17 mode, as well as some corner cases in earlier language modes where we issue diagnostics for things other than not satisfying the formal constexpr requirements. llvm-svn: 367254
This commit is contained in:
parent
8e9516f2aa
commit
a625da716c
|
@ -2076,8 +2076,16 @@ public:
|
||||||
bool &AddToScope);
|
bool &AddToScope);
|
||||||
bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
|
bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
|
||||||
|
|
||||||
bool CheckConstexprFunctionDecl(const FunctionDecl *FD);
|
enum class CheckConstexprKind {
|
||||||
bool CheckConstexprFunctionBody(const FunctionDecl *FD, Stmt *Body);
|
/// Diagnose issues that are non-constant or that are extensions.
|
||||||
|
Diagnose,
|
||||||
|
/// Identify whether this function satisfies the formal rules for constexpr
|
||||||
|
/// functions in the current lanugage mode (with no extensions).
|
||||||
|
CheckValid
|
||||||
|
};
|
||||||
|
|
||||||
|
bool CheckConstexprFunctionDefinition(const FunctionDecl *FD,
|
||||||
|
CheckConstexprKind Kind);
|
||||||
|
|
||||||
void DiagnoseHiddenVirtualMethods(CXXMethodDecl *MD);
|
void DiagnoseHiddenVirtualMethods(CXXMethodDecl *MD);
|
||||||
void FindHiddenVirtualMethods(CXXMethodDecl *MD,
|
void FindHiddenVirtualMethods(CXXMethodDecl *MD,
|
||||||
|
|
|
@ -13532,8 +13532,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsInstantiation && FD && FD->isConstexpr() && !FD->isInvalidDecl() &&
|
if (!IsInstantiation && FD && FD->isConstexpr() && !FD->isInvalidDecl() &&
|
||||||
(!CheckConstexprFunctionDecl(FD) ||
|
!CheckConstexprFunctionDefinition(FD, CheckConstexprKind::Diagnose))
|
||||||
!CheckConstexprFunctionBody(FD, Body)))
|
|
||||||
FD->setInvalidDecl();
|
FD->setInvalidDecl();
|
||||||
|
|
||||||
if (FD && FD->hasAttr<NakedAttr>()) {
|
if (FD && FD->hasAttr<NakedAttr>()) {
|
||||||
|
|
|
@ -1569,11 +1569,34 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check that the given type is a literal type. Issue a diagnostic if not,
|
||||||
|
/// if Kind is Diagnose.
|
||||||
|
/// \return \c true if a problem has been found (and optionally diagnosed).
|
||||||
|
template <typename... Ts>
|
||||||
|
static bool CheckLiteralType(Sema &SemaRef, Sema::CheckConstexprKind Kind,
|
||||||
|
SourceLocation Loc, QualType T, unsigned DiagID,
|
||||||
|
Ts &&...DiagArgs) {
|
||||||
|
if (T->isDependentType())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (Kind) {
|
||||||
|
case Sema::CheckConstexprKind::Diagnose:
|
||||||
|
return SemaRef.RequireLiteralType(Loc, T, DiagID,
|
||||||
|
std::forward<Ts>(DiagArgs)...);
|
||||||
|
|
||||||
|
case Sema::CheckConstexprKind::CheckValid:
|
||||||
|
return !T->isLiteralType(SemaRef.Context);
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm_unreachable("unknown CheckConstexprKind");
|
||||||
|
}
|
||||||
|
|
||||||
// CheckConstexprParameterTypes - Check whether a function's parameter types
|
// CheckConstexprParameterTypes - Check whether a function's parameter types
|
||||||
// are all literal types. If so, return true. If not, produce a suitable
|
// are all literal types. If so, return true. If not, produce a suitable
|
||||||
// diagnostic and return false.
|
// diagnostic and return false.
|
||||||
static bool CheckConstexprParameterTypes(Sema &SemaRef,
|
static bool CheckConstexprParameterTypes(Sema &SemaRef,
|
||||||
const FunctionDecl *FD) {
|
const FunctionDecl *FD,
|
||||||
|
Sema::CheckConstexprKind Kind) {
|
||||||
unsigned ArgIndex = 0;
|
unsigned ArgIndex = 0;
|
||||||
const FunctionProtoType *FT = FD->getType()->getAs<FunctionProtoType>();
|
const FunctionProtoType *FT = FD->getType()->getAs<FunctionProtoType>();
|
||||||
for (FunctionProtoType::param_type_iterator i = FT->param_type_begin(),
|
for (FunctionProtoType::param_type_iterator i = FT->param_type_begin(),
|
||||||
|
@ -1581,11 +1604,10 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef,
|
||||||
i != e; ++i, ++ArgIndex) {
|
i != e; ++i, ++ArgIndex) {
|
||||||
const ParmVarDecl *PD = FD->getParamDecl(ArgIndex);
|
const ParmVarDecl *PD = FD->getParamDecl(ArgIndex);
|
||||||
SourceLocation ParamLoc = PD->getLocation();
|
SourceLocation ParamLoc = PD->getLocation();
|
||||||
if (!(*i)->isDependentType() &&
|
if (CheckLiteralType(SemaRef, Kind, ParamLoc, *i,
|
||||||
SemaRef.RequireLiteralType(
|
diag::err_constexpr_non_literal_param, ArgIndex + 1,
|
||||||
ParamLoc, *i, diag::err_constexpr_non_literal_param, ArgIndex + 1,
|
PD->getSourceRange(), isa<CXXConstructorDecl>(FD),
|
||||||
PD->getSourceRange(), isa<CXXConstructorDecl>(FD),
|
FD->isConsteval()))
|
||||||
FD->isConsteval()))
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1605,13 +1627,18 @@ static unsigned getRecordDiagFromTagKind(TagTypeKind Tag) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckConstexprFunctionDecl - Check whether a function declaration satisfies
|
static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
|
||||||
// the requirements of a constexpr function definition or a constexpr
|
Stmt *Body,
|
||||||
// constructor definition. If so, return true. If not, produce appropriate
|
Sema::CheckConstexprKind Kind);
|
||||||
// diagnostics and return false.
|
|
||||||
|
// Check whether a function declaration satisfies the requirements of a
|
||||||
|
// constexpr function definition or a constexpr constructor definition. If so,
|
||||||
|
// return true. If not, produce appropriate diagnostics (unless asked not to by
|
||||||
|
// Kind) and return false.
|
||||||
//
|
//
|
||||||
// This implements C++11 [dcl.constexpr]p3,4, as amended by DR1360.
|
// This implements C++11 [dcl.constexpr]p3,4, as amended by DR1360.
|
||||||
bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
|
bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD,
|
||||||
|
CheckConstexprKind Kind) {
|
||||||
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
|
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
|
||||||
if (MD && MD->isInstance()) {
|
if (MD && MD->isInstance()) {
|
||||||
// C++11 [dcl.constexpr]p4:
|
// C++11 [dcl.constexpr]p4:
|
||||||
|
@ -1623,6 +1650,9 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
|
||||||
// functions.
|
// functions.
|
||||||
const CXXRecordDecl *RD = MD->getParent();
|
const CXXRecordDecl *RD = MD->getParent();
|
||||||
if (RD->getNumVBases()) {
|
if (RD->getNumVBases()) {
|
||||||
|
if (Kind == CheckConstexprKind::CheckValid)
|
||||||
|
return false;
|
||||||
|
|
||||||
Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base)
|
Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base)
|
||||||
<< isa<CXXConstructorDecl>(NewFD)
|
<< isa<CXXConstructorDecl>(NewFD)
|
||||||
<< getRecordDiagFromTagKind(RD->getTagKind()) << RD->getNumVBases();
|
<< getRecordDiagFromTagKind(RD->getTagKind()) << RD->getNumVBases();
|
||||||
|
@ -1641,8 +1671,12 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
|
||||||
const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD);
|
const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD);
|
||||||
if (Method && Method->isVirtual()) {
|
if (Method && Method->isVirtual()) {
|
||||||
if (getLangOpts().CPlusPlus2a) {
|
if (getLangOpts().CPlusPlus2a) {
|
||||||
Diag(Method->getLocation(), diag::warn_cxx17_compat_constexpr_virtual);
|
if (Kind == CheckConstexprKind::Diagnose)
|
||||||
|
Diag(Method->getLocation(), diag::warn_cxx17_compat_constexpr_virtual);
|
||||||
} else {
|
} else {
|
||||||
|
if (Kind == CheckConstexprKind::CheckValid)
|
||||||
|
return false;
|
||||||
|
|
||||||
Method = Method->getCanonicalDecl();
|
Method = Method->getCanonicalDecl();
|
||||||
Diag(Method->getLocation(), diag::err_constexpr_virtual);
|
Diag(Method->getLocation(), diag::err_constexpr_virtual);
|
||||||
|
|
||||||
|
@ -1660,18 +1694,20 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
|
||||||
|
|
||||||
// - its return type shall be a literal type;
|
// - its return type shall be a literal type;
|
||||||
QualType RT = NewFD->getReturnType();
|
QualType RT = NewFD->getReturnType();
|
||||||
if (!RT->isDependentType() &&
|
if (CheckLiteralType(*this, Kind, NewFD->getLocation(), RT,
|
||||||
RequireLiteralType(NewFD->getLocation(), RT,
|
diag::err_constexpr_non_literal_return,
|
||||||
diag::err_constexpr_non_literal_return,
|
NewFD->isConsteval()))
|
||||||
NewFD->isConsteval()))
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - each of its parameter types shall be a literal type;
|
// - each of its parameter types shall be a literal type;
|
||||||
if (!CheckConstexprParameterTypes(*this, NewFD))
|
if (!CheckConstexprParameterTypes(*this, NewFD, Kind))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
Stmt *Body = NewFD->getBody();
|
||||||
|
assert(Body &&
|
||||||
|
"CheckConstexprFunctionDefinition called on function with no body");
|
||||||
|
return CheckConstexprFunctionBody(*this, NewFD, Body, Kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check the given declaration statement is legal within a constexpr function
|
/// Check the given declaration statement is legal within a constexpr function
|
||||||
|
@ -1680,7 +1716,8 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
|
||||||
/// \return true if the body is OK (maybe only as an extension), false if we
|
/// \return true if the body is OK (maybe only as an extension), false if we
|
||||||
/// have diagnosed a problem.
|
/// have diagnosed a problem.
|
||||||
static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
|
static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
|
||||||
DeclStmt *DS, SourceLocation &Cxx1yLoc) {
|
DeclStmt *DS, SourceLocation &Cxx1yLoc,
|
||||||
|
Sema::CheckConstexprKind Kind) {
|
||||||
// C++11 [dcl.constexpr]p3 and p4:
|
// C++11 [dcl.constexpr]p3 and p4:
|
||||||
// The definition of a constexpr function(p3) or constructor(p4) [...] shall
|
// The definition of a constexpr function(p3) or constructor(p4) [...] shall
|
||||||
// contain only
|
// contain only
|
||||||
|
@ -1704,10 +1741,12 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
|
||||||
const auto *TN = cast<TypedefNameDecl>(DclIt);
|
const auto *TN = cast<TypedefNameDecl>(DclIt);
|
||||||
if (TN->getUnderlyingType()->isVariablyModifiedType()) {
|
if (TN->getUnderlyingType()->isVariablyModifiedType()) {
|
||||||
// Don't allow variably-modified types in constexpr functions.
|
// Don't allow variably-modified types in constexpr functions.
|
||||||
TypeLoc TL = TN->getTypeSourceInfo()->getTypeLoc();
|
if (Kind == Sema::CheckConstexprKind::Diagnose) {
|
||||||
SemaRef.Diag(TL.getBeginLoc(), diag::err_constexpr_vla)
|
TypeLoc TL = TN->getTypeSourceInfo()->getTypeLoc();
|
||||||
<< TL.getSourceRange() << TL.getType()
|
SemaRef.Diag(TL.getBeginLoc(), diag::err_constexpr_vla)
|
||||||
<< isa<CXXConstructorDecl>(Dcl);
|
<< TL.getSourceRange() << TL.getType()
|
||||||
|
<< isa<CXXConstructorDecl>(Dcl);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
@ -1716,12 +1755,17 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
|
||||||
case Decl::Enum:
|
case Decl::Enum:
|
||||||
case Decl::CXXRecord:
|
case Decl::CXXRecord:
|
||||||
// C++1y allows types to be defined, not just declared.
|
// C++1y allows types to be defined, not just declared.
|
||||||
if (cast<TagDecl>(DclIt)->isThisDeclarationADefinition())
|
if (cast<TagDecl>(DclIt)->isThisDeclarationADefinition()) {
|
||||||
SemaRef.Diag(DS->getBeginLoc(),
|
if (Kind == Sema::CheckConstexprKind::Diagnose) {
|
||||||
SemaRef.getLangOpts().CPlusPlus14
|
SemaRef.Diag(DS->getBeginLoc(),
|
||||||
? diag::warn_cxx11_compat_constexpr_type_definition
|
SemaRef.getLangOpts().CPlusPlus14
|
||||||
: diag::ext_constexpr_type_definition)
|
? diag::warn_cxx11_compat_constexpr_type_definition
|
||||||
<< isa<CXXConstructorDecl>(Dcl);
|
: diag::ext_constexpr_type_definition)
|
||||||
|
<< isa<CXXConstructorDecl>(Dcl);
|
||||||
|
} else if (!SemaRef.getLangOpts().CPlusPlus14) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case Decl::EnumConstant:
|
case Decl::EnumConstant:
|
||||||
|
@ -1739,31 +1783,37 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
|
||||||
const auto *VD = cast<VarDecl>(DclIt);
|
const auto *VD = cast<VarDecl>(DclIt);
|
||||||
if (VD->isThisDeclarationADefinition()) {
|
if (VD->isThisDeclarationADefinition()) {
|
||||||
if (VD->isStaticLocal()) {
|
if (VD->isStaticLocal()) {
|
||||||
SemaRef.Diag(VD->getLocation(),
|
if (Kind == Sema::CheckConstexprKind::Diagnose) {
|
||||||
diag::err_constexpr_local_var_static)
|
SemaRef.Diag(VD->getLocation(),
|
||||||
<< isa<CXXConstructorDecl>(Dcl)
|
diag::err_constexpr_local_var_static)
|
||||||
<< (VD->getTLSKind() == VarDecl::TLS_Dynamic);
|
<< isa<CXXConstructorDecl>(Dcl)
|
||||||
|
<< (VD->getTLSKind() == VarDecl::TLS_Dynamic);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!VD->getType()->isDependentType() &&
|
if (CheckLiteralType(SemaRef, Kind, VD->getLocation(), VD->getType(),
|
||||||
SemaRef.RequireLiteralType(
|
diag::err_constexpr_local_var_non_literal_type,
|
||||||
VD->getLocation(), VD->getType(),
|
isa<CXXConstructorDecl>(Dcl)))
|
||||||
diag::err_constexpr_local_var_non_literal_type,
|
|
||||||
isa<CXXConstructorDecl>(Dcl)))
|
|
||||||
return false;
|
return false;
|
||||||
if (!VD->getType()->isDependentType() &&
|
if (!VD->getType()->isDependentType() &&
|
||||||
!VD->hasInit() && !VD->isCXXForRangeDecl()) {
|
!VD->hasInit() && !VD->isCXXForRangeDecl()) {
|
||||||
SemaRef.Diag(VD->getLocation(),
|
if (Kind == Sema::CheckConstexprKind::Diagnose) {
|
||||||
diag::err_constexpr_local_var_no_init)
|
SemaRef.Diag(VD->getLocation(),
|
||||||
<< isa<CXXConstructorDecl>(Dcl);
|
diag::err_constexpr_local_var_no_init)
|
||||||
|
<< isa<CXXConstructorDecl>(Dcl);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SemaRef.Diag(VD->getLocation(),
|
if (Kind == Sema::CheckConstexprKind::Diagnose) {
|
||||||
SemaRef.getLangOpts().CPlusPlus14
|
SemaRef.Diag(VD->getLocation(),
|
||||||
? diag::warn_cxx11_compat_constexpr_local_var
|
SemaRef.getLangOpts().CPlusPlus14
|
||||||
: diag::ext_constexpr_local_var)
|
? diag::warn_cxx11_compat_constexpr_local_var
|
||||||
<< isa<CXXConstructorDecl>(Dcl);
|
: diag::ext_constexpr_local_var)
|
||||||
|
<< isa<CXXConstructorDecl>(Dcl);
|
||||||
|
} else if (!SemaRef.getLangOpts().CPlusPlus14) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1776,8 +1826,10 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
SemaRef.Diag(DS->getBeginLoc(), diag::err_constexpr_body_invalid_stmt)
|
if (Kind == Sema::CheckConstexprKind::Diagnose) {
|
||||||
<< isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval();
|
SemaRef.Diag(DS->getBeginLoc(), diag::err_constexpr_body_invalid_stmt)
|
||||||
|
<< isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval();
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1792,17 +1844,23 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
|
||||||
/// struct or union nested within the class being checked.
|
/// struct or union nested within the class being checked.
|
||||||
/// \param Inits All declarations, including anonymous struct/union members and
|
/// \param Inits All declarations, including anonymous struct/union members and
|
||||||
/// indirect members, for which any initialization was provided.
|
/// indirect members, for which any initialization was provided.
|
||||||
/// \param Diagnosed Set to true if an error is produced.
|
/// \param Diagnosed Whether we've emitted the error message yet. Used to attach
|
||||||
static void CheckConstexprCtorInitializer(Sema &SemaRef,
|
/// multiple notes for different members to the same error.
|
||||||
|
/// \param Kind Whether we're diagnosing a constructor as written or determining
|
||||||
|
/// whether the formal requirements are satisfied.
|
||||||
|
/// \return \c false if we're checking for validity and the constructor does
|
||||||
|
/// not satisfy the requirements on a constexpr constructor.
|
||||||
|
static bool CheckConstexprCtorInitializer(Sema &SemaRef,
|
||||||
const FunctionDecl *Dcl,
|
const FunctionDecl *Dcl,
|
||||||
FieldDecl *Field,
|
FieldDecl *Field,
|
||||||
llvm::SmallSet<Decl*, 16> &Inits,
|
llvm::SmallSet<Decl*, 16> &Inits,
|
||||||
bool &Diagnosed) {
|
bool &Diagnosed,
|
||||||
|
Sema::CheckConstexprKind Kind) {
|
||||||
if (Field->isInvalidDecl())
|
if (Field->isInvalidDecl())
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
if (Field->isUnnamedBitfield())
|
if (Field->isUnnamedBitfield())
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
// Anonymous unions with no variant members and empty anonymous structs do not
|
// Anonymous unions with no variant members and empty anonymous structs do not
|
||||||
// need to be explicitly initialized. FIXME: Anonymous structs that contain no
|
// need to be explicitly initialized. FIXME: Anonymous structs that contain no
|
||||||
|
@ -1811,22 +1869,30 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef,
|
||||||
(Field->getType()->isUnionType()
|
(Field->getType()->isUnionType()
|
||||||
? !Field->getType()->getAsCXXRecordDecl()->hasVariantMembers()
|
? !Field->getType()->getAsCXXRecordDecl()->hasVariantMembers()
|
||||||
: Field->getType()->getAsCXXRecordDecl()->isEmpty()))
|
: Field->getType()->getAsCXXRecordDecl()->isEmpty()))
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
if (!Inits.count(Field)) {
|
if (!Inits.count(Field)) {
|
||||||
if (!Diagnosed) {
|
if (Kind == Sema::CheckConstexprKind::Diagnose) {
|
||||||
SemaRef.Diag(Dcl->getLocation(), diag::err_constexpr_ctor_missing_init);
|
if (!Diagnosed) {
|
||||||
Diagnosed = true;
|
SemaRef.Diag(Dcl->getLocation(), diag::err_constexpr_ctor_missing_init);
|
||||||
|
Diagnosed = true;
|
||||||
|
}
|
||||||
|
SemaRef.Diag(Field->getLocation(),
|
||||||
|
diag::note_constexpr_ctor_missing_init);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
SemaRef.Diag(Field->getLocation(), diag::note_constexpr_ctor_missing_init);
|
|
||||||
} else if (Field->isAnonymousStructOrUnion()) {
|
} else if (Field->isAnonymousStructOrUnion()) {
|
||||||
const RecordDecl *RD = Field->getType()->castAs<RecordType>()->getDecl();
|
const RecordDecl *RD = Field->getType()->castAs<RecordType>()->getDecl();
|
||||||
for (auto *I : RD->fields())
|
for (auto *I : RD->fields())
|
||||||
// If an anonymous union contains an anonymous struct of which any member
|
// If an anonymous union contains an anonymous struct of which any member
|
||||||
// is initialized, all members must be initialized.
|
// is initialized, all members must be initialized.
|
||||||
if (!RD->isUnion() || Inits.count(I))
|
if (!RD->isUnion() || Inits.count(I))
|
||||||
CheckConstexprCtorInitializer(SemaRef, Dcl, I, Inits, Diagnosed);
|
if (!CheckConstexprCtorInitializer(SemaRef, Dcl, I, Inits, Diagnosed,
|
||||||
|
Kind))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check the provided statement is allowed in a constexpr function
|
/// Check the provided statement is allowed in a constexpr function
|
||||||
|
@ -1834,7 +1900,8 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef,
|
||||||
static bool
|
static bool
|
||||||
CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
|
CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
|
||||||
SmallVectorImpl<SourceLocation> &ReturnStmts,
|
SmallVectorImpl<SourceLocation> &ReturnStmts,
|
||||||
SourceLocation &Cxx1yLoc, SourceLocation &Cxx2aLoc) {
|
SourceLocation &Cxx1yLoc, SourceLocation &Cxx2aLoc,
|
||||||
|
Sema::CheckConstexprKind Kind) {
|
||||||
// - its function-body shall be [...] a compound-statement that contains only
|
// - its function-body shall be [...] a compound-statement that contains only
|
||||||
switch (S->getStmtClass()) {
|
switch (S->getStmtClass()) {
|
||||||
case Stmt::NullStmtClass:
|
case Stmt::NullStmtClass:
|
||||||
|
@ -1847,7 +1914,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
|
||||||
// - using-directives,
|
// - using-directives,
|
||||||
// - typedef declarations and alias-declarations that do not define
|
// - typedef declarations and alias-declarations that do not define
|
||||||
// classes or enumerations,
|
// classes or enumerations,
|
||||||
if (!CheckConstexprDeclStmt(SemaRef, Dcl, cast<DeclStmt>(S), Cxx1yLoc))
|
if (!CheckConstexprDeclStmt(SemaRef, Dcl, cast<DeclStmt>(S), Cxx1yLoc, Kind))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -1871,7 +1938,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
|
||||||
CompoundStmt *CompStmt = cast<CompoundStmt>(S);
|
CompoundStmt *CompStmt = cast<CompoundStmt>(S);
|
||||||
for (auto *BodyIt : CompStmt->body()) {
|
for (auto *BodyIt : CompStmt->body()) {
|
||||||
if (!CheckConstexprFunctionStmt(SemaRef, Dcl, BodyIt, ReturnStmts,
|
if (!CheckConstexprFunctionStmt(SemaRef, Dcl, BodyIt, ReturnStmts,
|
||||||
Cxx1yLoc, Cxx2aLoc))
|
Cxx1yLoc, Cxx2aLoc, Kind))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1889,11 +1956,11 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
|
||||||
|
|
||||||
IfStmt *If = cast<IfStmt>(S);
|
IfStmt *If = cast<IfStmt>(S);
|
||||||
if (!CheckConstexprFunctionStmt(SemaRef, Dcl, If->getThen(), ReturnStmts,
|
if (!CheckConstexprFunctionStmt(SemaRef, Dcl, If->getThen(), ReturnStmts,
|
||||||
Cxx1yLoc, Cxx2aLoc))
|
Cxx1yLoc, Cxx2aLoc, Kind))
|
||||||
return false;
|
return false;
|
||||||
if (If->getElse() &&
|
if (If->getElse() &&
|
||||||
!CheckConstexprFunctionStmt(SemaRef, Dcl, If->getElse(), ReturnStmts,
|
!CheckConstexprFunctionStmt(SemaRef, Dcl, If->getElse(), ReturnStmts,
|
||||||
Cxx1yLoc, Cxx2aLoc))
|
Cxx1yLoc, Cxx2aLoc, Kind))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1912,7 +1979,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
|
||||||
for (Stmt *SubStmt : S->children())
|
for (Stmt *SubStmt : S->children())
|
||||||
if (SubStmt &&
|
if (SubStmt &&
|
||||||
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
|
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
|
||||||
Cxx1yLoc, Cxx2aLoc))
|
Cxx1yLoc, Cxx2aLoc, Kind))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -1927,7 +1994,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
|
||||||
for (Stmt *SubStmt : S->children())
|
for (Stmt *SubStmt : S->children())
|
||||||
if (SubStmt &&
|
if (SubStmt &&
|
||||||
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
|
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
|
||||||
Cxx1yLoc, Cxx2aLoc))
|
Cxx1yLoc, Cxx2aLoc, Kind))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -1937,7 +2004,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
|
||||||
for (Stmt *SubStmt : S->children()) {
|
for (Stmt *SubStmt : S->children()) {
|
||||||
if (SubStmt &&
|
if (SubStmt &&
|
||||||
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
|
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
|
||||||
Cxx1yLoc, Cxx2aLoc))
|
Cxx1yLoc, Cxx2aLoc, Kind))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1947,7 +2014,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
|
||||||
// try block check).
|
// try block check).
|
||||||
if (!CheckConstexprFunctionStmt(SemaRef, Dcl,
|
if (!CheckConstexprFunctionStmt(SemaRef, Dcl,
|
||||||
cast<CXXCatchStmt>(S)->getHandlerBlock(),
|
cast<CXXCatchStmt>(S)->getHandlerBlock(),
|
||||||
ReturnStmts, Cxx1yLoc, Cxx2aLoc))
|
ReturnStmts, Cxx1yLoc, Cxx2aLoc, Kind))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -1961,16 +2028,21 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SemaRef.Diag(S->getBeginLoc(), diag::err_constexpr_body_invalid_stmt)
|
if (Kind == Sema::CheckConstexprKind::Diagnose) {
|
||||||
<< isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval();
|
SemaRef.Diag(S->getBeginLoc(), diag::err_constexpr_body_invalid_stmt)
|
||||||
|
<< isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval();
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check the body for the given constexpr function declaration only contains
|
/// Check the body for the given constexpr function declaration only contains
|
||||||
/// the permitted types of statement. C++11 [dcl.constexpr]p3,p4.
|
/// 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.
|
/// \return true if the body is OK, false if we have found or diagnosed a
|
||||||
bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
|
/// problem.
|
||||||
|
static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
|
||||||
|
Stmt *Body,
|
||||||
|
Sema::CheckConstexprKind Kind) {
|
||||||
SmallVector<SourceLocation, 4> ReturnStmts;
|
SmallVector<SourceLocation, 4> ReturnStmts;
|
||||||
|
|
||||||
if (isa<CXXTryStmt>(Body)) {
|
if (isa<CXXTryStmt>(Body)) {
|
||||||
|
@ -1986,11 +2058,20 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
|
||||||
//
|
//
|
||||||
// This restriction is lifted in C++2a, as long as inner statements also
|
// This restriction is lifted in C++2a, as long as inner statements also
|
||||||
// apply the general constexpr rules.
|
// apply the general constexpr rules.
|
||||||
Diag(Body->getBeginLoc(),
|
switch (Kind) {
|
||||||
!getLangOpts().CPlusPlus2a
|
case Sema::CheckConstexprKind::CheckValid:
|
||||||
? diag::ext_constexpr_function_try_block_cxx2a
|
if (!SemaRef.getLangOpts().CPlusPlus2a)
|
||||||
: diag::warn_cxx17_compat_constexpr_function_try_block)
|
return false;
|
||||||
<< isa<CXXConstructorDecl>(Dcl);
|
break;
|
||||||
|
|
||||||
|
case Sema::CheckConstexprKind::Diagnose:
|
||||||
|
SemaRef.Diag(Body->getBeginLoc(),
|
||||||
|
!SemaRef.getLangOpts().CPlusPlus2a
|
||||||
|
? diag::ext_constexpr_function_try_block_cxx2a
|
||||||
|
: diag::warn_cxx17_compat_constexpr_function_try_block)
|
||||||
|
<< isa<CXXConstructorDecl>(Dcl);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// - its function-body shall be [...] a compound-statement that contains only
|
// - its function-body shall be [...] a compound-statement that contains only
|
||||||
|
@ -2001,23 +2082,30 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
|
||||||
SourceLocation Cxx1yLoc, Cxx2aLoc;
|
SourceLocation Cxx1yLoc, Cxx2aLoc;
|
||||||
for (Stmt *SubStmt : Body->children()) {
|
for (Stmt *SubStmt : Body->children()) {
|
||||||
if (SubStmt &&
|
if (SubStmt &&
|
||||||
!CheckConstexprFunctionStmt(*this, Dcl, SubStmt, ReturnStmts,
|
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
|
||||||
Cxx1yLoc, Cxx2aLoc))
|
Cxx1yLoc, Cxx2aLoc, Kind))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Cxx2aLoc.isValid())
|
if (Kind == Sema::CheckConstexprKind::CheckValid) {
|
||||||
Diag(Cxx2aLoc,
|
// If this is only valid as an extension, report that we don't satisfy the
|
||||||
getLangOpts().CPlusPlus2a
|
// constraints of the current language.
|
||||||
|
if ((Cxx2aLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus2a) ||
|
||||||
|
(Cxx1yLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus17))
|
||||||
|
return false;
|
||||||
|
} else if (Cxx2aLoc.isValid()) {
|
||||||
|
SemaRef.Diag(Cxx2aLoc,
|
||||||
|
SemaRef.getLangOpts().CPlusPlus2a
|
||||||
? diag::warn_cxx17_compat_constexpr_body_invalid_stmt
|
? diag::warn_cxx17_compat_constexpr_body_invalid_stmt
|
||||||
: diag::ext_constexpr_body_invalid_stmt_cxx2a)
|
: diag::ext_constexpr_body_invalid_stmt_cxx2a)
|
||||||
<< isa<CXXConstructorDecl>(Dcl);
|
<< isa<CXXConstructorDecl>(Dcl);
|
||||||
if (Cxx1yLoc.isValid())
|
} else if (Cxx1yLoc.isValid()) {
|
||||||
Diag(Cxx1yLoc,
|
SemaRef.Diag(Cxx1yLoc,
|
||||||
getLangOpts().CPlusPlus14
|
SemaRef.getLangOpts().CPlusPlus14
|
||||||
? diag::warn_cxx11_compat_constexpr_body_invalid_stmt
|
? diag::warn_cxx11_compat_constexpr_body_invalid_stmt
|
||||||
: diag::ext_constexpr_body_invalid_stmt)
|
: diag::ext_constexpr_body_invalid_stmt)
|
||||||
<< isa<CXXConstructorDecl>(Dcl);
|
<< isa<CXXConstructorDecl>(Dcl);
|
||||||
|
}
|
||||||
|
|
||||||
if (const CXXConstructorDecl *Constructor
|
if (const CXXConstructorDecl *Constructor
|
||||||
= dyn_cast<CXXConstructorDecl>(Dcl)) {
|
= dyn_cast<CXXConstructorDecl>(Dcl)) {
|
||||||
|
@ -2031,7 +2119,9 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
|
||||||
if (RD->isUnion()) {
|
if (RD->isUnion()) {
|
||||||
if (Constructor->getNumCtorInitializers() == 0 &&
|
if (Constructor->getNumCtorInitializers() == 0 &&
|
||||||
RD->hasVariantMembers()) {
|
RD->hasVariantMembers()) {
|
||||||
Diag(Dcl->getLocation(), diag::err_constexpr_union_ctor_no_init);
|
if (Kind == Sema::CheckConstexprKind::Diagnose)
|
||||||
|
SemaRef.Diag(Dcl->getLocation(),
|
||||||
|
diag::err_constexpr_union_ctor_no_init);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!Constructor->isDependentContext() &&
|
} else if (!Constructor->isDependentContext() &&
|
||||||
|
@ -2068,9 +2158,9 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
|
||||||
|
|
||||||
bool Diagnosed = false;
|
bool Diagnosed = false;
|
||||||
for (auto *I : RD->fields())
|
for (auto *I : RD->fields())
|
||||||
CheckConstexprCtorInitializer(*this, Dcl, I, Inits, Diagnosed);
|
if (!CheckConstexprCtorInitializer(SemaRef, Dcl, I, Inits, Diagnosed,
|
||||||
if (Diagnosed)
|
Kind))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -2079,22 +2169,45 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
|
||||||
// statement. We still do, unless the return type might be void, because
|
// statement. We still do, unless the return type might be void, because
|
||||||
// otherwise if there's no return statement, the function cannot
|
// otherwise if there's no return statement, the function cannot
|
||||||
// be used in a core constant expression.
|
// be used in a core constant expression.
|
||||||
bool OK = getLangOpts().CPlusPlus14 &&
|
bool OK = SemaRef.getLangOpts().CPlusPlus14 &&
|
||||||
(Dcl->getReturnType()->isVoidType() ||
|
(Dcl->getReturnType()->isVoidType() ||
|
||||||
Dcl->getReturnType()->isDependentType());
|
Dcl->getReturnType()->isDependentType());
|
||||||
Diag(Dcl->getLocation(),
|
switch (Kind) {
|
||||||
OK ? diag::warn_cxx11_compat_constexpr_body_no_return
|
case Sema::CheckConstexprKind::Diagnose:
|
||||||
: diag::err_constexpr_body_no_return)
|
SemaRef.Diag(Dcl->getLocation(),
|
||||||
<< Dcl->isConsteval();
|
OK ? diag::warn_cxx11_compat_constexpr_body_no_return
|
||||||
if (!OK)
|
: diag::err_constexpr_body_no_return)
|
||||||
return false;
|
<< Dcl->isConsteval();
|
||||||
|
if (!OK)
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Sema::CheckConstexprKind::CheckValid:
|
||||||
|
// The formal requirements don't include this rule in C++14, even
|
||||||
|
// though the "must be able to produce a constant expression" rules
|
||||||
|
// still imply it in some cases.
|
||||||
|
if (!SemaRef.getLangOpts().CPlusPlus14)
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else if (ReturnStmts.size() > 1) {
|
} else if (ReturnStmts.size() > 1) {
|
||||||
Diag(ReturnStmts.back(),
|
switch (Kind) {
|
||||||
getLangOpts().CPlusPlus14
|
case Sema::CheckConstexprKind::Diagnose:
|
||||||
? diag::warn_cxx11_compat_constexpr_body_multiple_return
|
SemaRef.Diag(
|
||||||
: diag::ext_constexpr_body_multiple_return);
|
ReturnStmts.back(),
|
||||||
for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I)
|
SemaRef.getLangOpts().CPlusPlus14
|
||||||
Diag(ReturnStmts[I], diag::note_constexpr_body_previous_return);
|
? diag::warn_cxx11_compat_constexpr_body_multiple_return
|
||||||
|
: diag::ext_constexpr_body_multiple_return);
|
||||||
|
for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I)
|
||||||
|
SemaRef.Diag(ReturnStmts[I],
|
||||||
|
diag::note_constexpr_body_previous_return);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Sema::CheckConstexprKind::CheckValid:
|
||||||
|
if (!SemaRef.getLangOpts().CPlusPlus14)
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2108,12 +2221,17 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
|
||||||
// C++11 [dcl.constexpr]p4:
|
// C++11 [dcl.constexpr]p4:
|
||||||
// - every constructor involved in initializing non-static data members and
|
// - every constructor involved in initializing non-static data members and
|
||||||
// base class sub-objects shall be a constexpr constructor.
|
// base class sub-objects shall be a constexpr constructor.
|
||||||
|
//
|
||||||
|
// Note that this rule is distinct from the "requirements for a constexpr
|
||||||
|
// function", so is not checked in CheckValid mode.
|
||||||
SmallVector<PartialDiagnosticAt, 8> Diags;
|
SmallVector<PartialDiagnosticAt, 8> Diags;
|
||||||
if (!Expr::isPotentialConstantExpr(Dcl, Diags)) {
|
if (Kind == Sema::CheckConstexprKind::Diagnose &&
|
||||||
Diag(Dcl->getLocation(), diag::ext_constexpr_function_never_constant_expr)
|
!Expr::isPotentialConstantExpr(Dcl, Diags)) {
|
||||||
<< isa<CXXConstructorDecl>(Dcl);
|
SemaRef.Diag(Dcl->getLocation(),
|
||||||
|
diag::ext_constexpr_function_never_constant_expr)
|
||||||
|
<< isa<CXXConstructorDecl>(Dcl);
|
||||||
for (size_t I = 0, N = Diags.size(); I != N; ++I)
|
for (size_t I = 0, N = Diags.size(); I != N; ++I)
|
||||||
Diag(Diags[I].first, Diags[I].second);
|
SemaRef.Diag(Diags[I].first, Diags[I].second);
|
||||||
// Don't return false here: we allow this for compatibility in
|
// Don't return false here: we allow this for compatibility in
|
||||||
// system headers.
|
// system headers.
|
||||||
}
|
}
|
||||||
|
|
|
@ -1776,10 +1776,9 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
|
||||||
!CallOperator->isConstexpr() &&
|
!CallOperator->isConstexpr() &&
|
||||||
!isa<CoroutineBodyStmt>(CallOperator->getBody()) &&
|
!isa<CoroutineBodyStmt>(CallOperator->getBody()) &&
|
||||||
!Class->getDeclContext()->isDependentContext()) {
|
!Class->getDeclContext()->isDependentContext()) {
|
||||||
TentativeAnalysisScope DiagnosticScopeGuard(*this);
|
|
||||||
CallOperator->setConstexprKind(
|
CallOperator->setConstexprKind(
|
||||||
(CheckConstexprFunctionDecl(CallOperator) &&
|
CheckConstexprFunctionDefinition(CallOperator,
|
||||||
CheckConstexprFunctionBody(CallOperator, CallOperator->getBody()))
|
CheckConstexprKind::CheckValid)
|
||||||
? CSK_constexpr
|
? CSK_constexpr
|
||||||
: CSK_unspecified);
|
: CSK_unspecified);
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,11 +157,8 @@ constexpr int DisallowedStmtsCXX1Y_2_1() {
|
||||||
constexpr int DisallowedStmtsCXX1Y_3() {
|
constexpr int DisallowedStmtsCXX1Y_3() {
|
||||||
// - a try-block,
|
// - a try-block,
|
||||||
try {} catch (...) {}
|
try {} catch (...) {}
|
||||||
#ifndef CXX2A
|
#if !defined(CXX2A)
|
||||||
// expected-error@-2 {{use of this statement in a constexpr function is a C++2a extension}}
|
// expected-error@-2 {{use of this statement in a constexpr function is a C++2a extension}}
|
||||||
#ifndef CXX1Y
|
|
||||||
// expected-error@-4 {{use of this statement in a constexpr function is a C++14 extension}}
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks %s -fcxx-exceptions
|
// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks %s -fcxx-exceptions
|
||||||
|
// RUN: %clang_cc1 -std=c++2a -verify -fsyntax-only -fblocks %s -fcxx-exceptions
|
||||||
// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -fcxx-exceptions
|
// RUN: %clang_cc1 -std=c++1z -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -fcxx-exceptions
|
||||||
// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -fblocks %s -DCPP14_AND_EARLIER -fcxx-exceptions
|
// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -fblocks %s -DCPP14_AND_EARLIER -fcxx-exceptions
|
||||||
|
|
||||||
|
@ -25,6 +26,34 @@ namespace ns2 {
|
||||||
auto L = [](int I) constexpr { asm("non-constexpr"); }; //expected-error{{not allowed in constexpr function}}
|
auto L = [](int I) constexpr { asm("non-constexpr"); }; //expected-error{{not allowed in constexpr function}}
|
||||||
} // end ns1
|
} // end ns1
|
||||||
|
|
||||||
|
// This is not constexpr until C++20, as the requirements on constexpr
|
||||||
|
// functions don't permit try-catch blocks.
|
||||||
|
#if __cplusplus <= 201703L
|
||||||
|
// expected-error@#try-catch {{constant expression}}
|
||||||
|
// expected-note@#try-catch {{non-constexpr function 'operator()'}}
|
||||||
|
// expected-note@#try-catch {{declared here}}
|
||||||
|
#endif
|
||||||
|
constexpr int try_catch = [] { // #try-catch
|
||||||
|
try { return 0; } catch (...) { return 1; }
|
||||||
|
}();
|
||||||
|
|
||||||
|
// These lambdas have constexpr operator() even though they can never produce a
|
||||||
|
// constant expression.
|
||||||
|
auto never_constant_1 = [] { // expected-note {{here}}
|
||||||
|
volatile int n = 0;
|
||||||
|
return n;
|
||||||
|
};
|
||||||
|
auto never_constant_2 = [] () -> int { // expected-note {{here}}
|
||||||
|
};
|
||||||
|
struct test_never_constant {
|
||||||
|
#if __cplusplus >= 201703L
|
||||||
|
// expected-error@+3 {{non-constexpr declaration of 'operator()' follows constexpr declaration}}
|
||||||
|
// expected-error@+3 {{non-constexpr declaration of 'operator()' follows constexpr declaration}}
|
||||||
|
#endif
|
||||||
|
friend auto decltype(never_constant_1)::operator()() const;
|
||||||
|
friend int decltype(never_constant_2)::operator()() const;
|
||||||
|
};
|
||||||
|
|
||||||
} // end ns test_constexpr_checking
|
} // end ns test_constexpr_checking
|
||||||
|
|
||||||
namespace test_constexpr_call {
|
namespace test_constexpr_call {
|
||||||
|
|
Loading…
Reference in New Issue