From ba57183965f117279342903edec19766e478c9a8 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 17 Jan 2013 23:46:04 +0000 Subject: [PATCH] Some builtins do not evaluate their arguments. Teach EvaluatedExprVisitor not to visit them. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172769 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/EvaluatedExprVisitor.h | 9 +++++++-- include/clang/AST/Expr.h | 4 ++++ include/clang/Basic/Builtins.def | 7 ++++--- include/clang/Basic/Builtins.h | 6 ++++++ lib/AST/Expr.cpp | 6 ++++++ test/SemaCXX/warn-unsequenced.cpp | 5 +++++ 6 files changed, 32 insertions(+), 5 deletions(-) diff --git a/include/clang/AST/EvaluatedExprVisitor.h b/include/clang/AST/EvaluatedExprVisitor.h index 6e6f3176ff..eb186c217e 100644 --- a/include/clang/AST/EvaluatedExprVisitor.h +++ b/include/clang/AST/EvaluatedExprVisitor.h @@ -61,12 +61,17 @@ public: // expressions. return this->Visit(E->getInit()); } - + void VisitCXXTypeidExpr(CXXTypeidExpr *E) { if (E->isPotentiallyEvaluated()) return this->Visit(E->getExprOperand()); } - + + void VisitCallExpr(CallExpr *CE) { + if (!CE->isUnevaluatedBuiltinCall(Context)) + return static_cast(this)->VisitExpr(CE); + } + /// \brief The basis case walks all of the children of the statement or /// expression, assuming they are all potentially evaluated. void VisitStmt(Stmt *S) { diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 10bb353101..5b6e660832 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -2193,6 +2193,10 @@ public: /// not, return 0. unsigned isBuiltinCall() const; + /// \brief Returns \c true if this is a call to a builtin which does not + /// evaluate side-effects within its arguments. + bool isUnevaluatedBuiltinCall(ASTContext &Ctx) const; + /// getCallReturnType - Get the return type of the call expr. This is not /// always the type of the expr itself, if the return type is a reference /// type. diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index 63fca6f9cc..0a513efdbc 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -82,6 +82,7 @@ // through an ellipsis // e -> const, but only when -fmath-errno=0 // j -> returns_twice (like setjmp) +// u -> arguments are not evaluated for their side-effects // FIXME: gcc has nonnull #if defined(BUILTIN) && !defined(LIBBUILTIN) @@ -395,8 +396,8 @@ BUILTIN(__builtin_bswap32, "UiUi", "nc") BUILTIN(__builtin_bswap64, "ULLiULLi", "nc") // Random GCC builtins -BUILTIN(__builtin_constant_p, "i.", "nct") -BUILTIN(__builtin_classify_type, "i.", "nct") +BUILTIN(__builtin_constant_p, "i.", "nctu") +BUILTIN(__builtin_classify_type, "i.", "nctu") BUILTIN(__builtin___CFStringMakeConstantString, "FC*cC*", "nc") BUILTIN(__builtin___NSStringMakeConstantString, "FC*cC*", "nc") BUILTIN(__builtin_va_start, "vA.", "nt") @@ -454,7 +455,7 @@ BUILTIN(__builtin_dwarf_sp_column, "Ui", "n") BUILTIN(__builtin_extend_pointer, "ULLiv*", "n") // _Unwind_Word == uint64_t // GCC Object size checking builtins -BUILTIN(__builtin_object_size, "zvC*i", "n") +BUILTIN(__builtin_object_size, "zvC*i", "nu") BUILTIN(__builtin___memcpy_chk, "v*v*vC*zz", "nF") BUILTIN(__builtin___memccpy_chk, "v*v*vC*izz", "nF") BUILTIN(__builtin___memmove_chk, "v*v*vC*zz", "nF") diff --git a/include/clang/Basic/Builtins.h b/include/clang/Basic/Builtins.h index 257daf10ec..3b88e1550c 100644 --- a/include/clang/Basic/Builtins.h +++ b/include/clang/Basic/Builtins.h @@ -109,6 +109,12 @@ public: return strchr(GetRecord(ID).Attributes, 'j') != 0; } + /// \brief Returns true if this builtin does not perform the side-effects + /// of its arguments. + bool isUnevaluated(unsigned ID) const { + return strchr(GetRecord(ID).Attributes, 'u') != 0; + } + /// \brief Return true if this is a builtin for a libc/libm function, /// with a "__builtin_" prefix (e.g. __builtin_abs). bool isLibFunction(unsigned ID) const { diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 4796257c92..718002f97d 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1137,6 +1137,12 @@ unsigned CallExpr::isBuiltinCall() const { return FDecl->getBuiltinID(); } +bool CallExpr::isUnevaluatedBuiltinCall(ASTContext &Ctx) const { + if (unsigned BI = isBuiltinCall()) + return Ctx.BuiltinInfo.isUnevaluated(BI); + return false; +} + QualType CallExpr::getCallReturnType() const { QualType CalleeType = getCallee()->getType(); if (const PointerType *FnTypePtr = CalleeType->getAs()) diff --git a/test/SemaCXX/warn-unsequenced.cpp b/test/SemaCXX/warn-unsequenced.cpp index 15ca1dba7a..c7acfca6db 100644 --- a/test/SemaCXX/warn-unsequenced.cpp +++ b/test/SemaCXX/warn-unsequenced.cpp @@ -95,4 +95,9 @@ void test() { xs[8] && (++a + a++); // expected-warning {{multiple unsequenced modifications}} xs[8] || (++a + a++); // expected-warning {{multiple unsequenced modifications}} + + (__builtin_classify_type(++a) ? 1 : 0) + ++a; // ok + (__builtin_constant_p(++a) ? 1 : 0) + ++a; // ok + (__builtin_object_size(&(++a, a), 0) ? 1 : 0) + ++a; // ok + (__builtin_expect(++a, 0) ? 1 : 0) + ++a; // expected-warning {{multiple unsequenced modifications}} } -- 2.40.0