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
diff --git a/include/clang/AST/EvaluatedExprVisitor.h b/include/clang/AST/EvaluatedExprVisitor.h
index 6e6f317..eb186c2 100644
--- a/include/clang/AST/EvaluatedExprVisitor.h
+++ b/include/clang/AST/EvaluatedExprVisitor.h
@@ -61,12 +61,17 @@
// 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<ImplClass*>(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 10bb353..5b6e660 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -2193,6 +2193,10 @@
/// 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 63fca6f..0a513ef 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_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_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 257daf1..3b88e15 100644
--- a/include/clang/Basic/Builtins.h
+++ b/include/clang/Basic/Builtins.h
@@ -109,6 +109,12 @@
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 4796257..718002f 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1137,6 +1137,12 @@
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<PointerType>())
diff --git a/test/SemaCXX/warn-unsequenced.cpp b/test/SemaCXX/warn-unsequenced.cpp
index 15ca1db..c7acfca 100644
--- a/test/SemaCXX/warn-unsequenced.cpp
+++ b/test/SemaCXX/warn-unsequenced.cpp
@@ -95,4 +95,9 @@
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}}
}