Index: clang/lib/Sema/SemaChecking.cpp =================================================================== --- clang/lib/Sema/SemaChecking.cpp +++ clang/lib/Sema/SemaChecking.cpp @@ -12918,6 +12918,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 @@ -12925,9 +12930,40 @@ // 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; + + // Visit the callee expression first. + Region = CalleeRegion; + if (SemaRef.getLangOpts().CPlusPlus17) { + SequencedSubexpression Sequenced(*this); + Visit(CE->getCallee()); + } else { + Visit(CE->getCallee()); + } + + // Then visit the argument expressions. + Region = OtherRegion; + for (const Expr *Argument : CE->arguments()) + Visit(Argument); + + Region = OldRegion; + if (SemaRef.getLangOpts().CPlusPlus17) { + Tree.merge(CalleeRegion); + Tree.merge(OtherRegion); + } } void VisitCXXConstructExpr(const CXXConstructExpr *CCE) { Index: clang/test/SemaCXX/warn-unsequenced.cpp =================================================================== --- clang/test/SemaCXX/warn-unsequenced.cpp +++ clang/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 {