riccibruno created this revision.
riccibruno added reviewers: rsmith, aaron.ballman, Rakete1111.
riccibruno added a project: clang.
Herald added a subscriber: cfe-commits.

In C++17 the postfix-expression of a call expression is sequenced before each 
expression in the expression-list and any default argument.


Repository:
  rC Clang

https://reviews.llvm.org/D58579

Files:
  include/clang/AST/Expr.h
  lib/Sema/SemaChecking.cpp
  test/SemaCXX/warn-unsequenced.cpp

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 {
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<Stmt *> 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<Expr>(*SubExpr));
+    } else {
+      Visit(cast<Expr>(*SubExpr));
+    }
+    assert(cast<Expr>(*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<Expr>(*SubExpr));
+
+    Region = OldRegion;
+    if (SemaRef.getLangOpts().CPlusPlus17) {
+      Tree.merge(CalleeRegion);
+      Tree.merge(OtherRegion);
+    }
   }
 
   void VisitCXXConstructExpr(const CXXConstructExpr *CCE) {
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<Stmt *> getRawSubExprs() {
+  ArrayRef<Stmt *> getRawSubExprs() const {
     return llvm::makeArrayRef(getTrailingStmts(),
                               PREARGS_START + getNumPreArgs() + getNumArgs());
   }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D58579: [Sema] Sequenc... Bruno Ricci via Phabricator via cfe-commits

Reply via email to