diff options
author | Gauthier Harnisch <tyker1@outlook.com> | 2019-06-15 08:32:56 +0000 |
---|---|---|
committer | Gauthier Harnisch <tyker1@outlook.com> | 2019-06-15 08:32:56 +0000 |
commit | 0bb4d46b2be5edd58621416de72e995cd6dd7ec4 (patch) | |
tree | ccc668ec1d20d2bd9c70d87d7d9a0801c853a385 /clang/lib/AST/ExprConstant.cpp | |
parent | e1aa69f75574b88ac18fbe683af39226ee5ad288 (diff) | |
download | bcm5719-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.cpp | 59 |
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"); |