Revert "[clang][SemaCXX] Diagnose tautological uses of consteval if and is_constant_evaluated"
This reverts commit 491b2810fb7fe5f080fa9c4f5945ed0a6909dc92. This change broke valid code and generated incorrect diagnostics, see https://reviews.llvm.org/D155064
This commit is contained in:
parent
6a34b12727
commit
880fa7faa9
@ -206,12 +206,6 @@ Improvements to Clang's diagnostics
|
||||
- Clang no longer emits irrelevant notes about unsatisfied constraint expressions
|
||||
on the left-hand side of ``||`` when the right-hand side constraint is satisfied.
|
||||
(`#54678: <https://github.com/llvm/llvm-project/issues/54678>`_).
|
||||
- Clang now diagnoses wider cases of tautological use of consteval if or
|
||||
``std::is_constant_evaluated``. This also suppresses some false positives.
|
||||
(`#43760: <https://github.com/llvm/llvm-project/issues/43760>`_)
|
||||
(`#51567: <https://github.com/llvm/llvm-project/issues/51567>`_)
|
||||
- Clang now diagnoses narrowing implicit conversions on variable initializers in immediate
|
||||
function context and on constexpr variable template initializers.
|
||||
- Clang now prints its 'note' diagnostic in cyan instead of black, to be more compatible
|
||||
with terminals with dark background colors. This is also more consistent with GCC.
|
||||
|
||||
|
@ -413,6 +413,10 @@ def warn_constexpr_unscoped_enum_out_of_range : Warning<
|
||||
def note_unimplemented_constexpr_lambda_feature_ast : Note<
|
||||
"unimplemented constexpr lambda feature: %0 (coming soon!)">;
|
||||
|
||||
def warn_is_constant_evaluated_always_true_constexpr : Warning<
|
||||
"'%0' will always evaluate to 'true' in a manifestly constant-evaluated expression">,
|
||||
InGroup<DiagGroup<"constant-evaluated">>;
|
||||
|
||||
// inline asm related.
|
||||
let CategoryName = "Inline Assembly Issue" in {
|
||||
def err_asm_invalid_escape : Error<
|
||||
|
@ -1591,8 +1591,8 @@ def err_static_assert_message_constexpr : Error<
|
||||
"the message in a static assertion must be produced by a "
|
||||
"constant expression">;
|
||||
|
||||
def warn_tautological_consteval_if : Warning<
|
||||
"consteval if is always %select{true|false}0 in this context">,
|
||||
def warn_consteval_if_always_true : Warning<
|
||||
"consteval if is always true in an %select{unevaluated|immediate}0 context">,
|
||||
InGroup<DiagGroup<"redundant-consteval-if">>;
|
||||
|
||||
def ext_inline_variable : ExtWarn<
|
||||
@ -8897,9 +8897,6 @@ def warn_side_effects_unevaluated_context : Warning<
|
||||
def warn_side_effects_typeid : Warning<
|
||||
"expression with side effects will be evaluated despite being used as an "
|
||||
"operand to 'typeid'">, InGroup<PotentiallyEvaluatedExpression>;
|
||||
def warn_tautological_is_constant_evaluated : Warning<
|
||||
"'%select{std::is_constant_evaluated|__builtin_is_constant_evaluated}0' will always evaluate to %select{false|true}1 in this context">,
|
||||
InGroup<DiagGroup<"constant-evaluated">>;
|
||||
def warn_unused_result : Warning<
|
||||
"ignoring return value of function declared with %0 attribute">,
|
||||
InGroup<UnusedResult>;
|
||||
|
@ -2003,10 +2003,12 @@ private:
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ if/switch/while/for condition expression.
|
||||
struct ForRangeInfo;
|
||||
Sema::ConditionResult ParseCXXCondition(
|
||||
StmtResult *InitStmt, SourceLocation Loc, Sema::ConditionKind CK,
|
||||
bool MissingOK, ForRangeInfo *FRI = nullptr,
|
||||
bool EnterForConditionScope = false, SourceLocation ConstexprLoc = {});
|
||||
Sema::ConditionResult ParseCXXCondition(StmtResult *InitStmt,
|
||||
SourceLocation Loc,
|
||||
Sema::ConditionKind CK,
|
||||
bool MissingOK,
|
||||
ForRangeInfo *FRI = nullptr,
|
||||
bool EnterForConditionScope = false);
|
||||
DeclGroupPtrTy ParseAliasDeclarationInInitStatement(DeclaratorContext Context,
|
||||
ParsedAttributes &Attrs);
|
||||
|
||||
@ -2104,8 +2106,7 @@ private:
|
||||
Sema::ConditionResult &CondResult,
|
||||
SourceLocation Loc, Sema::ConditionKind CK,
|
||||
SourceLocation &LParenLoc,
|
||||
SourceLocation &RParenLoc,
|
||||
SourceLocation ConstexprLoc = {});
|
||||
SourceLocation &RParenLoc);
|
||||
StmtResult ParseIfStatement(SourceLocation *TrailingElseLoc);
|
||||
StmtResult ParseSwitchStatement(SourceLocation *TrailingElseLoc);
|
||||
StmtResult ParseWhileStatement(SourceLocation *TrailingElseLoc);
|
||||
|
@ -1358,9 +1358,6 @@ public:
|
||||
bool InDiscardedStatement;
|
||||
bool InImmediateFunctionContext;
|
||||
bool InImmediateEscalatingFunctionContext;
|
||||
// The immediate occurances of consteval if or std::is_constant_evaluated()
|
||||
// are tautologically false
|
||||
bool IsRuntimeEvaluated;
|
||||
|
||||
bool IsCurrentlyCheckingDefaultArgumentOrInitializer = false;
|
||||
|
||||
@ -1390,8 +1387,7 @@ public:
|
||||
NumCleanupObjects(NumCleanupObjects), NumTypos(0),
|
||||
ManglingContextDecl(ManglingContextDecl), ExprContext(ExprContext),
|
||||
InDiscardedStatement(false), InImmediateFunctionContext(false),
|
||||
InImmediateEscalatingFunctionContext(false),
|
||||
IsRuntimeEvaluated(false) {}
|
||||
InImmediateEscalatingFunctionContext(false) {}
|
||||
|
||||
bool isUnevaluated() const {
|
||||
return Context == ExpressionEvaluationContext::Unevaluated ||
|
||||
@ -1430,10 +1426,6 @@ public:
|
||||
/// A stack of expression evaluation contexts.
|
||||
SmallVector<ExpressionEvaluationContextRecord, 8> ExprEvalContexts;
|
||||
|
||||
/// Source location of the start of `constexpr` in constexpr-if
|
||||
/// used for diagnostics
|
||||
SourceLocation ConstexprIfLoc;
|
||||
|
||||
// Set of failed immediate invocations to avoid double diagnosing.
|
||||
llvm::SmallPtrSet<ConstantExpr *, 4> FailedImmediateInvocations;
|
||||
|
||||
|
@ -12178,6 +12178,22 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
|
||||
}
|
||||
|
||||
case Builtin::BI__builtin_is_constant_evaluated: {
|
||||
const auto *Callee = Info.CurrentCall->getCallee();
|
||||
if (Info.InConstantContext && !Info.CheckingPotentialConstantExpression &&
|
||||
(Info.CallStackDepth == 1 ||
|
||||
(Info.CallStackDepth == 2 && Callee->isInStdNamespace() &&
|
||||
Callee->getIdentifier() &&
|
||||
Callee->getIdentifier()->isStr("is_constant_evaluated")))) {
|
||||
// FIXME: Find a better way to avoid duplicated diagnostics.
|
||||
if (Info.EvalStatus.Diag)
|
||||
Info.report((Info.CallStackDepth == 1)
|
||||
? E->getExprLoc()
|
||||
: Info.CurrentCall->getCallRange().getBegin(),
|
||||
diag::warn_is_constant_evaluated_always_true_constexpr)
|
||||
<< (Info.CallStackDepth == 1 ? "__builtin_is_constant_evaluated"
|
||||
: "std::is_constant_evaluated");
|
||||
}
|
||||
|
||||
return Success(Info.InConstantContext, E);
|
||||
}
|
||||
|
||||
|
@ -2461,15 +2461,6 @@ Decl *Parser::ParseDeclarationAfterDeclarator(
|
||||
return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
|
||||
}
|
||||
|
||||
/// Determine whether the given declaration is a global variable or
|
||||
/// static data member.
|
||||
static bool isNonlocalVariable(const Decl *D) {
|
||||
if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(D))
|
||||
return Var->hasGlobalStorage();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
|
||||
Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) {
|
||||
// RAII type used to track whether we're inside an initializer.
|
||||
@ -2502,36 +2493,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
|
||||
ThisDecl = nullptr;
|
||||
}
|
||||
};
|
||||
struct EnterInitializerExpressionEvaluationContext {
|
||||
Sema &S;
|
||||
bool Entered;
|
||||
|
||||
EnterInitializerExpressionEvaluationContext(Sema &S, Declarator &D,
|
||||
Decl *ThisDecl)
|
||||
: S(S), Entered(false) {
|
||||
if (ThisDecl && S.getLangOpts().CPlusPlus && !ThisDecl->isInvalidDecl()) {
|
||||
Entered = true;
|
||||
bool RuntimeEvaluated = S.ExprEvalContexts.back().IsRuntimeEvaluated;
|
||||
Sema::ExpressionEvaluationContext NewEEC =
|
||||
S.ExprEvalContexts.back().Context;
|
||||
if ((D.getDeclSpec().getTypeQualifiers() == DeclSpec::TQ_const ||
|
||||
isNonlocalVariable(ThisDecl)) &&
|
||||
S.ExprEvalContexts.back().IsRuntimeEvaluated) {
|
||||
RuntimeEvaluated = false;
|
||||
}
|
||||
if (D.getDeclSpec().hasConstexprSpecifier()) {
|
||||
NewEEC = Sema::ExpressionEvaluationContext::ConstantEvaluated;
|
||||
RuntimeEvaluated = false;
|
||||
}
|
||||
S.PushExpressionEvaluationContext(NewEEC, ThisDecl);
|
||||
S.ExprEvalContexts.back().IsRuntimeEvaluated = RuntimeEvaluated;
|
||||
}
|
||||
}
|
||||
~EnterInitializerExpressionEvaluationContext() {
|
||||
if (Entered)
|
||||
S.PopExpressionEvaluationContext();
|
||||
}
|
||||
};
|
||||
|
||||
enum class InitKind { Uninitialized, Equal, CXXDirect, CXXBraced };
|
||||
InitKind TheInitKind;
|
||||
@ -2631,7 +2592,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
|
||||
<< getLangOpts().CPlusPlus20;
|
||||
} else {
|
||||
InitializerScopeRAII InitScope(*this, D, ThisDecl);
|
||||
EnterInitializerExpressionEvaluationContext InitEC(Actions, D, ThisDecl);
|
||||
|
||||
if (Tok.is(tok::code_completion)) {
|
||||
cutOffParsing();
|
||||
@ -2679,7 +2639,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
|
||||
ExprVector Exprs;
|
||||
|
||||
InitializerScopeRAII InitScope(*this, D, ThisDecl);
|
||||
EnterInitializerExpressionEvaluationContext InitEC(Actions, D, ThisDecl);
|
||||
|
||||
auto ThisVarDecl = dyn_cast_or_null<VarDecl>(ThisDecl);
|
||||
auto RunSignatureHelp = [&]() {
|
||||
@ -2730,7 +2689,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
|
||||
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
|
||||
|
||||
InitializerScopeRAII InitScope(*this, D, ThisDecl);
|
||||
EnterInitializerExpressionEvaluationContext InitEC(Actions, D, ThisDecl);
|
||||
|
||||
PreferredType.enterVariableInit(Tok.getLocation(), ThisDecl);
|
||||
ExprResult Init(ParseBraceInitializer());
|
||||
|
@ -3234,14 +3234,9 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
|
||||
|
||||
bool IsFieldInitialization = isa_and_present<FieldDecl>(D);
|
||||
|
||||
bool IsConstexpr = false;
|
||||
if (const auto *VD = dyn_cast_if_present<VarDecl>(D))
|
||||
IsConstexpr = VD->isConstexpr();
|
||||
|
||||
EnterExpressionEvaluationContext Context(
|
||||
Actions,
|
||||
IsConstexpr ? Sema::ExpressionEvaluationContext::ConstantEvaluated
|
||||
: IsFieldInitialization
|
||||
IsFieldInitialization
|
||||
? Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed
|
||||
: Sema::ExpressionEvaluationContext::PotentiallyEvaluated,
|
||||
D);
|
||||
|
@ -2093,13 +2093,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
||||
};
|
||||
if (OpKind == tok::l_paren || !LHS.isInvalid()) {
|
||||
if (Tok.isNot(tok::r_paren)) {
|
||||
// FIXME: arguments in consteval functions are constant expression
|
||||
// regardless of the evaluation context of callsite. However, we
|
||||
// cannot know whether the called function is constevasl before the
|
||||
// declaration is resolved.
|
||||
bool IsRuntimeEvaluated =
|
||||
Actions.ExprEvalContexts.back().IsRuntimeEvaluated;
|
||||
Actions.ExprEvalContexts.back().IsRuntimeEvaluated = false;
|
||||
if (ParseExpressionList(ArgExprs, [&] {
|
||||
PreferredType.enterFunctionArgument(Tok.getLocation(),
|
||||
RunSignatureHelp);
|
||||
@ -2116,8 +2109,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
||||
for (auto &E : ArgExprs)
|
||||
Actions.CorrectDelayedTyposInExpr(E);
|
||||
}
|
||||
Actions.ExprEvalContexts.back().IsRuntimeEvaluated =
|
||||
IsRuntimeEvaluated;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2041,8 +2041,7 @@ Parser::ParseAliasDeclarationInInitStatement(DeclaratorContext Context,
|
||||
Sema::ConditionResult
|
||||
Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
|
||||
Sema::ConditionKind CK, bool MissingOK,
|
||||
ForRangeInfo *FRI, bool EnterForConditionScope,
|
||||
SourceLocation ConstexprLoc) {
|
||||
ForRangeInfo *FRI, bool EnterForConditionScope) {
|
||||
// Helper to ensure we always enter a continue/break scope if requested.
|
||||
struct ForConditionScopeRAII {
|
||||
Scope *S;
|
||||
@ -2099,28 +2098,9 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
|
||||
*InitStmt = Actions.ActOnNullStmt(SemiLoc);
|
||||
return ParseCXXCondition(nullptr, Loc, CK, MissingOK);
|
||||
}
|
||||
bool InitStmtIsExprStmt = false;
|
||||
if (InitStmt) {
|
||||
RevertingTentativeParsingAction PA(*this);
|
||||
SkipUntil(tok::r_paren, tok::semi, StopBeforeMatch);
|
||||
InitStmtIsExprStmt = Tok.is(tok::semi);
|
||||
}
|
||||
|
||||
ExprResult Expr; // expression
|
||||
{
|
||||
EnterExpressionEvaluationContext Consteval(
|
||||
Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated,
|
||||
/*LambdaContextDecl=*/nullptr,
|
||||
Sema::ExpressionEvaluationContextRecord::EK_Other,
|
||||
/*ShouldEnter=*/CK == Sema::ConditionKind::ConstexprIf &&
|
||||
!InitStmtIsExprStmt);
|
||||
SourceLocation OuterConstexprIfLoc = Actions.ConstexprIfLoc;
|
||||
Actions.ConstexprIfLoc = ConstexprLoc;
|
||||
|
||||
// Parse the expression.
|
||||
Expr = ParseExpression(); // expression
|
||||
Actions.ConstexprIfLoc = OuterConstexprIfLoc;
|
||||
}
|
||||
// Parse the expression.
|
||||
ExprResult Expr = ParseExpression(); // expression
|
||||
if (Expr.isInvalid())
|
||||
return Sema::ConditionError();
|
||||
|
||||
@ -2208,21 +2188,6 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
|
||||
if (CopyInitialization)
|
||||
ConsumeToken();
|
||||
|
||||
Sema::ExpressionEvaluationContext NewEEC =
|
||||
Actions.ExprEvalContexts.back().Context;
|
||||
bool RuntimeEvaluated = Actions.ExprEvalContexts.back().IsRuntimeEvaluated;
|
||||
if (DS.getTypeQualifiers() == DeclSpec::TQ_const)
|
||||
RuntimeEvaluated = false;
|
||||
|
||||
if (CK == Sema::ConditionKind::ConstexprIf || DS.hasConstexprSpecifier()) {
|
||||
RuntimeEvaluated = false;
|
||||
NewEEC = Sema::ExpressionEvaluationContext::ConstantEvaluated;
|
||||
}
|
||||
EnterExpressionEvaluationContext Initializer(Actions, NewEEC, DeclOut);
|
||||
Actions.ExprEvalContexts.back().IsRuntimeEvaluated = RuntimeEvaluated;
|
||||
SourceLocation OuterConstexprIfLoc = Actions.ConstexprIfLoc;
|
||||
Actions.ConstexprIfLoc = ConstexprLoc;
|
||||
|
||||
ExprResult InitExpr = ExprError();
|
||||
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
|
||||
Diag(Tok.getLocation(),
|
||||
@ -2249,7 +2214,6 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
|
||||
Actions.ActOnInitializerError(DeclOut);
|
||||
|
||||
Actions.FinalizeDeclaration(DeclOut);
|
||||
Actions.ConstexprIfLoc = OuterConstexprIfLoc;
|
||||
return Actions.ActOnConditionVariable(DeclOut, Loc, CK);
|
||||
}
|
||||
|
||||
|
@ -1293,17 +1293,18 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
|
||||
/// errors in the condition.
|
||||
/// Additionally, it will assign the location of the outer-most '(' and ')',
|
||||
/// to LParenLoc and RParenLoc, respectively.
|
||||
bool Parser::ParseParenExprOrCondition(
|
||||
StmtResult *InitStmt, Sema::ConditionResult &Cond, SourceLocation Loc,
|
||||
Sema::ConditionKind CK, SourceLocation &LParenLoc,
|
||||
SourceLocation &RParenLoc, SourceLocation ConstexprLoc) {
|
||||
bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt,
|
||||
Sema::ConditionResult &Cond,
|
||||
SourceLocation Loc,
|
||||
Sema::ConditionKind CK,
|
||||
SourceLocation &LParenLoc,
|
||||
SourceLocation &RParenLoc) {
|
||||
BalancedDelimiterTracker T(*this, tok::l_paren);
|
||||
T.consumeOpen();
|
||||
SourceLocation Start = Tok.getLocation();
|
||||
|
||||
if (getLangOpts().CPlusPlus) {
|
||||
Cond = ParseCXXCondition(InitStmt, Loc, CK, false, nullptr, false,
|
||||
ConstexprLoc);
|
||||
Cond = ParseCXXCondition(InitStmt, Loc, CK, false);
|
||||
} else {
|
||||
ExprResult CondExpr = ParseExpression();
|
||||
|
||||
@ -1463,13 +1464,12 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
|
||||
bool IsConsteval = false;
|
||||
SourceLocation NotLocation;
|
||||
SourceLocation ConstevalLoc;
|
||||
SourceLocation ConstexprLoc;
|
||||
|
||||
if (Tok.is(tok::kw_constexpr)) {
|
||||
Diag(Tok, getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_constexpr_if
|
||||
: diag::ext_constexpr_if);
|
||||
IsConstexpr = true;
|
||||
ConstexprLoc = ConsumeToken();
|
||||
ConsumeToken();
|
||||
} else {
|
||||
if (Tok.is(tok::exclaim)) {
|
||||
NotLocation = ConsumeToken();
|
||||
@ -1515,7 +1515,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
|
||||
if (ParseParenExprOrCondition(&InitStmt, Cond, IfLoc,
|
||||
IsConstexpr ? Sema::ConditionKind::ConstexprIf
|
||||
: Sema::ConditionKind::Boolean,
|
||||
LParen, RParen, ConstexprLoc))
|
||||
LParen, RParen))
|
||||
return StmtError();
|
||||
|
||||
if (IsConstexpr)
|
||||
@ -1558,16 +1558,11 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
|
||||
if (NotLocation.isInvalid() && IsConsteval) {
|
||||
Context = Sema::ExpressionEvaluationContext::ImmediateFunctionContext;
|
||||
ShouldEnter = true;
|
||||
} else if (NotLocation.isValid() && IsConsteval) {
|
||||
Context = Actions.ExprEvalContexts.back().Context;
|
||||
ShouldEnter = true;
|
||||
}
|
||||
|
||||
EnterExpressionEvaluationContext PotentiallyDiscarded(
|
||||
Actions, Context, nullptr,
|
||||
Sema::ExpressionEvaluationContextRecord::EK_Other, ShouldEnter);
|
||||
if (NotLocation.isValid() && IsConsteval)
|
||||
Actions.ExprEvalContexts.back().IsRuntimeEvaluated = true;
|
||||
ThenStmt = ParseStatement(&InnerStatementTrailingElseLoc);
|
||||
}
|
||||
|
||||
@ -1608,16 +1603,11 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
|
||||
if (NotLocation.isValid() && IsConsteval) {
|
||||
Context = Sema::ExpressionEvaluationContext::ImmediateFunctionContext;
|
||||
ShouldEnter = true;
|
||||
} else if (NotLocation.isInvalid() && IsConsteval) {
|
||||
Context = Actions.ExprEvalContexts.back().Context;
|
||||
ShouldEnter = true;
|
||||
}
|
||||
|
||||
EnterExpressionEvaluationContext PotentiallyDiscarded(
|
||||
Actions, Context, nullptr,
|
||||
Sema::ExpressionEvaluationContextRecord::EK_Other, ShouldEnter);
|
||||
if (NotLocation.isInvalid() && IsConsteval)
|
||||
Actions.ExprEvalContexts.back().IsRuntimeEvaluated = true;
|
||||
ElseStmt = ParseStatement();
|
||||
|
||||
if (ElseStmt.isUsable())
|
||||
|
@ -14836,8 +14836,7 @@ static void DiagnoseIntInBoolContext(Sema &S, Expr *E) {
|
||||
static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
|
||||
SourceLocation CC,
|
||||
bool *ICContext = nullptr,
|
||||
bool IsListInit = false,
|
||||
bool IsConstexprInit = false) {
|
||||
bool IsListInit = false) {
|
||||
if (E->isTypeDependent() || E->isValueDependent()) return;
|
||||
|
||||
const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr();
|
||||
@ -15146,14 +15145,11 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
|
||||
SmallString<32> PrettyTargetValue;
|
||||
TargetFloatValue.toString(PrettyTargetValue, TargetPrecision);
|
||||
|
||||
PartialDiagnostic PD =
|
||||
S.DiagRuntimeBehavior(
|
||||
E->getExprLoc(), E,
|
||||
S.PDiag(diag::warn_impcast_integer_float_precision_constant)
|
||||
<< PrettySourceValue << PrettyTargetValue << E->getType() << T
|
||||
<< E->getSourceRange() << clang::SourceRange(CC);
|
||||
if (IsConstexprInit)
|
||||
S.Diag(E->getExprLoc(), PD);
|
||||
else
|
||||
S.DiagRuntimeBehavior(E->getExprLoc(), E, PD);
|
||||
<< PrettySourceValue << PrettyTargetValue << E->getType() << T
|
||||
<< E->getSourceRange() << clang::SourceRange(CC));
|
||||
}
|
||||
} else {
|
||||
// Otherwise, the implicit conversion may lose precision.
|
||||
@ -15207,14 +15203,11 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
|
||||
std::string PrettySourceValue = toString(Value, 10);
|
||||
std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange);
|
||||
|
||||
PartialDiagnostic PD =
|
||||
S.DiagRuntimeBehavior(
|
||||
E->getExprLoc(), E,
|
||||
S.PDiag(diag::warn_impcast_integer_precision_constant)
|
||||
<< PrettySourceValue << PrettyTargetValue << E->getType() << T
|
||||
<< E->getSourceRange() << SourceRange(CC);
|
||||
if (IsConstexprInit)
|
||||
S.Diag(E->getExprLoc(), PD);
|
||||
else
|
||||
S.DiagRuntimeBehavior(E->getExprLoc(), E, PD);
|
||||
<< PrettySourceValue << PrettyTargetValue << E->getType() << T
|
||||
<< E->getSourceRange() << SourceRange(CC));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -15256,14 +15249,11 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
|
||||
std::string PrettySourceValue = toString(Value, 10);
|
||||
std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange);
|
||||
|
||||
PartialDiagnostic PD =
|
||||
S.DiagRuntimeBehavior(
|
||||
E->getExprLoc(), E,
|
||||
S.PDiag(diag::warn_impcast_integer_precision_constant)
|
||||
<< PrettySourceValue << PrettyTargetValue << E->getType() << T
|
||||
<< E->getSourceRange() << SourceRange(CC);
|
||||
if (IsConstexprInit)
|
||||
S.Diag(E->getExprLoc(), PD);
|
||||
else
|
||||
S.DiagRuntimeBehavior(E->getExprLoc(), E, PD);
|
||||
<< PrettySourceValue << PrettyTargetValue << E->getType() << T
|
||||
<< E->getSourceRange() << SourceRange(CC));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -15425,17 +15415,6 @@ static void AnalyzeImplicitConversions(
|
||||
if (auto *Src = OVE->getSourceExpr())
|
||||
SourceExpr = Src;
|
||||
|
||||
bool IsConstexprInit =
|
||||
S.isConstantEvaluated() &&
|
||||
isa_and_present<VarDecl>(S.ExprEvalContexts.back().ManglingContextDecl);
|
||||
// Constant-evaluated initializers are not diagnosed by DiagRuntimeBehavior,
|
||||
// but narrowings from the evaluated result to the variable type should be
|
||||
// diagnosed.
|
||||
if (IsConstexprInit && SourceExpr->getType() != T) {
|
||||
CheckImplicitConversion(S, SourceExpr, T, CC, nullptr, IsListInit,
|
||||
/*IsConstexprInit=*/true);
|
||||
}
|
||||
|
||||
if (const auto *UO = dyn_cast<UnaryOperator>(SourceExpr))
|
||||
if (UO->getOpcode() == UO_Not &&
|
||||
UO->getSubExpr()->isKnownToHaveBooleanValue())
|
||||
@ -15471,7 +15450,7 @@ static void AnalyzeImplicitConversions(
|
||||
// Go ahead and check any implicit conversions we might have skipped.
|
||||
// The non-canonical typecheck is just an optimization;
|
||||
// CheckImplicitConversion will filter out dead implicit conversions.
|
||||
if (!IsConstexprInit && SourceExpr->getType() != T)
|
||||
if (SourceExpr->getType() != T)
|
||||
CheckImplicitConversion(S, SourceExpr, T, CC, nullptr, IsListInit);
|
||||
|
||||
// Now continue drilling into this expression.
|
||||
|
@ -15443,7 +15443,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
|
||||
|
||||
// Do not push if it is a lambda because one is already pushed when building
|
||||
// the lambda in ActOnStartOfLambdaDefinition().
|
||||
if (!isLambdaCallOperator(FD)) {
|
||||
if (!isLambdaCallOperator(FD))
|
||||
// [expr.const]/p14.1
|
||||
// An expression or conversion is in an immediate function context if it is
|
||||
// potentially evaluated and either: its innermost enclosing non-block scope
|
||||
@ -15451,9 +15451,6 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
|
||||
PushExpressionEvaluationContext(
|
||||
FD->isConsteval() ? ExpressionEvaluationContext::ImmediateFunctionContext
|
||||
: ExprEvalContexts.back().Context);
|
||||
if (!FD->isConsteval() && !FD->isConstexpr())
|
||||
ExprEvalContexts.back().IsRuntimeEvaluated = true;
|
||||
}
|
||||
|
||||
// Each ExpressionEvaluationContextRecord also keeps track of whether the
|
||||
// context is nested in an immediate function context, so smaller contexts
|
||||
|
@ -18241,6 +18241,15 @@ void Sema::ActOnPureSpecifier(Decl *D, SourceLocation ZeroLoc) {
|
||||
Diag(D->getLocation(), diag::err_illegal_initializer);
|
||||
}
|
||||
|
||||
/// Determine whether the given declaration is a global variable or
|
||||
/// static data member.
|
||||
static bool isNonlocalVariable(const Decl *D) {
|
||||
if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(D))
|
||||
return Var->hasGlobalStorage();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Invoked when we are about to parse an initializer for the declaration
|
||||
/// 'Dcl'.
|
||||
///
|
||||
@ -18263,6 +18272,9 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
|
||||
// If we are parsing the initializer for a static data member, push a
|
||||
// new expression evaluation context that is associated with this static
|
||||
// data member.
|
||||
if (isNonlocalVariable(D))
|
||||
PushExpressionEvaluationContext(
|
||||
ExpressionEvaluationContext::PotentiallyEvaluated, D);
|
||||
}
|
||||
|
||||
/// Invoked after we are finished parsing an initializer for the declaration D.
|
||||
@ -18271,6 +18283,9 @@ void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) {
|
||||
if (!D || D->isInvalidDecl())
|
||||
return;
|
||||
|
||||
if (isNonlocalVariable(D))
|
||||
PopExpressionEvaluationContext();
|
||||
|
||||
if (S && D->isOutOfLine())
|
||||
ExitDeclaratorContext(S);
|
||||
}
|
||||
|
@ -7091,32 +7091,6 @@ static void DiagnosedUnqualifiedCallsToStdFunctions(Sema &S,
|
||||
<< FixItHint::CreateInsertion(DRE->getLocation(), "std::");
|
||||
}
|
||||
|
||||
// Diagnose uses of std::is_constant_evaluated or
|
||||
// __builtin_is_constant_evaluated in contexts where the result is known at
|
||||
// compile time.
|
||||
static void DiagnoseTautologicalCallToIsConstantEvaluated(Sema &S,
|
||||
const CallExpr *CE) {
|
||||
if (S.inTemplateInstantiation() || CE->getBeginLoc().isMacroID())
|
||||
return;
|
||||
if (const FunctionDecl *FD = CE->getDirectCallee()) {
|
||||
bool IsBuiltin =
|
||||
FD->getBuiltinID() == Builtin::BI__builtin_is_constant_evaluated;
|
||||
SourceLocation ConstexprIfLoc = S.ConstexprIfLoc;
|
||||
|
||||
if ((FD->isInStdNamespace() &&
|
||||
FD->getNameAsString() == "is_constant_evaluated") ||
|
||||
IsBuiltin) {
|
||||
bool AlwaysTrue = S.ExprEvalContexts.back().isConstantEvaluated() ||
|
||||
S.ExprEvalContexts.back().isUnevaluated();
|
||||
bool AlwaysFalse = S.ExprEvalContexts.back().IsRuntimeEvaluated;
|
||||
if (AlwaysTrue || AlwaysFalse)
|
||||
S.Diag(CE->getBeginLoc(), diag::warn_tautological_is_constant_evaluated)
|
||||
<< IsBuiltin << AlwaysTrue
|
||||
<< FixItHint::CreateRemoval(ConstexprIfLoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
|
||||
MultiExprArg ArgExprs, SourceLocation RParenLoc,
|
||||
Expr *ExecConfig) {
|
||||
@ -7141,10 +7115,8 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
|
||||
Call = ActOnOpenMPCall(Call, Scope, LParenLoc, ArgExprs, RParenLoc,
|
||||
ExecConfig);
|
||||
if (LangOpts.CPlusPlus) {
|
||||
if (const auto *CE = dyn_cast<CallExpr>(Call.get())) {
|
||||
if (const auto *CE = dyn_cast<CallExpr>(Call.get()))
|
||||
DiagnosedUnqualifiedCallsToStdFunctions(*this, CE);
|
||||
DiagnoseTautologicalCallToIsConstantEvaluated(*this, CE);
|
||||
}
|
||||
}
|
||||
return Call;
|
||||
}
|
||||
@ -18636,8 +18608,6 @@ void Sema::PopExpressionEvaluationContext() {
|
||||
} else
|
||||
llvm_unreachable("Couldn't infer lambda error message.");
|
||||
|
||||
if (auto *VD = dyn_cast_if_present<VarDecl>(Rec.ManglingContextDecl))
|
||||
VD->setInvalidDecl();
|
||||
for (const auto *L : Rec.Lambdas)
|
||||
Diag(L->getBeginLoc(), D);
|
||||
}
|
||||
|
@ -1444,13 +1444,12 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
||||
|
||||
// Enter a new evaluation context to insulate the lambda from any
|
||||
// cleanups from the enclosing full-expression.
|
||||
bool InImmediateFunctionContext = isImmediateFunctionContext();
|
||||
PushExpressionEvaluationContext(
|
||||
LSI->CallOperator->isConsteval() || InImmediateFunctionContext
|
||||
LSI->CallOperator->isConsteval()
|
||||
? ExpressionEvaluationContext::ImmediateFunctionContext
|
||||
: ExpressionEvaluationContext::PotentiallyEvaluated);
|
||||
ExprEvalContexts.back().InImmediateFunctionContext =
|
||||
LSI->CallOperator->isConsteval() || InImmediateFunctionContext;
|
||||
LSI->CallOperator->isConsteval();
|
||||
ExprEvalContexts.back().InImmediateEscalatingFunctionContext =
|
||||
getLangOpts().CPlusPlus20 && LSI->CallOperator->isImmediateEscalating();
|
||||
}
|
||||
|
@ -933,14 +933,16 @@ StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc,
|
||||
}
|
||||
|
||||
if (ConstevalOrNegatedConsteval) {
|
||||
bool AlwaysTrue = ExprEvalContexts.back().isConstantEvaluated() ||
|
||||
ExprEvalContexts.back().isUnevaluated();
|
||||
bool AlwaysFalse = ExprEvalContexts.back().IsRuntimeEvaluated;
|
||||
if (AlwaysTrue || AlwaysFalse)
|
||||
Diags.Report(IfLoc, diag::warn_tautological_consteval_if)
|
||||
<< (AlwaysTrue
|
||||
? StatementKind == IfStatementKind::ConstevalNegated
|
||||
: StatementKind == IfStatementKind::ConstevalNonNegated);
|
||||
bool Immediate = ExprEvalContexts.back().Context ==
|
||||
ExpressionEvaluationContext::ImmediateFunctionContext;
|
||||
if (CurContext->isFunctionOrMethod()) {
|
||||
const auto *FD =
|
||||
dyn_cast<FunctionDecl>(Decl::castFromDeclContext(CurContext));
|
||||
if (FD && FD->isImmediateFunction())
|
||||
Immediate = true;
|
||||
}
|
||||
if (isUnevaluatedContext() || Immediate)
|
||||
Diags.Report(IfLoc, diag::warn_consteval_if_always_true) << Immediate;
|
||||
}
|
||||
|
||||
return BuildIfStmt(IfLoc, StatementKind, LParenLoc, InitStmt, Cond, RParenLoc,
|
||||
|
@ -5378,11 +5378,8 @@ void Sema::InstantiateVariableInitializer(
|
||||
Var->setImplicitlyInline();
|
||||
|
||||
if (OldVar->getInit()) {
|
||||
Sema::ExpressionEvaluationContext InitEvalContext =
|
||||
Var->isConstexpr()
|
||||
? Sema::ExpressionEvaluationContext::ConstantEvaluated
|
||||
: Sema::ExpressionEvaluationContext::PotentiallyEvaluated;
|
||||
EnterExpressionEvaluationContext Evaluated(*this, InitEvalContext, Var);
|
||||
EnterExpressionEvaluationContext Evaluated(
|
||||
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var);
|
||||
|
||||
// Instantiate the initializer.
|
||||
ExprResult Init;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter %s -Wno-constant-evaluated -verify
|
||||
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter %s -Wno-constant-evaluated -S -emit-llvm -o - | FileCheck %s
|
||||
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter %s -verify
|
||||
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter %s -S -emit-llvm -o - | FileCheck %s
|
||||
// RUN: %clang_cc1 -verify=ref %s -Wno-constant-evaluated
|
||||
// RUN: %clang_cc1 -verify=ref %s -Wno-constant-evaluated %s -S -emit-llvm -o - | FileCheck %s
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -fexperimental-new-constant-interpreter -Wno-redundant-consteval-if %s -verify
|
||||
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -Wno-redundant-consteval-if %s -verify=ref
|
||||
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -fexperimental-new-constant-interpreter %s -verify
|
||||
// RUN: %clang_cc1 -std=c++23 -fsyntax-only %s -verify=ref
|
||||
|
||||
// expected-no-diagnostics
|
||||
// ref-no-diagnostics
|
||||
|
@ -225,11 +225,15 @@ namespace SizeOf {
|
||||
#if __cplusplus >= 202002L
|
||||
/// FIXME: The following code should be accepted.
|
||||
consteval int foo(int n) { // ref-error {{consteval function never produces a constant expression}}
|
||||
return sizeof(int[n]); // ref-note 2 {{not valid in a constant expression}}
|
||||
return sizeof(int[n]); // ref-note 3{{not valid in a constant expression}} \
|
||||
// expected-note {{not valid in a constant expression}}
|
||||
}
|
||||
constinit int var = foo(5); // ref-note {{in call to}} \
|
||||
constinit int var = foo(5); // ref-error {{not a constant expression}} \
|
||||
// ref-note 2{{in call to}} \
|
||||
// ref-error {{does not have a constant initializer}} \
|
||||
// ref-note {{required by 'constinit' specifier}} \
|
||||
// expected-error {{is not a constant expression}} \
|
||||
// expected-note {{in call to}} \
|
||||
// expected-error {{does not have a constant initializer}} \
|
||||
// expected-note {{required by 'constinit' specifier}} \
|
||||
|
||||
|
@ -244,8 +244,8 @@ namespace UndefinedBehavior {
|
||||
constexpr int n13 = n5 + n5; // expected-error {{constant expression}} expected-note {{value -4294967296 is outside the range of }}
|
||||
constexpr int n14 = n3 - n5; // expected-error {{constant expression}} expected-note {{value 4294967295 is outside the range of }}
|
||||
constexpr int n15 = n5 * n5; // expected-error {{constant expression}} expected-note {{value 4611686018427387904 is outside the range of }}
|
||||
constexpr signed char c1 = 100 * 2; // ok expected-warning {{changes value from 200 to -56}}
|
||||
constexpr signed char c2 = '\x64' * '\2'; // also ok expected-warning {{changes value from 200 to -56}}
|
||||
constexpr signed char c1 = 100 * 2; // ok expected-warning{{changes value}}
|
||||
constexpr signed char c2 = '\x64' * '\2'; // also ok expected-warning{{changes value}}
|
||||
constexpr long long ll1 = 0x7fffffffffffffff; // ok
|
||||
constexpr long long ll2 = ll1 + 1; // expected-error {{constant}} expected-note {{ 9223372036854775808 }}
|
||||
constexpr long long ll3 = -ll1 - 1; // ok
|
||||
|
@ -43,11 +43,12 @@ struct Temporary {
|
||||
constexpr Temporary t = {3}; // expected-error {{must have constant destruction}} expected-note {{created here}} expected-note {{in call}}
|
||||
|
||||
namespace P1073R3 {
|
||||
consteval int f() { return 42; } // expected-note {{declared here}}
|
||||
consteval int f() { return 42; } // expected-note 2 {{declared here}}
|
||||
consteval auto g() { return f; }
|
||||
consteval int h(int (*p)() = g()) { return p(); }
|
||||
constexpr int r = h();
|
||||
constexpr auto e = g(); // expected-error {{constexpr variable 'e' must be initialized by a constant expression}} \
|
||||
expected-note {{pointer to a consteval declaration is not a constant expression}}
|
||||
constexpr auto e = g(); // expected-error {{call to consteval function 'P1073R3::g' is not a constant expression}} \
|
||||
expected-error {{constexpr variable 'e' must be initialized by a constant expression}} \
|
||||
expected-note 2 {{pointer to a consteval declaration is not a constant expression}}
|
||||
static_assert(r == 42);
|
||||
} // namespace P1073R3
|
||||
|
@ -16,5 +16,4 @@ constexpr auto literal = []{};
|
||||
#if __cplusplus < 201703L
|
||||
// expected-error@-2 {{constexpr variable cannot have non-literal type}}
|
||||
// expected-note@-3 {{lambda closure types are non-literal types before C++17}}
|
||||
// expected-error@-4 {{a lambda expression may not appear inside of a constant expression}}
|
||||
#endif
|
||||
|
@ -38,8 +38,7 @@ void test_consteval() {
|
||||
}() == 1);
|
||||
|
||||
if consteval [[likely]] { // expected-warning {{attribute 'likely' has no effect when annotating an 'if consteval' statement}}\
|
||||
// expected-note 2{{annotating the 'if consteval' statement here}} \
|
||||
// expected-warning {{consteval if is always false}}
|
||||
// expected-note 2{{annotating the 'if consteval' statement here}}
|
||||
|
||||
|
||||
}
|
||||
@ -50,8 +49,7 @@ void test_consteval() {
|
||||
}
|
||||
|
||||
void test_consteval_jumps() {
|
||||
if consteval { // expected-warning {{consteval if is always false}} \
|
||||
// expected-note 4{{jump enters controlled statement of consteval if}}
|
||||
if consteval { // expected-note 4{{jump enters controlled statement of consteval if}}
|
||||
goto a;
|
||||
goto b; // expected-error {{cannot jump from this goto statement to its label}}
|
||||
a:;
|
||||
@ -67,16 +65,14 @@ void test_consteval_jumps() {
|
||||
void test_consteval_switch() {
|
||||
int x = 42;
|
||||
switch (x) {
|
||||
if consteval { // expected-warning {{consteval if is always false}} \
|
||||
// expected-note 2{{jump enters controlled statement of consteval if}}
|
||||
if consteval { // expected-note 2{{jump enters controlled statement of consteval if}}
|
||||
case 1:; // expected-error {{cannot jump from switch statement to this case label}}
|
||||
default:; // expected-error {{cannot jump from switch statement to this case label}}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
switch (x) {
|
||||
if consteval { // expected-warning {{consteval if is always false}} \
|
||||
// expected-note 2{{jump enters controlled statement of consteval if}}
|
||||
if consteval { // expected-note 2{{jump enters controlled statement of consteval if}}
|
||||
} else {
|
||||
case 2:; // expected-error {{cannot jump from switch statement to this case label}}
|
||||
default:; // expected-error {{cannot jump from switch statement to this case label}}
|
||||
@ -103,32 +99,32 @@ constexpr int h(int i) { // expected-note {{declared here}}
|
||||
}
|
||||
|
||||
consteval void warn_in_consteval() {
|
||||
if consteval { // expected-warning {{consteval if is always true in this context}}
|
||||
if consteval {} // expected-warning {{consteval if is always true in this context}}
|
||||
if consteval { // expected-warning {{consteval if is always true in an immediate context}}
|
||||
if consteval {} // expected-warning {{consteval if is always true in an immediate context}}
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void warn_in_consteval2() {
|
||||
if consteval {
|
||||
if consteval {} // expected-warning {{consteval if is always true in this context}}
|
||||
if consteval {} // expected-warning {{consteval if is always true in an immediate context}}
|
||||
}
|
||||
}
|
||||
|
||||
auto y = []() consteval {
|
||||
if consteval { // expected-warning {{consteval if is always true in this context}}
|
||||
if consteval {} // expected-warning {{consteval if is always true in this context}}
|
||||
if consteval { // expected-warning {{consteval if is always true in an immediate context}}
|
||||
if consteval {} // expected-warning {{consteval if is always true in an immediate context}}
|
||||
}
|
||||
};
|
||||
|
||||
namespace test_transform {
|
||||
int f(auto n) {
|
||||
if consteval { // expected-warning {{consteval if is always false}}
|
||||
if consteval {
|
||||
n.foo; //expected-error {{no member named}}
|
||||
}
|
||||
else {
|
||||
}
|
||||
|
||||
if !consteval { // expected-warning {{consteval if is always true}}
|
||||
if !consteval {
|
||||
n.foo; //expected-error {{no member named}}
|
||||
}
|
||||
else {
|
||||
|
@ -33,7 +33,7 @@ int main(void) {
|
||||
CONST float fnot_too_big = not_too_big;
|
||||
CONST int too_big = 0x7ffffff0;
|
||||
#if defined(CPP)
|
||||
//expected-warning@+2{{implicit conversion from 'const int' to 'const float' changes value from 2147483632 to 2147483648}}
|
||||
//expected-warning@+2{{implicit conversion}}
|
||||
#endif
|
||||
CONST float fbig = too_big; // inexact
|
||||
#if !defined(CPP)
|
||||
|
@ -1,4 +1,4 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify -triple x86_64-apple-darwin %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-apple-darwin %s
|
||||
|
||||
// This file tests -Wconstant-conversion, a subcategory of -Wconversion
|
||||
// which is on by default.
|
||||
@ -31,59 +31,3 @@ void test_bitfield() {
|
||||
s.one_bit = 1; // expected-warning {{implicit truncation from 'int' to a one-bit wide bit-field changes value from 1 to -1}}
|
||||
s.one_bit = true; // no-warning
|
||||
}
|
||||
|
||||
namespace Initializers {
|
||||
constexpr char ok = true ? 0 : 200;
|
||||
constexpr char a = 200; // expected-warning {{implicit conversion from 'int' to 'const char' changes value from 200 to -56}}
|
||||
char b = 200; // expected-warning {{implicit conversion from 'int' to 'char' changes value from 200 to -56}}
|
||||
const char c = 200; // expected-warning {{implicit conversion from 'int' to 'const char' changes value from 200 to -56}}
|
||||
|
||||
void f() {
|
||||
constexpr char a = 200; // expected-warning {{implicit conversion from 'int' to 'const char' changes value from 200 to -56}}
|
||||
char b = 200; // expected-warning {{implicit conversion from 'int' to 'char' changes value from 200 to -56}}
|
||||
const char c = 200; // expected-warning {{implicit conversion from 'int' to 'const char' changes value from 200 to -56}}
|
||||
static char d = 2 * 100; // expected-warning {{implicit conversion from 'int' to 'char' changes value from 200 to -56}}
|
||||
}
|
||||
|
||||
constexpr void g() {
|
||||
constexpr char a = 2 * 100; // expected-warning {{implicit conversion from 'int' to 'const char' changes value from 200 to -56}}
|
||||
char b = 2 * 100; // expected-warning {{implicit conversion from 'int' to 'char' changes value from 200 to -56}}
|
||||
const char c = 2 * 100; // expected-warning {{implicit conversion from 'int' to 'const char' changes value from 200 to -56}}
|
||||
}
|
||||
|
||||
consteval void h() {
|
||||
char ok = true ? 0 : 200;
|
||||
constexpr char a = 200; // expected-warning {{implicit conversion from 'int' to 'const char' changes value from 200 to -56}}
|
||||
char b = 200; // expected-warning {{implicit conversion from 'int' to 'char' changes value from 200 to -56}}
|
||||
const char c = 200; // expected-warning {{implicit conversion from 'int' to 'const char' changes value from 200 to -56}}
|
||||
}
|
||||
|
||||
template <int N>
|
||||
int templ() {
|
||||
constexpr char a = false ? 129 : N; // expected-warning {{implicit conversion from 'int' to 'const char' changes value from 200 to -56}} \
|
||||
// expected-warning {{implicit conversion from 'int' to 'const char' changes value from 345 to 89}}
|
||||
return 3;
|
||||
}
|
||||
|
||||
void call_templ() {
|
||||
int ok = templ<127>();
|
||||
int l = templ<3>();
|
||||
int m = templ<200>(); // expected-note {{in instantiation of}}
|
||||
int n = templ<345>(); // expected-note {{in instantiation of}}
|
||||
}
|
||||
|
||||
template <int a, int b>
|
||||
constexpr signed char diff = a > b ? a - b : b - a; // expected-warning{{changes value from 201 to -55}} \
|
||||
// expected-warning{{changes value from 199 to -57}} \
|
||||
// expected-warning{{changes value from 299 to 43}} \
|
||||
// expected-warning{{changes value from 301 to 45}}
|
||||
|
||||
void test_diff() {
|
||||
char ok1 = diff<201, 100>;
|
||||
char ok2 = diff<101, 200>;
|
||||
char s1 = diff<301, 100>; // expected-note {{in instantiation of}}
|
||||
char s2 = diff<101, 300>; // expected-note {{in instantiation of}}
|
||||
char w1 = diff<101, 400>; // expected-note {{in instantiation of}}
|
||||
char w2 = diff<401, 100>; // expected-note {{in instantiation of}}
|
||||
}
|
||||
}
|
||||
|
@ -1961,7 +1961,7 @@ namespace ConstexprConstructorRecovery {
|
||||
|
||||
namespace Lifetime {
|
||||
void f() {
|
||||
constexpr int &n = n; // expected-error {{constant expression}} expected-note {{use of reference outside its lifetime}}
|
||||
constexpr int &n = n; // expected-error {{constant expression}} expected-note {{use of reference outside its lifetime}} expected-warning {{not yet bound to a value}}
|
||||
constexpr int m = m; // expected-error {{constant expression}} expected-note {{read of object outside its lifetime}}
|
||||
}
|
||||
|
||||
|
@ -713,7 +713,7 @@ constexpr derp d;
|
||||
struct test {
|
||||
consteval int operator[](int i) const { return {}; }
|
||||
consteval const derp * operator->() const { return &d; }
|
||||
consteval int f() const { return 12; } // expected-note {{declared here}}
|
||||
consteval int f() const { return 12; } // expected-note 2{{declared here}}
|
||||
};
|
||||
|
||||
constexpr test a;
|
||||
@ -726,7 +726,8 @@ constexpr int s = a.operator[](1);
|
||||
constexpr int t = a[1];
|
||||
constexpr int u = a.operator->()->b;
|
||||
constexpr int v = a->b;
|
||||
constexpr int w = (a.*&test::f)();
|
||||
// FIXME: I believe this case should work, but we currently reject.
|
||||
constexpr int w = (a.*&test::f)(); // expected-error {{cannot take address of consteval function 'f' outside of an immediate invocation}}
|
||||
constexpr int x = a.f();
|
||||
|
||||
// Show that we reject when not in an immediate context.
|
||||
@ -1072,17 +1073,18 @@ struct tester {
|
||||
consteval const char* make_name(const char* name) { return name;}
|
||||
consteval const char* pad(int P) { return "thestring"; }
|
||||
|
||||
int bad = 10; // expected-note 5{{declared here}}
|
||||
int bad = 10; // expected-note 6{{declared here}}
|
||||
|
||||
tester glob1(make_name("glob1"));
|
||||
tester glob2(make_name("glob2"));
|
||||
constexpr tester cglob(make_name("cglob"));
|
||||
tester paddedglob(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::tester::tester' is not a constant expression}} \
|
||||
tester paddedglob(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::make_name' is not a constant expression}} \
|
||||
// expected-note {{read of non-const variable 'bad' is not allowed in a constant expression}}
|
||||
|
||||
constexpr tester glob3 = { make_name("glob3") };
|
||||
constexpr tester glob4 = { make_name(pad(bad)) }; // expected-error {{constexpr variable 'glob4' must be initialized by a constant expression}} \
|
||||
// expected-note {{read of non-const variable 'bad' is not allowed in a constant expression}}
|
||||
constexpr tester glob4 = { make_name(pad(bad)) }; // expected-error {{call to consteval function 'GH58207::make_name' is not a constant expression}} \
|
||||
// expected-error {{constexpr variable 'glob4' must be initialized by a constant expression}} \
|
||||
// expected-note 2{{read of non-const variable 'bad' is not allowed in a constant expression}}
|
||||
|
||||
auto V = make_name(pad(3));
|
||||
auto V1 = make_name(pad(bad)); // expected-error {{call to consteval function 'GH58207::make_name' is not a constant expression}} \
|
||||
@ -1092,12 +1094,12 @@ auto V1 = make_name(pad(bad)); // expected-error {{call to consteval function 'G
|
||||
void foo() {
|
||||
static tester loc1(make_name("loc1"));
|
||||
static constexpr tester loc2(make_name("loc2"));
|
||||
static tester paddedloc(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::tester::tester' is not a constant expression}} \
|
||||
static tester paddedloc(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::make_name' is not a constant expression}} \
|
||||
// expected-note {{read of non-const variable 'bad' is not allowed in a constant expression}}
|
||||
}
|
||||
|
||||
void bar() {
|
||||
static tester paddedloc(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::tester::tester' is not a constant expression}} \
|
||||
static tester paddedloc(make_name(pad(bad))); // expected-error {{call to consteval function 'GH58207::make_name' is not a constant expression}} \
|
||||
// expected-note {{read of non-const variable 'bad' is not allowed in a constant expression}}
|
||||
}
|
||||
}
|
||||
@ -1131,7 +1133,7 @@ namespace GH65985 {
|
||||
int consteval operator""_foo(unsigned long long V) {
|
||||
return 0;
|
||||
}
|
||||
int consteval operator""_bar(unsigned long long V); // expected-note 2{{here}}
|
||||
int consteval operator""_bar(unsigned long long V); // expected-note 3{{here}}
|
||||
|
||||
int consteval f() {
|
||||
return 0;
|
||||
@ -1147,7 +1149,10 @@ struct C {
|
||||
// expected-note {{undefined function 'operator""_bar' cannot be used in a constant expression}} \
|
||||
// expected-error {{in-class initializer for static data member is not a constant expression}}
|
||||
|
||||
static constexpr int d = 1_bar; // expected-error {{constexpr variable 'd' must be initialized by a constant expression}} \
|
||||
// FIXME: remove duplicate diagnostics
|
||||
static constexpr int d = 1_bar; // expected-error {{call to consteval function 'GH65985::operator""_bar' is not a constant expression}} \
|
||||
// expected-note {{undefined function 'operator""_bar' cannot be used in a constant expression}} \
|
||||
// expected-error {{constexpr variable 'd' must be initialized by a constant expression}} \
|
||||
// expected-note {{undefined function 'operator""_bar' cannot be used in a constant expression}}
|
||||
|
||||
static const int e = f();
|
||||
@ -1162,12 +1167,12 @@ namespace GH66562 {
|
||||
|
||||
namespace ns
|
||||
{
|
||||
consteval int foo(int x) { return 1; }
|
||||
consteval int foo(int x) { return 1; } // expected-note {{declared here}}
|
||||
}
|
||||
|
||||
template <class A>
|
||||
struct T {
|
||||
static constexpr auto xx = ns::foo(A{});
|
||||
static constexpr auto xx = ns::foo(A{}); // expected-error {{cannot take address of consteval function 'foo' outside of an immediate invocation}}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ constexpr auto h() {
|
||||
|
||||
constexpr auto i() {
|
||||
if consteval {
|
||||
if consteval { // expected-warning {{consteval if is always true in this context}}
|
||||
if consteval { // expected-warning {{consteval if is always true in an immediate context}}
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
|
@ -209,7 +209,7 @@ struct SS {
|
||||
SS::SS(){} // expected-note {{in the default initializer of 'x'}}
|
||||
|
||||
consteval int f2(int x) {
|
||||
if (!__builtin_is_constant_evaluated()) side_effect(); // expected-warning {{'__builtin_is_constant_evaluated' will always evaluate to true}}
|
||||
if (!__builtin_is_constant_evaluated()) side_effect();
|
||||
return x;
|
||||
}
|
||||
struct S2 {
|
||||
@ -332,14 +332,16 @@ S s(0); // expected-note {{in the default initializer of 'j'}}
|
||||
}
|
||||
|
||||
namespace GH65985 {
|
||||
consteval int invalid(); // expected-note {{declared here}}
|
||||
consteval int invalid(); // expected-note 2{{declared here}}
|
||||
constexpr int escalating(auto) {
|
||||
return invalid();
|
||||
// expected-note@-1 {{undefined function 'invalid' cannot be used in a constant expression}}
|
||||
// expected-note@-1 {{'escalating<int>' is an immediate function because its body contains a call to a consteval function 'invalid' and that call is not a constant expression}}
|
||||
// expected-note@-2 2{{undefined function 'invalid' cannot be used in a constant expression}}
|
||||
}
|
||||
struct S {
|
||||
static constexpr int a = escalating(0); // expected-note {{in call to}}
|
||||
// expected-error@-1 {{constexpr variable 'a' must be initialized by a constant expression}}
|
||||
static constexpr int a = escalating(0); // expected-note 2{{in call to}}
|
||||
// expected-error@-1 {{call to immediate function 'GH65985::escalating<int>' is not a constant expression}}
|
||||
// expected-error@-2 {{constexpr variable 'a' must be initialized by a constant expression}}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
// RUN: %clang_cc1 -std=c++2b -Wno-unused-value -fdiagnostics-parseable-fixits -fsyntax-only %s 2>&1 | FileCheck %s
|
||||
namespace std {
|
||||
constexpr inline bool
|
||||
is_constant_evaluated() noexcept {
|
||||
if consteval { return true; } else { return false; }
|
||||
}
|
||||
} // namespace std
|
||||
|
||||
constexpr void cexpr() {
|
||||
if constexpr (std::is_constant_evaluated()) {}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:6-[[@LINE-1]]:16}:""
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:6-[[@LINE-2]]:16}:""
|
||||
constexpr int a = std::is_constant_evaluated();
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:{{.*}}-[[@LINE-1]]:{{.*}}}:""
|
||||
|
||||
if constexpr (const int ce = __builtin_is_constant_evaluated()) {}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:6-[[@LINE-1]]:16}:""
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:6-[[@LINE-2]]:16}:""
|
||||
constexpr int b = std::is_constant_evaluated();
|
||||
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:{{.*}}-[[@LINE-1]]:{{.*}}}:""
|
||||
}
|
@ -12,7 +12,7 @@ template<typename T> auto v1 = [](int a = T()) { return a; }();
|
||||
|
||||
struct S {
|
||||
template<class T>
|
||||
static constexpr T t = [](int f = T(7)){return f;}(); // expected-error{{a lambda expression may not appear inside of a constant expression}}
|
||||
static constexpr T t = [](int f = T(7)){return f;}(); // expected-error{{constexpr variable 't<int>' must be initialized by a constant expression}} expected-note{{cannot be used in a constant expression}}
|
||||
};
|
||||
|
||||
template <typename X>
|
||||
@ -21,7 +21,7 @@ int foo2() {
|
||||
fn1<char>(a);
|
||||
(void)v1<int>;
|
||||
(void)v1<int *>; // expected-note{{in instantiation of variable template specialization 'v1' requested here}}
|
||||
(void)S::t<int>;
|
||||
(void)S::t<int>; // expected-note{{in instantiation of static data member 'S::t<int>' requested here}}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -7,35 +7,35 @@ constexpr bool is_constant_evaluated() noexcept {
|
||||
} // namespace std
|
||||
|
||||
constexpr int fn1() {
|
||||
if constexpr (std::is_constant_evaluated()) // expected-warning {{'std::is_constant_evaluated' will always evaluate to true in this context}}
|
||||
if constexpr (std::is_constant_evaluated()) // expected-warning {{'std::is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}}
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
constexpr int fn2() {
|
||||
if constexpr (!std::is_constant_evaluated()) // expected-warning {{'std::is_constant_evaluated' will always evaluate to true in this context}}
|
||||
if constexpr (!std::is_constant_evaluated()) // expected-warning {{'std::is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}}
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
constexpr int fn3() {
|
||||
if constexpr (std::is_constant_evaluated() == false) // expected-warning {{'std::is_constant_evaluated' will always evaluate to true in this context}}
|
||||
if constexpr (std::is_constant_evaluated() == false) // expected-warning {{'std::is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}}
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
constexpr int fn4() {
|
||||
if constexpr (__builtin_is_constant_evaluated() == true) // expected-warning {{'__builtin_is_constant_evaluated' will always evaluate to true in this context}}
|
||||
if constexpr (__builtin_is_constant_evaluated() == true) // expected-warning {{'__builtin_is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}}
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
constexpr int fn5() {
|
||||
if constexpr (__builtin_is_constant_evaluated()) // expected-warning {{'__builtin_is_constant_evaluated' will always evaluate to true in this context}}
|
||||
if constexpr (__builtin_is_constant_evaluated()) // expected-warning {{'__builtin_is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}}
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
|
@ -1,262 +0,0 @@
|
||||
// RUN: %clang_cc1 -std=c++2b -Wno-unused-value -fsyntax-only -verify %s
|
||||
|
||||
namespace std {
|
||||
constexpr inline bool
|
||||
is_constant_evaluated() noexcept {
|
||||
if consteval { return true; } else { return false; }
|
||||
}
|
||||
} // namespace std
|
||||
|
||||
namespace P1938 {
|
||||
constexpr int f1() {
|
||||
if constexpr (!std::is_constant_evaluated() && sizeof(int) == 4) { // expected-warning {{always evaluate to true}}
|
||||
return 0;
|
||||
}
|
||||
if (std::is_constant_evaluated()) {
|
||||
return 42;
|
||||
} else {
|
||||
if constexpr (std::is_constant_evaluated()) { // expected-warning {{always evaluate to true}}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 7;
|
||||
}
|
||||
|
||||
|
||||
consteval int f2() {
|
||||
if (std::is_constant_evaluated() && f1()) { // expected-warning {{always evaluate to true}}
|
||||
return 42;
|
||||
}
|
||||
return 7;
|
||||
}
|
||||
|
||||
|
||||
int f3() {
|
||||
if (std::is_constant_evaluated() && f1()) { // expected-warning {{always evaluate to false}}
|
||||
return 42;
|
||||
}
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
|
||||
void non_qual() {
|
||||
int ff = std::is_constant_evaluated(); // expected-warning {{always evaluate to false}}
|
||||
const int aa = std::is_constant_evaluated();
|
||||
constexpr int tt = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
static int bb = std::is_constant_evaluated();
|
||||
constexpr int cc = [](){
|
||||
if consteval {return 8;}
|
||||
}();
|
||||
auto lamda = []() {
|
||||
if consteval {return 8;}
|
||||
else {return 4;}
|
||||
};
|
||||
constexpr auto cexpr_lambda = []() {
|
||||
if consteval {}
|
||||
return __builtin_is_constant_evaluated();
|
||||
};
|
||||
auto lamda_const = []() consteval {
|
||||
if consteval {return 8;} // expected-warning {{always true}}
|
||||
else {return 4;}
|
||||
};
|
||||
if consteval { // expected-warning {{always false}}
|
||||
int b = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void in_constexpr() {
|
||||
int aa = std::is_constant_evaluated();
|
||||
constexpr int bb = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
const int cc = std::is_constant_evaluated();
|
||||
if consteval {
|
||||
int dd = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
constexpr int ee = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
const int ff = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
} else {
|
||||
int dd = std::is_constant_evaluated(); // expected-warning {{always evaluate to false}}
|
||||
constexpr int ee = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
const int ff = std::is_constant_evaluated();
|
||||
const int qq = std::is_constant_evaluated() ? dd : 3;
|
||||
}
|
||||
|
||||
if consteval {
|
||||
if consteval {} // expected-warning {{always true}}
|
||||
if !consteval {} // expected-warning {{always false}}
|
||||
} else {
|
||||
if consteval {} // expected-warning {{always false}}
|
||||
if !consteval {} // expected-warning {{always true}}
|
||||
}
|
||||
if !consteval {
|
||||
if consteval {} // expected-warning {{always false}}
|
||||
if !consteval {} // expected-warning {{always true}}
|
||||
} else {
|
||||
if consteval {} // expected-warning {{always true}}
|
||||
if !consteval {} // expected-warning {{always false}}
|
||||
}
|
||||
}
|
||||
|
||||
consteval void in_consteval() {
|
||||
int aa = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
constexpr int bb = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
const int cc = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
auto lambda = []() {
|
||||
int a(std::is_constant_evaluated()); // expected-warning {{always evaluate to true}}
|
||||
constexpr int b = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
const int c = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
};
|
||||
if !consteval {} // expected-warning {{always false}}
|
||||
}
|
||||
|
||||
static_assert(std::is_constant_evaluated()); // expected-warning {{always evaluate to true}}
|
||||
static_assert(__builtin_is_constant_evaluated()); // expected-warning {{always evaluate to true}}
|
||||
|
||||
template <bool b>
|
||||
void templ() {
|
||||
if constexpr(std::is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
|
||||
constexpr bool c = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
if consteval {} // expected-warning {{always false}}
|
||||
}
|
||||
|
||||
template <> void templ<std::is_constant_evaluated()>() { // expected-warning {{always evaluate to true}}
|
||||
if constexpr(std::is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
|
||||
constexpr bool c = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
if consteval {} // expected-warning {{always false}}
|
||||
templ<false>();
|
||||
}
|
||||
|
||||
static_assert([] {
|
||||
if consteval {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}() == 0);
|
||||
constexpr bool b = __builtin_is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
constexpr bool c = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
constinit bool d = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
int p = __builtin_is_constant_evaluated();
|
||||
const int q = __builtin_is_constant_evaluated();
|
||||
|
||||
template <bool c = std::is_constant_evaluated()> // expected-warning {{always evaluate to true}}
|
||||
void vvv() {
|
||||
return;
|
||||
}
|
||||
|
||||
template<> void vvv<true>() {}
|
||||
template<> void vvv<false>() {}
|
||||
|
||||
template<typename T> concept C = __builtin_is_constant_evaluated();// expected-warning {{always evaluate to true}}
|
||||
|
||||
struct Foo {
|
||||
static constexpr bool ce = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
const static bool nonce = std::is_constant_evaluated();
|
||||
bool b = std::is_constant_evaluated();
|
||||
|
||||
Foo() {
|
||||
if constexpr(std::is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
|
||||
bool aa = std::is_constant_evaluated(); // expected-warning {{always evaluate to false}}
|
||||
static bool bb = std::is_constant_evaluated();
|
||||
constexpr bool cc = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
if consteval {} // expected-warning {{always false}}
|
||||
}
|
||||
constexpr Foo(int) {
|
||||
if constexpr(std::is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
|
||||
bool aa = std::is_constant_evaluated();
|
||||
static bool bb = std::is_constant_evaluated();
|
||||
constexpr bool cc = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
}
|
||||
consteval Foo(int *) {
|
||||
if constexpr(std::is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
|
||||
bool aa = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
static bool bb = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
constexpr bool cc = std::is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
}
|
||||
};
|
||||
|
||||
namespace condition {
|
||||
void f() {
|
||||
if constexpr (int a = __builtin_is_constant_evaluated(); // expected-warning {{always evaluate to false}}
|
||||
true) {}
|
||||
if constexpr (const int a = __builtin_is_constant_evaluated();
|
||||
true) {}
|
||||
if constexpr (constexpr int a = __builtin_is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
true) {}
|
||||
if constexpr (;const int b = __builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
|
||||
if constexpr (;constexpr int b = __builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
|
||||
|
||||
if (int a = __builtin_is_constant_evaluated(); // expected-warning {{always evaluate to false}}
|
||||
true) {}
|
||||
if (const int a = __builtin_is_constant_evaluated();
|
||||
true) {}
|
||||
if (constexpr int a = __builtin_is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
true) {}
|
||||
if (;int b = __builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to false}}
|
||||
if (;const int b = __builtin_is_constant_evaluated()) {}
|
||||
if (;constexpr int b = __builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
|
||||
|
||||
if constexpr (__builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
|
||||
if (__builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to false}}
|
||||
|
||||
if constexpr (__builtin_is_constant_evaluated(); true) {} // expected-warning {{always evaluate to false}}
|
||||
// False
|
||||
if constexpr (({__builtin_is_constant_evaluated();2;3;}); true) {}
|
||||
|
||||
if (__builtin_is_constant_evaluated(); true) {} // expected-warning {{always evaluate to false}}
|
||||
if constexpr (;__builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
|
||||
if (;__builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to false}}
|
||||
}
|
||||
|
||||
constexpr void g() {
|
||||
if constexpr (int a = __builtin_is_constant_evaluated();
|
||||
true) {}
|
||||
if constexpr (const int a = __builtin_is_constant_evaluated();
|
||||
true) {}
|
||||
if constexpr (constexpr int a = __builtin_is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
true) {}
|
||||
if constexpr (;const int b = __builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
|
||||
if constexpr (;constexpr int b = __builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
|
||||
|
||||
if (int a = __builtin_is_constant_evaluated();
|
||||
true) {}
|
||||
if (const int a = __builtin_is_constant_evaluated();
|
||||
true) {}
|
||||
if (constexpr int a = __builtin_is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
true) {}
|
||||
if (;int b = __builtin_is_constant_evaluated()) {}
|
||||
if (;const int b = __builtin_is_constant_evaluated()) {}
|
||||
if (;constexpr int b = __builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
|
||||
|
||||
if constexpr (__builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
|
||||
if (__builtin_is_constant_evaluated()) {}
|
||||
|
||||
if constexpr (__builtin_is_constant_evaluated(); true) {}
|
||||
if constexpr (({__builtin_is_constant_evaluated();2;3;}); true) {}
|
||||
|
||||
if (__builtin_is_constant_evaluated(); true) {}
|
||||
if constexpr (;__builtin_is_constant_evaluated()) {} // expected-warning {{always evaluate to true}}
|
||||
if (;__builtin_is_constant_evaluated()) {}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Arguments {
|
||||
int nonc(int n) { return n;}
|
||||
constexpr int cexpr(int n) { return n;}
|
||||
consteval int ceval(int n) { return n; }
|
||||
void f() {
|
||||
// FIXME: These are tauologically-false;
|
||||
int a1 = nonc(__builtin_is_constant_evaluated());
|
||||
const int b1 = nonc(__builtin_is_constant_evaluated());
|
||||
int a2 = cexpr(__builtin_is_constant_evaluated());
|
||||
|
||||
// ok
|
||||
const int b2 = cexpr(__builtin_is_constant_evaluated());
|
||||
constexpr int c2 = cexpr(__builtin_is_constant_evaluated()); // expected-warning {{always evaluate to true}}
|
||||
|
||||
// FIXME: These are tautologically-true;
|
||||
int a3 = ceval(__builtin_is_constant_evaluated());
|
||||
const int b3 = ceval(__builtin_is_constant_evaluated());
|
||||
|
||||
// ok
|
||||
constexpr int c3 = ceval(__builtin_is_constant_evaluated()); // expected-warning {{always evaluate to true}}
|
||||
}
|
||||
}
|
@ -135,21 +135,21 @@ namespace PackInTypeConstraint {
|
||||
|
||||
namespace BuiltinIsConstantEvaluated {
|
||||
// Check that we do all satisfaction and diagnostic checks in a constant context.
|
||||
template<typename T> concept C = __builtin_is_constant_evaluated(); // expected-warning {{always evaluate to true}}
|
||||
template<typename T> concept C = __builtin_is_constant_evaluated(); // expected-warning {{always}}
|
||||
static_assert(C<int>);
|
||||
|
||||
template<typename T> concept D = __builtin_is_constant_evaluated() == true; // expected-warning {{always evaluate to true}}
|
||||
template<typename T> concept D = __builtin_is_constant_evaluated() == true; // expected-warning {{always}}
|
||||
static_assert(D<int>);
|
||||
|
||||
template<typename T> concept E = __builtin_is_constant_evaluated() == true && // expected-warning {{always evaluate to true}}
|
||||
template<typename T> concept E = __builtin_is_constant_evaluated() == true && // expected-warning {{always}}
|
||||
false; // expected-note {{'false' evaluated to false}}
|
||||
static_assert(E<int>); // expected-error {{failed}} expected-note {{because 'int' does not satisfy 'E'}}
|
||||
|
||||
template<typename T> concept F = __builtin_is_constant_evaluated() == false; // expected-warning {{always evaluate to true}}
|
||||
template<typename T> concept F = __builtin_is_constant_evaluated() == false; // expected-warning {{always}}
|
||||
// expected-note@-1 {{'__builtin_is_constant_evaluated() == false' (1 == 0)}}
|
||||
static_assert(F<int>); // expected-error {{failed}} expected-note {{because 'int' does not satisfy 'F'}}
|
||||
|
||||
template<typename T> concept G = __builtin_is_constant_evaluated() && // expected-warning {{always evaluate to true}}
|
||||
template<typename T> concept G = __builtin_is_constant_evaluated() && // expected-warning {{always}}
|
||||
false; // expected-note {{'false' evaluated to false}}
|
||||
static_assert(G<int>); // expected-error {{failed}} expected-note {{because 'int' does not satisfy 'G'}}
|
||||
}
|
||||
|
@ -188,6 +188,7 @@ Frontend
|
||||
| EvaluateAsBooleanCondition (<test.cc:8:21, col:25>)
|
||||
| | EvaluateAsRValue (<test.cc:8:21, col:25>)
|
||||
| EvaluateAsInitializer (slow_value)
|
||||
| EvaluateAsConstantExpr (<test.cc:17:33, col:59>)
|
||||
| EvaluateAsConstantExpr (<test.cc:18:11, col:37>)
|
||||
| EvaluateAsRValue (<test.cc:22:14, line:23:58>)
|
||||
| EvaluateAsInitializer (slow_init_list)
|
||||
|
@ -24,14 +24,7 @@ _LIBCPP_INLINE_VISIBILITY inline constexpr bool is_constant_evaluated() noexcept
|
||||
#endif
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR bool __libcpp_is_constant_evaluated() _NOEXCEPT {
|
||||
// __builtin_is_constant_evaluated() in this function always evaluates to false in pre-C++11 mode
|
||||
// because this function is not constexpr-qualified.
|
||||
// The following macro use clarifies this and avoids warnings from compilers.
|
||||
#ifndef _LIBCPP_CXX03_LANG
|
||||
return __builtin_is_constant_evaluated();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
@ -93,10 +93,12 @@ constexpr void test_join_view() {
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test_containers<std::deque<int>, std::deque<int>>();
|
||||
test_containers<std::deque<int>, std::vector<int>>();
|
||||
test_containers<std::vector<int>, std::deque<int>>();
|
||||
test_containers<std::vector<int>, std::vector<int>>();
|
||||
if (!std::is_constant_evaluated()) {
|
||||
test_containers<std::deque<int>, std::deque<int>>();
|
||||
test_containers<std::deque<int>, std::vector<int>>();
|
||||
test_containers<std::vector<int>, std::deque<int>>();
|
||||
test_containers<std::vector<int>, std::vector<int>>();
|
||||
}
|
||||
|
||||
types::for_each(types::forward_iterator_list<int*>{}, []<class Iter> {
|
||||
test_join_view<Iter, Iter>();
|
||||
|
@ -24,7 +24,7 @@ int main(int, char**)
|
||||
#else
|
||||
// expected-error-re@+1 {{{{(static_assert|static assertion)}} failed}}
|
||||
static_assert(!std::is_constant_evaluated(), "");
|
||||
// expected-warning-re@-1 0-1 {{'std::is_constant_evaluated' will always evaluate to {{('true' in a manifestly constant-evaluated expression|true in this context)}}}}
|
||||
// expected-warning@-1 0-1 {{'std::is_constant_evaluated' will always evaluate to 'true' in a manifestly constant-evaluated expression}}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user