Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -2639,7 +2639,7 @@ /// a CallExpr without going through the slower virtual child_iterator /// interface. This provides efficient reverse iteration of the /// subexpressions. This is currently used for CFG construction. - ArrayRef getRawSubExprs() { + ArrayRef getRawSubExprs() const { return llvm::makeArrayRef(getTrailingStmts(), PREARGS_START + getNumPreArgs() + getNumArgs()); } Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -12490,6 +12490,11 @@ } void VisitCallExpr(const CallExpr *CE) { + // FIXME: CXXNewExpr and CXXDeleteExpr implicitly call functions. + + if (CE->isUnevaluatedBuiltinCall(Context)) + return; + // 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 @@ -12497,9 +12502,50 @@ // 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. + // C++17 [expr.call]p5 + // The postfix-expression is sequenced before each expression in the + // expression-list and any default argument. [...] + SequenceTree::Seq CalleeRegion; + SequenceTree::Seq OtherRegion; + if (SemaRef.getLangOpts().CPlusPlus17) { + CalleeRegion = Tree.allocate(Region); + OtherRegion = Tree.allocate(Region); + } else { + CalleeRegion = Region; + OtherRegion = Region; + } + SequenceTree::Seq OldRegion = Region; + + llvm::ArrayRef SubExprs = CE->getRawSubExprs(); + const Stmt *const *SubExpr = SubExprs.begin(); + const Stmt *const *EndExpr = SubExprs.end(); + + // Visit the callee expression first. + Region = CalleeRegion; + if (SemaRef.getLangOpts().CPlusPlus17) { + SequencedSubexpression Sequenced(*this); + Visit(cast(*SubExpr)); + } else { + Visit(cast(*SubExpr)); + } + assert(cast(*SubExpr) == CE->getCallee() && + "The first sub-expression of the call expression is" + " assumed to be the callee expression!"); + ++SubExpr; + + // Then visit the argument expressions. We are not able to use + // CallExpr::arguments since we also need to visit the pre-argument + // expressions. + Region = OtherRegion; + for (; SubExpr != EndExpr; ++SubExpr) + Visit(cast(*SubExpr)); + + Region = OldRegion; + if (SemaRef.getLangOpts().CPlusPlus17) { + Tree.merge(CalleeRegion); + Tree.merge(OtherRegion); + } } void VisitCXXConstructExpr(const CXXConstructExpr *CCE) { Index: test/SemaCXX/warn-unsequenced.cpp =================================================================== --- test/SemaCXX/warn-unsequenced.cpp +++ test/SemaCXX/warn-unsequenced.cpp @@ -15,7 +15,6 @@ int n; }; -// TODO: Implement the C++17 sequencing rules. void test() { int a; int xs[10]; @@ -256,6 +255,17 @@ p[i++] = (i = 42); // cxx11-warning {{multiple unsequenced modifications to 'i'}} p++[i++] = (i = p ? i++ : i++); // cxx11-warning {{unsequenced modification and access to 'p'}} // cxx11-warning@-1 {{multiple unsequenced modifications to 'i'}} + + (i++, f)(i++, 42); // cxx11-warning {{multiple unsequenced modifications to 'i'}} + (i++ + i++, f)(42, 42); // cxx11-warning {{multiple unsequenced modifications to 'i'}} + // cxx17-warning@-1 {{multiple unsequenced modifications to 'i'}} + int (*pf)(int, int); + (pf = f)(pf != nullptr, pf != nullptr); // cxx11-warning {{unsequenced modification and access to 'pf'}} + pf((pf = f) != nullptr, 42); // cxx11-warning {{unsequenced modification and access to 'pf'}} + f((pf = f, 42), (pf = f, 42)); // cxx11-warning {{multiple unsequenced modifications to 'pf'}} + // cxx17-warning@-1 {{multiple unsequenced modifications to 'pf'}} + pf((pf = f) != nullptr, pf == nullptr); // cxx11-warning {{unsequenced modification and access to 'pf'}} + // cxx17-warning@-1 {{unsequenced modification and access to 'pf'}} } namespace members {