Skip to content

Commit 0bb4d46

Browse files
committed
[clang] perform semantic checking in constant context
Summary: Since the addition of __builtin_is_constant_evaluated the result of an expression can change based on whether it is evaluated in constant context. a lot of semantic checking performs evaluations with out specifying context. which can lead to wrong diagnostics. for example: ``` constexpr int i0 = (long long)__builtin_is_constant_evaluated() * (1ll << 33); //#1 constexpr int i1 = (long long)!__builtin_is_constant_evaluated() * (1ll << 33); //#2 ``` before the patch, #2 was diagnosed incorrectly and #1 wasn't diagnosed. after the patch #1 is diagnosed as it should and #2 isn't. Changes: - add a flag to Sema to passe in constant context mode. - in SemaChecking.cpp calls to Expr::Evaluate* are now done in constant context when they should. - in SemaChecking.cpp diagnostics for UB are not checked for in constant context because an error will be emitted by the constant evaluator. - in SemaChecking.cpp diagnostics for construct that cannot appear in constant context are not checked for in constant context. - in SemaChecking.cpp diagnostics on constant expression are always emitted because constant expression are always evaluated. - semantic checking for initialization of constexpr variables is now done in constant context. - adapt test that were depending on warning changes. - add test. Reviewers: rsmith Reviewed By: rsmith Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D62009 llvm-svn: 363488
1 parent e1aa69f commit 0bb4d46

File tree

8 files changed

+215
-96
lines changed

8 files changed

+215
-96
lines changed

clang/include/clang/AST/Expr.h

+12-9
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,8 @@ class Expr : public ValueStmt {
599599
/// which we can fold and convert to a boolean condition using
600600
/// any crazy technique that we want to, even if the expression has
601601
/// side-effects.
602-
bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx) const;
602+
bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx,
603+
bool InConstantContext = false) const;
603604

604605
enum SideEffectsKind {
605606
SE_NoSideEffects, ///< Strictly evaluate the expression.
@@ -611,20 +612,21 @@ class Expr : public ValueStmt {
611612
/// EvaluateAsInt - Return true if this is a constant which we can fold and
612613
/// convert to an integer, using any crazy technique that we want to.
613614
bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx,
614-
SideEffectsKind AllowSideEffects = SE_NoSideEffects) const;
615+
SideEffectsKind AllowSideEffects = SE_NoSideEffects,
616+
bool InConstantContext = false) const;
615617

616618
/// EvaluateAsFloat - Return true if this is a constant which we can fold and
617619
/// convert to a floating point value, using any crazy technique that we
618620
/// want to.
619-
bool
620-
EvaluateAsFloat(llvm::APFloat &Result, const ASTContext &Ctx,
621-
SideEffectsKind AllowSideEffects = SE_NoSideEffects) const;
621+
bool EvaluateAsFloat(llvm::APFloat &Result, const ASTContext &Ctx,
622+
SideEffectsKind AllowSideEffects = SE_NoSideEffects,
623+
bool InConstantContext = false) const;
622624

623625
/// EvaluateAsFloat - Return true if this is a constant which we can fold and
624626
/// convert to a fixed point value.
625-
bool EvaluateAsFixedPoint(
626-
EvalResult &Result, const ASTContext &Ctx,
627-
SideEffectsKind AllowSideEffects = SE_NoSideEffects) const;
627+
bool EvaluateAsFixedPoint(EvalResult &Result, const ASTContext &Ctx,
628+
SideEffectsKind AllowSideEffects = SE_NoSideEffects,
629+
bool InConstantContext = false) const;
628630

629631
/// isEvaluatable - Call EvaluateAsRValue to see if this expression can be
630632
/// constant folded without side-effects, but discard the result.
@@ -660,7 +662,8 @@ class Expr : public ValueStmt {
660662

661663
/// EvaluateAsLValue - Evaluate an expression to see if we can fold it to an
662664
/// lvalue with link time known address, with no side-effects.
663-
bool EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const;
665+
bool EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx,
666+
bool InConstantContext = false) const;
664667

665668
/// EvaluateAsInitializer - Evaluate an expression as if it were the
666669
/// initializer of the given declaration. Returns true if the initializer

clang/include/clang/Basic/DiagnosticASTKinds.td

+2
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ def note_constexpr_past_end_subobject : Note<
8585
"access array element of|ERROR|"
8686
"access real component of|access imaginary component of}0 "
8787
"pointer past the end of object">;
88+
def note_non_null_attribute_failed : Note<
89+
"null passed to a callee that requires a non-null argument">;
8890
def note_constexpr_null_subobject : Note<
8991
"cannot %select{access base class of|access derived class of|access field of|"
9092
"access array element of|perform pointer arithmetic on|"

clang/include/clang/Sema/Sema.h

+9
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,15 @@ class Sema {
797797
}
798798
};
799799

800+
/// Used to change context to isConstantEvaluated without pushing a heavy
801+
/// ExpressionEvaluationContextRecord object.
802+
bool isConstantEvaluatedOverride;
803+
804+
bool isConstantEvaluated() {
805+
return ExprEvalContexts.back().isConstantEvaluated() ||
806+
isConstantEvaluatedOverride;
807+
}
808+
800809
/// RAII object to handle the state changes required to synthesize
801810
/// a function body.
802811
class SynthesizedFunctionScope {

clang/lib/AST/ExprConstant.cpp

+45-14
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include "clang/Basic/Builtins.h"
4848
#include "clang/Basic/FixedPoint.h"
4949
#include "clang/Basic/TargetInfo.h"
50+
#include "llvm/ADT/SmallBitVector.h"
5051
#include "llvm/Support/SaveAndRestore.h"
5152
#include "llvm/Support/raw_ostream.h"
5253
#include <cstring>
@@ -5091,9 +5092,25 @@ typedef SmallVector<APValue, 8> ArgVector;
50915092
}
50925093

50935094
/// EvaluateArgs - Evaluate the arguments to a function call.
5094-
static bool EvaluateArgs(ArrayRef<const Expr*> Args, ArgVector &ArgValues,
5095-
EvalInfo &Info) {
5095+
static bool EvaluateArgs(ArrayRef<const Expr *> Args, ArgVector &ArgValues,
5096+
EvalInfo &Info, const FunctionDecl *Callee) {
50965097
bool Success = true;
5098+
llvm::SmallBitVector ForbiddenNullArgs;
5099+
if (Callee->hasAttr<NonNullAttr>()) {
5100+
ForbiddenNullArgs.resize(Args.size());
5101+
for (const auto *Attr : Callee->specific_attrs<NonNullAttr>()) {
5102+
if (!Attr->args_size()) {
5103+
ForbiddenNullArgs.set();
5104+
break;
5105+
} else
5106+
for (auto Idx : Attr->args()) {
5107+
unsigned ASTIdx = Idx.getASTIndex();
5108+
if (ASTIdx >= Args.size())
5109+
continue;
5110+
ForbiddenNullArgs[ASTIdx] = 1;
5111+
}
5112+
}
5113+
}
50975114
for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
50985115
I != E; ++I) {
50995116
if (!Evaluate(ArgValues[I - Args.begin()], Info, *I)) {
@@ -5102,6 +5119,13 @@ static bool EvaluateArgs(ArrayRef<const Expr*> Args, ArgVector &ArgValues,
51025119
if (!Info.noteFailure())
51035120
return false;
51045121
Success = false;
5122+
} else if (!ForbiddenNullArgs.empty() &&
5123+
ForbiddenNullArgs[I - Args.begin()] &&
5124+
ArgValues[I - Args.begin()].isNullPointer()) {
5125+
Info.CCEDiag(*I, diag::note_non_null_attribute_failed);
5126+
if (!Info.noteFailure())
5127+
return false;
5128+
Success = false;
51055129
}
51065130
}
51075131
return Success;
@@ -5114,7 +5138,7 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
51145138
EvalInfo &Info, APValue &Result,
51155139
const LValue *ResultSlot) {
51165140
ArgVector ArgValues(Args.size());
5117-
if (!EvaluateArgs(Args, ArgValues, Info))
5141+
if (!EvaluateArgs(Args, ArgValues, Info, Callee))
51185142
return false;
51195143

51205144
if (!Info.CheckCallLimit(CallLoc))
@@ -5338,7 +5362,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
53385362
const CXXConstructorDecl *Definition,
53395363
EvalInfo &Info, APValue &Result) {
53405364
ArgVector ArgValues(Args.size());
5341-
if (!EvaluateArgs(Args, ArgValues, Info))
5365+
if (!EvaluateArgs(Args, ArgValues, Info, Definition))
53425366
return false;
53435367

53445368
return HandleConstructorCall(E, This, ArgValues.data(), Definition,
@@ -11855,54 +11879,61 @@ bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx,
1185511879
return ::EvaluateAsRValue(this, Result, Ctx, Info);
1185611880
}
1185711881

11858-
bool Expr::EvaluateAsBooleanCondition(bool &Result,
11859-
const ASTContext &Ctx) const {
11882+
bool Expr::EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx,
11883+
bool InConstantContext) const {
1186011884
assert(!isValueDependent() &&
1186111885
"Expression evaluator can't be called on a dependent expression.");
1186211886
EvalResult Scratch;
11863-
return EvaluateAsRValue(Scratch, Ctx) &&
11887+
return EvaluateAsRValue(Scratch, Ctx, InConstantContext) &&
1186411888
HandleConversionToBool(Scratch.Val, Result);
1186511889
}
1186611890

1186711891
bool Expr::EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx,
11868-
SideEffectsKind AllowSideEffects) const {
11892+
SideEffectsKind AllowSideEffects,
11893+
bool InConstantContext) const {
1186911894
assert(!isValueDependent() &&
1187011895
"Expression evaluator can't be called on a dependent expression.");
1187111896
EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects);
11897+
Info.InConstantContext = InConstantContext;
1187211898
return ::EvaluateAsInt(this, Result, Ctx, AllowSideEffects, Info);
1187311899
}
1187411900

1187511901
bool Expr::EvaluateAsFixedPoint(EvalResult &Result, const ASTContext &Ctx,
11876-
SideEffectsKind AllowSideEffects) const {
11902+
SideEffectsKind AllowSideEffects,
11903+
bool InConstantContext) const {
1187711904
assert(!isValueDependent() &&
1187811905
"Expression evaluator can't be called on a dependent expression.");
1187911906
EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects);
11907+
Info.InConstantContext = InConstantContext;
1188011908
return ::EvaluateAsFixedPoint(this, Result, Ctx, AllowSideEffects, Info);
1188111909
}
1188211910

1188311911
bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx,
11884-
SideEffectsKind AllowSideEffects) const {
11912+
SideEffectsKind AllowSideEffects,
11913+
bool InConstantContext) const {
1188511914
assert(!isValueDependent() &&
1188611915
"Expression evaluator can't be called on a dependent expression.");
1188711916

1188811917
if (!getType()->isRealFloatingType())
1188911918
return false;
1189011919

1189111920
EvalResult ExprResult;
11892-
if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isFloat() ||
11921+
if (!EvaluateAsRValue(ExprResult, Ctx, InConstantContext) ||
11922+
!ExprResult.Val.isFloat() ||
1189311923
hasUnacceptableSideEffect(ExprResult, AllowSideEffects))
1189411924
return false;
1189511925

1189611926
Result = ExprResult.Val.getFloat();
1189711927
return true;
1189811928
}
1189911929

11900-
bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const {
11930+
bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx,
11931+
bool InConstantContext) const {
1190111932
assert(!isValueDependent() &&
1190211933
"Expression evaluator can't be called on a dependent expression.");
1190311934

1190411935
EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold);
11905-
11936+
Info.InConstantContext = InConstantContext;
1190611937
LValue LV;
1190711938
if (!EvaluateLValue(this, LV, Info) || Result.HasSideEffects ||
1190811939
!CheckLValueConstantExpression(Info, getExprLoc(),
@@ -12685,7 +12716,7 @@ bool Expr::isPotentialConstantExprUnevaluated(Expr *E,
1268512716
// Fabricate a call stack frame to give the arguments a plausible cover story.
1268612717
ArrayRef<const Expr*> Args;
1268712718
ArgVector ArgValues(0);
12688-
bool Success = EvaluateArgs(Args, ArgValues, Info);
12719+
bool Success = EvaluateArgs(Args, ArgValues, Info, FD);
1268912720
(void)Success;
1269012721
assert(Success &&
1269112722
"Failed to set up arguments for potential constant evaluation");

clang/lib/Sema/Sema.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
158158
ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr),
159159
CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr) {
160160
TUScope = nullptr;
161+
isConstantEvaluatedOverride = false;
161162

162163
LoadedExternalKnownNamespaces = false;
163164
for (unsigned I = 0; I != NSAPI::NumNSNumberLiteralMethods; ++I)

0 commit comments

Comments
 (0)