summaryrefslogtreecommitdiffstats
path: root/clang/lib/AST/ExprConstant.cpp
diff options
context:
space:
mode:
authorGauthier Harnisch <tyker1@outlook.com>2019-06-15 08:32:56 +0000
committerGauthier Harnisch <tyker1@outlook.com>2019-06-15 08:32:56 +0000
commit0bb4d46b2be5edd58621416de72e995cd6dd7ec4 (patch)
treeccc668ec1d20d2bd9c70d87d7d9a0801c853a385 /clang/lib/AST/ExprConstant.cpp
parente1aa69f75574b88ac18fbe683af39226ee5ad288 (diff)
downloadbcm5719-llvm-0bb4d46b2be5edd58621416de72e995cd6dd7ec4.tar.gz
bcm5719-llvm-0bb4d46b2be5edd58621416de72e995cd6dd7ec4.zip
[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
Diffstat (limited to 'clang/lib/AST/ExprConstant.cpp')
-rw-r--r--clang/lib/AST/ExprConstant.cpp59
1 files changed, 45 insertions, 14 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 57d428282cb..c0c807b11c9 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -47,6 +47,7 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/FixedPoint.h"
#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/SmallBitVector.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/raw_ostream.h"
#include <cstring>
@@ -5091,9 +5092,25 @@ typedef SmallVector<APValue, 8> ArgVector;
}
/// EvaluateArgs - Evaluate the arguments to a function call.
-static bool EvaluateArgs(ArrayRef<const Expr*> Args, ArgVector &ArgValues,
- EvalInfo &Info) {
+static bool EvaluateArgs(ArrayRef<const Expr *> Args, ArgVector &ArgValues,
+ EvalInfo &Info, const FunctionDecl *Callee) {
bool Success = true;
+ llvm::SmallBitVector ForbiddenNullArgs;
+ if (Callee->hasAttr<NonNullAttr>()) {
+ ForbiddenNullArgs.resize(Args.size());
+ for (const auto *Attr : Callee->specific_attrs<NonNullAttr>()) {
+ if (!Attr->args_size()) {
+ ForbiddenNullArgs.set();
+ break;
+ } else
+ for (auto Idx : Attr->args()) {
+ unsigned ASTIdx = Idx.getASTIndex();
+ if (ASTIdx >= Args.size())
+ continue;
+ ForbiddenNullArgs[ASTIdx] = 1;
+ }
+ }
+ }
for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
I != E; ++I) {
if (!Evaluate(ArgValues[I - Args.begin()], Info, *I)) {
@@ -5102,6 +5119,13 @@ static bool EvaluateArgs(ArrayRef<const Expr*> Args, ArgVector &ArgValues,
if (!Info.noteFailure())
return false;
Success = false;
+ } else if (!ForbiddenNullArgs.empty() &&
+ ForbiddenNullArgs[I - Args.begin()] &&
+ ArgValues[I - Args.begin()].isNullPointer()) {
+ Info.CCEDiag(*I, diag::note_non_null_attribute_failed);
+ if (!Info.noteFailure())
+ return false;
+ Success = false;
}
}
return Success;
@@ -5114,7 +5138,7 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
EvalInfo &Info, APValue &Result,
const LValue *ResultSlot) {
ArgVector ArgValues(Args.size());
- if (!EvaluateArgs(Args, ArgValues, Info))
+ if (!EvaluateArgs(Args, ArgValues, Info, Callee))
return false;
if (!Info.CheckCallLimit(CallLoc))
@@ -5338,7 +5362,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
const CXXConstructorDecl *Definition,
EvalInfo &Info, APValue &Result) {
ArgVector ArgValues(Args.size());
- if (!EvaluateArgs(Args, ArgValues, Info))
+ if (!EvaluateArgs(Args, ArgValues, Info, Definition))
return false;
return HandleConstructorCall(E, This, ArgValues.data(), Definition,
@@ -11855,33 +11879,38 @@ bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx,
return ::EvaluateAsRValue(this, Result, Ctx, Info);
}
-bool Expr::EvaluateAsBooleanCondition(bool &Result,
- const ASTContext &Ctx) const {
+bool Expr::EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx,
+ bool InConstantContext) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
EvalResult Scratch;
- return EvaluateAsRValue(Scratch, Ctx) &&
+ return EvaluateAsRValue(Scratch, Ctx, InConstantContext) &&
HandleConversionToBool(Scratch.Val, Result);
}
bool Expr::EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx,
- SideEffectsKind AllowSideEffects) const {
+ SideEffectsKind AllowSideEffects,
+ bool InConstantContext) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects);
+ Info.InConstantContext = InConstantContext;
return ::EvaluateAsInt(this, Result, Ctx, AllowSideEffects, Info);
}
bool Expr::EvaluateAsFixedPoint(EvalResult &Result, const ASTContext &Ctx,
- SideEffectsKind AllowSideEffects) const {
+ SideEffectsKind AllowSideEffects,
+ bool InConstantContext) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects);
+ Info.InConstantContext = InConstantContext;
return ::EvaluateAsFixedPoint(this, Result, Ctx, AllowSideEffects, Info);
}
bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx,
- SideEffectsKind AllowSideEffects) const {
+ SideEffectsKind AllowSideEffects,
+ bool InConstantContext) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
@@ -11889,7 +11918,8 @@ bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx,
return false;
EvalResult ExprResult;
- if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isFloat() ||
+ if (!EvaluateAsRValue(ExprResult, Ctx, InConstantContext) ||
+ !ExprResult.Val.isFloat() ||
hasUnacceptableSideEffect(ExprResult, AllowSideEffects))
return false;
@@ -11897,12 +11927,13 @@ bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx,
return true;
}
-bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const {
+bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx,
+ bool InConstantContext) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold);
-
+ Info.InConstantContext = InConstantContext;
LValue LV;
if (!EvaluateLValue(this, LV, Info) || Result.HasSideEffects ||
!CheckLValueConstantExpression(Info, getExprLoc(),
@@ -12685,7 +12716,7 @@ bool Expr::isPotentialConstantExprUnevaluated(Expr *E,
// Fabricate a call stack frame to give the arguments a plausible cover story.
ArrayRef<const Expr*> Args;
ArgVector ArgValues(0);
- bool Success = EvaluateArgs(Args, ArgValues, Info);
+ bool Success = EvaluateArgs(Args, ArgValues, Info, FD);
(void)Success;
assert(Success &&
"Failed to set up arguments for potential constant evaluation");
OpenPOWER on IntegriCloud