diff options
author | Nick Lewycky <nicholas@mxc.ca> | 2017-05-17 23:56:54 +0000 |
---|---|---|
committer | Nick Lewycky <nicholas@mxc.ca> | 2017-05-17 23:56:54 +0000 |
commit | 9add1594d2cd5250bf6ea57bcfdb3dce676ba736 (patch) | |
tree | e58268d783d63d72c73008b5f680b5c991cc6946 | |
parent | 0cf5b2f88a299e17ca80e562f2fe9f35c7375ba3 (diff) | |
download | bcm5719-llvm-9add1594d2cd5250bf6ea57bcfdb3dce676ba736.tar.gz bcm5719-llvm-9add1594d2cd5250bf6ea57bcfdb3dce676ba736.zip |
The constant expression evaluator should examine function arguments for non-constexpr function calls unless the EvalInfo says to stop.
llvm-svn: 303317
-rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 33 | ||||
-rw-r--r-- | clang/test/Sema/integer-overflow.c | 8 |
2 files changed, 36 insertions, 5 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 75bb0cac51b..bd8b3abd927 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -4579,7 +4579,7 @@ public: } bool handleCallExpr(const CallExpr *E, APValue &Result, - const LValue *ResultSlot) { + const LValue *ResultSlot) { const Expr *Callee = E->getCallee()->IgnoreParens(); QualType CalleeType = Callee->getType(); @@ -4588,6 +4588,23 @@ public: auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs()); bool HasQualifier = false; + struct EvaluateIgnoredRAII { + public: + EvaluateIgnoredRAII(EvalInfo &Info, llvm::ArrayRef<const Expr*> ToEval) + : Info(Info), ToEval(ToEval) {} + ~EvaluateIgnoredRAII() { + if (Info.noteFailure()) { + for (auto E : ToEval) + EvaluateIgnoredValue(Info, E); + } + } + void cancel() { ToEval = {}; } + void drop_front() { ToEval = ToEval.drop_front(); } + private: + EvalInfo &Info; + llvm::ArrayRef<const Expr*> ToEval; + } EvalArguments(Info, Args); + // Extract function decl and 'this' pointer from the callee. if (CalleeType->isSpecificBuiltinType(BuiltinType::BoundMember)) { const ValueDecl *Member = nullptr; @@ -4637,10 +4654,12 @@ public: if (Args.empty()) return Error(E); - if (!EvaluateObjectArgument(Info, Args[0], ThisVal)) + const Expr *FirstArg = Args[0]; + Args = Args.drop_front(); + EvalArguments.drop_front(); + if (!EvaluateObjectArgument(Info, FirstArg, ThisVal)) return false; This = &ThisVal; - Args = Args.slice(1); } else if (MD && MD->isLambdaStaticInvoker()) { // Map the static invoker for the lambda back to the call operator. // Conveniently, we don't have to slice out the 'this' argument (as is @@ -4692,8 +4711,12 @@ public: const FunctionDecl *Definition = nullptr; Stmt *Body = FD->getBody(Definition); - if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body) || - !HandleFunctionCall(E->getExprLoc(), Definition, This, Args, Body, Info, + if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body)) + return false; + + EvalArguments.cancel(); + + if (!HandleFunctionCall(E->getExprLoc(), Definition, This, Args, Body, Info, Result, ResultSlot)) return false; diff --git a/clang/test/Sema/integer-overflow.c b/clang/test/Sema/integer-overflow.c index 62ee33e3d18..c2b6ba209b7 100644 --- a/clang/test/Sema/integer-overflow.c +++ b/clang/test/Sema/integer-overflow.c @@ -151,6 +151,14 @@ uint64_t check_integer_overflows(int i) { uint64_t *b; uint64_t b2 = b[4608 * 1024 * 1024] + 1; +// expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}} + f0(4608 * 1024 * 1024); + f0(4608ul * 1024 * 1024); +// expected-warning@+1 2{{overflow in expression; result is 536870912 with type 'int'}} + f1(4608 * 1024 * 1024, 4608 * 1024 * 1024); +// expected-warning@+1 2{{overflow in expression; result is 536870912 with type 'int'}} + f2(4608 * 1024 * 1024, 4608 * 1024 * 1024); + // expected-warning@+1 2{{overflow in expression; result is 536870912 with type 'int'}} int j1 = i ? (4608 * 1024 * 1024) : (4608 * 1024 * 1024); |