riccibruno updated this revision to Diff 271464.
riccibruno retitled this revision from "[clang] SequenceChecker: Also visit 
default arguments." to "[clang] SequenceChecker: Also visit default arguments 
and default initializers.".
riccibruno edited the summary of this revision.
riccibruno added a comment.

Ah, I forgot about default initializers. Thanks!

I have updated the patch to track chains of default arguments and/or 
initializers.
This shouldn't be too expensive since this will only be used when traversing a
`CXXDefaultArgExpr` or `CXXDefaultInitExpr`. Still I am running my usual 
benchmark
(all of boost) and will report with the results.

I think that this uncovers another issue (`test_default_init` in the test):
`SequenceChecker::VisitCXXConstructExpr` does not visit the default arguments 
of the constructor.
Because of this `SequenceChecker` misses the mutation in the example you gave, 
but only in <c++17.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81003/new/

https://reviews.llvm.org/D81003

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaChecking.cpp
  clang/test/SemaCXX/warn-unsequenced.cpp

Index: clang/test/SemaCXX/warn-unsequenced.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsequenced.cpp
+++ clang/test/SemaCXX/warn-unsequenced.cpp
@@ -268,6 +268,118 @@
                                           // cxx17-warning@-1 {{unsequenced modification and access to 'pf'}}
 }
 
+namespace default_arg {
+  int a;
+  void f1(int = a, int = a++); // cxx11-warning 2{{unsequenced modification and access to 'a'}}
+                               // cxx17-warning@-1 2{{unsequenced modification and access to 'a'}}
+
+  void f2(int = a++, int = a); // cxx11-warning {{unsequenced modification and access to 'a'}}
+                               // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+
+  void f3(int = a++, int = sizeof(a));
+
+  void test() {
+    int b;
+    f1();        // cxx11-note {{in default argument used here}}
+                 // cxx17-note@-1 {{in default argument used here}}
+    f1(a);       // cxx11-note {{in default argument used here}}
+                 // cxx17-note@-1 {{in default argument used here}}
+    f1(a,a);     // ok
+    f1(b);       // ok
+    f1(b,a++);   // ok
+
+    f2();        // cxx11-note {{in default argument used here}}
+                 // cxx17-note@-1 {{in default argument used here}}
+    f2(a);       // ok
+    f2(a++);     // cxx11-warning {{unsequenced modification and access to 'a'}}
+                 // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+
+    f3();       // ok
+    f3(a++);    // ok
+  }
+}
+
+namespace default_init {
+  int a;
+	struct X { int b = ++a; };
+  // cxx17-warning@-1 {{unsequenced modification and access to 'a'}}
+  void test_default_init() {
+    // FIXME: In C++17 the temporary is represented by
+    // a MaterializeTemporaryExpr wrapping a CXXFunctionalCastExpr.
+    //
+    // In C++11 the temporary is represented by a MaterializeTemporaryExpr
+    // wrapping a CXXTemporaryObjectExpr.
+    //
+    // However SequenceChecker::VisitCXXConstructExpr only visit the arguments
+    // of the CXXConstructExpr and is not visiting the arguments of
+    // the constructor.
+    int c = X{}.b + a;
+    // cxx17-note@-1 {{in default initializer used here}}
+  }
+}
+
+namespace default_arg_chain_0 {
+  int i;
+  int f0(int = i);
+  int f1(int = f0());
+  int f2(int = f1());
+  int f3(int, int = f2());
+
+  void test() {
+    f3(i);    // ok
+    f3(i++);  // cxx11-warning {{unsequenced modification and access to 'i'}}
+              // cxx17-warning@-1 {{unsequenced modification and access to 'i'}}
+  }
+}
+
+namespace default_arg_chain_1 {
+  int i;
+  int f0(int = i++); // cxx11-warning {{unsequenced modification and access to 'i'}}
+                     // cxx17-warning@-1 {{unsequenced modification and access to 'i'}}
+
+  int f1(int = f0());      // cxx11-note {{in default argument used here}}
+                           // cxx17-note@-1 {{in default argument used here}}
+
+  int f2(int = f1());      // cxx11-note {{in default argument used here}}
+                           // cxx17-note@-1 {{in default argument used here}}
+
+  int f3(int, int = f2()); // cxx11-note {{in default argument used here}}
+                           // cxx17-note@-1 {{in default argument used here}}
+
+  void test() {
+    f3(0);    // ok
+    f3(i);    // cxx11-note {{in default argument used here}}
+              // cxx17-note@-1 {{in default argument used here}}
+  }
+}
+
+namespace default_arg_init_chain {
+  int i;
+  struct X { int b = ++i; }; // cxx17-warning 4{{unsequenced modification and access to 'i'}}
+
+  // FIXME: see note above in default_init.
+
+  int g0(int = X{}.b); // cxx17-note 4{{in default initializer used here}}
+  int g1(int = g0());  // cxx17-note 4{{in default argument used here}}
+  int g2(int = g1());  // cxx17-note 4{{in default argument used here}}
+  int g3(int = g2());  // cxx17-note 4{{in default argument used here}}
+
+  int g4a(int, int = g3() + i);  // cxx17-note {{in default argument used here}}
+  int g4b(int, int = i + g3());  // cxx17-note {{in default argument used here}}
+
+  int g5a(int = 0, int = g3());  // cxx17-note {{in default argument used here}}
+  int g5b(int = g3(), int = 0);
+
+  void test() {
+    g5a();        // ok
+    g5b();        // ok
+    g5a(i);       // cxx17-note {{in default argument used here}}
+    g5b(g3());    // ok
+    g5b(g3(), i); // cxx17-note {{in default argument used here}}
+  }
+}
+
+
 namespace PR20819 {
   struct foo { void bar(int); };
   foo get_foo(int);
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -12434,9 +12434,28 @@
     const Expr *UsageExpr;
     SequenceTree::Seq Seq;
 
-    Usage() : UsageExpr(nullptr), Seq() {}
+    /// The index in \p AdditionalSLData for the additional \p SourceLocation
+    /// data if >= 0, or -1 if there is no additional data (the common case).
+    int AdditionalSLDataIndex;
+
+    Usage() : UsageExpr(nullptr), Seq(), AdditionalSLDataIndex(-1) {}
+  };
+
+  /// A structure storing extra location data. These structures
+  /// form a chain in \p AdditionalSLData.
+  struct AdditionalSourceLocationData {
+    SourceLocation SL;
+    unsigned DiagID;
+    int PrevIndex;
+    AdditionalSourceLocationData(SourceLocation SL, unsigned DiagID,
+                                 int PrevIndex)
+        : SL(SL), DiagID(DiagID), PrevIndex(PrevIndex) {}
   };
 
+  /// One \p AdditionalSourceLocationData is added to this vector
+  /// for each \p CXXDefaultArgExpr or \p CXXDefaultInitExpr.
+  SmallVector<AdditionalSourceLocationData, 2> AdditionalSLData;
+
   struct UsageInfo {
     Usage Uses[UK_Count];
 
@@ -12526,6 +12545,36 @@
     bool EvalOK = true;
   } *EvalTracker = nullptr;
 
+  /// RAII object used to wrap the visitation of an expression with additional
+  /// source location data. This is used to keep track of chains of default
+  /// argument and initializer.
+  class AdditionalSourceLocationTracker {
+  public:
+    AdditionalSourceLocationTracker(SequenceChecker &Self, SourceLocation SL,
+                                    unsigned DiagID)
+        : Self(Self), Prev(Self.AdditionalSLTracker), SL(SL), DiagID(DiagID),
+          AdditionalSLDataIndex(-1) {
+      Self.AdditionalSLTracker = this;
+      Self.AdditionalSLData.emplace_back(
+          SL, DiagID, Prev ? Prev->AdditionalSLDataIndex : -1);
+      AdditionalSLDataIndex = Self.AdditionalSLData.size() - 1;
+    }
+
+    ~AdditionalSourceLocationTracker() { Self.AdditionalSLTracker = Prev; }
+
+    AdditionalSourceLocationTracker *getPrev() const { return Prev; }
+    SourceLocation getLoc() const { return SL; }
+    unsigned getDiagID() const { return DiagID; }
+    int getAdditionalSLDataIndex() const { return AdditionalSLDataIndex; }
+
+  private:
+    SequenceChecker &Self;
+    AdditionalSourceLocationTracker *Prev;
+    SourceLocation SL;
+    unsigned DiagID;
+    int AdditionalSLDataIndex;
+  } *AdditionalSLTracker = nullptr;
+
   /// Find the object which is produced by the specified expression,
   /// if any.
   Object getObject(const Expr *E, bool Mod) const {
@@ -12563,6 +12612,12 @@
       // Then record the new usage with the current sequencing region.
       U.UsageExpr = UsageExpr;
       U.Seq = Region;
+
+      // If we have additional source location data, store the head of
+      // of the location data chain in \p U.
+      if (AdditionalSLTracker && AdditionalSLTracker->getLoc().isValid())
+        U.AdditionalSLDataIndex =
+            AdditionalSLTracker->getAdditionalSLDataIndex();
     }
   }
 
@@ -12590,6 +12645,26 @@
         SemaRef.PDiag(IsModMod ? diag::warn_unsequenced_mod_mod
                                : diag::warn_unsequenced_mod_use)
             << O << SourceRange(ModOrUse->getExprLoc()));
+
+    if (OtherKind != UK_Use) {
+      // Walk back the stored chain.
+      int Index = U.AdditionalSLDataIndex;
+      while (Index != -1) {
+        const AdditionalSourceLocationData &ASLD = AdditionalSLData[Index];
+        SemaRef.DiagRuntimeBehavior(ASLD.SL, {Mod, ModOrUse},
+                                    SemaRef.PDiag(ASLD.DiagID));
+        Index = ASLD.PrevIndex;
+      }
+    } else {
+      // walk back the current chain.
+      const AdditionalSourceLocationTracker *SLTracker = AdditionalSLTracker;
+      while (SLTracker && SLTracker->getLoc().isValid()) {
+        SemaRef.DiagRuntimeBehavior(SLTracker->getLoc(), {Mod, ModOrUse},
+                                    SemaRef.PDiag(SLTracker->getDiagID()));
+        SLTracker = SLTracker->getPrev();
+      }
+    }
+
     UI.Diagnosed = true;
   }
 
@@ -13013,6 +13088,22 @@
     });
   }
 
+  void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *DIE) {
+    // Remember that we are visiting this default initializer.
+    AdditionalSourceLocationTracker SL(
+        *this, DIE->getUsedLocation(),
+        diag::note_in_default_initializer_used_here);
+    Visit(DIE->getExpr());
+  }
+
+  void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *DAE) {
+    // Remember that we are visiting this default argument.
+    AdditionalSourceLocationTracker SL(
+        *this, DAE->getUsedLocation(),
+        diag::note_in_default_argument_used_here);
+    Visit(DAE->getExpr());
+  }
+
   void VisitCXXConstructExpr(const CXXConstructExpr *CCE) {
     // This is a call, so all subexpressions are sequenced before the result.
     SequencedSubexpression Sequenced(*this);
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2119,6 +2119,10 @@
   "multiple unsequenced modifications to %0">, InGroup<Unsequenced>;
 def warn_unsequenced_mod_use : Warning<
   "unsequenced modification and access to %0">, InGroup<Unsequenced>;
+def note_in_default_argument_used_here : Note<
+  "in default argument used here">;
+def note_in_default_initializer_used_here : Note<
+  "in default initializer used here">;
 
 def select_initialized_entity_kind : TextSubstitution<
   "%select{copying variable|copying parameter|"
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to