/// \brief Visitor for expressions which looks for unsequenced operations on the
/// same object.
class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
+ typedef EvaluatedExprVisitor<SequenceChecker> Base;
+
/// \brief A tree of sequenced regions within an expression. Two regions are
/// unsequenced if one is an ancestor or a descendent of the other. When we
/// finish processing an expression with sequencing, such as a comma
public:
SequenceChecker(Sema &S, Expr *E,
llvm::SmallVectorImpl<Expr*> &WorkList)
- : EvaluatedExprVisitor<SequenceChecker>(S.Context), SemaRef(S),
- Region(Tree.root()), ModAsSideEffect(0), WorkList(WorkList),
- EvalTracker(0) {
+ : Base(S.Context), SemaRef(S), Region(Tree.root()),
+ ModAsSideEffect(0), WorkList(WorkList), EvalTracker(0) {
Visit(E);
}
void VisitExpr(Expr *E) {
// By default, just recurse to evaluated subexpressions.
- EvaluatedExprVisitor<SequenceChecker>::VisitStmt(E);
+ Base::VisitStmt(E);
}
void VisitCastExpr(CastExpr *E) {
}
}
+ void VisitCallExpr(CallExpr *CE) {
+ // C++11 [intro.execution]p15:
+ // When calling a function [...], every value computation and side effect
+ // associated with any argument expression, or with the postfix expression
+ // designating the called function, is sequenced before execution of every
+ // expression or statement in the body of the function [and thus before
+ // the value computation of its result].
+ SequencedSubexpression Sequenced(*this);
+ Base::VisitCallExpr(CE);
+
+ // FIXME: CXXNewExpr and CXXDeleteExpr implicitly call functions.
+ }
+
void VisitCXXConstructExpr(CXXConstructExpr *CCE) {
+ // This is a call, so all subexpressions are sequenced before the result.
+ SequencedSubexpression Sequenced(*this);
+
if (!CCE->isListInitialization())
return VisitExpr(CCE);
f(a = 0, a); // expected-warning {{unsequenced modification and access}}
f(a, a += 0); // expected-warning {{unsequenced modification and access}}
f(a = 0, a = 0); // expected-warning {{multiple unsequenced modifications}}
+ a = f(++a, 0); // ok
+ a = f(a++, 0); // ok
+ a = f(++a, a++); // expected-warning {{multiple unsequenced modifications}}
a = ++a; // expected-warning {{multiple unsequenced modifications}}
a += ++a; // expected-warning {{unsequenced modification and access}}
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wno-unused %s
-int f(int, int);
+int f(int, int = 0);
struct A {
int x, y;
};
struct S {
S(int, int);
+ int n;
};
void test() {
f(a = 0, a); // expected-warning {{unsequenced modification and access}}
f(a, a += 0); // expected-warning {{unsequenced modification and access}}
f(a = 0, a = 0); // expected-warning {{multiple unsequenced modifications}}
+ a = f(++a); // ok
+ a = f(a++); // ok
+ a = f(++a, a++); // expected-warning {{multiple unsequenced modifications}}
// Compound assignment "A OP= B" is equivalent to "A = A OP B" except that A
// is evaluated only once.
S str2 = { a++, a++ }; // ok
S str3 = { a++ + a, a++ }; // expected-warning {{unsequenced modification and access}}
+ struct Z { A a; S s; } z = { { ++a, ++a }, { ++a, ++a } }; // ok
+ a = S { ++a, a++ }.n; // ok
+ A { ++a, a++ }.x; // ok
+ a = A { ++a, a++ }.x; // expected-warning {{unsequenced modifications}}
+ A { ++a, a++ }.x + A { ++a, a++ }.y; // expected-warning {{unsequenced modifications}}
+
(xs[2] && (a = 0)) + a; // ok
(0 && (a = 0)) + a; // ok
(1 && (a = 0)) + a; // expected-warning {{unsequenced modification and access}}