[clang] 3214f7b - Revert "[clang][dataflow] Show triangle in `` element. (#67431)"

2023-09-28 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-09-28T09:07:20Z
New Revision: 3214f7bf6c6f1218404584b6c36bd3d4033eb22d

URL: 
https://github.com/llvm/llvm-project/commit/3214f7bf6c6f1218404584b6c36bd3d4033eb22d
DIFF: 
https://github.com/llvm/llvm-project/commit/3214f7bf6c6f1218404584b6c36bd3d4033eb22d.diff

LOG: Revert "[clang][dataflow] Show triangle in `` element. (#67431)"

This reverts commit fb933fc6d76de854cb9eadf984f8900b9304d347.

The commit broke buildbots due to non-ASCII characters in
HTMLLogger.css.

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/HTMLLogger.css
clang/lib/Analysis/FlowSensitive/HTMLLogger.html

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.css 
b/clang/lib/Analysis/FlowSensitive/HTMLLogger.css
index 9737d1416f22abe..0ac1902ea4651ec 100644
--- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.css
+++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.css
@@ -123,21 +123,10 @@ code.line:has(.bb-select):before {
   font-size: x-small;
   flex-grow: 1;
 }
-.value > summary {
+.value summary {
   background-color: #ace;
   display: flex;
-  cursor: pointer;
-}
-.value > summary::before {
-  content: '►';
-  margin-right: 0.5em;
-  font-size: 0.9em;
-}
-.value[open] > summary::before {
-  content: '▼';
-}
-.value > summary > .location {
-  margin-left: auto;
+  justify-content: space-between;
 }
 .value .address {
   font-size: xx-small;

diff  --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.html 
b/clang/lib/Analysis/FlowSensitive/HTMLLogger.html
index 6d866d57e144866..87695623cb318b2 100644
--- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.html
+++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.html
@@ -18,7 +18,7 @@
 #{{v.value_id}}
   
   
-{{v.type}} @{{v.location}}
+{{v.type}} @{{v.location}}
   
 
 https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 6236bf5 - [clang][dataflow] Strengthen flow condition assertions.

2023-07-18 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-18T13:41:43Z
New Revision: 6236bf53418eb23c62a73d6346f0edec914084e7

URL: 
https://github.com/llvm/llvm-project/commit/6236bf53418eb23c62a73d6346f0edec914084e7
DIFF: 
https://github.com/llvm/llvm-project/commit/6236bf53418eb23c62a73d6346f0edec914084e7.diff

LOG: [clang][dataflow] Strengthen flow condition assertions.

Instead of asserting merely that the flow condition doesn't imply that a 
variable is true, make the stronger assertion that the flow condition implies 
that the variable is false.

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D155067

Added: 


Modified: 
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index e2800452ab6bdb..291f8329a60fde 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -3619,7 +3619,8 @@ TEST(TransferTest, BooleanEquality) {
 EXPECT_TRUE(EnvThen.flowConditionImplies(BarValThen));
 
 auto &BarValElse = getFormula(*BarDecl, EnvElse);
-EXPECT_FALSE(EnvElse.flowConditionImplies(BarValElse));
+EXPECT_TRUE(
+EnvElse.flowConditionImplies(EnvElse.arena().makeNot(BarValElse)));
   });
 }
 
@@ -3650,7 +3651,8 @@ TEST(TransferTest, BooleanInequality) {
 ASSERT_THAT(BarDecl, NotNull());
 
 auto &BarValThen = getFormula(*BarDecl, EnvThen);
-EXPECT_FALSE(EnvThen.flowConditionImplies(BarValThen));
+EXPECT_TRUE(
+EnvThen.flowConditionImplies(EnvThen.arena().makeNot(BarValThen)));
 
 auto &BarValElse = getFormula(*BarDecl, EnvElse);
 EXPECT_TRUE(EnvElse.flowConditionImplies(BarValElse));



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 8b5d3ba - [clang][dataflow] Print the source line if we saw unexpected diagnostics in tests.

2023-07-20 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-20T12:40:22Z
New Revision: 8b5d3ba829c162fd4890fd65a4629ce0715825ee

URL: 
https://github.com/llvm/llvm-project/commit/8b5d3ba829c162fd4890fd65a4629ce0715825ee
DIFF: 
https://github.com/llvm/llvm-project/commit/8b5d3ba829c162fd4890fd65a4629ce0715825ee.diff

LOG: [clang][dataflow] Print the source line if we saw unexpected diagnostics 
in tests.

This makes it easier to determine which line the unexpected happened on; 
previously, we would only get the line number.

Reviewed By: ymandel

Differential Revision: https://reviews.llvm.org/D155802

Added: 


Modified: 
clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp

Removed: 




diff  --git 
a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
index 4bac015c995f68..a181f284370886 100644
--- 
a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
+++ 
b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
@@ -12,6 +12,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Basic/SourceLocation.h"
+#include "clang/Frontend/TextDiagnostic.h"
 #include "clang/Tooling/Tooling.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/STLExtras.h"
@@ -1334,7 +1335,17 @@ class UncheckedOptionalAccessTest
   auto &SrcMgr = AO.ASTCtx.getSourceManager();
   llvm::DenseSet DiagnosticLines;
   for (SourceLocation &Loc : Diagnostics) {
-DiagnosticLines.insert(SrcMgr.getPresumedLineNumber(Loc));
+unsigned Line = SrcMgr.getPresumedLineNumber(Loc);
+DiagnosticLines.insert(Line);
+if (!AnnotationLines.contains(Line)) {
+  IntrusiveRefCntPtr DiagOpts(
+  new DiagnosticOptions());
+  TextDiagnostic TD(llvm::errs(), AO.ASTCtx.getLangOpts(),
+DiagOpts.get());
+  TD.emitDiagnostic(
+  FullSourceLoc(Loc, SrcMgr), DiagnosticsEngine::Error,
+  "unexpected diagnostic", std::nullopt, std::nullopt);
+}
   }
 
   EXPECT_THAT(DiagnosticLines, ContainerEq(AnnotationLines));



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 477ee05 - [clang][dataflow] Add an `operator<<` for `OptionalTypeIdentifier`.

2023-07-20 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-20T12:52:53Z
New Revision: 477ee05f83c6cc4f11b45e61e606934b99e72290

URL: 
https://github.com/llvm/llvm-project/commit/477ee05f83c6cc4f11b45e61e606934b99e72290
DIFF: 
https://github.com/llvm/llvm-project/commit/477ee05f83c6cc4f11b45e61e606934b99e72290.diff

LOG: [clang][dataflow] Add an `operator<<` for `OptionalTypeIdentifier`.

When tests fail in UncheckedOptionalAccessModelTest.cpp, this prints the name 
of the optional type instead of a blob of hex.

Reviewed By: ymandel

Differential Revision: https://reviews.llvm.org/D155788

Added: 


Modified: 
clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp

Removed: 




diff  --git 
a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
index a181f284370886..719ec271e134c4 100644
--- 
a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
+++ 
b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
@@ -1267,6 +1267,12 @@ struct OptionalTypeIdentifier {
   std::string TypeName;
 };
 
+static raw_ostream &operator<<(raw_ostream &OS,
+   const OptionalTypeIdentifier &TypeId) {
+  OS << TypeId.NamespaceName << "::" << TypeId.TypeName;
+  return OS;
+}
+
 class UncheckedOptionalAccessTest
 : public ::testing::TestWithParam {
 protected:



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 44f98d0 - [clang][dataflow] Eliminate duplication between `AggregateStorageLocation` and `StructValue`.

2023-07-24 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-24T13:20:01Z
New Revision: 44f98d0101fe82352e7c5fa98f1b2e9dc1159200

URL: 
https://github.com/llvm/llvm-project/commit/44f98d0101fe82352e7c5fa98f1b2e9dc1159200
DIFF: 
https://github.com/llvm/llvm-project/commit/44f98d0101fe82352e7c5fa98f1b2e9dc1159200.diff

LOG: [clang][dataflow] Eliminate duplication between `AggregateStorageLocation` 
and `StructValue`.

After this change, `StructValue` is just a wrapper for an 
`AggregateStorageLocation`. For the wider context, see 
https://discourse.llvm.org/t/70086.

## How to review

- Start by looking at the comments added / changed in Value.h, 
StorageLocation.h,
  and DataflowEnvironment.h. This will give you a good overview of the semantic
  changes.

- Look at the corresponding .cpp files that implement the semantic changes.

- Transfer.cpp, TypeErasedDataflowAnalysis.cpp, and RecordOps.cpp show how the
  core of the framework is affected by the semantic changes.

- UncheckedOptionalAccessModel.cpp shows how this complex model is affected by
  the changes.

- Many of the changes in the rest of the patch are mechanical in nature.

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D155446

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/include/clang/Analysis/FlowSensitive/StorageLocation.h
clang/include/clang/Analysis/FlowSensitive/Value.h
clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
clang/lib/Analysis/FlowSensitive/RecordOps.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp
clang/unittests/Analysis/FlowSensitive/TestingSupport.h
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index 9d99b6771f71e1..5cf52ad3d72235 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -334,6 +334,31 @@ class Environment {
   /// in the environment.
   AggregateStorageLocation *getThisPointeeStorageLocation() const;
 
+  /// Returns the location of the result object for a record-type prvalue.
+  ///
+  /// In C++, prvalues of record type serve only a limited purpose: They can
+  /// only be used to initialize a result object (e.g. a variable or a
+  /// temporary). This function returns the location of that result object.
+  ///
+  /// When creating a prvalue of record type, we already need the storage
+  /// location of the result object to pass in `this`, even though prvalues are
+  /// otherwise not associated with storage locations.
+  ///
+  /// FIXME: Currently, this simply returns a stable storage location for `E`,
+  /// but this doesn't do the right thing in scenarios like the following:
+  /// ```
+  /// MyClass c = some_condition()? MyClass(foo) : MyClass(bar);
+  /// ```
+  /// Here, `MyClass(foo)` and `MyClass(bar)` will have two 
diff erent storage
+  /// locations, when in fact their storage locations should be the same.
+  /// Eventually, we want to propagate storage locations from result objects
+  /// down to the prvalues that initialize them, similar to the way that this 
is
+  /// done in Clang's CodeGen.
+  ///
+  /// Requirements:
+  ///  `E` must be a prvalue of record type.
+  AggregateStorageLocation &getResultObjectLocation(const Expr &RecordPRValue);
+
   /// Returns the return value of the current function. This can be null if:
   /// - The function has a void return type
   /// - No return value could be determined for the function, for example
@@ -385,10 +410,16 @@ class Environment {
   PointerValue &getOrCreateNullPointerValue(QualType PointeeType);
 
   /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise
-  /// return null. If `Type` is a pointer or reference type, creates all the
-  /// necessary storage locations and values for indirections until it finds a
+  /// returns null.
+  ///
+  /// If `Type` is a pointer or reference type, creates all the necessary
+  /// storage locations and values for indirections until it finds a
   /// non-pointer/non-reference type.
   ///
+  /// If `Type` is a class, struct, or union type, calls `setValue()` to
+  /// associate the `StructValue` with its storage location
+  /// (`StructValue::getAggregateLoc()`).
+  ///
   /// If `Type` is one of the following types, this function will always return
   /// a non-null pointer:
   /// - `bool`
@@ -430,7 +461,7 @@ class En

[clang] c3cf630 - [clang][dataflow] Remove checks that test for consistency between `StructValue` and `AggregateStorageLocation`.

2023-07-24 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-24T13:20:04Z
New Revision: c3cf630d80a26a3bfc0845592f86e555addce3ca

URL: 
https://github.com/llvm/llvm-project/commit/c3cf630d80a26a3bfc0845592f86e555addce3ca
DIFF: 
https://github.com/llvm/llvm-project/commit/c3cf630d80a26a3bfc0845592f86e555addce3ca.diff

LOG: [clang][dataflow] Remove checks that test for consistency between 
`StructValue` and `AggregateStorageLocation`.

Now that the redundancy between these two classes has been eliminated, these
checks aren't needed any more.

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D155813

Added: 


Modified: 
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 78f13a044ce64b..edd015bbf10937 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -27,11 +27,6 @@
 #include 
 #include 
 
-// FIXME: There are still remaining checks here that check for consistency
-// between `StructValue` and `AggregateStorageLocation`. Now that the 
redundancy
-// between these two classes has been eliminated, these checks aren't needed 
any
-// more, so remove them.
-
 namespace {
 
 using namespace clang;
@@ -268,13 +263,7 @@ TEST(TransferTest, StructVarDecl) {
 
 const auto *FooLoc =
 cast(Env.getStorageLocation(*FooDecl));
-const auto *BarLoc =
-cast(FooLoc->getChild(*BarDecl));
-
-const auto *FooVal = cast(Env.getValue(*FooLoc));
-const auto *BarVal =
-cast(getFieldValue(FooVal, *BarDecl, Env));
-EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
+EXPECT_TRUE(isa(getFieldValue(FooLoc, *BarDecl, Env)));
   });
 }
 
@@ -317,13 +306,7 @@ TEST(TransferTest, StructVarDeclWithInit) {
 
 const auto *FooLoc =
 cast(Env.getStorageLocation(*FooDecl));
-const auto *BarLoc =
-cast(FooLoc->getChild(*BarDecl));
-
-const auto *FooVal = cast(Env.getValue(*FooLoc));
-const auto *BarVal =
-cast(getFieldValue(FooVal, *BarDecl, Env));
-EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
+EXPECT_TRUE(isa(getFieldValue(FooLoc, *BarDecl, Env)));
   });
 }
 
@@ -365,13 +348,7 @@ TEST(TransferTest, ClassVarDecl) {
 
 const auto *FooLoc =
 cast(Env.getStorageLocation(*FooDecl));
-const auto *BarLoc =
-cast(FooLoc->getChild(*BarDecl));
-
-const auto *FooVal = cast(Env.getValue(*FooLoc));
-const auto *BarVal =
-cast(getFieldValue(FooVal, *BarDecl, Env));
-EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
+EXPECT_TRUE(isa(getFieldValue(FooLoc, *BarDecl, Env)));
   });
 }
 
@@ -1046,13 +1023,7 @@ TEST(TransferTest, StructParamDecl) {
 
 const auto *FooLoc =
 cast(Env.getStorageLocation(*FooDecl));
-const auto *BarLoc =
-cast(FooLoc->getChild(*BarDecl));
-
-const auto *FooVal = cast(Env.getValue(*FooLoc));
-const auto *BarVal =
-cast(getFieldValue(FooVal, *BarDecl, Env));
-EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
+EXPECT_TRUE(isa(getFieldValue(FooLoc, *BarDecl, Env)));
   });
 }
 
@@ -1150,9 +1121,8 @@ TEST(TransferTest, StructMember) {
 
 const auto *FooLoc =
 cast(Env.getStorageLocation(*FooDecl));
-const auto *FooVal = cast(Env.getValue(*FooLoc));
 const auto *BarVal =
-cast(getFieldValue(FooVal, *BarDecl, Env));
+cast(getFieldValue(FooLoc, *BarDecl, Env));
 
 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
 ASSERT_THAT(BazDecl, NotNull());
@@ -1392,9 +1362,8 @@ TEST(TransferTest, ClassMember) {
 
 const auto *FooLoc =
 cast(Env.getStorageLocation(*FooDecl));
-const auto *FooVal = cast(Env.getValue(*FooLoc));
 const auto *BarVal =
-cast(getFieldValue(FooVal, *BarDecl, Env));
+cast(getFieldValue(FooLoc, *BarDecl, Env));
 
 const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
 ASSERT_THAT(BazDecl, NotNull());
@@ -1553,14 +1522,10 @@ TEST(TransferTest, StructThisMember) {
 
 const auto *QuxLoc =
 cast(ThisLoc->getChild(*QuxDecl));
-const auto *QuxVal = dyn_cast(Env.getValue(*QuxLoc));
-ASSERT_THAT(QuxVal, NotNull());
+EXPECT_THAT(dyn_cast(Env.getValue(*QuxLoc)), NotNull());
 
-const auto *BazLoc =
-cast(QuxLoc->getChild(*BazDecl));
 const auto *BazVal =
-cast(getFieldValue(QuxVal, *BazDecl, Env));
-EXPECT_EQ(Env.getValue(*BazLoc), BazVal);
+cast(getFieldValue(QuxLoc, *BazDecl, Env));
 
 const ValueDecl *QuuxDecl = findValueD

[clang] e6e83cb - [clang][dataflow] Don't crash when constructing an array of records.

2023-07-27 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-27T12:46:13Z
New Revision: e6e83cbcc748a55a7eddce67b228298820cb9315

URL: 
https://github.com/llvm/llvm-project/commit/e6e83cbcc748a55a7eddce67b228298820cb9315
DIFF: 
https://github.com/llvm/llvm-project/commit/e6e83cbcc748a55a7eddce67b228298820cb9315.diff

LOG: [clang][dataflow] Don't crash when constructing an array of records.

When I wrote https://reviews.llvm.org/D155446, I assumed that a 
`CXXConstructExpr` would always have record type, but this isn't true: It can 
have array type when constructing an array of records. The code would crash in 
this situation because `createValue()` would return null.

This patch includes a test that reproduces the crash without the other changes 
in the patch.

Reviewed By: sammccall

Differential Revision: https://reviews.llvm.org/D156402

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index 0b7c22fe24e301..8f8f807a3a4b22 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -500,9 +500,14 @@ class TransferVisitor : public 
ConstStmtVisitor {
   return;
 }
 
-auto &InitialVal = *cast(Env.createValue(S->getType()));
-copyRecord(InitialVal.getAggregateLoc(), Env.getResultObjectLocation(*S),
-   Env);
+// `CXXConstructExpr` can have array type if default-initializing an array
+// of records, and we currently can't create values for arrays. So check if
+// we've got a record type.
+if (S->getType()->isRecordType()) {
+  auto &InitialVal = *cast(Env.createValue(S->getType()));
+  copyRecord(InitialVal.getAggregateLoc(), Env.getResultObjectLocation(*S),
+ Env);
+}
 
 transferInlineCall(S, ConstructorDecl);
   }

diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 5acb28bd87abff..57c8a5f3589bc4 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -310,6 +310,28 @@ TEST(TransferTest, StructVarDeclWithInit) {
   });
 }
 
+TEST(TransferTest, StructArrayVarDecl) {
+  std::string Code = R"(
+struct A {};
+
+void target() {
+  A Array[2];
+  // [[p]]
+}
+  )";
+  runDataflow(
+  Code,
+  [](const llvm::StringMap> &Results,
+ ASTContext &ASTCtx) {
+const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+
+const ValueDecl *ArrayDecl = findValueDecl(ASTCtx, "Array");
+
+// We currently don't create values for arrays.
+ASSERT_THAT(Env.getValue(*ArrayDecl), IsNull());
+  });
+}
+
 TEST(TransferTest, ClassVarDecl) {
   std::string Code = R"(
 class A {



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 771d7d7 - [clang][dataflow] HTMLLogger: Don't crash if CFG contains unreachable blocks.

2023-07-27 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-27T13:02:42Z
New Revision: 771d7d71df418f12c80632ec6c3488af98f9b196

URL: 
https://github.com/llvm/llvm-project/commit/771d7d71df418f12c80632ec6c3488af98f9b196
DIFF: 
https://github.com/llvm/llvm-project/commit/771d7d71df418f12c80632ec6c3488af98f9b196.diff

LOG: [clang][dataflow] HTMLLogger: Don't crash if CFG contains unreachable 
blocks.

Reviewed By: sammccall

Differential Revision: https://reviews.llvm.org/D156411

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp 
b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
index ee89e074f84676..ea9052b0e7171e 100644
--- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
+++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
@@ -462,8 +462,9 @@ class HTMLLogger : public Logger {
   GraphS << "  " << blockID(I) << " [id=" << blockID(I) << "]\n";
 for (const auto *Block : CFG) {
   for (const auto &Succ : Block->succs()) {
-GraphS << "  " << blockID(Block->getBlockID()) << " -> "
-   << blockID(Succ.getReachableBlock()->getBlockID()) << "\n";
+if (Succ.getReachableBlock())
+  GraphS << "  " << blockID(Block->getBlockID()) << " -> "
+ << blockID(Succ.getReachableBlock()->getBlockID()) << "\n";
   }
 }
 GraphS << "}\n";



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 1b334a2 - [clang][dataflow] Eliminate `ReferenceValue`.

2023-07-27 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-27T13:14:47Z
New Revision: 1b334a2ae7af8ad8b2e3367db6433f1bc7b2b1a4

URL: 
https://github.com/llvm/llvm-project/commit/1b334a2ae7af8ad8b2e3367db6433f1bc7b2b1a4
DIFF: 
https://github.com/llvm/llvm-project/commit/1b334a2ae7af8ad8b2e3367db6433f1bc7b2b1a4.diff

LOG: [clang][dataflow] Eliminate `ReferenceValue`.

There are no remaining uses of this class in the framework.

This patch is part of the ongoing migration to strict handling of value 
categories (see https://discourse.llvm.org/t/70086 for details).

Reviewed By: ymandel, xazax.hun, gribozavr2

Differential Revision: https://reviews.llvm.org/D155922

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/include/clang/Analysis/FlowSensitive/Value.h
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/DebugSupport.cpp
clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
clang/lib/Analysis/FlowSensitive/Value.cpp
clang/unittests/Analysis/FlowSensitive/ValueTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index 5cf52ad3d72235..6a6c6856cce95b 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -47,6 +47,7 @@ enum class SkipPast {
   /// No indirections should be skipped past.
   None,
   /// An optional reference should be skipped past.
+  /// This is deprecated; it is equivalent to `None` and will be removed.
   Reference,
 };
 
@@ -304,9 +305,10 @@ class Environment {
   ///  `E` must be a glvalue or a `BuiltinType::BuiltinFn`
   void setStorageLocationStrict(const Expr &E, StorageLocation &Loc);
 
-  /// Returns the storage location assigned to `E` in the environment, applying
-  /// the `SP` policy for skipping past indirections, or null if `E` isn't
-  /// assigned a storage location in the environment.
+  /// Returns the storage location assigned to `E` in the environment, or null
+  /// if `E` isn't assigned a storage location in the environment.
+  ///
+  /// The `SP` parameter has no effect.
   ///
   /// This function is deprecated; prefer `getStorageLocationStrict()`.
   /// For details, see https://discourse.llvm.org/t/70086.
@@ -490,12 +492,14 @@ class Environment {
   /// isn't assigned a value in the environment.
   Value *getValue(const StorageLocation &Loc) const;
 
-  /// Equivalent to `getValue(getStorageLocation(D, SP), SkipPast::None)` if 
`D`
-  /// is assigned a storage location in the environment, otherwise returns 
null.
+  /// Equivalent to `getValue(getStorageLocation(D))` if `D` is assigned a
+  /// storage location in the environment, otherwise returns null.
   Value *getValue(const ValueDecl &D) const;
 
-  /// Equivalent to `getValue(getStorageLocation(E, SP), SkipPast::None)` if 
`E`
-  /// is assigned a storage location in the environment, otherwise returns 
null.
+  /// Equivalent to `getValue(getStorageLocation(E, SP))` if `E` is assigned a
+  /// storage location in the environment, otherwise returns null.
+  ///
+  /// The `SP` parameter has no effect.
   ///
   /// This function is deprecated; prefer `getValueStrict()`. For details, see
   /// https://discourse.llvm.org/t/70086.
@@ -672,9 +676,6 @@ class Environment {
   StorageLocation &createObjectInternal(const VarDecl *D, QualType Ty,
 const Expr *InitExpr);
 
-  StorageLocation &skip(StorageLocation &Loc, SkipPast SP) const;
-  const StorageLocation &skip(const StorageLocation &Loc, SkipPast SP) const;
-
   /// Shared implementation of `pushCall` overloads. Note that unlike
   /// `pushCall`, this member is invoked on the environment of the callee, not
   /// of the caller.

diff  --git a/clang/include/clang/Analysis/FlowSensitive/Value.h 
b/clang/include/clang/Analysis/FlowSensitive/Value.h
index 7d9a7b7d28254b..d1432fe8217a13 100644
--- a/clang/include/clang/Analysis/FlowSensitive/Value.h
+++ b/clang/include/clang/Analysis/FlowSensitive/Value.h
@@ -34,7 +34,6 @@ class Value {
 public:
   enum class Kind {
 Integer,
-Reference,
 Pointer,
 Struct,
 
@@ -165,23 +164,6 @@ class IntegerValue : public Value {
   }
 };
 
-/// Models a dereferenced pointer. For example, a reference in C++ or an lvalue
-/// in C.
-class ReferenceValue final : public Value {
-public:
-  explicit ReferenceValue(StorageLocation &ReferentLoc)
-  : Value(Kind::Reference), ReferentLoc(ReferentLoc) {}
-
-  static bool classof(const Value *Val) {
-return Val->getKind() == Kind::Reference;
-  }
-
-  StorageLocation &getReferentLoc() const { return ReferentLoc; }
-
-private:
-  StorageLocation &ReferentLoc;
-};
-
 /// Models a symbolic pointer. Specifically, any value of type `T*`.
 class PointerVa

[clang] e95134b - [clang][dataflow] Reverse course on `getValue()` deprecation.

2023-07-27 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-27T13:14:49Z
New Revision: e95134b9cb1885b0da929737858163486a5c399c

URL: 
https://github.com/llvm/llvm-project/commit/e95134b9cb1885b0da929737858163486a5c399c
DIFF: 
https://github.com/llvm/llvm-project/commit/e95134b9cb1885b0da929737858163486a5c399c.diff

LOG: [clang][dataflow] Reverse course on `getValue()` deprecation.

In the [value categories RFC](https://discourse.llvm.org/t/70086), I proposed 
that the end state of the migration should be that `getValue()` should only be 
legal to call on prvalues.

As a stepping stone, to allow migrating off existing calls to `getValue()`, I 
proposed introducing `getValueStrict()`, which would already have the new 
semantics.

However, I've now reconsidered this. Any expression, whether prvalue or 
glvalue, has a value, so really there isn't any reason to forbid calling 
`getValue()` on glvalues. I'm therefore removing the deprecation from 
`getValue()` and transitioning existing `getValueStrict()` calls back to 
`getValue()`.

The other "strict" accessors are a different case. `setValueStrict()` should 
only be called on prvalues because glvalues need to have a storage location 
associated with them; it doesn't make sense to only set a value for them. And, 
of course, `getStorageLocationStrict()` and `setStorageLocationStrict()` should 
obviously only be called on glvalues because prvalues don't have storage 
locations.

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D155921

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index 6a6c6856cce95b..460727973ed4c8 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -499,20 +499,14 @@ class Environment {
   /// Equivalent to `getValue(getStorageLocation(E, SP))` if `E` is assigned a
   /// storage location in the environment, otherwise returns null.
   ///
-  /// The `SP` parameter has no effect.
-  ///
-  /// This function is deprecated; prefer `getValueStrict()`. For details, see
-  /// https://discourse.llvm.org/t/70086.
-  Value *getValue(const Expr &E, SkipPast SP) const;
+  /// The `SP` parameter is deprecated and has no effect. New callers should
+  /// avoid passing this parameter.
+  Value *getValue(const Expr &E, SkipPast SP = SkipPast::None) const;
 
   /// Returns the `Value` assigned to the prvalue `E` in the environment, or
   /// null if `E` isn't assigned a value in the environment.
   ///
-  /// This function is the preferred alternative to
-  /// `getValue(const Expr &, SkipPast)`. Once the migration to strict handling
-  /// of value categories is complete (see https://discourse.llvm.org/t/70086),
-  /// `getValue()` will be removed and this function will be renamed to
-  /// `getValue()`.
+  /// This function is deprecated. Call `getValue(E)` instead.
   ///
   /// Requirements:
   ///

diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index d3d5f3338ddf49..903d9ec300e2f6 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -686,7 +686,7 @@ void Environment::setValueStrict(const Expr &E, Value &Val) 
{
   assert(E.isPRValue());
 
   if (auto *StructVal = dyn_cast(&Val)) {
-if (auto *ExistingVal = cast_or_null(getValueStrict(E)))
+if (auto *ExistingVal = cast_or_null(getValue(E)))
   assert(&ExistingVal->getAggregateLoc() == &StructVal->getAggregateLoc());
 if (StorageLocation *ExistingLoc = getStorageLocation(E, SkipPast::None))
   assert(ExistingLoc == &StructVal->getAggregateLoc());
@@ -724,9 +724,7 @@ Value *Environment::getValue(const Expr &E, SkipPast SP) 
const {
 
 Value *Environment::getValueStrict(const Expr &E) const {
   assert(E.isPRValue());
-  Value *Val = getValue(E, SkipPast::None);
-
-  return Val;
+  return getValue(E);
 }
 
 Value *Environment::createValue(QualType Type) {
@@ -859,7 +857,7 @@ StorageLocation &Environment::createObjectInternal(const 
VarDecl *D,
 // assert that `InitExpr` is interpreted, rather than supplying a
 // default value (assuming we don't update the environment A

[clang] a1a63d6 - [clang][dataflow] Add two repros for non-convergence involving pointers in loops.

2023-08-23 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-08-23T07:03:16Z
New Revision: a1a63d68a46882e051eedcb632723e15f2ee331b

URL: 
https://github.com/llvm/llvm-project/commit/a1a63d68a46882e051eedcb632723e15f2ee331b
DIFF: 
https://github.com/llvm/llvm-project/commit/a1a63d68a46882e051eedcb632723e15f2ee331b.diff

LOG: [clang][dataflow] Add two repros for non-convergence involving pointers in 
loops.

These are broken out from https://reviews.llvm.org/D156658, which it now seems 
obvious isn't the right way to solve the non-convergence.

Instead, my plan is to address the non-convergence through pointer value 
widening, but the exact way this should be implemented is TBD. In the meantime, 
I think there's value in getting these repros submitted to record the current 
undesirable behavior.

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D158513

Added: 


Modified: 
clang/unittests/Analysis/FlowSensitive/TestingSupport.h
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h 
b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
index 11dc4ed76aa4fc..44dbf27a745867 100644
--- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
+++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
@@ -402,8 +402,8 @@ llvm::Error checkDataflowWithNoopAnalysis(
 std::function<
 void(const llvm::StringMap> &,
  ASTContext &)>
-VerifyResults,
-DataflowAnalysisOptions Options,
+VerifyResults = [](const auto &, auto &) {},
+DataflowAnalysisOptions Options = {BuiltinOptions()},
 LangStandard::Kind Std = LangStandard::lang_cxx17,
 llvm::StringRef TargetFun = "target");
 

diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 117230e14aa9e9..4c31de3c8085bd 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -2667,11 +2667,7 @@ TEST(TransferTest, CannotAnalyzeFunctionTemplate) {
 void target() {}
   )";
   ASSERT_THAT_ERROR(
-  checkDataflowWithNoopAnalysis(
-  Code,
-  [](const llvm::StringMap> 
&Results,
- ASTContext &ASTCtx) {},
-  {BuiltinOptions()}),
+  checkDataflowWithNoopAnalysis(Code),
   llvm::FailedWithMessage("Cannot analyze templated declarations"));
 }
 
@@ -2683,11 +2679,7 @@ TEST(TransferTest, CannotAnalyzeMethodOfClassTemplate) {
 };
   )";
   ASSERT_THAT_ERROR(
-  checkDataflowWithNoopAnalysis(
-  Code,
-  [](const llvm::StringMap> 
&Results,
- ASTContext &ASTCtx) {},
-  {BuiltinOptions()}),
+  checkDataflowWithNoopAnalysis(Code),
   llvm::FailedWithMessage("Cannot analyze templated declarations"));
 }
 
@@ -3836,6 +3828,52 @@ TEST(TransferTest, 
LoopWithStructReferenceAssignmentConverges) {
   });
 }
 
+TEST(TransferTest, LoopDereferencingChangingPointerConverges) {
+  std::string Code = R"cc(
+bool some_condition();
+
+void target(int i1, int i2) {
+  int *p = &i1;
+  while (true) {
+(void)*p;
+if (some_condition())
+  p = &i1;
+else
+  p = &i2;
+  }
+}
+  )cc";
+  // FIXME: Implement pointer value widening to make analysis converge.
+  ASSERT_THAT_ERROR(
+  checkDataflowWithNoopAnalysis(Code),
+  llvm::FailedWithMessage("maximum number of iterations reached"));
+}
+
+TEST(TransferTest, LoopDereferencingChangingRecordPointerConverges) {
+  std::string Code = R"cc(
+struct Lookup {
+  int x;
+};
+
+bool some_condition();
+
+void target(Lookup l1, Lookup l2) {
+  Lookup *l = &l1;
+  while (true) {
+(void)l->x;
+if (some_condition())
+  l = &l1;
+else
+  l = &l2;
+  }
+}
+  )cc";
+  // FIXME: Implement pointer value widening to make analysis converge.
+  ASSERT_THAT_ERROR(
+  checkDataflowWithNoopAnalysis(Code),
+  llvm::FailedWithMessage("maximum number of iterations reached"));
+}
+
 TEST(TransferTest, DoesNotCrashOnUnionThisExpr) {
   std::string Code = R"(
 union Union {



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 8c0acbf - [clang][dataflow] Avoid -Wunused-variable.

2023-07-28 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-28T07:57:50Z
New Revision: 8c0acbf8370f29943798cd434cd0b91bbd554cdf

URL: 
https://github.com/llvm/llvm-project/commit/8c0acbf8370f29943798cd434cd0b91bbd554cdf
DIFF: 
https://github.com/llvm/llvm-project/commit/8c0acbf8370f29943798cd434cd0b91bbd554cdf.diff

LOG: [clang][dataflow] Avoid -Wunused-variable.

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index 903d9ec300e2f6..214e0c061ed7bc 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -686,9 +686,11 @@ void Environment::setValueStrict(const Expr &E, Value 
&Val) {
   assert(E.isPRValue());
 
   if (auto *StructVal = dyn_cast(&Val)) {
-if (auto *ExistingVal = cast_or_null(getValue(E)))
+if ([[maybe_unused]] auto *ExistingVal =
+cast_or_null(getValue(E)))
   assert(&ExistingVal->getAggregateLoc() == &StructVal->getAggregateLoc());
-if (StorageLocation *ExistingLoc = getStorageLocation(E, SkipPast::None))
+if ([[maybe_unused]] StorageLocation *ExistingLoc =
+getStorageLocation(E, SkipPast::None))
   assert(ExistingLoc == &StructVal->getAggregateLoc());
 else
   setStorageLocation(E, StructVal->getAggregateLoc());



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] f76f667 - [clang][dataflow] Use `Strict` accessors where we weren't using them yet.

2023-07-31 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-31T19:40:04Z
New Revision: f76f6674d8221f59f9e515e3cc03ad07fa72fe46

URL: 
https://github.com/llvm/llvm-project/commit/f76f6674d8221f59f9e515e3cc03ad07fa72fe46
DIFF: 
https://github.com/llvm/llvm-project/commit/f76f6674d8221f59f9e515e3cc03ad07fa72fe46.diff

LOG: [clang][dataflow] Use `Strict` accessors where we weren't using them yet.

This eliminates all uses of the deprecated accessors.

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D156672

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index 214e0c061ed7bc..c1cd00a73491ae 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -336,8 +336,8 @@ Environment Environment::pushCall(const CallExpr *Call) 
const {
   if (const auto *MethodCall = dyn_cast(Call)) {
 if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) {
   if (!isa(Arg))
-Env.ThisPointeeLoc = cast(
-getStorageLocation(*Arg, SkipPast::Reference));
+  Env.ThisPointeeLoc =
+  cast(getStorageLocationStrict(*Arg));
   // Otherwise (when the argument is `this`), retain the current
   // environment's `ThisPointeeLoc`.
 }
@@ -832,9 +832,8 @@ StorageLocation &Environment::createObjectInternal(const 
VarDecl *D,
 // can happen that we can't see the initializer, so `InitExpr` may still
 // be null.
 if (InitExpr) {
-  if (auto *InitExprLoc =
-  getStorageLocation(*InitExpr, SkipPast::Reference))
-return *InitExprLoc;
+  if (auto *InitExprLoc = getStorageLocationStrict(*InitExpr))
+  return *InitExprLoc;
 }
 
 // Even though we have an initializer, we might not get an
@@ -913,16 +912,13 @@ getImplicitObjectLocation(const CXXMemberCallExpr &MCE,
   Expr *ImplicitObject = MCE.getImplicitObjectArgument();
   if (ImplicitObject == nullptr)
 return nullptr;
-  StorageLocation *Loc =
-  Env.getStorageLocation(*ImplicitObject, SkipPast::Reference);
-  if (Loc == nullptr)
-return nullptr;
   if (ImplicitObject->getType()->isPointerType()) {
-if (auto *Val = cast_or_null(Env.getValue(*Loc)))
+if (auto *Val = cast_or_null(Env.getValue(*ImplicitObject)))
   return &cast(Val->getPointeeLoc());
 return nullptr;
   }
-  return cast(Loc);
+  return cast_or_null(
+  Env.getStorageLocationStrict(*ImplicitObject));
 }
 
 AggregateStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
@@ -930,15 +926,13 @@ AggregateStorageLocation *getBaseObjectLocation(const 
MemberExpr &ME,
   Expr *Base = ME.getBase();
   if (Base == nullptr)
 return nullptr;
-  StorageLocation *Loc = Env.getStorageLocation(*Base, SkipPast::Reference);
-  if (Loc == nullptr)
-return nullptr;
   if (ME.isArrow()) {
-if (auto *Val = cast_or_null(Env.getValue(*Loc)))
+if (auto *Val = cast_or_null(Env.getValue(*Base)))
   return &cast(Val->getPointeeLoc());
 return nullptr;
   }
-  return cast(Loc);
+  return cast_or_null(
+  Env.getStorageLocationStrict(*Base));
 }
 
 std::vector getFieldsForInitListExpr(const RecordDecl *RD) {

diff  --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp 
b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
index ef51402e171ed6..9b0daf2d95183f 100644
--- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
+++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
@@ -254,10 +254,17 @@ class HTMLLogger : public Logger {
   if (ElementIndex > 0) {
 auto S =
 Iters.back().first->Elements[ElementIndex - 1].getAs();
-if (const Expr *E = S ? llvm::dyn_cast(S->getStmt()) : nullptr)
-  if (auto *Loc = State.Env.getStorageLocation(*E, SkipPast::None))
-JOS->attributeObject(
-"value", [&] { ModelDumper(*JOS, State.Env).dump(*Loc); });
+if (const Expr *E = S ? llvm::dyn_cast(S->getStmt()) : nullptr) {
+  if (E->isPRValue()) {
+if (auto *V = State.Env.getValue(*E))
+  JOS->attributeObject(
+  "value", [&] { ModelDumper(*JOS, State.Env).dump(*V); });
+  } else {
+if (auto *Loc = State.Env.getStorageLocationStrict(*E))
+  JOS->attributeObject(
+  "value", [&] { ModelDumper(*JOS, State.Env).dump(*Loc); });
+  }
+}
   }
   if (!ContextLogs.empty()) {
 JOS->attribute("logs", ContextLogs);

diff  --git 
a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessMode

[clang] 17ba278 - [clang][dataflow] Remove deprecated accessors as well as `SkipPast`.

2023-07-31 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-31T19:40:06Z
New Revision: 17ba278f76116b12eb7a954c8963ee5a5a19c32b

URL: 
https://github.com/llvm/llvm-project/commit/17ba278f76116b12eb7a954c8963ee5a5a19c32b
DIFF: 
https://github.com/llvm/llvm-project/commit/17ba278f76116b12eb7a954c8963ee5a5a19c32b.diff

LOG: [clang][dataflow] Remove deprecated accessors as well as `SkipPast`.

Depends On D156672

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D156673

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index 460727973ed4c8..bd89c7e5c74a3c 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -38,19 +38,6 @@
 namespace clang {
 namespace dataflow {
 
-/// Indicates what kind of indirections should be skipped past when retrieving
-/// storage locations or values.
-///
-/// FIXME: Consider renaming this or replacing it with a more appropriate 
model.
-/// See the discussion in https://reviews.llvm.org/D116596 for context.
-enum class SkipPast {
-  /// No indirections should be skipped past.
-  None,
-  /// An optional reference should be skipped past.
-  /// This is deprecated; it is equivalent to `None` and will be removed.
-  Reference,
-};
-
 /// Indicates the result of a tentative comparison.
 enum class ComparisonResult {
   Same,
@@ -280,40 +267,15 @@ class Environment {
   /// refers directly to the referenced object, not a `ReferenceValue`.
   StorageLocation *getStorageLocation(const ValueDecl &D) const;
 
-  /// Assigns `Loc` as the storage location of `E` in the environment.
-  ///
-  /// This function is deprecated; prefer `setStorageLocationStrict()`.
-  /// For details, see https://discourse.llvm.org/t/70086.
-  ///
-  /// Requirements:
-  ///
-  ///  `E` must not be assigned a storage location in the environment.
-  void setStorageLocation(const Expr &E, StorageLocation &Loc);
-
   /// Assigns `Loc` as the storage location of the glvalue `E` in the
   /// environment.
   ///
-  /// This function is the preferred alternative to
-  /// `setStorageLocation(const Expr &, StorageLocation &)`. Once the migration
-  /// to strict handling of value categories is complete (see
-  /// https://discourse.llvm.org/t/70086), `setStorageLocation()` will be
-  /// removed and this function will be renamed to `setStorageLocation()`.
-  ///
   /// Requirements:
   ///
   ///  `E` must not be assigned a storage location in the environment.
   ///  `E` must be a glvalue or a `BuiltinType::BuiltinFn`
   void setStorageLocationStrict(const Expr &E, StorageLocation &Loc);
 
-  /// Returns the storage location assigned to `E` in the environment, or null
-  /// if `E` isn't assigned a storage location in the environment.
-  ///
-  /// The `SP` parameter has no effect.
-  ///
-  /// This function is deprecated; prefer `getStorageLocationStrict()`.
-  /// For details, see https://discourse.llvm.org/t/70086.
-  StorageLocation *getStorageLocation(const Expr &E, SkipPast SP) const;
-
   /// Returns the storage location assigned to the glvalue `E` in the
   /// environment, or null if `E` isn't assigned a storage location in the
   /// environment.
@@ -321,12 +283,6 @@ class Environment {
   /// If the storage location for `E` is associated with a
   /// `ReferenceValue RefVal`, returns `RefVal.getReferentLoc()` instead.
   ///
-  /// This function is the preferred alternative to
-  /// `getStorageLocation(const Expr &, SkipPast)`. Once the migration
-  /// to strict handling of value categories is complete (see
-  /// https://discourse.llvm.org/t/70086), `getStorageLocation()` will be
-  /// removed and this function will be renamed to `getStorageLocation()`.
-  ///
   /// Requirements:
   ///  `E` must be a glvalue or a `BuiltinType::BuiltinFn`
   StorageLocation *getStorageLocationStrict(const Expr &E) const;
@@ -498,20 +454,7 @@ class Environment {
 
   /// Equivalent to `getValue(getStorageLocation(E, SP))` if `E` is assigned a
   /// storage location in the environment, otherwise returns null.
-  ///
-  /// The `SP` parameter is deprecated and has no effect. New callers should
-  /// avoid passing this parameter.
-  Value *getValue(const Expr &E, SkipPast SP = SkipPast::None) const;
-
-  /// Returns the `Value` assigned to the prvalue `E` in the environment, or
-  /// null if `E` isn't assigned a value in the environment.
-  ///
-  /// This function is deprecated. Call `getValue(E)` instead.
-  ///
-  /// Requirements:
-  ///
-  ///  `E` must be a prvalue
-  Value *getValueStrict(const Expr &E) const;
+  Value *getValue(const Expr &E) const;
 
   // FIXME

[clang] b244b6a - [clang][dataflow] Remove `Strict` suffix from accessors.

2023-07-31 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-31T19:40:09Z
New Revision: b244b6ae0b2153521c5e55ff4705a88618f503aa

URL: 
https://github.com/llvm/llvm-project/commit/b244b6ae0b2153521c5e55ff4705a88618f503aa
DIFF: 
https://github.com/llvm/llvm-project/commit/b244b6ae0b2153521c5e55ff4705a88618f503aa.diff

LOG: [clang][dataflow] Remove `Strict` suffix from accessors.

For the time being, we're keeping the `Strict` versions around as deprecated 
synonyms so that clients can be migrated, but these synonyms will be removed 
soon.

Depends On D156673

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D156674

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index bd89c7e5c74a3c..0e5cfad263c797 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -274,7 +274,12 @@ class Environment {
   ///
   ///  `E` must not be assigned a storage location in the environment.
   ///  `E` must be a glvalue or a `BuiltinType::BuiltinFn`
-  void setStorageLocationStrict(const Expr &E, StorageLocation &Loc);
+  void setStorageLocation(const Expr &E, StorageLocation &Loc);
+
+  /// Deprecated synonym for `setStorageLocation()`.
+  void setStorageLocationStrict(const Expr &E, StorageLocation &Loc) {
+setStorageLocation(E, Loc);
+  }
 
   /// Returns the storage location assigned to the glvalue `E` in the
   /// environment, or null if `E` isn't assigned a storage location in the
@@ -285,7 +290,12 @@ class Environment {
   ///
   /// Requirements:
   ///  `E` must be a glvalue or a `BuiltinType::BuiltinFn`
-  StorageLocation *getStorageLocationStrict(const Expr &E) const;
+  StorageLocation *getStorageLocation(const Expr &E) const;
+
+  /// Deprecated synonym for `getStorageLocation()`.
+  StorageLocation *getStorageLocationStrict(const Expr &E) const {
+return getStorageLocation(E);
+  }
 
   /// Returns the storage location assigned to the `this` pointee in the
   /// environment or null if the `this` pointee has no assigned storage 
location
@@ -442,7 +452,10 @@ class Environment {
   ///  same as that of any `StructValue` that has already been associated with
   ///  `E`. This is to guarantee that the result object initialized by a 
prvalue
   ///  `StructValue` has a durable storage location.
-  void setValueStrict(const Expr &E, Value &Val);
+  void setValue(const Expr &E, Value &Val);
+
+  /// Deprecated synonym for `setValue()`.
+  void setValueStrict(const Expr &E, Value &Val) { setValue(E, Val); }
 
   /// Returns the value assigned to `Loc` in the environment or null if `Loc`
   /// isn't assigned a value in the environment.
@@ -585,11 +598,11 @@ class Environment {
   // The copy-constructor is for use in fork() only.
   Environment(const Environment &) = default;
 
-  /// Internal version of `setStorageLocationStrict()` that doesn't check if 
the
+  /// Internal version of `setStorageLocation()` that doesn't check if the
   /// expression is a prvalue.
   void setStorageLocationInternal(const Expr &E, StorageLocation &Loc);
 
-  /// Internal version of `getStorageLocationStrict()` that doesn't check if 
the
+  /// Internal version of `getStorageLocation()` that doesn't check if the
   /// expression is a prvalue.
   StorageLocation *getStorageLocationInternal(const Expr &E) const;
 

diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index 48f8e63a165efe..503158c91c3f4f 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -337,7 +337,7 @@ Environment Environment::pushCall(const CallExpr *Call) 
const {
 if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) {
   if (!isa(Arg))
   Env.ThisPointeeLoc =
-  cast(getStorageLocationStrict(*Arg));
+  cast(getStorageLocation(*Arg));
   // Otherwise (when the argument is `this`), retain the current
   // environment's `ThisPointeeLoc`.
 }
@@ -396,10 +396,10 @@ void Environment::popCall(const CallExpr *Call, const 
Environment &CalleeEnv) {

[clang] 8c1a519 - [clang][dataflow] Remove deprecated `Strict` accessors.

2023-08-01 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-08-01T20:07:00Z
New Revision: 8c1a519ee423f4097092095a44ba850bf0dd498d

URL: 
https://github.com/llvm/llvm-project/commit/8c1a519ee423f4097092095a44ba850bf0dd498d
DIFF: 
https://github.com/llvm/llvm-project/commit/8c1a519ee423f4097092095a44ba850bf0dd498d.diff

LOG: [clang][dataflow] Remove deprecated `Strict` accessors.

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D156790

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index 0e5cfad263c797..7ac2ff3102adcd 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -276,11 +276,6 @@ class Environment {
   ///  `E` must be a glvalue or a `BuiltinType::BuiltinFn`
   void setStorageLocation(const Expr &E, StorageLocation &Loc);
 
-  /// Deprecated synonym for `setStorageLocation()`.
-  void setStorageLocationStrict(const Expr &E, StorageLocation &Loc) {
-setStorageLocation(E, Loc);
-  }
-
   /// Returns the storage location assigned to the glvalue `E` in the
   /// environment, or null if `E` isn't assigned a storage location in the
   /// environment.
@@ -292,11 +287,6 @@ class Environment {
   ///  `E` must be a glvalue or a `BuiltinType::BuiltinFn`
   StorageLocation *getStorageLocation(const Expr &E) const;
 
-  /// Deprecated synonym for `getStorageLocation()`.
-  StorageLocation *getStorageLocationStrict(const Expr &E) const {
-return getStorageLocation(E);
-  }
-
   /// Returns the storage location assigned to the `this` pointee in the
   /// environment or null if the `this` pointee has no assigned storage 
location
   /// in the environment.
@@ -454,9 +444,6 @@ class Environment {
   ///  `StructValue` has a durable storage location.
   void setValue(const Expr &E, Value &Val);
 
-  /// Deprecated synonym for `setValue()`.
-  void setValueStrict(const Expr &E, Value &Val) { setValue(E, Val); }
-
   /// Returns the value assigned to `Loc` in the environment or null if `Loc`
   /// isn't assigned a value in the environment.
   Value *getValue(const StorageLocation &Loc) const;



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 9ecdbe3 - [clang][dataflow] Rename `AggregateStorageLocation` to `RecordStorageLocation` and `StructValue` to `RecordValue`.

2023-08-01 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-08-01T20:29:40Z
New Revision: 9ecdbe3855a8048989a507ff8d470aee4d407589

URL: 
https://github.com/llvm/llvm-project/commit/9ecdbe3855a8048989a507ff8d470aee4d407589
DIFF: 
https://github.com/llvm/llvm-project/commit/9ecdbe3855a8048989a507ff8d470aee4d407589.diff

LOG: [clang][dataflow] Rename `AggregateStorageLocation` to 
`RecordStorageLocation` and `StructValue` to `RecordValue`.

- Both of these constructs are used to represent structs, classes, and unions;
  Clang uses the collective term "record" for these.

- The term "aggregate" in `AggregateStorageLocation` implies that, at some
  point, the intention may have been to use it also for arrays, but it don't
  think it's possible to use it for arrays. Records and arrays are very
  different and therefore need to be modeled differently. Records have a fixed
  set of named fields, which can have different type; arrays have a variable
  number of elements, but they all have the same type.

- Futhermore, "aggregate" has a very specific meaning in C++
  (https://en.cppreference.com/w/cpp/language/aggregate_initialization).
  Aggregates of class type may not have any user-declared or inherited
  constructors, no private or protected non-static data members, no virtual
  member functions, and so on, but we use `AggregateStorageLocations` to model 
all objects of class type.

In addition, for consistency, we also rename the following:

- `getAggregateLoc()` (in `RecordValue`, formerly known as `StructValue`) to
  simply `getLoc()`.

- `refreshStructValue()` to `refreshRecordValue()`

We keep the old names around as deprecated synonyms to enable clients to be 
migrated to the new names.

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D156788

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/include/clang/Analysis/FlowSensitive/RecordOps.h
clang/include/clang/Analysis/FlowSensitive/StorageLocation.h
clang/include/clang/Analysis/FlowSensitive/Value.h
clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/DebugSupport.cpp
clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
clang/lib/Analysis/FlowSensitive/RecordOps.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp
clang/unittests/Analysis/FlowSensitive/TestingSupport.h
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index 7ac2ff3102adcd..f812c01d42040b 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -76,7 +76,7 @@ class Environment {
 virtual ComparisonResult compare(QualType Type, const Value &Val1,
  const Environment &Env1, const Value 
&Val2,
  const Environment &Env2) {
-  // FIXME: Consider adding QualType to StructValue and removing the Type
+  // FIXME: Consider adding QualType to RecordValue and removing the Type
   // argument here.
   return ComparisonResult::Unknown;
 }
@@ -290,7 +290,7 @@ class Environment {
   /// Returns the storage location assigned to the `this` pointee in the
   /// environment or null if the `this` pointee has no assigned storage 
location
   /// in the environment.
-  AggregateStorageLocation *getThisPointeeStorageLocation() const;
+  RecordStorageLocation *getThisPointeeStorageLocation() const;
 
   /// Returns the location of the result object for a record-type prvalue.
   ///
@@ -315,7 +315,7 @@ class Environment {
   ///
   /// Requirements:
   ///  `E` must be a prvalue of record type.
-  AggregateStorageLocation &getResultObjectLocation(const Expr &RecordPRValue);
+  RecordStorageLocation &getResultObjectLocation(const Expr &RecordPRValue);
 
   /// Returns the return value of the current function. This can be null if:
   /// - The function has a void return type
@@ -375,8 +375,8 @@ class Environment {
   /// non-pointer/non-reference type.
   ///
   /// If `Type` is a class, struct, or union type, calls `setValue()` to
-  /// associate the `StructValue` with its storage location
-  /// (`StructValue::getAggregateLoc()`).
+  /// associate the `RecordValue` with its storage location
+  /// (`RecordValue::getLoc()`).
   ///
   /// I

[clang] e6cd409 - [clang][dataflow] In `ControlFlowContext`, handle `Decl` by reference instead of pointer.

2023-08-02 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-08-03T06:59:29Z
New Revision: e6cd409fc6396cb13c59b4a5190abc4b856f22a5

URL: 
https://github.com/llvm/llvm-project/commit/e6cd409fc6396cb13c59b4a5190abc4b856f22a5
DIFF: 
https://github.com/llvm/llvm-project/commit/e6cd409fc6396cb13c59b4a5190abc4b856f22a5.diff

LOG: [clang][dataflow] In `ControlFlowContext`, handle `Decl` by reference 
instead of pointer.

`build()` guarantees that we'll always have a `Decl`, so we can simplify the 
code.

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D156859

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
clang/lib/Analysis/FlowSensitive/Logger.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h 
b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
index bb36ed237c1e34..a45bb0635a2f36 100644
--- a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
+++ b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
@@ -48,7 +48,7 @@ class ControlFlowContext {
 
   /// Returns the `Decl` containing the statement used to construct the CFG, if
   /// available.
-  const Decl *getDecl() const { return ContainingDecl; }
+  const Decl &getDecl() const { return ContainingDecl; }
 
   /// Returns the CFG that is stored in this context.
   const CFG &getCFG() const { return *Cfg; }
@@ -64,9 +64,7 @@ class ControlFlowContext {
   }
 
 private:
-  // FIXME: Once the deprecated `build` method is removed, mark `D` as "must 
not
-  // be null" and add an assertion.
-  ControlFlowContext(const Decl *D, std::unique_ptr Cfg,
+  ControlFlowContext(const Decl &D, std::unique_ptr Cfg,
  llvm::DenseMap 
StmtToBlock,
  llvm::BitVector BlockReachable)
   : ContainingDecl(D), Cfg(std::move(Cfg)),
@@ -74,7 +72,7 @@ class ControlFlowContext {
 BlockReachable(std::move(BlockReachable)) {}
 
   /// The `Decl` containing the statement used to construct the CFG.
-  const Decl *ContainingDecl;
+  const Decl &ContainingDecl;
   std::unique_ptr Cfg;
   llvm::DenseMap StmtToBlock;
   llvm::BitVector BlockReachable;

diff  --git a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp 
b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
index c80525dc4f34f2..d5e0b443caf301 100644
--- a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
@@ -105,7 +105,7 @@ ControlFlowContext::build(const Decl &D, Stmt &S, 
ASTContext &C) {
 
   llvm::BitVector BlockReachable = findReachableBlocks(*Cfg);
 
-  return ControlFlowContext(&D, std::move(Cfg), std::move(StmtToBlock),
+  return ControlFlowContext(D, std::move(Cfg), std::move(StmtToBlock),
 std::move(BlockReachable));
 }
 

diff  --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp 
b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
index 9ec0160b1e3fe4..b1bfe10db20243 100644
--- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
+++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
@@ -166,15 +166,14 @@ class HTMLLogger : public Logger {
 this->CFG = &CFG;
 *OS << llvm::StringRef(HTMLLogger_html).split("").first;
 
-if (const auto *D = CFG.getDecl()) {
-  const auto &SM = A.getASTContext().getSourceManager();
-  *OS << "";
-  if (const auto *ND = dyn_cast(D))
-*OS << ND->getNameAsString() << " at ";
-  *OS << SM.getFilename(D->getLocation()) << ":"
-  << SM.getSpellingLineNumber(D->getLocation());
-  *OS << "\n";
-};
+const auto &D = CFG.getDecl();
+const auto &SM = A.getASTContext().getSourceManager();
+*OS << "";
+if (const auto *ND = dyn_cast(&D))
+  *OS << ND->getNameAsString() << " at ";
+*OS << SM.getFilename(D.getLocation()) << ":"
+<< SM.getSpellingLineNumber(D.getLocation());
+*OS << "\n";
 
 *OS << "" << HTMLLogger_css << "\n";
 *OS << "" << HTMLLogger_js << "\n";
@@ -307,9 +306,7 @@ class HTMLLogger : public Logger {
   // tokens are associated with, and even which BB element (so that clicking
   // can select the right element).
   void writeCode() {
-if (!CFG->getDecl())
-  return;
-const auto &AST = CFG->getDecl()->getASTContext();
+const auto &AST = CFG->getDecl().getASTContext();
 bool Invalid = false;
 
 // Extract the source code from the original file.
@@ -317,7 +314,7 @@ class HTMLLogger : public Logger {
 // indentation to worry about), but we need the boundaries of particular
 // AST nodes and the printer doesn't provide this.
 auto Range = clang::Lexer::makeFileChar

[clang] 880f306 - [clang][dataflow] Add a test for a struct that is directly self-referential through a reference.

2023-07-04 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-04T12:06:13Z
New Revision: 880f306226fcb97d85d422480954eb8765ff31c7

URL: 
https://github.com/llvm/llvm-project/commit/880f306226fcb97d85d422480954eb8765ff31c7
DIFF: 
https://github.com/llvm/llvm-project/commit/880f306226fcb97d85d422480954eb8765ff31c7.diff

LOG: [clang][dataflow] Add a test for a struct that is directly 
self-referential through a reference.

The ongoing migration to strict handling of value
categories (see https://discourse.llvm.org/t/70086) will change the way we
handle fields of reference type, and I want to put a test in place that makes
sure we continue to handle this special case correctly.

Depends On D154420

Reviewed By: gribozavr2, xazax.hun

Differential Revision: https://reviews.llvm.org/D154421

Added: 


Modified: 
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index f7210d29d06cc9..2ccd3e82baadc9 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -656,6 +656,30 @@ TEST(TransferTest, SelfReferentialPointerVarDecl) {
   });
 }
 
+TEST(TransferTest, DirectlySelfReferentialReference) {
+  std::string Code = R"(
+struct target {
+  target() {
+(void)0;
+// [[p]]
+  }
+  target &self = *this;
+};
+  )";
+  runDataflow(
+  Code,
+  [](const llvm::StringMap> &Results,
+ ASTContext &ASTCtx) {
+const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+const ValueDecl *SelfDecl = findValueDecl(ASTCtx, "self");
+
+auto *ThisLoc = Env.getThisPointeeStorageLocation();
+auto *RefVal =
+cast(Env.getValue(ThisLoc->getChild(*SelfDecl)));
+ASSERT_EQ(&RefVal->getReferentLoc(), ThisLoc);
+  });
+}
+
 TEST(TransferTest, MultipleVarsDecl) {
   std::string Code = R"(
 void target() {



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 1e7329c - [clang][dataflow] Model variables / fields / funcs used in default initializers.

2023-07-04 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-04T12:06:10Z
New Revision: 1e7329cd79c53165f113edfe6a2ff06d12899632

URL: 
https://github.com/llvm/llvm-project/commit/1e7329cd79c53165f113edfe6a2ff06d12899632
DIFF: 
https://github.com/llvm/llvm-project/commit/1e7329cd79c53165f113edfe6a2ff06d12899632.diff

LOG: [clang][dataflow] Model variables / fields / funcs used in default 
initializers.

The newly added test fails without the other changes in this patch.

Reviewed By: sammccall, gribozavr2

Differential Revision: https://reviews.llvm.org/D154420

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index 689f8abb51c8e0..4a11c09a44f63b 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -194,6 +194,8 @@ getFieldsGlobalsAndFuncs(const Stmt &S,
   for (auto *Child : S.children())
 if (Child != nullptr)
   getFieldsGlobalsAndFuncs(*Child, Fields, Vars, Funcs);
+  if (const auto *DefaultInit = dyn_cast(&S))
+getFieldsGlobalsAndFuncs(*DefaultInit->getExpr(), Fields, Vars, Funcs);
 
   if (auto *DS = dyn_cast(&S)) {
 if (DS->isSingleDecl())

diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 210b85f7ae8d67..f7210d29d06cc9 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -5547,4 +5547,40 @@ TEST(TransferTest, AnonymousStructWithInitializer) {
   });
 }
 
+TEST(TransferTest, AnonymousStructWithReferenceField) {
+  std::string Code = R"(
+int global_i = 0;
+struct target {
+  target() {
+(void)0;
+// [[p]]
+  }
+  struct {
+int &i = global_i;
+  };
+};
+  )";
+  runDataflow(
+  Code,
+  [](const llvm::StringMap> &Results,
+ ASTContext &ASTCtx) {
+const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+const ValueDecl *GlobalIDecl = findValueDecl(ASTCtx, "global_i");
+const ValueDecl *IDecl = findValueDecl(ASTCtx, "i");
+const IndirectFieldDecl *IndirectField =
+findIndirectFieldDecl(ASTCtx, "i");
+
+auto *ThisLoc =
+
cast(Env.getThisPointeeStorageLocation());
+auto &AnonStruct = cast(ThisLoc->getChild(
+*cast(IndirectField->chain().front(;
+
+auto *RefVal =
+cast(Env.getValue(AnonStruct.getChild(*IDecl)));
+
+ASSERT_EQ(&RefVal->getReferentLoc(),
+  Env.getStorageLocation(*GlobalIDecl));
+  });
+}
+
 } // namespace



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] d0be47c - [clang][dataflow] Make `runDataflowReturnError()` a non-template function.

2023-07-04 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-04T12:44:49Z
New Revision: d0be47c51cfdb8b94eb20279c02e8e2875380919

URL: 
https://github.com/llvm/llvm-project/commit/d0be47c51cfdb8b94eb20279c02e8e2875380919
DIFF: 
https://github.com/llvm/llvm-project/commit/d0be47c51cfdb8b94eb20279c02e8e2875380919.diff

LOG: [clang][dataflow] Make `runDataflowReturnError()` a non-template function.

It turns out this didn't need to be a template at all.

Likewise, change callers to they're non-template functions.

Also, correct / clarify some comments in RecordOps.h.

This is in response to post-commit comments on https://reviews.llvm.org/D153006.

Reviewed By: gribozavr2

Differential Revision: https://reviews.llvm.org/D154339

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/RecordOps.h
clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp
clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
clang/unittests/Analysis/FlowSensitive/TestingSupport.h
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/RecordOps.h 
b/clang/include/clang/Analysis/FlowSensitive/RecordOps.h
index f5a0a5a501c119..c9c302b9199bf2 100644
--- a/clang/include/clang/Analysis/FlowSensitive/RecordOps.h
+++ b/clang/include/clang/Analysis/FlowSensitive/RecordOps.h
@@ -23,7 +23,7 @@ namespace dataflow {
 ///
 /// This performs a deep copy, i.e. it copies every field and recurses on
 /// fields of record type. It also copies properties from the `StructValue`
-/// associated with `Dst` to the `StructValue` associated with `Src` (if these
+/// associated with `Src` to the `StructValue` associated with `Dst` (if these
 /// `StructValue`s exist).
 ///
 /// If there is a `StructValue` associated with `Dst` in the environment, this
@@ -52,6 +52,11 @@ void copyRecord(AggregateStorageLocation &Src, 
AggregateStorageLocation &Dst,
 /// refer to the same storage location. If `StructValue`s are associated with
 /// `Loc1` and `Loc2`, it also compares the properties on those `StructValue`s.
 ///
+/// Note on how to interpret the result:
+/// - If this returns true, the records are guaranteed to be equal at runtime.
+/// - If this returns false, the records may still be equal at runtime; our
+///   analysis merely cannot guarantee that they will be equal.
+///
 /// Requirements:
 ///
 ///  `Src` and `Dst` must have the same canonical unqualified type.

diff  --git a/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp
index a89011e423cd27..1f5fce1f2dd467 100644
--- a/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp
@@ -16,14 +16,18 @@ namespace dataflow {
 namespace test {
 namespace {
 
-template 
-void runDataflow(llvm::StringRef Code, VerifyResultsT VerifyResults,
- LangStandard::Kind Std = LangStandard::lang_cxx17,
- llvm::StringRef TargetFun = "target") {
+void runDataflow(
+llvm::StringRef Code,
+std::function<
+void(const llvm::StringMap> &,
+ ASTContext &)>
+VerifyResults,
+LangStandard::Kind Std = LangStandard::lang_cxx17,
+llvm::StringRef TargetFun = "target") {
   ASSERT_THAT_ERROR(
-  runDataflowReturnError(Code, VerifyResults,
- DataflowAnalysisOptions{BuiltinOptions{}}, Std,
- TargetFun),
+  checkDataflowWithNoopAnalysis(Code, VerifyResults,
+DataflowAnalysisOptions{BuiltinOptions{}},
+Std, TargetFun),
   llvm::Succeeded());
 }
 

diff  --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp 
b/clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
index a88b8d88c74c07..72bdfee26fe7f3 100644
--- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
@@ -153,6 +153,43 @@ test::buildStatementToAnnotationMapping(const FunctionDecl 
*Func,
   return Result;
 }
 
+llvm::Error test::checkDataflowWithNoopAnalysis(
+llvm::StringRef Code,
+std::function<
+void(const llvm::StringMap> &,
+ ASTContext &)>
+VerifyResults,
+DataflowAnalysisOptions Options, LangStandard::Kind Std,
+llvm::StringRef TargetFun) {
+  using ast_matchers::hasName;
+  llvm::SmallVector ASTBuildArgs = {
+  // -fnodelayed-template-parsing is the default everywhere but on Windows.
+  // Set it explicitly so that tests behave the same on Windows as on other
+  // platforms.
+  "-fsyntax-only", "-fno-delayed-template-parsing",
+  "-std=" +
+  std::string(LangStandard::getLangStandardForKind(Std).getName())};
+  AnalysisInputs AI(
+  Code, hasName(TargetFun),
+  [UseBuiltinModel = Options.BuiltinOpts.has

[clang] ca01be5 - [clang][dataflow] Bug fix: `BuiltinFnToFnPtr` cast does not produce a pointer.

2023-07-05 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-06T06:56:02Z
New Revision: ca01be54c1e94c552eceb00fc21b4363fae63d6c

URL: 
https://github.com/llvm/llvm-project/commit/ca01be54c1e94c552eceb00fc21b4363fae63d6c
DIFF: 
https://github.com/llvm/llvm-project/commit/ca01be54c1e94c552eceb00fc21b4363fae63d6c.diff

LOG: [clang][dataflow] Bug fix: `BuiltinFnToFnPtr` cast does not produce a 
pointer.

See comments in the code for details.

Reviewed By: xazax.hun

Differential Revision: https://reviews.llvm.org/D154479

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index 5ad176dc1cdbe9..d69e0f5a5e1030 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -419,8 +419,7 @@ class TransferVisitor : public 
ConstStmtVisitor {
   // FIXME: Implement pointers to members. For now, don't associate a value
   // with this expression.
   break;
-case CK_FunctionToPointerDecay:
-case CK_BuiltinFnToFnPtr: {
+case CK_FunctionToPointerDecay: {
   StorageLocation *PointeeLoc =
   Env.getStorageLocation(*SubExpr, SkipPast::Reference);
   if (PointeeLoc == nullptr)
@@ -432,6 +431,12 @@ class TransferVisitor : public 
ConstStmtVisitor {
   Env.setValue(PointerLoc, PointerVal);
   break;
 }
+case CK_BuiltinFnToFnPtr:
+  // Despite its name, the result type of `BuiltinFnToFnPtr` is a function,
+  // not a function pointer. In addition, builtin functions can only be
+  // called directly; it is not legal to take their address. We therefore
+  // don't need to create a value or storage location for them.
+  break;
 default:
   break;
 }

diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 3f99ff5652ce28..83ea176034c0d7 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -5480,8 +5480,8 @@ TEST(TransferTest, FunctionToPointerDecayHasValue) {
   });
 }
 
-// Check that the pointer that a builtin function decays to is associated with
-// a value.
+// Check that a builtin function is not associated with a value. (It's only
+// possible to call builtin functions directly, not take their address.)
 TEST(TransferTest, BuiltinFunctionModeled) {
   std::string Code = R"(
 void target() {
@@ -5509,7 +5509,7 @@ TEST(TransferTest, BuiltinFunctionModeled) {
   ASTCtx));
 
 ASSERT_THAT(ImplicitCast, NotNull());
-EXPECT_THAT(Env.getValueStrict(*ImplicitCast), NotNull());
+EXPECT_THAT(Env.getValueStrict(*ImplicitCast), IsNull());
   });
 }
 



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] e8a1560 - [clang][dataflow] Various changes to handling of modeled fields.

2023-07-09 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-10T06:45:53Z
New Revision: e8a1560d1de9514d3f1631388fe966476778e540

URL: 
https://github.com/llvm/llvm-project/commit/e8a1560d1de9514d3f1631388fe966476778e540
DIFF: 
https://github.com/llvm/llvm-project/commit/e8a1560d1de9514d3f1631388fe966476778e540.diff

LOG: [clang][dataflow] Various changes to handling of modeled fields.

- Rename `getReferencedFields()` to `getModeledFields()`. Move the logic that
  returns all object fields when doing a context-sensitive analysis to here from
  `DataflowAnalysisContext::createStorageLocation()`. I think all callers of
  the previous `getReferencedFields()` should use this logic; the fact that they
  were not doing so looks like a bug.

- Make `getModeledFields()` public. I have an upcoming patch that will need to
  use this function from Transfer.cpp, and there doesn't seem to be any reason
  why this function should not be public.

- Use a `SmallSetVector` to get deterministic iteration order. I have a pending
  patch where I'm getting flaky tests because
  `Environment::createValueUnlessSelfReferential()` is non-deterministically
  populating different fields depending on the iteration order. This change
  fixes those flaky tests.

Reviewed By: gribozavr2

Differential Revision: https://reviews.llvm.org/D154586

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

Removed: 




diff  --git 
a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
index 2a31a3477e8ceb..e5c325b876bd7a 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
@@ -51,8 +51,12 @@ class Logger;
 const Expr &ignoreCFGOmittedNodes(const Expr &E);
 const Stmt &ignoreCFGOmittedNodes(const Stmt &S);
 
+/// A set of `FieldDecl *`. Use `SmallSetVector` to guarantee deterministic
+/// iteration order.
+using FieldSet = llvm::SmallSetVector;
+
 /// Returns the set of all fields in the type.
-llvm::DenseSet getObjectFields(QualType Type);
+FieldSet getObjectFields(QualType Type);
 
 struct ContextSensitiveOptions {
   /// The maximum depth to analyze. A value of zero is equivalent to disabling
@@ -181,6 +185,10 @@ class DataflowAnalysisContext {
   /// been stored in flow conditions.
   Solver::Result querySolver(llvm::SetVector Constraints);
 
+  /// Returns the fields of `Type`, limited to the set of fields modeled by 
this
+  /// context.
+  FieldSet getModeledFields(QualType Type);
+
 private:
   friend class Environment;
 
@@ -196,11 +204,7 @@ class DataflowAnalysisContext {
   };
 
   // Extends the set of modeled field declarations.
-  void addModeledFields(const llvm::DenseSet &Fields);
-
-  /// Returns the fields of `Type`, limited to the set of fields modeled by 
this
-  /// context.
-  llvm::DenseSet getReferencedFields(QualType Type);
+  void addModeledFields(const FieldSet &Fields);
 
   /// Adds all constraints of the flow condition identified by `Token` and all
   /// of its transitive dependencies to `Constraints`. `VisitedTokens` is used
@@ -257,7 +261,7 @@ class DataflowAnalysisContext {
   llvm::DenseMap FunctionContexts;
 
   // Fields modeled by environments covered by this context.
-  llvm::DenseSet ModeledFields;
+  FieldSet ModeledFields;
 
   std::unique_ptr LogOwner; // If created via flags.
 };

diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
index a807ef8209be85..b0c1014e3c975e 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
@@ -40,31 +40,28 @@ static llvm::cl::opt DataflowLog(
 namespace clang {
 namespace dataflow {
 
-void DataflowAnalysisContext::addModeledFields(
-const llvm::DenseSet &Fields) {
-  llvm::set_union(ModeledFields, Fields);
+FieldSet DataflowAnalysisContext::getModeledFields(QualType Type) {
+  // During context-sensitive analysis, a struct may be allocated in one
+  // function, but its field accessed in a function lower in the stack than
+  // the allocation. Since we only collect fields used in the function where
+  // the allocation occurs, we can't apply that filter when performing
+  // context-sensitive analysis. But, this only applies to storage locations,
+  // since field access it not allowed to fail. In contrast, field *values*
+  // don't need this allowance, since the API allows for uninitialized fields.
+  if (Opts.ContextSensitiveOpts)
+return getObjectFields(Type);
+
+  return llvm::set_intersection(getObjectFields(Type), ModeledFields);
 }
 
-llvm::DenseSet
-DataflowAnalysis

[clang] f653d14 - [clang][dataflow] Various refactorings to UncheckedOptionalAccessModel.

2023-07-09 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-10T06:45:55Z
New Revision: f653d14065a362c98114082c4e9a3b1ede7a90f5

URL: 
https://github.com/llvm/llvm-project/commit/f653d14065a362c98114082c4e9a3b1ede7a90f5
DIFF: 
https://github.com/llvm/llvm-project/commit/f653d14065a362c98114082c4e9a3b1ede7a90f5.diff

LOG: [clang][dataflow] Various refactorings to UncheckedOptionalAccessModel.

These are intended to ease an upcoming change that will eliminate the 
duplication between `AggregateStorageLocation` and `StructValue` (see 
https://discourse.llvm.org/t/70086 for details), but many of the changes also 
have value in their own right.

Depends On D154586

Reviewed By: ymandel, gribozavr2

Differential Revision: https://reviews.llvm.org/D154597

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp

Removed: 




diff  --git 
a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp 
b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
index a239d54674e96c..91aa9d11e751cd 100644
--- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
@@ -255,12 +255,22 @@ void setHasValue(Value &OptionalVal, BoolValue 
&HasValueVal) {
 
 /// Creates a symbolic value for an `optional` value using `HasValueVal` as the
 /// symbolic value of its "has_value" property.
-StructValue &createOptionalValue(Environment &Env, BoolValue &HasValueVal) {
+StructValue &createOptionalValue(BoolValue &HasValueVal, Environment &Env) {
   auto &OptionalVal = Env.create();
   setHasValue(OptionalVal, HasValueVal);
   return OptionalVal;
 }
 
+/// Creates a symbolic value for an `optional` value at an existing storage
+/// location. Uses `HasValueVal` as the symbolic value of the "has_value"
+/// property.
+StructValue &createOptionalValue(AggregateStorageLocation &Loc,
+ BoolValue &HasValueVal, Environment &Env) {
+  StructValue &OptionalVal = createOptionalValue(HasValueVal, Env);
+  Env.setValue(Loc, OptionalVal);
+  return OptionalVal;
+}
+
 /// Returns the symbolic value that represents the "has_value" property of the
 /// optional value `OptionalVal`. Returns null if `OptionalVal` is null.
 BoolValue *getHasValue(Environment &Env, Value *OptionalVal) {
@@ -422,15 +432,6 @@ bool isNonEmptyOptional(const Value &OptionalVal, const 
Environment &Env) {
   return HasValueVal != nullptr && Env.flowConditionImplies(*HasValueVal);
 }
 
-StorageLocation *maybeSkipPointer(StorageLocation *Loc,
-  const Environment &Env) {
-  if (Loc == nullptr)
-return nullptr;
-  if (auto *Val = dyn_cast_or_null(Env.getValue(*Loc)))
-return &Val->getPointeeLoc();
-  return Loc;
-}
-
 Value *getValueBehindPossiblePointer(const Expr &E, const Environment &Env) {
   Value *Val = Env.getValue(E, SkipPast::Reference);
   if (auto *PointerVal = dyn_cast_or_null(Val))
@@ -467,7 +468,7 @@ void transferMakeOptionalCall(const CallExpr *E,
   auto &Loc = State.Env.createStorageLocation(*E);
   State.Env.setStorageLocation(*E, Loc);
   State.Env.setValue(
-  Loc, createOptionalValue(State.Env, 
State.Env.getBoolLiteralValue(true)));
+  Loc, createOptionalValue(State.Env.getBoolLiteralValue(true), 
State.Env));
 }
 
 void transferOptionalHasValueCall(const CXXMemberCallExpr *CallExpr,
@@ -544,15 +545,12 @@ void transferCallReturningOptional(const CallExpr *E,
   auto &Loc = State.Env.createStorageLocation(*E);
   State.Env.setStorageLocation(*E, Loc);
   State.Env.setValue(
-  Loc, createOptionalValue(State.Env, State.Env.makeAtomicBoolValue()));
+  Loc, createOptionalValue(State.Env.makeAtomicBoolValue(), State.Env));
 }
 
-void assignOptionalValue(const Expr &E, Environment &Env,
- BoolValue &HasValueVal) {
-  if (auto *OptionalLoc = maybeSkipPointer(
-  Env.getStorageLocation(E, SkipPast::Reference), Env)) {
-Env.setValue(*OptionalLoc, createOptionalValue(Env, HasValueVal));
-  }
+void constructOptionalValue(const Expr &E, Environment &Env,
+BoolValue &HasValueVal) {
+  Env.setValueStrict(E, createOptionalValue(HasValueVal, Env));
 }
 
 /// Returns a symbolic value for the "has_value" property of an `optional`
@@ -590,25 +588,23 @@ void transferValueOrConversionConstructor(
 LatticeTransferState &State) {
   assert(E->getNumArgs() > 0);
 
-  assignOptionalValue(*E, State.Env,
-  valueOrConversionHasValue(*E->getConstructor(),
-*E->getArg(0), MatchRes,
-State));
+  constructOptionalValue(*E, State.Env,
+ valueOrConversionHasValue(*E->getConstructor(),
+   *E->getArg(0), MatchRes,
+ 

[clang] 8bc13c8 - [clang][dataflow] Add `AnalysisInputs::withSolverFactory()`.

2023-07-10 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-10T13:43:13Z
New Revision: 8bc13c884727f0b9be876303d654dd1eda300dc3

URL: 
https://github.com/llvm/llvm-project/commit/8bc13c884727f0b9be876303d654dd1eda300dc3
DIFF: 
https://github.com/llvm/llvm-project/commit/8bc13c884727f0b9be876303d654dd1eda300dc3.diff

LOG: [clang][dataflow] Add `AnalysisInputs::withSolverFactory()`.

Reviewed By: sammccall

Differential Revision: https://reviews.llvm.org/D154833

Added: 


Modified: 
clang/unittests/Analysis/FlowSensitive/TestingSupport.h

Removed: 




diff  --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h 
b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
index 93991d87d77f20..1568fc9a200e47 100644
--- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
+++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
@@ -143,6 +143,12 @@ template  struct AnalysisInputs {
 BuiltinOptions = std::move(Options);
 return std::move(*this);
   }
+  AnalysisInputs &&
+  withSolverFactory(std::function()> Factory) && {
+assert(Factory);
+SolverFactory = std::move(Factory);
+return std::move(*this);
+  }
 
   /// Required. Input code that is analyzed.
   llvm::StringRef Code;
@@ -170,6 +176,10 @@ template  struct AnalysisInputs {
   tooling::FileContentMappings ASTBuildVirtualMappedFiles = {};
   /// Configuration options for the built-in model.
   DataflowAnalysisContext::Options BuiltinOptions;
+  /// SAT solver factory.
+  std::function()> SolverFactory = [] {
+return std::make_unique();
+  };
 };
 
 /// Returns assertions based on annotations that are present after statements 
in
@@ -248,7 +258,7 @@ checkDataflow(AnalysisInputs AI,
 auto &CFCtx = *MaybeCFCtx;
 
 // Initialize states for running dataflow analysis.
-DataflowAnalysisContext DACtx(std::make_unique(),
+DataflowAnalysisContext DACtx(AI.SolverFactory(),
   {/*Opts=*/AI.BuiltinOptions});
 Environment InitEnv(DACtx, *Target);
 auto Analysis = AI.MakeAnalysis(Context, InitEnv);



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] e53da3e - [clang][dataflow][NFC] Expand a comment.

2023-07-10 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-11T06:32:08Z
New Revision: e53da3eab42e6efd448c1c60c14668e1eb3d907c

URL: 
https://github.com/llvm/llvm-project/commit/e53da3eab42e6efd448c1c60c14668e1eb3d907c
DIFF: 
https://github.com/llvm/llvm-project/commit/e53da3eab42e6efd448c1c60c14668e1eb3d907c.diff

LOG: [clang][dataflow][NFC] Expand a comment.

Reviewed By: sammccall

Differential Revision: https://reviews.llvm.org/D154834

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index c3de50894c9ede..73e20705cff501 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -123,6 +123,9 @@ static Value *mergeDistinctValues(QualType Type, Value 
&Val1,
   // returns false to avoid storing unneeded values in `DACtx`.
   // FIXME: Creating the value based on the type alone creates misshapen values
   // for lvalues, since the type does not reflect the need for 
`ReferenceValue`.
+  // This issue will be resolved when `ReferenceValue` is eliminated as part
+  // of the ongoing migration to strict handling of value categories (see
+  // https://discourse.llvm.org/t/70086 for details).
   if (Value *MergedVal = MergedEnv.createValue(Type))
 if (Model.merge(Type, Val1, Env1, Val2, Env2, *MergedVal, MergedEnv))
   return MergedVal;



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 2902ea3 - [clang][dataflow] Introduce `getFieldValue()` test helpers.

2023-07-11 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-12T04:52:23Z
New Revision: 2902ea3d817bf381817ff76228c3212f4dc87d47

URL: 
https://github.com/llvm/llvm-project/commit/2902ea3d817bf381817ff76228c3212f4dc87d47
DIFF: 
https://github.com/llvm/llvm-project/commit/2902ea3d817bf381817ff76228c3212f4dc87d47.diff

LOG: [clang][dataflow] Introduce `getFieldValue()` test helpers.

These insulate tests against changes to the `getChild()` functions of 
`AggregateStorageLocation` and `StructValue` that will happen as part of the 
migration to strict handling of value categories (see 
https://discourse.llvm.org/t/70086 for details):

- `AggregateStorageLocation::getChild()` will soon return a `StorageLocation *`
  instead of a `StorageLocation &`. When this happens, `getFieldValue()` will be
  changed to return null if `AggregateStorageLocation::getChild()` returns null;
  test code will not need to change as it should already be checking whether the
  return value of `getFieldValue()` is null.

- `StructValue::getChild()` will soon return a `StorageLocation *` instead of a
  `Value *`. When this happens, `getFieldValue()` will be changed to look up the
  `Value *` in the `Environment`. Again, test code will not need to change.

The test helpers will continue to serve a useful purpose once the API changes 
are complete, so the intent is to leave them in place.

This patch changes DataflowEnvironmentTest.cpp and RecordOpsTest.cpp to use the 
test helpers. TransferTest.cpp will be changed in an upcoming patch to help 
keep patch sizes manageable for review.

Depends On D154934

Reviewed By: ymandel, xazax.hun, gribozavr2

Differential Revision: https://reviews.llvm.org/D154935

Added: 


Modified: 
clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp
clang/unittests/Analysis/FlowSensitive/TestingSupport.h

Removed: 




diff  --git 
a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
index 1c78dd380c7742..17c0f7b16c1c71 100644
--- a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
@@ -7,6 +7,7 @@
 
//===--===//
 
 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
+#include "TestingSupport.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
@@ -23,6 +24,7 @@ namespace {
 
 using namespace clang;
 using namespace dataflow;
+using ::clang::dataflow::test::getFieldValue;
 using ::testing::ElementsAre;
 using ::testing::NotNull;
 using ::testing::Pair;
@@ -89,14 +91,9 @@ TEST_F(EnvironmentTest, CreateValueRecursiveType) {
   // Verify that the struct and the field (`R`) with first appearance of the
   // type is created successfully.
   Environment Env(DAContext, *Fun);
-  Value *Val = Env.createValue(Ty);
-  ASSERT_NE(Val, nullptr);
-  StructValue *SVal = clang::dyn_cast(Val);
-  ASSERT_NE(SVal, nullptr);
-  Val = SVal->getChild(*R);
-  ASSERT_NE(Val, nullptr);
-  PointerValue *PV = clang::dyn_cast(Val);
-  EXPECT_NE(PV, nullptr);
+  StructValue *SVal = cast(Env.createValue(Ty));
+  PointerValue *PV = cast_or_null(getFieldValue(SVal, *R, Env));
+  EXPECT_THAT(PV, NotNull());
 }
 
 TEST_F(EnvironmentTest, InitGlobalVarsFun) {
@@ -175,8 +172,7 @@ TEST_F(EnvironmentTest, 
IncludeFieldsFromDefaultInitializers) {
   // constructor, even though it is not referenced directly in the constructor.
   Environment Env(DAContext, *Constructor);
   auto *Val = cast(Env.createValue(QTy));
-  ASSERT_THAT(Val, NotNull());
-  EXPECT_THAT(Val->getChild(*XDecl), NotNull());
+  EXPECT_THAT(getFieldValue(Val, *XDecl, Env), NotNull());
 }
 
 TEST_F(EnvironmentTest, InitGlobalVarsFieldFun) {
@@ -221,8 +217,7 @@ TEST_F(EnvironmentTest, InitGlobalVarsFieldFun) {
   const auto *GlobalLoc =
   cast(Env.getStorageLocation(*GlobalDecl));
   const auto *GlobalVal = cast(Env.getValue(*GlobalLoc));
-  const auto *BarVal = GlobalVal->getChild(*BarDecl);
-  ASSERT_THAT(BarVal, NotNull());
+  auto *BarVal = getFieldValue(GlobalVal, *BarDecl, Env);
   EXPECT_TRUE(isa(BarVal));
 }
 

diff  --git a/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp
index 1f5fce1f2dd467..dc81e9594b6914 100644
--- a/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp
@@ -63,12 +63,12 @@ TEST(RecordOpsTest, CopyRecord) {
 auto &Inner1 = cast(S1.getChild(*InnerDecl));
 auto &Inner2 = cast(S2.getChild(*InnerDecl));
 
-EXPECT_NE(Env.getValue(S1.getChild(*OuterIntDecl)),
-  Env.getValue(S2.getChild(*OuterIntDecl)));
+EXPECT

[clang] 103a0fc - [clang][dataflow] Use `getFieldValue()` in TransferTest.cpp.

2023-07-11 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-12T04:52:25Z
New Revision: 103a0fc0846050dd671e6485ab52491042f905c6

URL: 
https://github.com/llvm/llvm-project/commit/103a0fc0846050dd671e6485ab52491042f905c6
DIFF: 
https://github.com/llvm/llvm-project/commit/103a0fc0846050dd671e6485ab52491042f905c6.diff

LOG: [clang][dataflow] Use `getFieldValue()` in TransferTest.cpp.

For context, see https://reviews.llvm.org/D154935.

Depends On D154935

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D154949

Added: 


Modified: 
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index baadea57e43751..3ae3106bca4673 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -262,7 +262,8 @@ TEST(TransferTest, StructVarDecl) {
 cast(&FooLoc->getChild(*BarDecl));
 
 const auto *FooVal = cast(Env.getValue(*FooLoc));
-const auto *BarVal = cast(FooVal->getChild(*BarDecl));
+const auto *BarVal =
+cast(getFieldValue(FooVal, *BarDecl, Env));
 EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
   });
 }
@@ -310,7 +311,8 @@ TEST(TransferTest, StructVarDeclWithInit) {
 cast(&FooLoc->getChild(*BarDecl));
 
 const auto *FooVal = cast(Env.getValue(*FooLoc));
-const auto *BarVal = cast(FooVal->getChild(*BarDecl));
+const auto *BarVal =
+cast(getFieldValue(FooVal, *BarDecl, Env));
 EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
   });
 }
@@ -357,7 +359,8 @@ TEST(TransferTest, ClassVarDecl) {
 cast(&FooLoc->getChild(*BarDecl));
 
 const auto *FooVal = cast(Env.getValue(*FooLoc));
-const auto *BarVal = cast(FooVal->getChild(*BarDecl));
+const auto *BarVal =
+cast(getFieldValue(FooVal, *BarDecl, Env));
 EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
   });
 }
@@ -470,37 +473,37 @@ TEST(TransferTest, SelfReferentialReferenceVarDecl) {
 ASSERT_THAT(BazRefDecl, NotNull());
 ASSERT_THAT(BazPtrDecl, NotNull());
 
-const auto *FooLoc =
-cast(Env.getStorageLocation(*FooDecl));
-const auto *FooReferentVal = cast(Env.getValue(*FooLoc));
+const auto &FooLoc =
+*cast(Env.getStorageLocation(*FooDecl));
+const auto &FooReferentVal = *cast(Env.getValue(FooLoc));
 
-const auto *BarVal =
-cast(FooReferentVal->getChild(*BarDecl));
-const auto *BarReferentVal =
-cast(Env.getValue(BarVal->getReferentLoc()));
+const auto &BarVal =
+*cast(FooReferentVal.getChild(*BarDecl));
+const auto &BarReferentVal =
+*cast(Env.getValue(BarVal.getReferentLoc()));
 
-const auto *FooRefVal =
-cast(BarReferentVal->getChild(*FooRefDecl));
+const auto &FooRefVal =
+*cast(getFieldValue(&BarReferentVal, *FooRefDecl, 
Env));
 const auto &FooReferentLoc =
-cast(FooRefVal->getReferentLoc());
+cast(FooRefVal.getReferentLoc());
 EXPECT_THAT(Env.getValue(FooReferentLoc), NotNull());
-EXPECT_THAT(Env.getValue(FooReferentLoc.getChild(*BarDecl)), IsNull());
+EXPECT_THAT(getFieldValue(&FooReferentLoc, *BarDecl, Env), IsNull());
 
-const auto *FooPtrVal =
-cast(BarReferentVal->getChild(*FooPtrDecl));
+const auto &FooPtrVal =
+*cast(getFieldValue(&BarReferentVal, *FooPtrDecl, Env));
 const auto &FooPtrPointeeLoc =
-cast(FooPtrVal->getPointeeLoc());
+cast(FooPtrVal.getPointeeLoc());
 EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), NotNull());
-EXPECT_THAT(Env.getValue(FooPtrPointeeLoc.getChild(*BarDecl)), IsNull());
+EXPECT_THAT(getFieldValue(&FooPtrPointeeLoc, *BarDecl, Env), IsNull());
 
-const auto *BazRefVal =
-cast(BarReferentVal->getChild(*BazRefDecl));
-const StorageLocation &BazReferentLoc = BazRefVal->getReferentLoc();
+const auto &BazRefVal =
+*cast(getFieldValue(&BarReferentVal, *BazRefDecl, 
Env));
+const StorageLocation &BazReferentLoc = BazRefVal.getReferentLoc();
 EXPECT_THAT(Env.getValue(BazReferentLoc), NotNull());
 
-const auto *BazPtrVal =
-cast(BarReferentVal->getChild(*BazPtrDecl));
-const StorageLocation &BazPtrPointeeLoc = BazPtrVal->getPointeeLoc();
+const auto &BazPtrVal =
+*cast(getFieldValue(&BarReferentVal, *BazPtrDecl, Env));
+const StorageLocation &BazPtrPointeeLoc = BazPtrVal.getPointeeLoc();
 EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull());
   });
 }
@@ -630,35 +633,36 @@ TEST(TransferTest, SelfReferentialPointerVarDecl) {
 ASSERT_THAT(BazRefDecl, NotNull());
 ASSERT_THAT(BazPtrDecl, NotNull());
 
-const auto *FooLoc =
-cast(Env.getStorageLocation(*FooDecl));
-

[clang] 0014aab - [clang][dataflow] Use `IntegerValue` instead of `StructValue` in `ValueTest`.

2023-07-11 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-12T04:52:22Z
New Revision: 0014aab2d5882525c23130108e17fbbb5a2120f1

URL: 
https://github.com/llvm/llvm-project/commit/0014aab2d5882525c23130108e17fbbb5a2120f1
DIFF: 
https://github.com/llvm/llvm-project/commit/0014aab2d5882525c23130108e17fbbb5a2120f1.diff

LOG: [clang][dataflow] Use `IntegerValue` instead of `StructValue` in 
`ValueTest`.

Soon, it will no longer be possible to default-construct `StructValue`. For 
details, see https://discourse.llvm.org/t/70086.

For completeness, also add a test that `areEquivalentValues()` on different 
`IntegerValue`s returns false.

Reviewed By: xazax.hun, gribozavr2

Differential Revision: https://reviews.llvm.org/D154934

Added: 


Modified: 
clang/unittests/Analysis/FlowSensitive/ValueTest.cpp

Removed: 




diff  --git a/clang/unittests/Analysis/FlowSensitive/ValueTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/ValueTest.cpp
index 02f3adeaeda756..19ea7a04928f28 100644
--- a/clang/unittests/Analysis/FlowSensitive/ValueTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/ValueTest.cpp
@@ -19,10 +19,16 @@ using namespace clang;
 using namespace dataflow;
 
 TEST(ValueTest, EquivalenceReflexive) {
-  StructValue V;
+  IntegerValue V;
   EXPECT_TRUE(areEquivalentValues(V, V));
 }
 
+TEST(ValueTest, DifferentIntegerValuesNotEquivalent) {
+  IntegerValue V1;
+  IntegerValue V2;
+  EXPECT_FALSE(areEquivalentValues(V1, V2));
+}
+
 TEST(ValueTest, AliasedReferencesEquivalent) {
   auto L = ScalarStorageLocation(QualType());
   ReferenceValue V1(L);



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 1e9b4fc - [clang][dataflow] Various refactorings in TypeErasedDataflowAnalysisTest.cpp

2023-07-11 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-12T04:52:27Z
New Revision: 1e9b4fc1dcf27ae43477efe0329f738e4419871b

URL: 
https://github.com/llvm/llvm-project/commit/1e9b4fc1dcf27ae43477efe0329f738e4419871b
DIFF: 
https://github.com/llvm/llvm-project/commit/1e9b4fc1dcf27ae43477efe0329f738e4419871b.diff

LOG: [clang][dataflow] Various refactorings in 
TypeErasedDataflowAnalysisTest.cpp

These simplify the code in their own right, but they are also useful in that 
they minimize the number of changes that will need to be made when then API of 
`AggregateStorageLocation` and `StructValue` changes as part of the migration 
to strict handling of value categories (see https://discourse.llvm.org/t/70086).

Depends On D154949

Reviewed By: xazax.hun, gribozavr2

Differential Revision: https://reviews.llvm.org/D154952

Added: 


Modified: 
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp

Removed: 




diff  --git 
a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
index 473750ad7a6cb4..d811aed8fddd99 100644
--- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
@@ -370,6 +370,13 @@ TEST_F(NoreturnDestructorTest, 
ConditionalOperatorNestedBranchReturns) {
   // FIXME: Called functions at point `p` should contain only "foo".
 }
 
+StructValue &createNewStructValue(AggregateStorageLocation &Loc,
+  Environment &Env) {
+  auto &Val = *cast(Env.createValue(Loc.getType()));
+  Env.setValue(Loc, Val);
+  return Val;
+}
+
 // Models an analysis that uses flow conditions.
 class SpecialBoolAnalysis final
 : public DataflowAnalysis {
@@ -390,23 +397,18 @@ class SpecialBoolAnalysis final
 if (const auto *E = selectFirst(
 "call", match(cxxConstructExpr(HasSpecialBoolType).bind("call"), 
*S,
   getASTContext( {
-  auto &ConstructorVal = *Env.createValue(E->getType());
-  ConstructorVal.setProperty("is_set", Env.getBoolLiteralValue(false));
-  Env.setValue(*Env.getStorageLocation(*E, SkipPast::None), 
ConstructorVal);
+  cast(Env.getValueStrict(*E))
+  ->setProperty("is_set", Env.getBoolLiteralValue(false));
 } else if (const auto *E = selectFirst(
"call", 
match(cxxMemberCallExpr(callee(cxxMethodDecl(ofClass(

SpecialBoolRecordDecl
  .bind("call"),
  *S, getASTContext( {
-  auto *Object = E->getImplicitObjectArgument();
-  assert(Object != nullptr);
-
-  auto *ObjectLoc = getImplicitObjectLocation(*E, Env);
-  assert(ObjectLoc != nullptr);
+  auto &ObjectLoc =
+  *cast(getImplicitObjectLocation(*E, Env));
 
-  auto &ConstructorVal = *Env.createValue(Object->getType());
-  ConstructorVal.setProperty("is_set", Env.getBoolLiteralValue(true));
-  Env.setValue(*ObjectLoc, ConstructorVal);
+  createNewStructValue(ObjectLoc, Env)
+  .setProperty("is_set", Env.getBoolLiteralValue(true));
 }
   }
 
@@ -551,21 +553,19 @@ class OptionalIntAnalysis final
 *S, getASTContext());
 if (const auto *E = selectFirst(
 "construct", Matches)) {
-  auto &ConstructorVal = *Env.createValue(E->getType());
-  ConstructorVal.setProperty("has_value", Env.getBoolLiteralValue(false));
-  Env.setValue(*Env.getStorageLocation(*E, SkipPast::None), 
ConstructorVal);
+  cast(Env.getValueStrict(*E))
+  ->setProperty("has_value", Env.getBoolLiteralValue(false));
 } else if (const auto *E =
selectFirst("operator", Matches)) {
   assert(E->getNumArgs() > 0);
   auto *Object = E->getArg(0);
   assert(Object != nullptr);
 
-  auto *ObjectLoc = Env.getStorageLocation(*Object, SkipPast::Reference);
-  assert(ObjectLoc != nullptr);
+  auto &ObjectLoc = *cast(
+  Env.getStorageLocation(*Object, SkipPast::Reference));
 
-  auto &ConstructorVal = *Env.createValue(Object->getType());
-  ConstructorVal.setProperty("has_value", Env.getBoolLiteralValue(true));
-  Env.setValue(*ObjectLoc, ConstructorVal);
+  createNewStructValue(ObjectLoc, Env)
+  .setProperty("has_value", Env.getBoolLiteralValue(true));
 }
   }
 
@@ -1227,9 +1227,7 @@ class TopAnalysis final : public 
DataflowAnalysis {
 match(callExpr(callee(functionDecl(hasName("makeTop".bind("top"),
   *S, getASTContext());
 if (const auto *E = selectFirst("top", Matches)) {
-  auto &Loc = Env.createStorageLocation(*E);
-  Env.setValue(Loc, Env.makeTopBoolValue());
-  Env.setStorageLocation(*E, Loc);
+  Env.setValueStrict(*E, Env.ma

[clang] b47bdcb - [clang][dataflow] Include fields initialized in an `InitListExpr` in `getModeledFields()`.

2023-07-11 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-12T04:52:29Z
New Revision: b47bdcbc7207aac617d3c35dfc029f79b0a46fd8

URL: 
https://github.com/llvm/llvm-project/commit/b47bdcbc7207aac617d3c35dfc029f79b0a46fd8
DIFF: 
https://github.com/llvm/llvm-project/commit/b47bdcbc7207aac617d3c35dfc029f79b0a46fd8.diff

LOG: [clang][dataflow] Include fields initialized in an `InitListExpr` in 
`getModeledFields()`.

Previously, we were including these fields only in the specific instance that 
was initialized by the `InitListExpr`, but not in other instances of the same 
type. This is inconsistent and error-prone.

Depends On D154952

Reviewed By: xazax.hun, gribozavr2

Differential Revision: https://reviews.llvm.org/D154961

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index 7c1d01ce816e2b..5bd2e5518a5463 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -644,6 +644,10 @@ getImplicitObjectLocation(const CXXMemberCallExpr &MCE, 
const Environment &Env);
 AggregateStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
 const Environment &Env);
 
+/// Returns the fields of `RD` that are initialized by an `InitListExpr`, in 
the
+/// order in which they appear in `InitListExpr::inits()`.
+std::vector getFieldsForInitListExpr(const RecordDecl *RD);
+
 } // namespace dataflow
 } // namespace clang
 

diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index 73e20705cff501..9b1fca41e911cc 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -215,6 +215,10 @@ getFieldsGlobalsAndFuncs(const Stmt &S, FieldSet &Fields,
 insertIfFunction(*VD, Funcs);
 if (const auto *FD = dyn_cast(VD))
   Fields.insert(FD);
+  } else if (auto *InitList = dyn_cast(&S)) {
+if (RecordDecl *RD = InitList->getType()->getAsRecordDecl())
+  for (const auto *FD : getFieldsForInitListExpr(RD))
+Fields.insert(FD);
   }
 }
 
@@ -958,5 +962,17 @@ AggregateStorageLocation *getBaseObjectLocation(const 
MemberExpr &ME,
   return cast(Loc);
 }
 
+std::vector getFieldsForInitListExpr(const RecordDecl *RD) {
+  // Unnamed bitfields are only used for padding and do not appear in
+  // `InitListExpr`'s inits. However, those fields do appear in `RecordDecl`'s
+  // field list, and we thus need to remove them before mapping inits to
+  // fields to avoid mapping inits to the wrongs fields.
+  std::vector Fields;
+  llvm::copy_if(
+  RD->fields(), std::back_inserter(Fields),
+  [](const FieldDecl *Field) { return !Field->isUnnamedBitfield(); });
+  return Fields;
+}
+
 } // namespace dataflow
 } // namespace clang

diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index ac971f69150f1e..e1a2606de81033 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -715,14 +715,8 @@ class TransferVisitor : public 
ConstStmtVisitor {
 Env.setValue(Loc, *Val);
 
 if (Type->isStructureOrClassType()) {
-  // Unnamed bitfields are only used for padding and are not appearing in
-  // `InitListExpr`'s inits. However, those fields do appear in 
RecordDecl's
-  // field list, and we thus need to remove them before mapping inits to
-  // fields to avoid mapping inits to the wrongs fields.
-  std::vector Fields;
-  llvm::copy_if(
-  Type->getAsRecordDecl()->fields(), std::back_inserter(Fields),
-  [](const FieldDecl *Field) { return !Field->isUnnamedBitfield(); });
+  std::vector Fields =
+  getFieldsForInitListExpr(Type->getAsRecordDecl());
   for (auto It : llvm::zip(Fields, S->inits())) {
 const FieldDecl *Field = std::get<0>(It);
 assert(Field != nullptr);

diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 3ae3106bca4673..254226fd6d3ee9 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -2833,6 +2833,7 @@ TEST(TransferTest, AggregateInitialization) {
 
 void target(int BarArg, int FooArg, int QuxArg) {
   B Quux{BarArg, {FooArg}, QuxArg};
+  B OtherB;
   /*[[p]]*/
 }
   )";
@@ -2849,6 +2850,7 @@ TEST(TransferTest, Ag

[clang] bd9b57d - [clang][dataflow] Fix initializing a reference field with an `InitListExpr`.

2023-07-11 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-12T04:52:30Z
New Revision: bd9b57de4ff7c65be0d69179232ba2d5fe832195

URL: 
https://github.com/llvm/llvm-project/commit/bd9b57de4ff7c65be0d69179232ba2d5fe832195
DIFF: 
https://github.com/llvm/llvm-project/commit/bd9b57de4ff7c65be0d69179232ba2d5fe832195.diff

LOG: [clang][dataflow] Fix initializing a reference field with an 
`InitListExpr`.

I added a test for this as the ongoing migration to strict handling of value 
categories (see https://discourse.llvm.org/t/70086) will change the code that 
handles this case. It turns out we already didn't handle this correctly, so I 
fixed the existing implementation.

Depends On D154961

Reviewed By: xazax.hun

Differential Revision: https://reviews.llvm.org/D154965

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index e1a2606de81033..4c97e81184bba3 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -717,14 +717,15 @@ class TransferVisitor : public 
ConstStmtVisitor {
 if (Type->isStructureOrClassType()) {
   std::vector Fields =
   getFieldsForInitListExpr(Type->getAsRecordDecl());
-  for (auto It : llvm::zip(Fields, S->inits())) {
-const FieldDecl *Field = std::get<0>(It);
+  for (auto [Field, Init] : llvm::zip(Fields, S->inits())) {
 assert(Field != nullptr);
-
-const Expr *Init = std::get<1>(It);
 assert(Init != nullptr);
 
-if (Value *InitVal = Env.getValue(*Init, SkipPast::None))
+if (Field->getType()->isReferenceType()) {
+  if (StorageLocation *Loc = Env.getStorageLocationStrict(*Init))
+cast(Val)->setChild(*Field,
+ Env.create(*Loc));
+} else if (Value *InitVal = Env.getValue(*Init, SkipPast::None))
   cast(Val)->setChild(*Field, *InitVal);
   }
 }

diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 254226fd6d3ee9..a89ff8e7bc5ab5 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -2912,6 +2912,34 @@ TEST(TransferTest, AggregateInitialization) {
   }
 }
 
+TEST(TransferTest, AggregateInitializationReferenceField) {
+  std::string Code = R"(
+struct S {
+  int &RefField;
+};
+
+void target(int i) {
+  S s = { i };
+  /*[[p]]*/
+}
+  )";
+  runDataflow(
+  Code,
+  [](const llvm::StringMap> &Results,
+ ASTContext &ASTCtx) {
+const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+
+const ValueDecl *RefFieldDecl = findValueDecl(ASTCtx, "RefField");
+
+auto &ILoc = getLocForDecl(ASTCtx, Env, "i");
+auto &SLoc = getLocForDecl(ASTCtx, Env, "s");
+
+auto &RefValue =
+*cast(getFieldValue(&SLoc, *RefFieldDecl, Env));
+EXPECT_EQ(&RefValue.getReferentLoc(), &ILoc);
+  });
+}
+
 TEST(TransferTest, AssignToUnionMember) {
   std::string Code = R"(
 union A {



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 4782597 - [clang][dataflow] Add a test for not explicitly initialized fields in aggregate initialization.

2023-07-17 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-17T07:26:08Z
New Revision: 4782597e3cd1b26cf8bd437e36fd6320f55d3d89

URL: 
https://github.com/llvm/llvm-project/commit/4782597e3cd1b26cf8bd437e36fd6320f55d3d89
DIFF: 
https://github.com/llvm/llvm-project/commit/4782597e3cd1b26cf8bd437e36fd6320f55d3d89.diff

LOG: [clang][dataflow] Add a test for not explicitly initialized fields in 
aggregate initialization.

Reviewed By: ymandel

Differential Revision: https://reviews.llvm.org/D155074

Added: 


Modified: 
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 5a5540cbaee3dc..e2800452ab6bdb 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -2944,6 +2944,39 @@ TEST(TransferTest, 
AggregateInitializationReferenceField) {
   });
 }
 
+TEST(TransferTest, AggregateInitialization_NotExplicitlyInitializedField) {
+  std::string Code = R"(
+struct S {
+  int i1;
+  int i2;
+};
+
+void target(int i) {
+  S s = { i };
+  /*[[p]]*/
+}
+  )";
+  runDataflow(
+  Code,
+  [](const llvm::StringMap> &Results,
+ ASTContext &ASTCtx) {
+const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+
+const ValueDecl *I1FieldDecl = findValueDecl(ASTCtx, "i1");
+const ValueDecl *I2FieldDecl = findValueDecl(ASTCtx, "i2");
+
+auto &SLoc = getLocForDecl(ASTCtx, Env, "s");
+
+auto &IValue = getValueForDecl(ASTCtx, Env, "i");
+auto &I1Value =
+*cast(getFieldValue(&SLoc, *I1FieldDecl, Env));
+EXPECT_EQ(&I1Value, &IValue);
+auto &I2Value =
+*cast(getFieldValue(&SLoc, *I2FieldDecl, Env));
+EXPECT_NE(&I2Value, &IValue);
+  });
+}
+
 TEST(TransferTest, AssignToUnionMember) {
   std::string Code = R"(
 union A {



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 243a79c - [clang][dataflow] Simplify implementation of `transferStdForwardCall()` in optional check.

2023-07-17 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-17T07:26:11Z
New Revision: 243a79ca01f8142a8d8c9873ba58fefdafa48745

URL: 
https://github.com/llvm/llvm-project/commit/243a79ca01f8142a8d8c9873ba58fefdafa48745
DIFF: 
https://github.com/llvm/llvm-project/commit/243a79ca01f8142a8d8c9873ba58fefdafa48745.diff

LOG: [clang][dataflow] Simplify implementation of `transferStdForwardCall()` in 
optional check.

The argument and return value of `std::forward` is always a reference, so we 
can simply forward the storage location.

Depends On D155075

Reviewed By: ymandel, gribozavr2, xazax.hun

Differential Revision: https://reviews.llvm.org/D155202

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp

Removed: 




diff  --git 
a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp 
b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
index 7f516984094648..a39aa2240c4fc6 100644
--- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
@@ -683,25 +683,8 @@ void transferStdForwardCall(const CallExpr *E, const 
MatchFinder::MatchResult &,
 LatticeTransferState &State) {
   assert(E->getNumArgs() == 1);
 
-  StorageLocation *LocRet = State.Env.getStorageLocation(*E, SkipPast::None);
-  if (LocRet != nullptr)
-return;
-
-  StorageLocation *LocArg =
-  State.Env.getStorageLocation(*E->getArg(0), SkipPast::Reference);
-
-  if (LocArg == nullptr)
-return;
-
-  Value *ValArg = State.Env.getValue(*LocArg);
-  if (ValArg == nullptr)
-ValArg = &createOptionalValue(State.Env.makeAtomicBoolValue(), State.Env);
-
-  // Create a new storage location
-  LocRet = &State.Env.createStorageLocation(*E);
-  State.Env.setStorageLocation(*E, *LocRet);
-
-  State.Env.setValue(*LocRet, *ValArg);
+  if (auto *Loc = State.Env.getStorageLocationStrict(*E->getArg(0)))
+State.Env.setStorageLocationStrict(*E, *Loc);
 }
 
 const Formula &evaluateEquality(Arena &A, const Formula &EqVal,



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] d17f455 - [clang][dataflow] Add `refreshStructValue()`.

2023-07-17 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-17T07:26:13Z
New Revision: d17f455a6348806c73641e742af08b0a974e13d5

URL: 
https://github.com/llvm/llvm-project/commit/d17f455a6348806c73641e742af08b0a974e13d5
DIFF: 
https://github.com/llvm/llvm-project/commit/d17f455a6348806c73641e742af08b0a974e13d5.diff

LOG: [clang][dataflow] Add `refreshStructValue()`.

Besides being a useful abstraction, this function will help insulate existing 
clients of the framework from upcoming changes to the API of `StructValue` and 
`AggregateStorageLocation`.

Depends On D155202

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D155204

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index dc82ccea4a27d4..9d99b6771f71e1 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -389,6 +389,12 @@ class Environment {
   /// necessary storage locations and values for indirections until it finds a
   /// non-pointer/non-reference type.
   ///
+  /// If `Type` is one of the following types, this function will always return
+  /// a non-null pointer:
+  /// - `bool`
+  /// - Any integer type
+  /// - Any class, struct, or union type
+  ///
   /// Requirements:
   ///
   ///  `Type` must not be null.
@@ -692,6 +698,24 @@ AggregateStorageLocation *getBaseObjectLocation(const 
MemberExpr &ME,
 /// order in which they appear in `InitListExpr::inits()`.
 std::vector getFieldsForInitListExpr(const RecordDecl *RD);
 
+/// Associates a new `StructValue` with `Loc` and returns the new value.
+/// It is not defined whether the field values remain the same or not.
+///
+/// This function is primarily intended for use by checks that set custom
+/// properties on `StructValue`s to model the state of these values. Such 
checks
+/// should avoid modifying the properties of an existing `StructValue` because
+/// these changes would be visible to other `Environment`s that share the same
+/// `StructValue`. Instead, call `refreshStructValue()`, then set the 
properties
+/// on the new `StructValue` that it returns. Typical usage:
+///
+///   refreshStructValue(Loc, Env).setProperty("my_prop", MyPropValue);
+StructValue &refreshStructValue(AggregateStorageLocation &Loc,
+Environment &Env);
+
+/// Associates a new `StructValue` with `Expr` and returns the new value.
+/// See also documentation for the overload above.
+StructValue &refreshStructValue(const Expr &Expr, Environment &Env);
+
 } // namespace dataflow
 } // namespace clang
 

diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index fdd6b5959cd722..5d301b815d38e0 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -987,5 +987,30 @@ std::vector getFieldsForInitListExpr(const 
RecordDecl *RD) {
   return Fields;
 }
 
+StructValue &refreshStructValue(AggregateStorageLocation &Loc,
+Environment &Env) {
+  auto &NewVal = *cast(Env.createValue(Loc.getType()));
+  Env.setValue(Loc, NewVal);
+  return NewVal;
+}
+
+StructValue &refreshStructValue(const Expr &Expr, Environment &Env) {
+  assert(Expr.getType()->isRecordType());
+
+  auto &NewVal = *cast(Env.createValue(Expr.getType()));
+
+  if (Expr.isPRValue()) {
+Env.setValueStrict(Expr, NewVal);
+  } else {
+StorageLocation *Loc = Env.getStorageLocationStrict(Expr);
+if (Loc == nullptr) {
+  Loc = &Env.createStorageLocation(Expr);
+}
+Env.setValue(*Loc, NewVal);
+  }
+
+  return NewVal;
+}
+
 } // namespace dataflow
 } // namespace clang

diff  --git 
a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
index 11b346fbf64f3b..462ffb5eb389ce 100644
--- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
@@ -370,13 +370,6 @@ TEST_F(NoreturnDestructorTest, 
ConditionalOperatorNestedBranchReturns) {
   // FIXME: Called functions at point `p` should contain only "foo".
 }
 
-StructValue &createNewStructValue(AggregateStorageLocation &Loc,
-  Environment &Env) {
-  auto &Val = *cast(Env.createValue(Loc.getType()));
-  Env.setValue(Loc, Val);
-  return Val;
-}
-
 // Models an analysis that uses flow conditions.
 class SpecialBoolAnalysis fina

[clang] 6d76854 - [clang][dataflow] Add `DataflowEnvironment::createObject()`.

2023-07-17 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-17T07:26:10Z
New Revision: 6d768548ecc0ca37026986f397392c1d0ace9736

URL: 
https://github.com/llvm/llvm-project/commit/6d768548ecc0ca37026986f397392c1d0ace9736
DIFF: 
https://github.com/llvm/llvm-project/commit/6d768548ecc0ca37026986f397392c1d0ace9736.diff

LOG: [clang][dataflow] Add `DataflowEnvironment::createObject()`.

This consolidates the code used in various places to initialize objects 
(usually for variables) into one central location.

It will also help reduce the number of changes needed when we make the upcoming 
API changes to `AggregateStorageLocation` and `StructValue`.

Depends On D155074

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D155075

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index 07af485e786c81..dc82ccea4a27d4 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -394,6 +394,32 @@ class Environment {
   ///  `Type` must not be null.
   Value *createValue(QualType Type);
 
+  /// Creates an object (i.e. a storage location with an associated value) of
+  /// type `Ty`. If `InitExpr` is non-null and has a value associated with it,
+  /// initializes the object with this value. Otherwise, initializes the object
+  /// with a value created using `createValue()`.
+  StorageLocation &createObject(QualType Ty, const Expr *InitExpr = nullptr) {
+return createObjectInternal(nullptr, Ty, InitExpr);
+  }
+
+  /// Creates an object for the variable declaration `D`. If `D` has an
+  /// initializer and this initializer is associated with a value, initializes
+  /// the object with this value.  Otherwise, initializes the object with a
+  /// value created using `createValue()`. Uses the storage location returned 
by
+  /// `DataflowAnalysisContext::getStableStorageLocation(D)`.
+  StorageLocation &createObject(const VarDecl &D) {
+return createObjectInternal(&D, D.getType(), D.getInit());
+  }
+
+  /// Creates an object for the variable declaration `D`. If `InitExpr` is
+  /// non-null and has a value associated with it, initializes the object with
+  /// this value. Otherwise, initializes the object with a value created using
+  /// `createValue()`.  Uses the storage location returned by
+  /// `DataflowAnalysisContext::getStableStorageLocation(D)`.
+  StorageLocation &createObject(const VarDecl &D, const Expr *InitExpr) {
+return createObjectInternal(&D, D.getType(), InitExpr);
+  }
+
   /// Assigns `Val` as the value of `Loc` in the environment.
   void setValue(const StorageLocation &Loc, Value &Val);
 
@@ -592,6 +618,11 @@ class Environment {
   llvm::DenseSet &Visited,
   int Depth, int &CreatedValuesCount);
 
+  /// Shared implementation of `createObject()` overloads.
+  /// `D` and `InitExpr` may be null.
+  StorageLocation &createObjectInternal(const VarDecl *D, QualType Ty,
+const Expr *InitExpr);
+
   StorageLocation &skip(StorageLocation &Loc, SkipPast SP) const;
   const StorageLocation &skip(const StorageLocation &Loc, SkipPast SP) const;
 

diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
index 531115efa64f94..bb1c2c7a1de10d 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
@@ -72,7 +72,7 @@ StorageLocation &
 DataflowAnalysisContext::getStableStorageLocation(const VarDecl &D) {
   if (auto *Loc = getStorageLocation(D))
 return *Loc;
-  auto &Loc = createStorageLocation(D.getType());
+  auto &Loc = createStorageLocation(D.getType().getNonReferenceType());
   setStorageLocation(D, Loc);
   return Loc;
 }

diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index a49c529c37a46b..fdd6b5959cd722 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -260,10 +260,8 @@ void Environment::initFieldsGlobalsAndFuncs(const 
FunctionDecl *FuncDecl) {
   for (const VarDecl *D : Vars) {
 if (getStorageLocation(*D) != nullptr)
   continue;
-auto &Loc = createStorageLocation(D->getType().getNonReferenceType());
-setStorageLocation(*D, Loc);
-if (auto *Val = createValue(D->get

[clang] 0f6cf55 - [clang][dataflow] Bugfix for `refreshStructValue()`.

2023-07-17 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-07-17T18:56:25Z
New Revision: 0f6cf555674959d0b21769fc1c46e23584561f2a

URL: 
https://github.com/llvm/llvm-project/commit/0f6cf555674959d0b21769fc1c46e23584561f2a
DIFF: 
https://github.com/llvm/llvm-project/commit/0f6cf555674959d0b21769fc1c46e23584561f2a.diff

LOG: [clang][dataflow] Bugfix for `refreshStructValue()`.

In the case where the expression was not yet associated with a storage 
location, we created a new storage location but failed to associate it with the 
expression.

The newly added test fails without the fix.

Reviewed By: xazax.hun

Differential Revision: https://reviews.llvm.org/D155465

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index 5d301b815d38e0..54632f5662b63d 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -1005,6 +1005,7 @@ StructValue &refreshStructValue(const Expr &Expr, 
Environment &Env) {
 StorageLocation *Loc = Env.getStorageLocationStrict(Expr);
 if (Loc == nullptr) {
   Loc = &Env.createStorageLocation(Expr);
+  Env.setStorageLocation(Expr, *Loc);
 }
 Env.setValue(*Loc, NewVal);
   }

diff  --git 
a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
index e9531d1e7e8fd4..ba316f7d35e895 100644
--- a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
@@ -25,6 +25,7 @@ namespace {
 using namespace clang;
 using namespace dataflow;
 using ::clang::dataflow::test::getFieldValue;
+using ::testing::IsNull;
 using ::testing::NotNull;
 
 class EnvironmentTest : public ::testing::Test {
@@ -252,4 +253,35 @@ TEST_F(EnvironmentTest, InitGlobalVarsConstructor) {
   EXPECT_THAT(Env.getValue(*Var), NotNull());
 }
 
+TEST_F(EnvironmentTest, RefreshStructValue) {
+  using namespace ast_matchers;
+
+  std::string Code = R"cc(
+ struct S {};
+ void target () {
+   S s;
+   s;
+ }
+  )cc";
+
+  auto Unit =
+  tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
+  auto &Context = Unit->getASTContext();
+
+  ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
+
+  auto Results = match(functionDecl(hasName("target")).bind("target"), 
Context);
+  const auto *Target = selectFirst("target", Results);
+  ASSERT_THAT(Target, NotNull());
+
+  Results = match(declRefExpr(to(varDecl(hasName("s".bind("s"), Context);
+  const auto *DRE = selectFirst("s", Results);
+  ASSERT_THAT(DRE, NotNull());
+
+  Environment Env(DAContext, *Target);
+  EXPECT_THAT(Env.getStorageLocationStrict(*DRE), IsNull());
+  refreshStructValue(*DRE, Env);
+  EXPECT_THAT(Env.getStorageLocationStrict(*DRE), NotNull());
+}
+
 } // namespace



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 4866a6e - [clang][dataflow] Produce pointer values for callees of member operator calls.

2023-08-24 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-08-24T07:12:14Z
New Revision: 4866a6e1d3327a0499ef0e017a973a78d4e377bc

URL: 
https://github.com/llvm/llvm-project/commit/4866a6e1d3327a0499ef0e017a973a78d4e377bc
DIFF: 
https://github.com/llvm/llvm-project/commit/4866a6e1d3327a0499ef0e017a973a78d4e377bc.diff

LOG: [clang][dataflow] Produce pointer values for callees of member operator 
calls.

Calls to member operators are a special case in that their callees have pointer
type. The callees of non-operator non-static member functions are not pointers.
See the comments in the code for details.

This issue came up in the Crubit nullability check; the fact that we weren't
modeling the `PointerValue` caused non-convergence.

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D158592

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index 8617cf4c8ca4a2..200a981584bb76 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -175,12 +175,16 @@ class TransferVisitor : public 
ConstStmtVisitor {
 const ValueDecl *VD = S->getDecl();
 assert(VD != nullptr);
 
-// `DeclRefExpr`s to fields and non-static methods aren't glvalues, and
-// there's also no sensible `Value` we can assign to them, so skip them.
-if (isa(VD))
-  return;
-if (auto *Method = dyn_cast(VD);
-Method && !Method->isStatic())
+// Some `DeclRefExpr`s aren't glvalues, so we can't associate them with a
+// `StorageLocation`, and there's also no sensible `Value` that we can
+// assign to them. Examples:
+// - Non-static member variables
+// - Non static member functions
+//   Note: Member operators are an exception to this, but apparently only
+//   if the `DeclRefExpr` is used within the callee of a
+//   `CXXOperatorCallExpr`. In other cases, for example when applying the
+//   address-of operator, the `DeclRefExpr` is a prvalue.
+if (!S->isGLValue())
   return;
 
 auto *DeclLoc = Env.getStorageLocation(*VD);

diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 4c31de3c8085bd..ef28f2f233b844 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -5588,6 +5588,59 @@ TEST(TransferTest, BuiltinFunctionModeled) {
   });
 }
 
+// Check that a callee of a member operator call is modeled as a 
`PointerValue`.
+// Member operator calls are unusual in that their callee is a pointer that
+// stems from a `FunctionToPointerDecay`. In calls to non-operator non-static
+// member functions, the callee is a `MemberExpr` (which does not have pointer
+// type).
+// We want to make sure that we produce a pointer value for the callee in this
+// specific scenario and that its storage location is durable (for 
convergence).
+TEST(TransferTest, MemberOperatorCallModelsPointerForCallee) {
+  std::string Code = R"(
+struct S {
+  bool operator!=(S s);
+};
+void target() {
+  S s;
+  (void)(s != s);
+  (void)(s != s);
+  // [[p]]
+}
+  )";
+  runDataflow(
+  Code,
+  [](const llvm::StringMap> &Results,
+ ASTContext &ASTCtx) {
+using ast_matchers::selectFirst;
+using ast_matchers::match;
+using ast_matchers::traverse;
+using ast_matchers::cxxOperatorCallExpr;
+
+const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+
+auto Matches = match(
+traverse(TK_AsIs, cxxOperatorCallExpr().bind("call")), ASTCtx);
+
+ASSERT_EQ(Matches.size(), 2);
+
+auto *Call1 = Matches[0].getNodeAs("call");
+auto *Call2 = Matches[1].getNodeAs("call");
+
+ASSERT_THAT(Call1, NotNull());
+ASSERT_THAT(Call2, NotNull());
+
+EXPECT_EQ(cast(Call1->getCallee())->getCastKind(),
+  CK_FunctionToPointerDecay);
+EXPECT_EQ(cast(Call2->getCallee())->getCastKind(),
+  CK_FunctionToPointerDecay);
+
+auto *Ptr1 = cast(Env.getValue(*Call1->getCallee()));
+auto *Ptr2 = cast(Env.getValue(*Call2->getCallee()));
+
+ASSERT_EQ(&Ptr1->getPointeeLoc(), &Ptr2->getPointeeLoc());
+  });
+}
+
 // Check that fields of anonymous records are modeled.
 TEST(TransferTest, AnonymousStruct) {
   std::string Code = R"(



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] aef05a1 - [clang][dataflow][NFC] Eliminate `getStorageLocation()` / `setStorageLocation()` in `DataflowAnalysisContext`.

2023-08-28 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-08-29T06:53:48Z
New Revision: aef05a12329cf83c0a6fe46b464ab6ac08ee3439

URL: 
https://github.com/llvm/llvm-project/commit/aef05a12329cf83c0a6fe46b464ab6ac08ee3439
DIFF: 
https://github.com/llvm/llvm-project/commit/aef05a12329cf83c0a6fe46b464ab6ac08ee3439.diff

LOG: [clang][dataflow][NFC] Eliminate `getStorageLocation()` / 
`setStorageLocation()` in `DataflowAnalysisContext`.

Instead, inline them into the `getStableStorageLocation()` overloads, which is 
the only place they were called from (and should be called from).

`getStorageLocation()` / `setStorageLocation()` were confusing because neither 
their name nor their documentation made reference to the fact that the storage 
location is stable.

It didn't make sense to keep these as private member functions either. The code 
for the two `getStableStorageLocation()` overloads has become only marginally 
more complex by inlining these functions, and the `Expr` version is actually 
more efficient because we only call `ignoreCFGOmittedNodes()` once instead of 
twice.

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D158981

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp

Removed: 




diff  --git 
a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
index e5c325b876bd7a..685bbe486b54e1 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
@@ -103,39 +103,6 @@ class DataflowAnalysisContext {
   /// Returns a stable storage location for `E`.
   StorageLocation &getStableStorageLocation(const Expr &E);
 
-  /// Assigns `Loc` as the storage location of `D`.
-  ///
-  /// Requirements:
-  ///
-  ///  `D` must not be assigned a storage location.
-  void setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {
-assert(!DeclToLoc.contains(&D));
-DeclToLoc[&D] = &Loc;
-  }
-
-  /// Returns the storage location assigned to `D` or null if `D` has no
-  /// assigned storage location.
-  StorageLocation *getStorageLocation(const ValueDecl &D) const {
-return DeclToLoc.lookup(&D);
-  }
-
-  /// Assigns `Loc` as the storage location of `E`.
-  ///
-  /// Requirements:
-  ///
-  ///  `E` must not be assigned a storage location.
-  void setStorageLocation(const Expr &E, StorageLocation &Loc) {
-const Expr &CanonE = ignoreCFGOmittedNodes(E);
-assert(!ExprToLoc.contains(&CanonE));
-ExprToLoc[&CanonE] = &Loc;
-  }
-
-  /// Returns the storage location assigned to `E` or null if `E` has no
-  /// assigned storage location.
-  StorageLocation *getStorageLocation(const Expr &E) const {
-return ExprToLoc.lookup(&ignoreCFGOmittedNodes(E));
-  }
-
   /// Returns a pointer value that represents a null pointer. Calls with
   /// `PointeeType` that are canonically equivalent will return the same 
result.
   /// A null `PointeeType` can be used for the pointee of `std::nullptr_t`.

diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
index 0a6d7792208258..47a994f4bbdb6a 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
@@ -74,19 +74,21 @@ StorageLocation 
&DataflowAnalysisContext::createStorageLocation(QualType Type) {
 
 StorageLocation &
 DataflowAnalysisContext::getStableStorageLocation(const VarDecl &D) {
-  if (auto *Loc = getStorageLocation(D))
+  if (auto *Loc = DeclToLoc.lookup(&D))
 return *Loc;
   auto &Loc = createStorageLocation(D.getType().getNonReferenceType());
-  setStorageLocation(D, Loc);
+  DeclToLoc[&D] = &Loc;
   return Loc;
 }
 
 StorageLocation &
 DataflowAnalysisContext::getStableStorageLocation(const Expr &E) {
-  if (auto *Loc = getStorageLocation(E))
+  const Expr &CanonE = ignoreCFGOmittedNodes(E);
+
+  if (auto *Loc = ExprToLoc.lookup(&CanonE))
 return *Loc;
-  auto &Loc = createStorageLocation(E.getType());
-  setStorageLocation(E, Loc);
+  auto &Loc = createStorageLocation(CanonE.getType());
+  ExprToLoc[&CanonE] = &Loc;
   return Loc;
 }
 



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 330d5bc - [clang][dataflow] Don't associate prvalue expressions with storage locations.

2023-08-29 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-08-29T07:28:46Z
New Revision: 330d5bcbf61043b5ca2bf5a65bd4488718c85e6e

URL: 
https://github.com/llvm/llvm-project/commit/330d5bcbf61043b5ca2bf5a65bd4488718c85e6e
DIFF: 
https://github.com/llvm/llvm-project/commit/330d5bcbf61043b5ca2bf5a65bd4488718c85e6e.diff

LOG: [clang][dataflow] Don't associate prvalue expressions with storage 
locations.

Instead, map prvalue expressions directly to values in a newly introduced map 
`Environment::ExprToVal`.

This change introduces an additional member variable in `Environment` but is an 
overall win:

- It is more conceptually correctly, since prvalues don't have storage
  locations.

- It eliminates complexity from
  `Environment::setValue(const Expr &E, Value &Val)`.

- It reduces the amount of data stored in `Environment`: A prvalue now has a
  single entry in `ExprToVal` instead of one in `ExprToLoc` and one in
  `LocToVal`.

- Not allocating `StorageLocation`s for prvalues additionally reduces memory
  usage.

This patch is the last step in the migration to strict handling of value 
categories (see https://discourse.llvm.org/t/70086 for details). The changes 
here are almost entirely internal to `Environment`.

The only externally observable change is that when associating a `RecordValue` 
with the location returned by `Environment::getResultObjectLocation()` for a 
given expression, callers additionally need to associate the `RecordValue` with 
the expression themselves.

Reviewed By: xazax.hun

Differential Revision: https://reviews.llvm.org/D158977

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index f812c01d42040b..95514d940c3f6a 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -651,14 +651,17 @@ class Environment {
   // function being analyzed is only a function and not a method.
   RecordStorageLocation *ThisPointeeLoc = nullptr;
 
-  // Maps from program declarations and statements to storage locations that 
are
+  // Maps from declarations and glvalue expression to storage locations that 
are
   // assigned to them. Unlike the maps in `DataflowAnalysisContext`, these
   // include only storage locations that are in scope for a particular basic
   // block.
   llvm::DenseMap DeclToLoc;
   llvm::DenseMap ExprToLoc;
+  // Maps from prvalue expressions and storage locations to the values that
+  // are assigned to them.
   // We preserve insertion order so that join/widen process values in
   // deterministic sequence. This in turn produces deterministic SAT formulas.
+  llvm::MapVector ExprToVal;
   llvm::MapVector LocToVal;
 
   Atom FlowConditionToken;

diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index f6c8f7d2d395ec..f15ea52d6b4699 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -171,6 +171,105 @@ static Value &widenDistinctValues(QualType Type, Value 
&Prev,
   return Current;
 }
 
+// Returns whether the values in `Map1` and `Map2` compare equal for those
+// keys that `Map1` and `Map2` have in common.
+template 
+bool compareKeyToValueMaps(const llvm::MapVector &Map1,
+   const llvm::MapVector &Map2,
+   const Environment &Env1, const Environment &Env2,
+   Environment::ValueModel &Model) {
+  for (auto &Entry : Map1) {
+Key K = Entry.first;
+assert(K != nullptr);
+
+Value *Val = Entry.second;
+assert(Val != nullptr);
+
+auto It = Map2.find(K);
+if (It == Map2.end())
+  continue;
+assert(It->second != nullptr);
+
+if (!areEquivalentValues(*Val, *It->second) &&
+!compareDistinctValues(K->getType(), *Val, Env1, *It->second, Env2,
+   Model))
+  return false;
+  }
+
+  return true;
+}
+
+// Perform a join on either `LocToVal` or `ExprToVal`. `Key` must be either
+// `const StorageLocation *` or `const Expr *`.
+template 
+llvm::MapVector
+joinKeyToValueMap(const llvm::MapVector &Map1,
+  const llvm::MapVector &Map2,
+  const Environment &Env1, const Environment &Env2,
+  Environment &JoinedEnv, Environment::ValueModel &Model) {
+  llvm::MapVector MergedMap;
+  for (auto &Entry : Map1) {
+Key K = Entry.first;
+assert(K != nullptr);
+
+Value *Val = Entry.second;
+asse

[clang] 6eb1b23 - [clang][dataflow][NFC] Remove obsolete references to `ReferenceValue` from comments.

2023-08-29 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-08-30T06:55:40Z
New Revision: 6eb1b237f5eca0f9b16b66a1f4e8964554027e38

URL: 
https://github.com/llvm/llvm-project/commit/6eb1b237f5eca0f9b16b66a1f4e8964554027e38
DIFF: 
https://github.com/llvm/llvm-project/commit/6eb1b237f5eca0f9b16b66a1f4e8964554027e38.diff

LOG: [clang][dataflow][NFC] Remove obsolete references to `ReferenceValue` from 
comments.

`ReferenceValue` was removed in https://reviews.llvm.org/D155922.

Reviewed By: xazax.hun

Differential Revision: https://reviews.llvm.org/D159090

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/include/clang/Analysis/FlowSensitive/Value.h
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index 95514d940c3f6a..f5e4057f957a96 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -254,17 +254,10 @@ class Environment {
   /// Requirements:
   ///
   ///  `D` must not already have a storage location in the environment.
-  ///
-  ///  If `D` has reference type, `Loc` must refer directly to the referenced
-  ///  object (if any), not to a `ReferenceValue`, and it is not permitted to
-  ///  later change `Loc` to refer to a `ReferenceValue.`
   void setStorageLocation(const ValueDecl &D, StorageLocation &Loc);
 
   /// Returns the storage location assigned to `D` in the environment, or null
   /// if `D` isn't assigned a storage location in the environment.
-  ///
-  /// Note that if `D` has reference type, the storage location that is 
returned
-  /// refers directly to the referenced object, not a `ReferenceValue`.
   StorageLocation *getStorageLocation(const ValueDecl &D) const;
 
   /// Assigns `Loc` as the storage location of the glvalue `E` in the
@@ -280,9 +273,6 @@ class Environment {
   /// environment, or null if `E` isn't assigned a storage location in the
   /// environment.
   ///
-  /// If the storage location for `E` is associated with a
-  /// `ReferenceValue RefVal`, returns `RefVal.getReferentLoc()` instead.
-  ///
   /// Requirements:
   ///  `E` must be a glvalue or a `BuiltinType::BuiltinFn`
   StorageLocation *getStorageLocation(const Expr &E) const;
@@ -437,7 +427,6 @@ class Environment {
   /// Requirements:
   ///
   ///  `E` must be a prvalue
-  ///  `Val` must not be a `ReferenceValue`
   ///  If `Val` is a `RecordValue`, its `RecordStorageLocation` must be the
   ///  same as that of any `RecordValue` that has already been associated with
   ///  `E`. This is to guarantee that the result object initialized by a 
prvalue

diff  --git a/clang/include/clang/Analysis/FlowSensitive/Value.h 
b/clang/include/clang/Analysis/FlowSensitive/Value.h
index b2f71de593f995..da9fe6be9489c2 100644
--- a/clang/include/clang/Analysis/FlowSensitive/Value.h
+++ b/clang/include/clang/Analysis/FlowSensitive/Value.h
@@ -83,8 +83,8 @@ class Value {
 /// transitivity. It does *not* include comparison of `Properties`.
 ///
 /// Computes equivalence for these subclasses:
-/// * ReferenceValue, PointerValue -- pointee locations are equal. Does not
-///   compute deep equality of `Value` at said location.
+/// * PointerValue -- pointee locations are equal. Does not compute deep
+///   equality of `Value` at said location.
 /// * TopBoolValue -- both are `TopBoolValue`s.
 ///
 /// Otherwise, falls back to pointer equality.

diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index c0092694ef385d..fcd9b20027cde9 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -276,8 +276,7 @@ class TransferVisitor : public 
ConstStmtVisitor {
 
 case CK_LValueToRValue: {
   // When an L-value is used as an R-value, it may result in sharing, so we
-  // need to unpack any nested `Top`s. We also need to strip off the
-  // `ReferenceValue` associated with the lvalue.
+  // need to unpack any nested `Top`s.
   auto *SubExprVal = maybeUnpackLValueExpr(*SubExpr, Env);
   if (SubExprVal == nullptr)
 break;

diff  --git 
a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
index de0b5c7b239055..01162c89a36c8e 100644
--- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
@@ -153,9 +153,9 @@ TEST(DataflowAnalysisTest, NonConvergingAnalysis) {
 
 // Regression test for joins of bool-typed lvalue expressions. The first loop
 // results i

[clang] 37458c6 - [clang][dataflow] Eliminate deprecated `DataflowAnalysis` constructor.

2023-09-04 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-09-04T07:00:11Z
New Revision: 37458c66bfefaa4f4cb40043cb88413e5b826e3f

URL: 
https://github.com/llvm/llvm-project/commit/37458c66bfefaa4f4cb40043cb88413e5b826e3f
DIFF: 
https://github.com/llvm/llvm-project/commit/37458c66bfefaa4f4cb40043cb88413e5b826e3f.diff

LOG: [clang][dataflow] Eliminate deprecated `DataflowAnalysis` constructor.

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D159261

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
clang/include/clang/Analysis/FlowSensitive/NoopAnalysis.h
clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp
clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
index db02e1b73c6aff7..abd34f40922121e 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
@@ -85,14 +85,6 @@ class DataflowAnalysis : public TypeErasedDataflowAnalysis {
 
   explicit DataflowAnalysis(ASTContext &Context) : Context(Context) {}
 
-  /// Deprecated. Use the `DataflowAnalysisOptions` constructor instead.
-  explicit DataflowAnalysis(ASTContext &Context, bool ApplyBuiltinTransfer)
-  : DataflowAnalysis(
-Context,
-{ApplyBuiltinTransfer
- ? DataflowAnalysisContext::Options{}
- : std::optional()}) {}
-
   explicit DataflowAnalysis(ASTContext &Context,
 DataflowAnalysisOptions Options)
   : TypeErasedDataflowAnalysis(Options), Context(Context) {}

diff  --git a/clang/include/clang/Analysis/FlowSensitive/NoopAnalysis.h 
b/clang/include/clang/Analysis/FlowSensitive/NoopAnalysis.h
index 016b6b3ba014540..393f68300cb80c1 100644
--- a/clang/include/clang/Analysis/FlowSensitive/NoopAnalysis.h
+++ b/clang/include/clang/Analysis/FlowSensitive/NoopAnalysis.h
@@ -27,15 +27,6 @@ class NoopAnalysis : public DataflowAnalysis {
   NoopAnalysis(ASTContext &Context)
   : DataflowAnalysis(Context) {}
 
-  /// Deprecated. Use the `DataflowAnalysisOptions` constructor instead.
-  NoopAnalysis(ASTContext &Context, bool ApplyBuiltinTransfer)
-  : DataflowAnalysis(Context,
-ApplyBuiltinTransfer) {}
-
-  /// `ApplyBuiltinTransfer` controls whether to run the built-in transfer
-  /// functions that model memory during the analysis. Their results are not
-  /// used by `NoopAnalysis`, but tests that need to inspect the environment
-  /// should enable them.
   NoopAnalysis(ASTContext &Context, DataflowAnalysisOptions Options)
   : DataflowAnalysis(Context, Options) {}
 

diff  --git a/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp
index 0edf3ca6b359b27..1cb51a9cf37c5c4 100644
--- a/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp
@@ -113,8 +113,7 @@ class ModelAdaptorAnalysis
 : public DataflowAnalysis, NoopLattice> {
 public:
   explicit ModelAdaptorAnalysis(ASTContext &Context)
-  : DataflowAnalysis(
-Context, /*ApplyBuiltinTransfer=*/true) {}
+  : DataflowAnalysis(Context) {}
 
   static NoopLattice initialElement() { return NoopLattice(); }
 

diff  --git a/clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
index 937ab039f72f9ee..5de3dd8dccb68a9 100644
--- a/clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
@@ -86,7 +86,9 @@ void checkDataflow(
 Code, std::move(TargetFuncMatcher),
 [](ASTContext &Context, Environment &) {
   return NoopAnalysis(
-  Context, /*ApplyBuiltinTransfer=*/false);
+  Context,
+  // Don't apply builtin transfer function.
+  DataflowAnalysisOptions{std::nullopt});
 })
 .withASTBuildArgs({"-fsyntax-only", "-std=c++17"}),
 /*VerifyResults=*/std::move(Expectations)),

diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 8100db2aec40909..0a5cf62e5ea2332 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/cla

[clang] 266c12a - [clang][dataflow] When dumping `ExprToVal`, dump the `Value`, not just its location.

2023-09-04 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-09-04T07:38:33Z
New Revision: 266c12a1bd603fa3ecbf26a6f93621f0f8488da1

URL: 
https://github.com/llvm/llvm-project/commit/266c12a1bd603fa3ecbf26a6f93621f0f8488da1
DIFF: 
https://github.com/llvm/llvm-project/commit/266c12a1bd603fa3ecbf26a6f93621f0f8488da1.diff

LOG: [clang][dataflow] When dumping `ExprToVal`, dump the `Value`, not just its 
location.

This makes `ExprToVal` dumping consistent with `LocToVal` dumping.

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D159274

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index f15ea52d6b4699..b40fbbc991c8f8 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -918,7 +918,7 @@ void Environment::dump(raw_ostream &OS) const {
 
   OS << "ExprToVal:\n";
   for (auto [E, V] : ExprToVal)
-OS << "  [" << E << ", " << V << "]\n";
+OS << "  [" << E << ", " << V << ": " << *V << "]\n";
 
   OS << "LocToVal:\n";
   for (auto [L, V] : LocToVal) {



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] d948d91 - [clang][dataflow] Remove deprecated synonyms related to `RecordStorageLocation` and `RecordValue`

2023-09-04 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-09-04T08:18:43Z
New Revision: d948d9121f104f06b47361528289030a28e1e044

URL: 
https://github.com/llvm/llvm-project/commit/d948d9121f104f06b47361528289030a28e1e044
DIFF: 
https://github.com/llvm/llvm-project/commit/d948d9121f104f06b47361528289030a28e1e044.diff

LOG: [clang][dataflow] Remove deprecated synonyms related to 
`RecordStorageLocation` and `RecordValue`

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D159264

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/include/clang/Analysis/FlowSensitive/StorageLocation.h
clang/include/clang/Analysis/FlowSensitive/Value.h

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index f5e4057f957a969..c128ee4ea85c928 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -690,15 +690,6 @@ RecordValue &refreshRecordValue(RecordStorageLocation 
&Loc, Environment &Env);
 /// See also documentation for the overload above.
 RecordValue &refreshRecordValue(const Expr &Expr, Environment &Env);
 
-/// Deprecated synonym for `refreshRecordValue()`.
-inline RecordValue &refreshStructValue(RecordStorageLocation &Loc,
-   Environment &Env) {
-  return refreshRecordValue(Loc, Env);
-}
-inline RecordValue &refreshStructValue(const Expr &Expr, Environment &Env) {
-  return refreshRecordValue(Expr, Env);
-}
-
 } // namespace dataflow
 } // namespace clang
 

diff  --git a/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h 
b/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h
index 4a55adad74616ed..89d2bbfbb69f9fb 100644
--- a/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h
+++ b/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h
@@ -34,8 +34,6 @@ class StorageLocation {
   enum class Kind {
 Scalar,
 Record,
-// Deprecated synonym for `Record`
-Aggregate = Record,
   };
 
   StorageLocation(Kind LocKind, QualType Type) : LocKind(LocKind), Type(Type) {
@@ -155,9 +153,6 @@ class RecordStorageLocation final : public StorageLocation {
   FieldToLoc Children;
 };
 
-/// Deprecated synonym for `RecordStorageLocation`.
-using AggregateStorageLocation = RecordStorageLocation;
-
 } // namespace dataflow
 } // namespace clang
 

diff  --git a/clang/include/clang/Analysis/FlowSensitive/Value.h 
b/clang/include/clang/Analysis/FlowSensitive/Value.h
index da9fe6be9489c20..6e911af7264ced9 100644
--- a/clang/include/clang/Analysis/FlowSensitive/Value.h
+++ b/clang/include/clang/Analysis/FlowSensitive/Value.h
@@ -36,8 +36,6 @@ class Value {
 Integer,
 Pointer,
 Record,
-// Deprecated synonym for `Record`
-Struct = Record,
 
 // TODO: Top values should not be need to be type-specific.
 TopBool,
@@ -227,9 +225,6 @@ class RecordValue final : public Value {
   /// Returns the storage location that this `RecordValue` is associated with.
   RecordStorageLocation &getLoc() const { return Loc; }
 
-  /// Deprecated synonym for `getLoc()`.
-  RecordStorageLocation &getAggregateLoc() const { return Loc; }
-
   /// Convenience function that returns the child storage location for `Field`.
   /// See also the documentation for `RecordStorageLocation::getChild()`.
   StorageLocation *getChild(const ValueDecl &Field) const {
@@ -240,9 +235,6 @@ class RecordValue final : public Value {
   RecordStorageLocation &Loc;
 };
 
-/// Deprecated synonym for `RecordValue`.
-using StructValue = RecordValue;
-
 raw_ostream &operator<<(raw_ostream &OS, const Value &Val);
 
 } // namespace dataflow



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] bf46b0b - [clang][dataflow] Eliminate deprecated `ControlFlowContext::build()` overload.

2023-09-04 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-09-04T08:30:54Z
New Revision: bf46b0b551011d958ae642f808894311513517ef

URL: 
https://github.com/llvm/llvm-project/commit/bf46b0b551011d958ae642f808894311513517ef
DIFF: 
https://github.com/llvm/llvm-project/commit/bf46b0b551011d958ae642f808894311513517ef.diff

LOG: [clang][dataflow] Eliminate deprecated `ControlFlowContext::build()` 
overload.

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D159262

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h 
b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
index a45bb0635a2f363..768387a121b920a 100644
--- a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
+++ b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
@@ -40,12 +40,6 @@ class ControlFlowContext {
   static llvm::Expected build(const Decl &D, Stmt &S,
   ASTContext &C);
 
-  /// Builds a ControlFlowContext from an AST node. `D` is the function in 
which
-  /// `S` resides. `D` must not be null and `D->isTemplated()` must be false.
-  LLVM_DEPRECATED("Use the version that takes a const Decl & instead", "")
-  static llvm::Expected build(const Decl *D, Stmt &S,
-  ASTContext &C);
-
   /// Returns the `Decl` containing the statement used to construct the CFG, if
   /// available.
   const Decl &getDecl() const { return ContainingDecl; }

diff  --git a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp 
b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
index d5e0b443caf3015..7f9bc31bd41f2dd 100644
--- a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
@@ -109,15 +109,5 @@ ControlFlowContext::build(const Decl &D, Stmt &S, 
ASTContext &C) {
 std::move(BlockReachable));
 }
 
-llvm::Expected
-ControlFlowContext::build(const Decl *D, Stmt &S, ASTContext &C) {
-  if (D == nullptr)
-return llvm::createStringError(
-std::make_error_code(std::errc::invalid_argument),
-"Declaration must not be null");
-
-  return build(*D, S, C);
-}
-
 } // namespace dataflow
 } // namespace clang



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] b50c87d - [clang][dataflow] #llvm #flow-analysis Simplify formula at CNF construction time, and short-cut solving of known contradictory formulas.

2023-09-04 Thread Martin Braenne via cfe-commits

Author: Burak Emir
Date: 2023-09-05T06:23:04Z
New Revision: b50c87d1e63f187105b5b73f7add37717ccce7f6

URL: 
https://github.com/llvm/llvm-project/commit/b50c87d1e63f187105b5b73f7add37717ccce7f6
DIFF: 
https://github.com/llvm/llvm-project/commit/b50c87d1e63f187105b5b73f7add37717ccce7f6.diff

LOG: [clang][dataflow] #llvm #flow-analysis Simplify formula at CNF 
construction time, and short-cut solving of known contradictory formulas.

In dataflow analysis, SAT solver: simplify formula during CNF construction and 
short-cut
solving when the formula has been recognized as contradictory.

Reviewed By: sammccall

Differential Revision: https://reviews.llvm.org/D158407

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp
clang/unittests/Analysis/FlowSensitive/SolverTest.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp 
b/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp
index 037886d09c4f7dd..05ae36ddbc898ec 100644
--- a/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp
+++ b/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp
@@ -12,8 +12,8 @@
 
//===--===//
 
 #include 
+#include 
 #include 
-#include 
 #include 
 #include 
 
@@ -23,8 +23,10 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/STLExtras.h"
 
+
 namespace clang {
 namespace dataflow {
 
@@ -62,6 +64,10 @@ static constexpr Literal NullLit = 0;
 /// Returns the positive literal `V`.
 static constexpr Literal posLit(Variable V) { return 2 * V; }
 
+static constexpr bool isPosLit(Literal L) { return 0 == (L & 1); }
+
+static constexpr bool isNegLit(Literal L) { return 1 == (L & 1); }
+
 /// Returns the negative literal `!V`.
 static constexpr Literal negLit(Variable V) { return 2 * V + 1; }
 
@@ -125,9 +131,14 @@ struct CNFFormula {
   /// formula.
   llvm::DenseMap Atomics;
 
+  /// Indicates that we already know the formula is unsatisfiable.
+  /// During construction, we catch simple cases of conflicting unit-clauses.
+  bool KnownContradictory;
+
   explicit CNFFormula(Variable LargestVar,
   llvm::DenseMap Atomics)
-  : LargestVar(LargestVar), Atomics(std::move(Atomics)) {
+  : LargestVar(LargestVar), Atomics(std::move(Atomics)),
+KnownContradictory(false) {
 Clauses.push_back(0);
 ClauseStarts.push_back(0);
 NextWatched.push_back(0);
@@ -135,33 +146,24 @@ struct CNFFormula {
 WatchedHead.resize(NumLiterals + 1, 0);
   }
 
-  /// Adds the `L1 v L2 v L3` clause to the formula. If `L2` or `L3` are
-  /// `NullLit` they are respectively omitted from the clause.
-  ///
+  /// Adds the `L1 v ... v Ln` clause to the formula.
   /// Requirements:
   ///
-  ///  `L1` must not be `NullLit`.
+  ///  `Li` must not be `NullLit`.
   ///
   ///  All literals in the input that are not `NullLit` must be distinct.
-  void addClause(Literal L1, Literal L2 = NullLit, Literal L3 = NullLit) {
-// The literals are guaranteed to be distinct from properties of Formula
-// and the construction in `buildCNF`.
-assert(L1 != NullLit && L1 != L2 && L1 != L3 &&
-   (L2 != L3 || L2 == NullLit));
+  void addClause(ArrayRef lits) {
+assert(!lits.empty());
+assert(llvm::all_of(lits, [](Literal L) { return L != NullLit; }));
 
 const ClauseID C = ClauseStarts.size();
 const size_t S = Clauses.size();
 ClauseStarts.push_back(S);
-
-Clauses.push_back(L1);
-if (L2 != NullLit)
-  Clauses.push_back(L2);
-if (L3 != NullLit)
-  Clauses.push_back(L3);
+Clauses.insert(Clauses.end(), lits.begin(), lits.end());
 
 // Designate the first literal as the "watched" literal of the clause.
-NextWatched.push_back(WatchedHead[L1]);
-WatchedHead[L1] = C;
+NextWatched.push_back(WatchedHead[lits.front()]);
+WatchedHead[lits.front()] = C;
   }
 
   /// Returns the number of literals in clause `C`.
@@ -176,6 +178,84 @@ struct CNFFormula {
   }
 };
 
+/// Applies simplifications while building up a BooleanFormula.
+/// We keep track of unit clauses, which tell us variables that must be
+/// true/false in any model that satisfies the overall formula.
+/// Such variables can be dropped from subsequently-added clauses, which
+/// may in turn yield more unit clauses or even a contradiction.
+/// The total added complexity of this preprocessing is O(N) where we
+/// for every clause, we do a lookup for each unit clauses.
+/// The lookup is O(1) on average. This method won't catch all
+/// contradictory formulas, more passes can in principle catch
+/// more cases but we leave all these and the general case to the
+/// proper SAT solver.
+struct CNFFormulaBuilder {
+  // Formula should outlive CNFFormulaBuilder.
+  explicit

[clang] f9026cf - [clang][dataflow] Fix Record initialization with InitListExpr and inheritances

2023-09-07 Thread Martin Braenne via cfe-commits

Author: Kinuko Yasuda
Date: 2023-09-07T07:37:50Z
New Revision: f9026cfb7680e2c2a4c8c91dd33f710ea1d321a3

URL: 
https://github.com/llvm/llvm-project/commit/f9026cfb7680e2c2a4c8c91dd33f710ea1d321a3
DIFF: 
https://github.com/llvm/llvm-project/commit/f9026cfb7680e2c2a4c8c91dd33f710ea1d321a3.diff

LOG: [clang][dataflow] Fix Record initialization with InitListExpr and 
inheritances

Usually RecordValues for record objects (e.g. struct) are initialized with
`Environment::createValue()` which internally calls `getObjectFields()` to
collects all fields from the current and base classes, and then filter them
with `ModeledValues` via `DACtx::getModeledFields()` so that the fields that
are actually referenced are modeled.

The consistent set of fields should be initialized when a record is initialized
with an initializer list (InitListExpr), however the existing code's behavior
was different.

Before this patch:
* When a struct is initialized with InitListExpr, its fields are
  initialized based on what is returned by `getFieldsForInitListExpr()`, which
  only collects the direct fields in the current class, but not from the base
  classes. Moreover, if the base classes have their own InitListExpr, values
  that are initialized by their InitListExpr's weren't merged into the
  child objects.

After this patch:
* When a struct is initialized with InitListExpr, it collects and merges the
  fields in the base classes that were initialized by their InitListExpr's.
  The code also asserts that the consistent set of fields are initialized
  with the ModeledFields.

Reviewed By: mboehme

Differential Revision: https://reviews.llvm.org/D159284

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index fcd9b20027cde9..67d8be392ae605 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -27,12 +27,12 @@
 #include "clang/Analysis/FlowSensitive/Value.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/OperatorKinds.h"
-#include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/Casting.h"
-#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Debug.h"
+#include 
 #include 
-#include 
-#include 
+
+#define DEBUG_TYPE "dataflow"
 
 namespace clang {
 namespace dataflow {
@@ -629,17 +629,66 @@ class TransferVisitor : public 
ConstStmtVisitor {
   return;
 }
 
-std::vector Fields =
-getFieldsForInitListExpr(Type->getAsRecordDecl());
 llvm::DenseMap FieldLocs;
 
-for (auto [Field, Init] : llvm::zip(Fields, S->inits())) {
-  assert(Field != nullptr);
-  assert(Init != nullptr);
+// This only contains the direct fields for the given type.
+std::vector FieldsForInit =
+getFieldsForInitListExpr(Type->getAsRecordDecl());
 
-  FieldLocs.insert({Field, &Env.createObject(Field->getType(), Init)});
+// `S->inits()` contains all the initializer epressions, including the
+// ones for direct base classes.
+auto Inits = S->inits();
+size_t InitIdx = 0;
+
+// Initialize base classes.
+if (auto* R = S->getType()->getAsCXXRecordDecl()) {
+  assert(FieldsForInit.size() + R->getNumBases() == Inits.size());
+  for ([[maybe_unused]] const CXXBaseSpecifier &Base : R->bases()) {
+assert(InitIdx < Inits.size());
+auto Init = Inits[InitIdx++];
+assert(Base.getType().getCanonicalType() ==
+   Init->getType().getCanonicalType());
+auto* BaseVal = cast_or_null(Env.getValue(*Init));
+if (!BaseVal)
+  BaseVal = cast(Env.createValue(Init->getType()));
+// Take ownership of the fields of the `RecordValue` for the base class
+// and incorporate them into the "flattened" set of fields for the
+// derived class.
+auto Children = BaseVal->getLoc().children();
+FieldLocs.insert(Children.begin(), Children.end());
+  }
 }
 
+assert(FieldsForInit.size() == Inits.size() - InitIdx);
+for (auto Field : FieldsForInit) {
+  assert(InitIdx < Inits.size());
+  auto Init = Inits[InitIdx++];
+  assert(
+  // The types are same, or
+  Field->getType().getCanonicalType().getUnqualifiedType() ==
+  Init->getType().getCanonicalType() ||
+  // The field's type is T&, and initializer is T
+  (Field->getType()->isReferenceType() &&
+  Field->getType().getCanonicalType()->getPointeeType() ==
+  Init->getType().getCanonicalType()));
+  auto& Loc = Env.createObject(Field->getType(), Init);
+  FieldLocs.insert({Field, &Loc});
+}
+
+LLVM_DEBUG({
+  // Check that we satisfy the invariant that a `RecordStorageLoation`
+  // contains 

[clang-tools-extra] ddbcd98 - [clang-tidy] Correctly handle evaluation order of designated initializers.

2023-03-16 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-03-16T08:15:13Z
New Revision: ddbcd985602dcb5fe78fcf2246cf53922db1f3c3

URL: 
https://github.com/llvm/llvm-project/commit/ddbcd985602dcb5fe78fcf2246cf53922db1f3c3
DIFF: 
https://github.com/llvm/llvm-project/commit/ddbcd985602dcb5fe78fcf2246cf53922db1f3c3.diff

LOG: [clang-tidy] Correctly handle evaluation order of designated initializers.

As designated initializers show up only in the syntactic form of the
InitListExpr, we need to make sure we're searching both forms of the
InitListExpr when determining successors in the evaluation order.

This fixes a bug in bugprone-use-after-move where previously we erroneously
concluded that two designated initializers were unsequenced. The newly added
tests fail without the fix.

Differential Revision: https://reviews.llvm.org/D145906

Added: 


Modified: 
clang-tools-extra/clang-tidy/utils/ExprSequence.cpp
clang-tools-extra/docs/ReleaseNotes.rst
clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp

Removed: 




diff  --git a/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp 
b/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp
index beb4c44467a80..f9555be57e738 100644
--- a/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp
+++ b/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp
@@ -8,6 +8,7 @@
 
 #include "ExprSequence.h"
 #include "clang/AST/ParentMapContext.h"
+#include "llvm/ADT/SmallVector.h"
 #include 
 
 namespace clang::tidy::utils {
@@ -49,6 +50,7 @@ static SmallVector getParentStmts(const Stmt 
*S,
 }
 
 namespace {
+
 bool isDescendantOrEqual(const Stmt *Descendant, const Stmt *Ancestor,
  ASTContext *Context) {
   if (Descendant == Ancestor)
@@ -60,6 +62,17 @@ bool isDescendantOrEqual(const Stmt *Descendant, const Stmt 
*Ancestor,
 
   return false;
 }
+
+llvm::SmallVector
+getAllInitListForms(const InitListExpr *InitList) {
+  llvm::SmallVector result = {InitList};
+  if (const InitListExpr *AltForm = InitList->getSyntacticForm())
+result.push_back(AltForm);
+  if (const InitListExpr *AltForm = InitList->getSemanticForm())
+result.push_back(AltForm);
+  return result;
+}
+
 } // namespace
 
 ExprSequence::ExprSequence(const CFG *TheCFG, const Stmt *Root,
@@ -111,9 +124,12 @@ const Stmt *ExprSequence::getSequenceSuccessor(const Stmt 
*S) const {
 } else if (const auto *InitList = dyn_cast(Parent)) {
   // Initializer list: Each initializer clause is sequenced after the
   // clauses that precede it.
-  for (unsigned I = 1; I < InitList->getNumInits(); ++I) {
-if (InitList->getInit(I - 1) == S)
-  return InitList->getInit(I);
+  for (const InitListExpr *Form : getAllInitListForms(InitList)) {
+for (unsigned I = 1; I < Form->getNumInits(); ++I) {
+  if (Form->getInit(I - 1) == S) {
+return Form->getInit(I);
+  }
+}
   }
 } else if (const auto *Compound = dyn_cast(Parent)) {
   // Compound statement: Each sub-statement is sequenced after the

diff  --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 2be8bfc51d675..b53516a742e2c 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -219,6 +219,10 @@ Changes in existing checks
   ` check when warning would be
   emitted in constructor for virtual base class initialization.
 
+- Improved :doc:`bugprone-use-after-move
+  ` to understand that there is a
+  sequence point between designated initializers.
+
 Removed checks
 ^^
 

diff  --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp
index 281f2083857ad..45cef8abfd1f6 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp
@@ -1155,18 +1155,32 @@ void initializerListSequences() {
   int i;
   A a;
 };
-A a;
-S1 s1{a.getInt(), std::move(a)};
+{
+  A a;
+  S1 s1{a.getInt(), std::move(a)};
+}
+{
+  A a;
+  S1 s1{.i = a.getInt(), .a = std::move(a)};
+}
   }
   {
 struct S2 {
   A a;
   int i;
 };
-A a;
-S2 s2{std::move(a), a.getInt()};
-// CHECK-NOTES: [[@LINE-1]]:25: warning: 'a' used after it was moved
-// CHECK-NOTES: [[@LINE-2]]:11: note: move occurred here
+{
+  A a;
+  S2 s2{std::move(a), a.getInt()};
+  // CHECK-NOTES: [[@LINE-1]]:27: warning: 'a' used after it was moved
+  // CHECK-NOTES: [[@LINE-2]]:13: note: move occurred here
+}
+{
+  A a;
+  S2 s2{.a = std::move(a), .i = a.getInt()};
+  // CHECK-NOTES: [[@LINE-1]]:37: warning: 'a' used after it was moved
+  // CHECK-NOTES: [[@LINE-2]]:13: note: move occurred here
+}
   }
 }
 



__

[clang] 5acd29e - [clang][dataflow] Fix crash when RHS of `&&` or `||` calls `noreturn` func.

2023-03-23 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-03-23T08:02:43Z
New Revision: 5acd29eb4d9e411b3631c26babcd1d2655623f4a

URL: 
https://github.com/llvm/llvm-project/commit/5acd29eb4d9e411b3631c26babcd1d2655623f4a
DIFF: 
https://github.com/llvm/llvm-project/commit/5acd29eb4d9e411b3631c26babcd1d2655623f4a.diff

LOG: [clang][dataflow] Fix crash when RHS of `&&` or `||` calls `noreturn` func.

The crash happened because the transfer fucntion for `&&` and `||`
unconditionally tried to retrieve the value of the RHS. However, if the RHS
is unreachable, there is no environment for it, and trying to retrieve the
operand's value causes an assertion failure.

See also the comments in the code for further details.

Reviewed By: xazax.hun, ymandel, sgatev, gribozavr2

Differential Revision: https://reviews.llvm.org/D146514

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
clang/include/clang/Analysis/FlowSensitive/Transfer.h
clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
clang/unittests/Analysis/FlowSensitive/TestingSupport.h
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h 
b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
index e641468f77d00..3495bdfc538cb 100644
--- a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
+++ b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
@@ -18,6 +18,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/Stmt.h"
 #include "clang/Analysis/CFG.h"
+#include "llvm/ADT/BitVector.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/Support/Error.h"
 #include 
@@ -47,18 +48,26 @@ class ControlFlowContext {
 return StmtToBlock;
   }
 
+  /// Returns whether `B` is reachable from the entry block.
+  bool isBlockReachable(const CFGBlock &B) const {
+return BlockReachable[B.getBlockID()];
+  }
+
 private:
   // FIXME: Once the deprecated `build` method is removed, mark `D` as "must 
not
   // be null" and add an assertion.
   ControlFlowContext(const Decl *D, std::unique_ptr Cfg,
- llvm::DenseMap 
StmtToBlock)
+ llvm::DenseMap 
StmtToBlock,
+ llvm::BitVector BlockReachable)
   : ContainingDecl(D), Cfg(std::move(Cfg)),
-StmtToBlock(std::move(StmtToBlock)) {}
+StmtToBlock(std::move(StmtToBlock)),
+BlockReachable(std::move(BlockReachable)) {}
 
   /// The `Decl` containing the statement used to construct the CFG.
   const Decl *ContainingDecl;
   std::unique_ptr Cfg;
   llvm::DenseMap StmtToBlock;
+  llvm::BitVector BlockReachable;
 };
 
 } // namespace dataflow

diff  --git a/clang/include/clang/Analysis/FlowSensitive/Transfer.h 
b/clang/include/clang/Analysis/FlowSensitive/Transfer.h
index 78a426ed94dd5..db3d780bf35e5 100644
--- a/clang/include/clang/Analysis/FlowSensitive/Transfer.h
+++ b/clang/include/clang/Analysis/FlowSensitive/Transfer.h
@@ -26,9 +26,9 @@ class StmtToEnvMap {
 public:
   virtual ~StmtToEnvMap() = default;
 
-  /// Returns the environment of the basic block that contains `S` or nullptr 
if
-  /// there isn't one.
-  /// FIXME: Ensure that the result can't be null and return a const reference.
+  /// Retrieves the environment of the basic block that contains `S`.
+  /// If `S` is reachable, returns a non-null pointer to the environment.
+  /// If `S` is not reachable, returns nullptr.
   virtual const Environment *getEnvironment(const Stmt &S) const = 0;
 };
 

diff  --git a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp 
b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
index 2492b5203724c..6699a0fc9d79e 100644
--- a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
@@ -16,6 +16,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/Stmt.h"
 #include "clang/Analysis/CFG.h"
+#include "llvm/ADT/BitVector.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/Support/Error.h"
 #include 
@@ -44,6 +45,28 @@ buildStmtToBasicBlockMap(const CFG &Cfg) {
   return StmtToBlock;
 }
 
+static llvm::BitVector findReachableBlocks(const CFG &Cfg) {
+  llvm::BitVector BlockReachable(Cfg.getNumBlockIDs(), false);
+
+  llvm::SmallVector BlocksToVisit;
+  BlocksToVisit.push_back(&Cfg.getEntry());
+  while (!BlocksToVisit.empty()) {
+const CFGBlock *Block = BlocksToVisit.back();
+BlocksToVisit.pop_back();
+
+if (BlockReachable[Block->getBlockID()])
+  continue;
+
+BlockReachable[Block->getBlockID()] = true;
+
+for (const CFGBlock *Succ : Block->succs())
+  if (Succ)
+BlocksToVisit.push_back(Succ);
+  }
+
+  return BlockReachable;
+}
+
 llvm::Expected
 ControlFlowContext::build(const Decl *D, St

[clang] 0608541 - [clang][dataflow][NFC] Eliminate StmtToEnvMap interface.

2023-03-28 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-03-28T08:05:57Z
New Revision: 0608541aa4b5932c092251b846e7b87576e4f2d4

URL: 
https://github.com/llvm/llvm-project/commit/0608541aa4b5932c092251b846e7b87576e4f2d4
DIFF: 
https://github.com/llvm/llvm-project/commit/0608541aa4b5932c092251b846e7b87576e4f2d4.diff

LOG: [clang][dataflow][NFC] Eliminate StmtToEnvMap interface.

Instead, we turn StmtToEnvMap into a concrete class with the implementation 
that used to live in StmtToEnvMapImpl.

The layering issue that originally required the indirection through the
`StmtToEnvMap` interface no longer exists.

Reviewed By: ymandel, xazax.hun, gribozavr2

Differential Revision: https://reviews.llvm.org/D146507

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/Transfer.h
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/Transfer.h 
b/clang/include/clang/Analysis/FlowSensitive/Transfer.h
index db3d780bf35e5..58bb77c4905c5 100644
--- a/clang/include/clang/Analysis/FlowSensitive/Transfer.h
+++ b/clang/include/clang/Analysis/FlowSensitive/Transfer.h
@@ -17,6 +17,7 @@
 #include "clang/AST/Stmt.h"
 #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
+#include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h"
 
 namespace clang {
 namespace dataflow {
@@ -24,12 +25,18 @@ namespace dataflow {
 /// Maps statements to the environments of basic blocks that contain them.
 class StmtToEnvMap {
 public:
-  virtual ~StmtToEnvMap() = default;
-
-  /// Retrieves the environment of the basic block that contains `S`.
-  /// If `S` is reachable, returns a non-null pointer to the environment.
-  /// If `S` is not reachable, returns nullptr.
-  virtual const Environment *getEnvironment(const Stmt &S) const = 0;
+  StmtToEnvMap(const ControlFlowContext &CFCtx,
+   llvm::ArrayRef>
+   BlockToState)
+  : CFCtx(CFCtx), BlockToState(BlockToState) {}
+
+  /// Returns the environment of the basic block that contains `S`.
+  /// The result is guaranteed never to be null.
+  const Environment *getEnvironment(const Stmt &S) const;
+
+private:
+  const ControlFlowContext &CFCtx;
+  llvm::ArrayRef> BlockToState;
 };
 
 /// Evaluates `S` and updates `Env` accordingly.

diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index a1ed37da54c28..be5c9992a6d9d 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -36,6 +36,16 @@
 namespace clang {
 namespace dataflow {
 
+const Environment *StmtToEnvMap::getEnvironment(const Stmt &S) const {
+  auto BlockIt = CFCtx.getStmtToBlock().find(&ignoreCFGOmittedNodes(S));
+  assert(BlockIt != CFCtx.getStmtToBlock().end());
+  if (!CFCtx.isBlockReachable(*BlockIt->getSecond()))
+return nullptr;
+  const auto &State = BlockToState[BlockIt->getSecond()->getBlockID()];
+  assert(State);
+  return &State->Env;
+}
+
 static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,
   Environment &Env) {
   if (auto *LHSValue =

diff  --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp 
b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
index 08bcd5e65e379..8e821e5a75d4a 100644
--- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
+++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
@@ -40,29 +40,6 @@
 namespace clang {
 namespace dataflow {
 
-class StmtToEnvMapImpl : public StmtToEnvMap {
-public:
-  StmtToEnvMapImpl(
-  const ControlFlowContext &CFCtx,
-  llvm::ArrayRef>
-  BlockToState)
-  : CFCtx(CFCtx), BlockToState(BlockToState) {}
-
-  const Environment *getEnvironment(const Stmt &S) const override {
-auto BlockIt = CFCtx.getStmtToBlock().find(&ignoreCFGOmittedNodes(S));
-assert(BlockIt != CFCtx.getStmtToBlock().end());
-if (!CFCtx.isBlockReachable(*BlockIt->getSecond()))
-  return nullptr;
-const auto &State = BlockToState[BlockIt->getSecond()->getBlockID()];
-assert(State);
-return &State->Env;
-  }
-
-private:
-  const ControlFlowContext &CFCtx;
-  llvm::ArrayRef> BlockToState;
-};
-
 /// Returns the index of `Block` in the successors of `Pred`.
 static int blockIndexInPredecessor(const CFGBlock &Pred,
const CFGBlock &Block) {
@@ -269,7 +246,7 @@ computeBlockInputState(const CFGBlock &Block, 
AnalysisContext &AC) {
 TypeErasedDataflowAnalysisState PredState = *MaybePredState;
 if (Analysis.builtinOptions()) {
   if (const Stmt *PredTerminatorStmt = Pred->getTerminatorStmt()) {
-const StmtToEnvMapImpl StmtToEnv(AC.CFCtx, AC.BlockSta

[clang] 1bc2d43 - [clang][dataflow][NFC] Put TransferVisitor in an unnamed namespace.

2023-03-28 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-03-28T10:03:39Z
New Revision: 1bc2d43e5c8fd0ec2e1a7e364fb42272ed7fb158

URL: 
https://github.com/llvm/llvm-project/commit/1bc2d43e5c8fd0ec2e1a7e364fb42272ed7fb158
DIFF: 
https://github.com/llvm/llvm-project/commit/1bc2d43e5c8fd0ec2e1a7e364fb42272ed7fb158.diff

LOG: [clang][dataflow][NFC] Put TransferVisitor in an unnamed namespace.

This avoids the risk of ODR violations.

Reviewed By: gribozavr2

Differential Revision: https://reviews.llvm.org/D147032

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Transfer.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index be5c9992a6d9d..d255d27e52c45 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -139,6 +139,8 @@ static Value *maybeUnpackLValueExpr(const Expr &E, 
Environment &Env) {
   return &UnpackedVal;
 }
 
+namespace {
+
 class TransferVisitor : public ConstStmtVisitor {
 public:
   TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env)
@@ -884,6 +886,8 @@ class TransferVisitor : public 
ConstStmtVisitor {
   Environment &Env;
 };
 
+} // namespace
+
 void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) {
   TransferVisitor(StmtToEnv, Env).Visit(&S);
 }



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 762cb1d - [clang][dataflow] Create `Value`s for integer literals.

2023-06-19 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-06-19T08:37:41Z
New Revision: 762cb1d377362daff234ac5172c2c1db4918f6d3

URL: 
https://github.com/llvm/llvm-project/commit/762cb1d377362daff234ac5172c2c1db4918f6d3
DIFF: 
https://github.com/llvm/llvm-project/commit/762cb1d377362daff234ac5172c2c1db4918f6d3.diff

LOG: [clang][dataflow] Create `Value`s for integer literals.

This patch includes a test that fails without the fix.

I discovered that we weren't creating `Value`s for integer literals when, in a
different patch, I tried to overwrite the value of a struct field with a literal
for the purposes of a test and was surprised to find that the struct compared
the same before and after the assignment.

This functionality therefore seems useful at least for tests, but is probably
also useful for actual analysis of code.

Reviewed By: ymandel, xazax.hun, gribozavr2

Differential Revision: https://reviews.llvm.org/D152813

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/Arena.h
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/Arena.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/Arena.h 
b/clang/include/clang/Analysis/FlowSensitive/Arena.h
index d8a123c52eb83..83b4ddeec0256 100644
--- a/clang/include/clang/Analysis/FlowSensitive/Arena.h
+++ b/clang/include/clang/Analysis/FlowSensitive/Arena.h
@@ -84,6 +84,12 @@ class Arena {
   /// will be a value that represents the true boolean literal.
   BoolValue &makeEquals(BoolValue &LHS, BoolValue &RHS);
 
+  /// Returns a symbolic integer value that models an integer literal equal to
+  /// `Value`. These literals are the same every time.
+  /// Integer literals are not typed; the type is determined by the `Expr` that
+  /// an integer literal is associated with.
+  IntegerValue &makeIntLiteral(llvm::APInt Value);
+
   /// Returns a symbolic boolean value that models a boolean literal equal to
   /// `Value`. These literals are the same every time.
   AtomicBoolValue &makeLiteral(bool Value) const {
@@ -103,8 +109,9 @@ class Arena {
   std::vector> Locs;
   std::vector> Vals;
 
-  // Indices that are used to avoid recreating the same composite boolean
-  // values.
+  // Indices that are used to avoid recreating the same integer literals and
+  // composite boolean values.
+  llvm::DenseMap IntegerLiterals;
   llvm::DenseMap, ConjunctionValue *>
   ConjunctionVals;
   llvm::DenseMap, DisjunctionValue *>

diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index a31f5ec116425..059cb841e89c7 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -448,6 +448,12 @@ class Environment {
 return DACtx->arena().create(std::forward(args)...);
   }
 
+  /// Returns a symbolic integer value that models an integer literal equal to
+  /// `Value`
+  IntegerValue &getIntLiteralValue(llvm::APInt Value) const {
+return DACtx->arena().makeIntLiteral(Value);
+  }
+
   /// Returns a symbolic boolean value that models a boolean literal equal to
   /// `Value`
   AtomicBoolValue &getBoolLiteralValue(bool Value) const {

diff  --git a/clang/lib/Analysis/FlowSensitive/Arena.cpp 
b/clang/lib/Analysis/FlowSensitive/Arena.cpp
index a0182af85a228..cff6c45e18542 100644
--- a/clang/lib/Analysis/FlowSensitive/Arena.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Arena.cpp
@@ -68,4 +68,12 @@ BoolValue &Arena::makeEquals(BoolValue &LHS, BoolValue &RHS) 
{
   return *Res.first->second;
 }
 
+IntegerValue &Arena::makeIntLiteral(llvm::APInt Value) {
+  auto [It, Inserted] = IntegerLiterals.try_emplace(Value, nullptr);
+
+  if (Inserted)
+It->second = &create();
+  return *It->second;
+}
+
 } // namespace clang::dataflow

diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index e0cb872cfa372..e7f596ace6aaa 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -48,9 +48,15 @@ const Environment *StmtToEnvMap::getEnvironment(const Stmt 
&S) const {
 
 static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,
   Environment &Env) {
-  if (auto *LHSValue = dyn_cast_or_null(Env.getValueStrict(LHS)))
-if (auto *RHSValue = dyn_cast_or_null(Env.getValueStrict(RHS)))
-  return Env.makeIff(*LHSValue, *RHSValue);
+  Value *LHSValue = Env.getValueStrict(LHS);
+  Value *RHSValue = Env.getValueStrict(RHS);
+
+  if (LHSValue == RHSValue)
+return Env.getBoolLiteralValue(true);
+
+  if (auto *LHSBool = dyn_cast_or_null(LHSValue))
+if (auto *RHSBool = d

[clang] efbb4aa - [clang][dataflow] Dump useful debugging information when we crash.

2023-06-22 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-06-23T06:49:28Z
New Revision: efbb4aaacedf0ded734d0b40c42d4419d03a59ff

URL: 
https://github.com/llvm/llvm-project/commit/efbb4aaacedf0ded734d0b40c42d4419d03a59ff
DIFF: 
https://github.com/llvm/llvm-project/commit/efbb4aaacedf0ded734d0b40c42d4419d03a59ff.diff

LOG: [clang][dataflow] Dump useful debugging information when we crash.

- The AST of the function we're currently analyzing
- The CFG
- The CFG element we're currently processing

Reviewed By: ymandel

Differential Revision: https://reviews.llvm.org/D153549

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp 
b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
index 38853c4d75429..de22d63812574 100644
--- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
+++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
@@ -18,6 +18,7 @@
 #include 
 #include 
 
+#include "clang/AST/ASTDumper.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/OperationKinds.h"
 #include "clang/AST/StmtVisitor.h"
@@ -179,6 +180,47 @@ struct AnalysisContext {
   llvm::ArrayRef> BlockStates;
 };
 
+class PrettyStackTraceAnalysis : public llvm::PrettyStackTraceEntry {
+public:
+  PrettyStackTraceAnalysis(const ControlFlowContext &CFCtx, const char 
*Message)
+  : CFCtx(CFCtx), Message(Message) {}
+
+  void print(raw_ostream &OS) const override {
+OS << Message << "\n";
+OS << "Decl:\n";
+CFCtx.getDecl()->dump(OS);
+OS << "CFG:\n";
+CFCtx.getCFG().print(OS, LangOptions(), false);
+  }
+
+private:
+  const ControlFlowContext &CFCtx;
+  const char *Message;
+};
+
+class PrettyStackTraceCFGElement : public llvm::PrettyStackTraceEntry {
+public:
+  PrettyStackTraceCFGElement(const CFGElement &Element, int BlockIdx,
+ int ElementIdx, const char *Message)
+  : Element(Element), BlockIdx(BlockIdx), ElementIdx(ElementIdx),
+Message(Message) {}
+
+  void print(raw_ostream &OS) const override {
+OS << Message << ": Element [B" << BlockIdx << "." << ElementIdx << "]\n";
+if (auto Stmt = Element.getAs()) {
+  OS << "Stmt:\n";
+  ASTDumper Dumper(OS, false);
+  Dumper.Visit(Stmt->getStmt());
+}
+  }
+
+private:
+  const CFGElement ∈
+  int BlockIdx;
+  int ElementIdx;
+  const char *Message;
+};
+
 } // namespace
 
 /// Computes the input state for a given basic block by joining the output
@@ -357,7 +399,11 @@ transferCFGBlock(const CFGBlock &Block, AnalysisContext 
&AC,
   AC.Log.enterBlock(Block);
   auto State = computeBlockInputState(Block, AC);
   AC.Log.recordState(State);
+  int ElementIdx = 1;
   for (const auto &Element : Block) {
+PrettyStackTraceCFGElement CrashInfo(Element, Block.getBlockID(),
+ ElementIdx++, "transferCFGBlock");
+
 AC.Log.enterElement(Element);
 // Built-in analysis
 if (AC.Analysis.builtinOptions()) {
@@ -395,6 +441,8 @@ runTypeErasedDataflowAnalysis(
 std::function
 PostVisitCFG) {
+  PrettyStackTraceAnalysis CrashInfo(CFCtx, "runTypeErasedDataflowAnalysis");
+
   PostOrderCFGView POV(&CFCtx.getCFG());
   ForwardDataflowWorklist Worklist(CFCtx.getCFG(), &POV);
 



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] f2123af - [clang][dataflow] Perform deep copies in copy and move operations.

2023-06-26 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-06-26T13:52:56Z
New Revision: f2123af1e7d7555af92b1bcff91bd5d0679a9b55

URL: 
https://github.com/llvm/llvm-project/commit/f2123af1e7d7555af92b1bcff91bd5d0679a9b55
DIFF: 
https://github.com/llvm/llvm-project/commit/f2123af1e7d7555af92b1bcff91bd5d0679a9b55.diff

LOG: [clang][dataflow] Perform deep copies in copy and move operations.

This serves two purposes:

- Because, today, we only copy the `StructValue`, modifying the destination of
  the copy also modifies the source. This is demonstrated by the new checks
  added to `CopyConstructor` and `MoveConstructor`, which fail without the
  deep copy.

- It lays the groundwork for eliminating the redundancy between
  `AggregateStorageLocation` and `StructValue`, which will happen as part of the
  ongoing migration to strict handling of value categories (seeo
  https://discourse.llvm.org/t/70086 for details). This will involve turning
  `StructValue` into essentially just a wrapper for `AggregateStorageLocation`;
  under this scheme, the current "shallow" copy (copying a `StructValue` from
  one `AggregateStorageLocation` to another) will no longer be possible.

Because we now perform deep copies, tests need to perform a deep equality
comparison instead of just comparing for equal identity of the `StructValue`s.
The new function `recordsEqual()` provides such a deep equality comparison.

Reviewed By: xazax.hun

Differential Revision: https://reviews.llvm.org/D153006

Added: 
clang/include/clang/Analysis/FlowSensitive/RecordOps.h
clang/lib/Analysis/FlowSensitive/RecordOps.cpp
clang/unittests/Analysis/FlowSensitive/RecordOpsTest.cpp

Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/include/clang/Analysis/FlowSensitive/StorageLocation.h
clang/include/clang/Analysis/FlowSensitive/Value.h
clang/lib/Analysis/FlowSensitive/CMakeLists.txt
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/CMakeLists.txt
clang/unittests/Analysis/FlowSensitive/TestingSupport.h
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index 1184fa60bd234..15e63c3d91a32 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -397,6 +397,9 @@ class Environment {
   /// Assigns `Val` as the value of `Loc` in the environment.
   void setValue(const StorageLocation &Loc, Value &Val);
 
+  /// Clears any association between `Loc` and a value in the environment.
+  void clearValue(const StorageLocation &Loc);
+
   /// Assigns `Val` as the value of the prvalue `E` in the environment.
   ///
   /// If `E` is not yet associated with a storage location, associates it with

diff  --git a/clang/include/clang/Analysis/FlowSensitive/RecordOps.h 
b/clang/include/clang/Analysis/FlowSensitive/RecordOps.h
new file mode 100644
index 0..f5a0a5a501c11
--- /dev/null
+++ b/clang/include/clang/Analysis/FlowSensitive/RecordOps.h
@@ -0,0 +1,71 @@
+//===-- RecordOps.h -*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+//  Operations on records (structs, classes, and unions).
+//
+//===--===//
+
+#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_RECORDOPS_H
+#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_RECORDOPS_H
+
+#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
+#include "clang/Analysis/FlowSensitive/StorageLocation.h"
+
+namespace clang {
+namespace dataflow {
+
+/// Copies a record (struct, class, or union) from `Src` to `Dst`.
+///
+/// This performs a deep copy, i.e. it copies every field and recurses on
+/// fields of record type. It also copies properties from the `StructValue`
+/// associated with `Dst` to the `StructValue` associated with `Src` (if these
+/// `StructValue`s exist).
+///
+/// If there is a `StructValue` associated with `Dst` in the environment, this
+/// function creates a new `StructValue` and associates it with `Dst`; clients
+/// need to be aware of this and must not assume that the `StructValue`
+/// associated with `Dst` remains the same after the call.
+///
+/// We create a new `StructValue` rather than modifying properties on the old
+/// `StructValue` because the old `StructValue` may be shared with other
+/// `Environment`s, and we don't want changes to proper

[clang] 9a4097e - [clang][dataflow] Use namespace qualifiers when defining functions.

2023-06-27 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-06-27T08:56:21Z
New Revision: 9a4097e9cd891e1445ba07ac6a21fe117fce

URL: 
https://github.com/llvm/llvm-project/commit/9a4097e9cd891e1445ba07ac6a21fe117fce
DIFF: 
https://github.com/llvm/llvm-project/commit/9a4097e9cd891e1445ba07ac6a21fe117fce.diff

LOG: [clang][dataflow] Use namespace qualifiers when defining functions.

See

https://llvm.org/docs/CodingStandards.html#use-namespace-qualifiers-to-implement-previously-declared-functions

Thank you to MaskRay for pointing this out on

https://reviews.llvm.org/D153006

Reviewed By: xazax.hun

Differential Revision: https://reviews.llvm.org/D153833

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/RecordOps.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/RecordOps.cpp 
b/clang/lib/Analysis/FlowSensitive/RecordOps.cpp
index d7145b0e2b312..eac9e3d4f93f2 100644
--- a/clang/lib/Analysis/FlowSensitive/RecordOps.cpp
+++ b/clang/lib/Analysis/FlowSensitive/RecordOps.cpp
@@ -14,11 +14,9 @@
 
 #define DEBUG_TYPE "dataflow"
 
-namespace clang {
-namespace dataflow {
-
-void copyRecord(AggregateStorageLocation &Src, AggregateStorageLocation &Dst,
-Environment &Env) {
+void clang::dataflow::copyRecord(AggregateStorageLocation &Src,
+ AggregateStorageLocation &Dst,
+ Environment &Env) {
   LLVM_DEBUG({
 if (Dst.getType().getCanonicalType().getUnqualifiedType() !=
 Src.getType().getCanonicalType().getUnqualifiedType()) {
@@ -62,9 +60,10 @@ void copyRecord(AggregateStorageLocation &Src, 
AggregateStorageLocation &Dst,
   }
 }
 
-bool recordsEqual(const AggregateStorageLocation &Loc1, const Environment 
&Env1,
-  const AggregateStorageLocation &Loc2,
-  const Environment &Env2) {
+bool clang::dataflow::recordsEqual(const AggregateStorageLocation &Loc1,
+   const Environment &Env1,
+   const AggregateStorageLocation &Loc2,
+   const Environment &Env2) {
   LLVM_DEBUG({
 if (Loc2.getType().getCanonicalType().getUnqualifiedType() !=
 Loc1.getType().getCanonicalType().getUnqualifiedType()) {
@@ -124,6 +123,3 @@ bool recordsEqual(const AggregateStorageLocation &Loc1, 
const Environment &Env1,
 
   return true;
 }
-
-} // namespace dataflow
-} // namespace clang



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] d04b198 - [clang][dataflow] Add a test that we can access fields of anonymous records.

2023-06-28 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-06-28T09:12:03Z
New Revision: d04b198973c9bda2376209b460943ac393190752

URL: 
https://github.com/llvm/llvm-project/commit/d04b198973c9bda2376209b460943ac393190752
DIFF: 
https://github.com/llvm/llvm-project/commit/d04b198973c9bda2376209b460943ac393190752.diff

LOG: [clang][dataflow] Add a test that we can access fields of anonymous 
records.

Reviewed By: sammccall, ymandel, gribozavr2, xazax.hun

Differential Revision: https://reviews.llvm.org/D153409

Added: 


Modified: 
clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
clang/unittests/Analysis/FlowSensitive/TestingSupport.h
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp 
b/clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
index 0d441b71e69c6..a88b8d88c74c0 100644
--- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
@@ -154,9 +154,19 @@ test::buildStatementToAnnotationMapping(const FunctionDecl 
*Func,
 }
 
 const ValueDecl *test::findValueDecl(ASTContext &ASTCtx, llvm::StringRef Name) 
{
-  auto TargetNodes = match(valueDecl(hasName(Name)).bind("v"), ASTCtx);
+  auto TargetNodes = match(
+  valueDecl(unless(indirectFieldDecl()), hasName(Name)).bind("v"), ASTCtx);
   assert(TargetNodes.size() == 1 && "Name must be unique");
   auto *const Result = selectFirst("v", TargetNodes);
   assert(Result != nullptr);
   return Result;
 }
+
+const IndirectFieldDecl *test::findIndirectFieldDecl(ASTContext &ASTCtx,
+ llvm::StringRef Name) {
+  auto TargetNodes = match(indirectFieldDecl(hasName(Name)).bind("i"), ASTCtx);
+  assert(TargetNodes.size() == 1 && "Name must be unique");
+  const auto *Result = selectFirst("i", TargetNodes);
+  assert(Result != nullptr);
+  return Result;
+}

diff  --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h 
b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
index e22600d7b2e44..856737d034855 100644
--- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
+++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
@@ -428,6 +428,14 @@ runDataflowReturnError(llvm::StringRef Code, 
VerifyResultsT VerifyResults,
 ///   `Name` must be unique in `ASTCtx`.
 const ValueDecl *findValueDecl(ASTContext &ASTCtx, llvm::StringRef Name);
 
+/// Returns the `IndirectFieldDecl` for the given identifier.
+///
+/// Requirements:
+///
+///   `Name` must be unique in `ASTCtx`.
+const IndirectFieldDecl *findIndirectFieldDecl(ASTContext &ASTCtx,
+   llvm::StringRef Name);
+
 /// Returns the storage location (of type `LocT`) for the given identifier.
 /// `LocT` must be a subclass of `StorageLocation` and must be of the
 /// appropriate type.

diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 5e7abcc6ce750..51550adeea894 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -5434,4 +5434,38 @@ TEST(TransferTest, BuiltinFunctionModeled) {
   });
 }
 
+// Check that fields of anonymous records are modeled.
+TEST(TransferTest, AnonymousStruct) {
+  std::string Code = R"(
+struct S {
+  struct {
+bool b;
+  };
+};
+void target() {
+  S s;
+  s.b = true;
+  // [[p]]
+}
+  )";
+  runDataflow(
+  Code,
+  [](const llvm::StringMap> &Results,
+ ASTContext &ASTCtx) {
+const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+const ValueDecl *SDecl = findValueDecl(ASTCtx, "s");
+const ValueDecl *BDecl = findValueDecl(ASTCtx, "b");
+const IndirectFieldDecl *IndirectField =
+findIndirectFieldDecl(ASTCtx, "b");
+
+auto *S =
+cast(Env.getStorageLocation(*SDecl));
+auto &AnonStruct = cast(
+S->getChild(*cast(IndirectField->chain().front(;
+
+auto *B = cast(Env.getValue(AnonStruct.getChild(*BDecl)));
+ASSERT_TRUE(Env.flowConditionImplies(*B));
+  });
+}
+
 } // namespace



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 834a84d - [clang][dataflow] Output debug info if `getChild()` doesn't find field.

2023-06-28 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-06-28T09:12:08Z
New Revision: 834a84d091ab7d196e966d8f08101136eb1c1e06

URL: 
https://github.com/llvm/llvm-project/commit/834a84d091ab7d196e966d8f08101136eb1c1e06
DIFF: 
https://github.com/llvm/llvm-project/commit/834a84d091ab7d196e966d8f08101136eb1c1e06.diff

LOG: [clang][dataflow] Output debug info if `getChild()` doesn't find field.

Depends On D153409

Reviewed By: xazax.hun

Differential Revision: https://reviews.llvm.org/D153851

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/StorageLocation.h

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h 
b/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h
index 58ebb9bf52586..453f1e13362b7 100644
--- a/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h
+++ b/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h
@@ -17,6 +17,9 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/Type.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/Debug.h"
+
+#define DEBUG_TYPE "dataflow"
 
 namespace clang {
 namespace dataflow {
@@ -85,6 +88,17 @@ class AggregateStorageLocation final : public 
StorageLocation {
   /// Returns the child storage location for `D`.
   StorageLocation &getChild(const ValueDecl &D) const {
 auto It = Children.find(&D);
+LLVM_DEBUG({
+  if (It == Children.end()) {
+llvm::dbgs() << "Couldn't find child " << D.getNameAsString()
+ << " on StorageLocation " << this << " of type "
+ << getType() << "\n";
+llvm::dbgs() << "Existing children:\n";
+for ([[maybe_unused]] auto [Field, Loc] : Children) {
+  llvm::dbgs() << Field->getNameAsString() << "\n";
+}
+  }
+});
 assert(It != Children.end());
 return *It->second;
   }
@@ -100,4 +114,6 @@ class AggregateStorageLocation final : public 
StorageLocation {
 } // namespace dataflow
 } // namespace clang
 
+#undef DEBUG_TYPE
+
 #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_STORAGELOCATION_H



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] abc8367 - [clang][dataflow] Don't crash if copy constructor arg doesn't have a storage location.

2023-06-28 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-06-28T11:15:52Z
New Revision: abc8367413ff377b79e9743ca85252f209f81d65

URL: 
https://github.com/llvm/llvm-project/commit/abc8367413ff377b79e9743ca85252f209f81d65
DIFF: 
https://github.com/llvm/llvm-project/commit/abc8367413ff377b79e9743ca85252f209f81d65.diff

LOG: [clang][dataflow] Don't crash if copy constructor arg doesn't have a 
storage location.

I accidentally used `cast` instead of `cast_or_null`.

Reviewed By: sammccall, xazax.hun

Differential Revision: https://reviews.llvm.org/D153956

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index c09b6b9a99ac3..54b8b3a108dc0 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -598,7 +598,7 @@ class TransferVisitor : public 
ConstStmtVisitor {
   const Expr *Arg = S->getArg(0);
   assert(Arg != nullptr);
 
-  auto *ArgLoc = cast(
+  auto *ArgLoc = cast_or_null(
   Env.getStorageLocation(*Arg, SkipPast::Reference));
   if (ArgLoc == nullptr)
 return;

diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 51550adeea894..f41c3f2fdd2f7 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -2237,6 +2237,21 @@ TEST(TransferTest, CopyConstructorWithParens) {
   });
 }
 
+TEST(TransferTest, CopyConstructorArgIsRefReturnedByFunction) {
+  // This is a crash repro.
+  std::string Code = R"(
+struct S {};
+const S &returnsSRef();
+void target() {
+  S s(returnsSRef());
+}
+  )";
+  runDataflow(
+  Code,
+  [](const llvm::StringMap> &Results,
+ ASTContext &ASTCtx) {});
+}
+
 TEST(TransferTest, MoveConstructor) {
   std::string Code = R"(
 namespace std {



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 74d8455 - [clang][dataflow] Make `getThisPointeeStorageLocation()` return an `AggregateStorageLocation`.

2023-06-28 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-06-29T04:07:08Z
New Revision: 74d8455ba6a19d9eeaa561fd0eccc8cbf5351a47

URL: 
https://github.com/llvm/llvm-project/commit/74d8455ba6a19d9eeaa561fd0eccc8cbf5351a47
DIFF: 
https://github.com/llvm/llvm-project/commit/74d8455ba6a19d9eeaa561fd0eccc8cbf5351a47.diff

LOG: [clang][dataflow] Make `getThisPointeeStorageLocation()` return an 
`AggregateStorageLocation`.

This avoids the need for casts at callsites.

Depends On D153852

Reviewed By: sammccall, xazax.hun, gribozavr2

Differential Revision: https://reviews.llvm.org/D153854

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index 8da359880e3ce3..faeb5eb69cd838 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -330,7 +330,7 @@ class Environment {
   /// Returns the storage location assigned to the `this` pointee in the
   /// environment or null if the `this` pointee has no assigned storage 
location
   /// in the environment.
-  StorageLocation *getThisPointeeStorageLocation() const;
+  AggregateStorageLocation *getThisPointeeStorageLocation() const;
 
   /// Returns the return value of the current function. This can be null if:
   /// - The function has a void return type
@@ -600,7 +600,7 @@ class Environment {
   StorageLocation *ReturnLoc = nullptr;
   // The storage location of the `this` pointee. Should only be null if the
   // function being analyzed is only a function and not a method.
-  StorageLocation *ThisPointeeLoc = nullptr;
+  AggregateStorageLocation *ThisPointeeLoc = nullptr;
 
   // Maps from program declarations and statements to storage locations that 
are
   // assigned to them. Unlike the maps in `DataflowAnalysisContext`, these

diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index f4867c4becea03..689f8abb51c8e0 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -309,7 +309,8 @@ Environment::Environment(DataflowAnalysisContext &DACtx,
 // FIXME: Initialize the ThisPointeeLoc of lambdas too.
 if (MethodDecl && !MethodDecl->isStatic()) {
   QualType ThisPointeeType = MethodDecl->getThisObjectType();
-  ThisPointeeLoc = &createStorageLocation(ThisPointeeType);
+  ThisPointeeLoc = &cast(
+  createStorageLocation(ThisPointeeType));
   if (Value *ThisPointeeVal = createValue(ThisPointeeType))
 setValue(*ThisPointeeLoc, *ThisPointeeVal);
 }
@@ -327,7 +328,8 @@ Environment Environment::pushCall(const CallExpr *Call) 
const {
   if (const auto *MethodCall = dyn_cast(Call)) {
 if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) {
   if (!isa(Arg))
-Env.ThisPointeeLoc = getStorageLocation(*Arg, SkipPast::Reference);
+Env.ThisPointeeLoc = cast(
+getStorageLocation(*Arg, SkipPast::Reference));
   // Otherwise (when the argument is `this`), retain the current
   // environment's `ThisPointeeLoc`.
 }
@@ -342,7 +344,8 @@ Environment Environment::pushCall(const CallExpr *Call) 
const {
 Environment Environment::pushCall(const CXXConstructExpr *Call) const {
   Environment Env(*this);
 
-  Env.ThisPointeeLoc = &Env.createStorageLocation(Call->getType());
+  Env.ThisPointeeLoc = &cast(
+  Env.createStorageLocation(Call->getType()));
   if (Value *Val = Env.createValue(Call->getType()))
 Env.setValue(*Env.ThisPointeeLoc, *Val);
 
@@ -685,7 +688,7 @@ StorageLocation 
*Environment::getStorageLocationStrict(const Expr &E) const {
   return Loc;
 }
 
-StorageLocation *Environment::getThisPointeeStorageLocation() const {
+AggregateStorageLocation *Environment::getThisPointeeStorageLocation() const {
   return ThisPointeeLoc;
 }
 

diff  --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp 
b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
index 99f18a07ed65c4..d2908725d79b3d 100644
--- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
+++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
@@ -366,8 +366,7 @@ builtinTransferInitializer(const CFGInitializer &Elt,
   assert(Init != nullptr);
 
   auto &Env = InputState.Env;
-  auto &ThisLoc =
-  *cast(Env.getThisPointeeStorageLocation());
+  auto &ThisLoc = *Env.getThisPointeeStorageLocation();
 
   if (!Init->isAnyMemberInitializer())
 // FIXME: Handle base 

[clang] d363248 - [clang][dataflow] Initialize fields of anonymous records correctly.

2023-06-28 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-06-29T04:07:04Z
New Revision: d36324866ee1fb4d1c26552b6b686a463d2b448f

URL: 
https://github.com/llvm/llvm-project/commit/d36324866ee1fb4d1c26552b6b686a463d2b448f
DIFF: 
https://github.com/llvm/llvm-project/commit/d36324866ee1fb4d1c26552b6b686a463d2b448f.diff

LOG: [clang][dataflow] Initialize fields of anonymous records correctly.

Previously, the newly added test would crash.

Depends On D153851

Reviewed By: gribozavr2

Differential Revision: https://reviews.llvm.org/D153852

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index 44801a41c10fa..f4867c4becea0 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -227,8 +227,12 @@ void Environment::initFieldsGlobalsAndFuncs(const 
FunctionDecl *FuncDecl) {
   // constructor-initializers.
   if (const auto *CtorDecl = dyn_cast(FuncDecl)) {
 for (const auto *Init : CtorDecl->inits()) {
-  if (const auto *M = Init->getAnyMember())
-  Fields.insert(M);
+  if (Init->isMemberInitializer()) {
+Fields.insert(Init->getMember());
+  } else if (Init->isIndirectMemberInitializer()) {
+for (const auto *I : Init->getIndirectMember()->chain())
+  Fields.insert(cast(I));
+  }
   const Expr *E = Init->getInit();
   assert(E != nullptr);
   getFieldsGlobalsAndFuncs(*E, Fields, Vars, Funcs);

diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index 54b8b3a108dc0..651930f0dd22b 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -153,7 +153,7 @@ static void propagateStorageLocation(const Expr &From, 
const Expr &To,
 Env.setStorageLocationStrict(To, *Loc);
 }
 
-// Forwards the value or storage location of `From` to `To` in cases where
+// Propagates the value or storage location of `From` to `To` in cases where
 // `From` may be either a glvalue or a prvalue. `To` must be a glvalue iff
 // `From` is a glvalue.
 static void propagateValueOrStorageLocation(const Expr &From, const Expr &To,
@@ -572,18 +572,7 @@ class TransferVisitor : public 
ConstStmtVisitor {
   void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) {
 const Expr *InitExpr = S->getExpr();
 assert(InitExpr != nullptr);
-
-Value *InitExprVal = Env.getValue(*InitExpr, SkipPast::None);
-if (InitExprVal == nullptr)
-  return;
-
-const FieldDecl *Field = S->getField();
-assert(Field != nullptr);
-
-auto &ThisLoc =
-*cast(Env.getThisPointeeStorageLocation());
-auto &FieldLoc = ThisLoc.getChild(*Field);
-Env.setValue(FieldLoc, *InitExprVal);
+propagateValueOrStorageLocation(*InitExpr, *S, Env);
   }
 
   void VisitCXXConstructExpr(const CXXConstructExpr *S) {

diff  --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp 
b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
index 16f8ab9683d56..99f18a07ed65c 100644
--- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
+++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
@@ -366,27 +366,41 @@ builtinTransferInitializer(const CFGInitializer &Elt,
   assert(Init != nullptr);
 
   auto &Env = InputState.Env;
-  const auto &ThisLoc =
+  auto &ThisLoc =
   *cast(Env.getThisPointeeStorageLocation());
 
-  const FieldDecl *Member = Init->getMember();
-  if (Member == nullptr)
-// Not a field initializer.
+  if (!Init->isAnyMemberInitializer())
+// FIXME: Handle base initialization
 return;
 
   auto *InitStmt = Init->getInit();
   assert(InitStmt != nullptr);
 
+  const FieldDecl *Member = nullptr;
+  StorageLocation *MemberLoc = nullptr;
+  if (Init->isMemberInitializer()) {
+Member = Init->getMember();
+MemberLoc = &ThisLoc.getChild(*Member);
+  } else {
+IndirectFieldDecl *IndirectField = Init->getIndirectMember();
+assert(IndirectField != nullptr);
+MemberLoc = &ThisLoc;
+for (const auto *I : IndirectField->chain()) {
+  Member = cast(I);
+  MemberLoc = 
&cast(MemberLoc)->getChild(*Member);
+}
+  }
+  assert(Member != nullptr);
+  assert(MemberLoc != nullptr);
+
   if (Member->getType()->isReferenceType()) {
 auto *InitStmtLoc = Env.getStorageLocationStrict(*InitStmt);
 if (InitStmtLoc == nullptr)
   return;
 
-auto &MemberLoc = ThisLoc.getChild(*Member);
-Env.setValue(MemberLoc, Env.create(*InitStmtLoc));
+Env.setValue(*MemberLoc, Env.create(*I

[clang] 1d7f9ce - [clang][dataflow] Don't crash when creating pointers to members.

2023-06-29 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-06-29T07:12:55Z
New Revision: 1d7f9ce61f6e689ca63df2e36808885c873cf80b

URL: 
https://github.com/llvm/llvm-project/commit/1d7f9ce61f6e689ca63df2e36808885c873cf80b
DIFF: 
https://github.com/llvm/llvm-project/commit/1d7f9ce61f6e689ca63df2e36808885c873cf80b.diff

LOG: [clang][dataflow] Don't crash when creating pointers to members.

The newly added tests crash without the other changes in this patch.

Reviewed By: sammccall, xazax.hun, gribozavr2

Differential Revision: https://reviews.llvm.org/D153960

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index 651930f0dd22b..5ad176dc1cdbe 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -231,6 +231,15 @@ class TransferVisitor : public 
ConstStmtVisitor {
   void VisitDeclRefExpr(const DeclRefExpr *S) {
 const ValueDecl *VD = S->getDecl();
 assert(VD != nullptr);
+
+// `DeclRefExpr`s to fields and non-static methods aren't glvalues, and
+// there's also no sensible `Value` we can assign to them, so skip them.
+if (isa(VD))
+  return;
+if (auto *Method = dyn_cast(VD);
+Method && !Method->isStatic())
+  return;
+
 auto *DeclLoc = Env.getStorageLocation(*VD);
 if (DeclLoc == nullptr)
   return;
@@ -397,8 +406,7 @@ class TransferVisitor : public 
ConstStmtVisitor {
   propagateValueOrStorageLocation(*SubExpr, *S, Env);
   break;
 }
-case CK_NullToPointer:
-case CK_NullToMemberPointer: {
+case CK_NullToPointer: {
   auto &Loc = Env.createStorageLocation(S->getType());
   Env.setStorageLocation(*S, Loc);
 
@@ -407,6 +415,10 @@ class TransferVisitor : public 
ConstStmtVisitor {
   Env.setValue(Loc, NullPointerVal);
   break;
 }
+case CK_NullToMemberPointer:
+  // FIXME: Implement pointers to members. For now, don't associate a value
+  // with this expression.
+  break;
 case CK_FunctionToPointerDecay:
 case CK_BuiltinFnToFnPtr: {
   StorageLocation *PointeeLoc =
@@ -440,14 +452,12 @@ class TransferVisitor : public 
ConstStmtVisitor {
   break;
 }
 case UO_AddrOf: {
-  // Do not form a pointer to a reference. If `SubExpr` is assigned a
-  // `ReferenceValue` then form a value that points to the location of its
-  // pointee.
-  StorageLocation *PointeeLoc = Env.getStorageLocationStrict(*SubExpr);
-  if (PointeeLoc == nullptr)
+  // FIXME: Model pointers to members.
+  if (S->getType()->isMemberPointerType())
 break;
 
-  Env.setValueStrict(*S, Env.create(*PointeeLoc));
+  if (StorageLocation *PointeeLoc = Env.getStorageLocationStrict(*SubExpr))
+Env.setValueStrict(*S, Env.create(*PointeeLoc));
   break;
 }
 case UO_LNot: {

diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 5d2a82b581f3b..210b85f7ae8d6 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -2530,10 +2530,56 @@ TEST(TransferTest, NullToPointerCast) {
   });
 }
 
+TEST(TransferTest, PointerToMemberVariable) {
+  std::string Code = R"(
+struct S {
+  int i;
+};
+void target() {
+  int S::*MemberPointer = &S::i;
+  // [[p]]
+}
+  )";
+  runDataflow(
+  Code,
+  [](const llvm::StringMap> &Results,
+ ASTContext &ASTCtx) {
+const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+
+const ValueDecl *MemberPointerDecl =
+findValueDecl(ASTCtx, "MemberPointer");
+ASSERT_THAT(MemberPointerDecl, NotNull());
+ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull());
+  });
+}
+
+TEST(TransferTest, PointerToMemberFunction) {
+  std::string Code = R"(
+struct S {
+  void Method();
+};
+void target() {
+  void (S::*MemberPointer)() = &S::Method;
+  // [[p]]
+}
+  )";
+  runDataflow(
+  Code,
+  [](const llvm::StringMap> &Results,
+ ASTContext &ASTCtx) {
+const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+
+const ValueDecl *MemberPointerDecl =
+findValueDecl(ASTCtx, "MemberPointer");
+ASSERT_THAT(MemberPointerDecl, NotNull());
+ASSERT_THAT(Env.getValue(*MemberPointerDecl), IsNull());
+  });
+}
+
 TEST(TransferTest, NullToMemberPointerCast) {
   std::string Code = R"(
 struct Foo {};
-void target(Foo *Foo) {
+void target() {
   int Foo::*MemberPointer = nullptr;
   // [[p]]
 }
@@ -2548,12 +2594,7 @@ TEST(TransferTest, NullToMemberPointerCast) {

[clang] ce0ab9d - [clang][dataflow][NFC] Share code between Environment ctor and pushCallInternal().

2023-04-03 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-04-03T08:25:10Z
New Revision: ce0ab9d11cec0a81c4e48645a23fa8eddea926ab

URL: 
https://github.com/llvm/llvm-project/commit/ce0ab9d11cec0a81c4e48645a23fa8eddea926ab
DIFF: 
https://github.com/llvm/llvm-project/commit/ce0ab9d11cec0a81c4e48645a23fa8eddea926ab.diff

LOG: [clang][dataflow][NFC] Share code between Environment ctor and 
pushCallInternal().

The deduplicated code is moved into initVars().

As an added bonus, pushCallInternal() now also gets the "Add all fields
mentioned in default member initializers" behavior, which apparently had been
added to the Environment ctor but not pushCallInternal().

Reviewed By: xazax.hun, ymandel

Differential Revision: https://reviews.llvm.org/D147326

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index 678e5b871cc83..b4ae172e3fa2f 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -460,8 +460,9 @@ class Environment {
   void pushCallInternal(const FunctionDecl *FuncDecl,
 ArrayRef Args);
 
-  /// Assigns storage locations and values to all variables in `Vars`.
-  void initVars(llvm::DenseSet Vars);
+  /// Assigns storage locations and values to all global variables and fields
+  /// referenced in `FuncDecl`. `FuncDecl` must have a body.
+  void initFieldsAndGlobals(const FunctionDecl *FuncDecl);
 
   // `DACtx` is not null and not owned by this object.
   DataflowAnalysisContext *DACtx;

diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index e3bde37ea68f7..fbb8d8ab7edda 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -203,7 +203,33 @@ static void getFieldsAndGlobalVars(const Stmt &S,
 
 // FIXME: Add support for resetting globals after function calls to enable
 // the implementation of sound analyses.
-void Environment::initVars(llvm::DenseSet Vars) {
+void Environment::initFieldsAndGlobals(const FunctionDecl *FuncDecl) {
+  assert(FuncDecl->getBody() != nullptr);
+
+  llvm::DenseSet Fields;
+  llvm::DenseSet Vars;
+
+  // Look for global variable and field references in the
+  // constructor-initializers.
+  if (const auto *CtorDecl = dyn_cast(FuncDecl)) {
+for (const auto *Init : CtorDecl->inits()) {
+  if (const auto *M = Init->getAnyMember())
+  Fields.insert(M);
+  const Expr *E = Init->getInit();
+  assert(E != nullptr);
+  getFieldsAndGlobalVars(*E, Fields, Vars);
+}
+// Add all fields mentioned in default member initializers.
+for (const FieldDecl *F : CtorDecl->getParent()->fields())
+  if (const auto *I = F->getInClassInitializer())
+  getFieldsAndGlobalVars(*I, Fields, Vars);
+  }
+  getFieldsAndGlobalVars(*FuncDecl->getBody(), Fields, Vars);
+
+  // These have to be added before the lines that follow to ensure that
+  // `create*` work correctly for structs.
+  DACtx->addModeledFields(Fields);
+
   for (const VarDecl *D : Vars) {
 if (getStorageLocation(*D, SkipPast::None) != nullptr)
   continue;
@@ -239,31 +265,7 @@ Environment::Environment(DataflowAnalysisContext &DACtx,
   if (const auto *FuncDecl = dyn_cast(&DeclCtx)) {
 assert(FuncDecl->getBody() != nullptr);
 
-llvm::DenseSet Fields;
-llvm::DenseSet Vars;
-
-// Look for global variable and field references in the
-// constructor-initializers.
-if (const auto *CtorDecl = dyn_cast(&DeclCtx)) {
-  for (const auto *Init : CtorDecl->inits()) {
-if (const auto *M = Init->getAnyMember())
-  Fields.insert(M);
-const Expr *E = Init->getInit();
-assert(E != nullptr);
-getFieldsAndGlobalVars(*E, Fields, Vars);
-  }
-  // Add all fields mentioned in default member initializers.
-  for (const FieldDecl *F  : CtorDecl->getParent()->fields())
-if (const auto *I = F->getInClassInitializer())
-  getFieldsAndGlobalVars(*I, Fields, Vars);
-}
-getFieldsAndGlobalVars(*FuncDecl->getBody(), Fields, Vars);
-
-// These have to be added before the lines that follow to ensure that
-// `create*` work correctly for structs.
-DACtx.addModeledFields(Fields);
-
-initVars(Vars);
+initFieldsAndGlobals(FuncDecl);
 
 for (const auto *ParamDecl : FuncDecl->parameters()) {
   assert(ParamDecl != nullptr);
@@ -337,26 +339,7 @@ void Environment::pushCallInternal(const FunctionDecl 
*FuncDecl,
ArrayRef Args) {
   CallStack.push_back(FuncDecl);

[clang] 745a957 - [clang][dataflow] Add `create()` methods to `Environment` and `DataflowAnalysisContext`.

2023-04-04 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-04-04T07:13:44Z
New Revision: 745a957f9dc562477cbe587fb3fa8305713b51b3

URL: 
https://github.com/llvm/llvm-project/commit/745a957f9dc562477cbe587fb3fa8305713b51b3
DIFF: 
https://github.com/llvm/llvm-project/commit/745a957f9dc562477cbe587fb3fa8305713b51b3.diff

LOG: [clang][dataflow] Add `create()` methods to `Environment` and 
`DataflowAnalysisContext`.

These methods provide a less verbose way of allocating `StorageLocation`s and
`Value`s than the existing `takeOwnership(make_unique(...))` pattern.

In addition, because allocation of `StorageLocation`s and `Value`s now happens
within the `DataflowAnalysisContext`, the `create()` open up the possibility
of using `BumpPtrAllocator` to allocate these objects if it turns out this
helps performance.

Reviewed By: ymandel, xazax.hun, gribozavr2

Differential Revision: https://reviews.llvm.org/D147302

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp

Removed: 




diff  --git 
a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
index a044f477ce1b..31bd9809a72a 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
@@ -86,14 +86,51 @@ class DataflowAnalysisContext {
   /*Logger=*/nullptr});
   ~DataflowAnalysisContext();
 
+  /// Creates a `T` (some subclass of `StorageLocation`), forwarding `args` to
+  /// the constructor, and returns a reference to it.
+  ///
+  /// The `DataflowAnalysisContext` takes ownership of the created object. The
+  /// object will be destroyed when the `DataflowAnalysisContext` is destroyed.
+  template 
+  std::enable_if_t::value, T &>
+  create(Args &&...args) {
+// Note: If allocation of individual `StorageLocation`s turns out to be
+// costly, consider creating specializations of `create` for commonly
+// used `StorageLocation` subclasses and make them use a 
`BumpPtrAllocator`.
+return *cast(
+Locs.emplace_back(std::make_unique(std::forward(args)...))
+.get());
+  }
+
+  /// Creates a `T` (some subclass of `Value`), forwarding `args` to the
+  /// constructor, and returns a reference to it.
+  ///
+  /// The `DataflowAnalysisContext` takes ownership of the created object. The
+  /// object will be destroyed when the `DataflowAnalysisContext` is destroyed.
+  template 
+  std::enable_if_t::value, T &>
+  create(Args &&...args) {
+// Note: If allocation of individual `Value`s turns out to be costly,
+// consider creating specializations of `create` for commonly used
+// `Value` subclasses and make them use a `BumpPtrAllocator`.
+return *cast(
+Vals.emplace_back(std::make_unique(std::forward(args)...))
+.get());
+  }
+
   /// Takes ownership of `Loc` and returns a reference to it.
   ///
+  /// This function is deprecated. Instead of
+  /// `takeOwnership(std::make_unique(args))`, prefer
+  /// `create(args)`.
+  ///
   /// Requirements:
   ///
   ///  `Loc` must not be null.
   template 
-  std::enable_if_t::value, T &>
-  takeOwnership(std::unique_ptr Loc) {
+  LLVM_DEPRECATED("use create instead", "")
+  std::enable_if_t::value,
+   T &> takeOwnership(std::unique_ptr Loc) {
 assert(Loc != nullptr);
 Locs.push_back(std::move(Loc));
 return *cast(Locs.back().get());
@@ -101,12 +138,17 @@ class DataflowAnalysisContext {
 
   /// Takes ownership of `Val` and returns a reference to it.
   ///
+  /// This function is deprecated. Instead of
+  /// `takeOwnership(std::make_unique(args))`, prefer
+  /// `create(args)`.
+  ///
   /// Requirements:
   ///
   ///  `Val` must not be null.
   template 
-  std::enable_if_t::value, T &>
-  takeOwnership(std::unique_ptr Val) {
+  LLVM_DEPRECATED("use create instead", "")
+  std::enable_if_t::value, T &> takeOwnership(
+  std::unique_ptr Val) {
 assert(Val != nullptr);
 Vals.push_back(std::move(Val));
 return *cast(Vals.back().get());
@@ -170,9 +212,9 @@ class DataflowAnalysisContext {
   }
 
   /// Creates an atomic boolean value.
-  AtomicBoolValue &createAtomicBoolValue() {
-return takeOwnership(std::make_unique());
-  }
+  LLVM_DEPRECATED("use create instead",
+  "create")
+  AtomicBoolValue &createAtomicBoolValue() { return create(); 
}
 
   /// Creates a Top value for booleans. Each instance i

[clang] 3c8ead2 - [clang][dataflow] Eliminate code duplication in Environment::createValueUnlessSelfReferential().

2023-04-06 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-04-06T07:01:44Z
New Revision: 3c8ead2662ac4a223467007c340c9f9a4b2b38af

URL: 
https://github.com/llvm/llvm-project/commit/3c8ead2662ac4a223467007c340c9f9a4b2b38af
DIFF: 
https://github.com/llvm/llvm-project/commit/3c8ead2662ac4a223467007c340c9f9a4b2b38af.diff

LOG: [clang][dataflow] Eliminate code duplication in 
Environment::createValueUnlessSelfReferential().

Reviewed By: sammccall

Differential Revision: https://reviews.llvm.org/D147601

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index faeabdcbeed66..ee8f6c5b8f574 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -688,9 +688,9 @@ Value *Environment::createValueUnlessSelfReferential(
 return &create();
   }
 
-  if (Type->isReferenceType()) {
+  if (Type->isReferenceType() || Type->isPointerType()) {
 CreatedValuesCount++;
-QualType PointeeType = Type->castAs()->getPointeeType();
+QualType PointeeType = Type->getPointeeType();
 auto &PointeeLoc = createStorageLocation(PointeeType);
 
 if (Visited.insert(PointeeType.getCanonicalType()).second) {
@@ -702,24 +702,10 @@ Value *Environment::createValueUnlessSelfReferential(
 setValue(PointeeLoc, *PointeeVal);
 }
 
-return &create(PointeeLoc);
-  }
-
-  if (Type->isPointerType()) {
-CreatedValuesCount++;
-QualType PointeeType = Type->castAs()->getPointeeType();
-auto &PointeeLoc = createStorageLocation(PointeeType);
-
-if (Visited.insert(PointeeType.getCanonicalType()).second) {
-  Value *PointeeVal = createValueUnlessSelfReferential(
-  PointeeType, Visited, Depth, CreatedValuesCount);
-  Visited.erase(PointeeType.getCanonicalType());
-
-  if (PointeeVal != nullptr)
-setValue(PointeeLoc, *PointeeVal);
-}
-
-return &create(PointeeLoc);
+if (Type->isReferenceType())
+  return &create(PointeeLoc);
+else
+  return &create(PointeeLoc);
   }
 
   if (Type->isStructureOrClassType() || Type->isUnionType()) {



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] effdfa7 - [clang][dataflow] Use `isRecordType()` where appropriate.

2023-04-06 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-04-06T07:26:24Z
New Revision: effdfa7d5f49b00b4c0d36f7c6835b519b0f46bb

URL: 
https://github.com/llvm/llvm-project/commit/effdfa7d5f49b00b4c0d36f7c6835b519b0f46bb
DIFF: 
https://github.com/llvm/llvm-project/commit/effdfa7d5f49b00b4c0d36f7c6835b519b0f46bb.diff

LOG: [clang][dataflow] Use `isRecordType()` where appropriate.

This is less verbose than checking for class, struct, and union individually,
and I believe it's also more efficient (not that that should be the overriding
concern).

Reviewed By: sammccall, xazax.hun

Differential Revision: https://reviews.llvm.org/D147603

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
index 4d8a42c1390c2..1fbc3759747e8 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
@@ -45,8 +45,7 @@ DataflowAnalysisContext::getReferencedFields(QualType Type) {
 }
 
 StorageLocation &DataflowAnalysisContext::createStorageLocation(QualType Type) 
{
-  if (!Type.isNull() &&
-  (Type->isStructureOrClassType() || Type->isUnionType())) {
+  if (!Type.isNull() && Type->isRecordType()) {
 llvm::DenseMap FieldLocs;
 // During context-sensitive analysis, a struct may be allocated in one
 // function, but its field accessed in a function lower in the stack than

diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index ee8f6c5b8f574..6a6343b5f169b 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -608,7 +608,7 @@ void Environment::setValue(const StorageLocation &Loc, 
Value &Val) {
 auto &AggregateLoc = *cast(&Loc);
 
 const QualType Type = AggregateLoc.getType();
-assert(Type->isStructureOrClassType() || Type->isUnionType());
+assert(Type->isRecordType());
 
 for (const FieldDecl *Field : DACtx->getReferencedFields(Type)) {
   assert(Field != nullptr);
@@ -708,7 +708,7 @@ Value *Environment::createValueUnlessSelfReferential(
   return &create(PointeeLoc);
   }
 
-  if (Type->isStructureOrClassType() || Type->isUnionType()) {
+  if (Type->isRecordType()) {
 CreatedValuesCount++;
 llvm::DenseMap FieldValues;
 for (const FieldDecl *Field : DACtx->getReferencedFields(Type)) {



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 991c7e1 - [clang][dataflow][NFC] Remove unused parameter from `insertIfGlobal()`.

2023-04-11 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-04-11T11:31:56Z
New Revision: 991c7e11728f6f6372e5dc865e3a4c0636a575ea

URL: 
https://github.com/llvm/llvm-project/commit/991c7e11728f6f6372e5dc865e3a4c0636a575ea
DIFF: 
https://github.com/llvm/llvm-project/commit/991c7e11728f6f6372e5dc865e3a4c0636a575ea.diff

LOG: [clang][dataflow][NFC] Remove unused parameter from `insertIfGlobal()`.

Reviewed By: gribozavr2

Differential Revision: https://reviews.llvm.org/D148004

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index 6a6343b5f169b..680036b6a5b39 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -156,7 +156,6 @@ static Value &widenDistinctValues(QualType Type, Value 
&Prev,
 
 /// Initializes a global storage value.
 static void insertIfGlobal(const Decl &D,
-   llvm::DenseSet &Fields,
llvm::DenseSet &Vars) {
   if (auto *V = dyn_cast(&D))
 if (V->hasGlobalStorage())
@@ -166,7 +165,7 @@ static void insertIfGlobal(const Decl &D,
 static void getFieldsAndGlobalVars(const Decl &D,
llvm::DenseSet &Fields,
llvm::DenseSet &Vars) {
-  insertIfGlobal(D, Fields, Vars);
+  insertIfGlobal(D, Vars);
   if (const auto *Decomp = dyn_cast(&D))
 for (const auto *B : Decomp->bindings())
   if (auto *ME = dyn_cast_or_null(B->getBinding()))
@@ -191,11 +190,11 @@ static void getFieldsAndGlobalVars(const Stmt &S,
   for (auto *D : DS->getDeclGroup())
   getFieldsAndGlobalVars(*D, Fields, Vars);
   } else if (auto *E = dyn_cast(&S)) {
-insertIfGlobal(*E->getDecl(), Fields, Vars);
+insertIfGlobal(*E->getDecl(), Vars);
   } else if (auto *E = dyn_cast(&S)) {
 // FIXME: should we be using `E->getFoundDecl()`?
 const ValueDecl *VD = E->getMemberDecl();
-insertIfGlobal(*VD, Fields, Vars);
+insertIfGlobal(*VD, Vars);
 if (const auto *FD = dyn_cast(VD))
   Fields.insert(FD);
   }



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 5a16665 - [clang][dataflow] Use `Strict` accessors in more places in Transfer.cpp.

2023-05-21 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-05-22T06:51:10Z
New Revision: 5a16665ed53500b7ee6703be3d5b9e0bca6f1c14

URL: 
https://github.com/llvm/llvm-project/commit/5a16665ed53500b7ee6703be3d5b9e0bca6f1c14
DIFF: 
https://github.com/llvm/llvm-project/commit/5a16665ed53500b7ee6703be3d5b9e0bca6f1c14.diff

LOG: [clang][dataflow] Use `Strict` accessors in more places in Transfer.cpp.

This patch handles the straightforward cases. Upcoming separate patches will 
handle the cases that are more subtle.

This patch is part of the ongoing migration to strict handling of value 
categories (see https://discourse.llvm.org/t/70086 for details).

Depends On D150653

Reviewed By: sammccall, ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D150655

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Transfer.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index 45c601ed49146..838ad934b5fbd 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -48,10 +48,8 @@ const Environment *StmtToEnvMap::getEnvironment(const Stmt 
&S) const {
 
 static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,
   Environment &Env) {
-  if (auto *LHSValue =
-  dyn_cast_or_null(Env.getValue(LHS, SkipPast::Reference)))
-if (auto *RHSValue =
-dyn_cast_or_null(Env.getValue(RHS, 
SkipPast::Reference)))
+  if (auto *LHSValue = dyn_cast_or_null(Env.getValueStrict(LHS)))
+if (auto *RHSValue = dyn_cast_or_null(Env.getValueStrict(RHS)))
   return Env.makeIff(*LHSValue, *RHSValue);
 
   return Env.makeAtomicBoolValue();
@@ -121,9 +119,7 @@ static BoolValue &unpackValue(BoolValue &V, Environment 
&Env) {
 // value, if any unpacking occured. Also, does the lvalue-to-rvalue conversion,
 // by skipping past the reference.
 static Value *maybeUnpackLValueExpr(const Expr &E, Environment &Env) {
-  // FIXME: this is too flexible: it _allows_ a reference, while it should
-  // _require_ one, since lvalues should always be wrapped in `ReferenceValue`.
-  auto *Loc = Env.getStorageLocation(E, SkipPast::Reference);
+  auto *Loc = Env.getStorageLocationStrict(E);
   if (Loc == nullptr)
 return nullptr;
   auto *Val = Env.getValue(*Loc);
@@ -139,6 +135,29 @@ static Value *maybeUnpackLValueExpr(const Expr &E, 
Environment &Env) {
   return &UnpackedVal;
 }
 
+static void propagateValue(const Expr &From, const Expr &To, Environment &Env) 
{
+  if (auto *Val = Env.getValueStrict(From))
+Env.setValueStrict(To, *Val);
+}
+
+static void propagateStorageLocation(const Expr &From, const Expr &To,
+ Environment &Env) {
+  if (auto *Loc = Env.getStorageLocationStrict(From))
+Env.setStorageLocationStrict(To, *Loc);
+}
+
+// Forwards the value or storage location of `From` to `To` in cases where
+// `From` may be either a glvalue or a prvalue. `To` must be a glvalue iff
+// `From` is a glvalue.
+static void propagateValueOrStorageLocation(const Expr &From, const Expr &To,
+Environment &Env) {
+  assert(From.isGLValue() == To.isGLValue());
+  if (From.isGLValue())
+propagateStorageLocation(From, To, Env);
+  else
+propagateValue(From, To, Env);
+}
+
 namespace {
 
 class TransferVisitor : public ConstStmtVisitor {
@@ -155,13 +174,11 @@ class TransferVisitor : public 
ConstStmtVisitor {
 
 switch (S->getOpcode()) {
 case BO_Assign: {
-  auto *LHSLoc = Env.getStorageLocation(*LHS, SkipPast::Reference);
+  auto *LHSLoc = Env.getStorageLocationStrict(*LHS);
   if (LHSLoc == nullptr)
 break;
 
-  // No skipping should be necessary, because any lvalues should have
-  // already been stripped off in evaluating the LValueToRValue cast.
-  auto *RHSVal = Env.getValue(*RHS, SkipPast::None);
+  auto *RHSVal = Env.getValueStrict(*RHS);
   if (RHSVal == nullptr)
 break;
 
@@ -276,7 +293,7 @@ class TransferVisitor : public 
ConstStmtVisitor {
 return;
   }
 
-  if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None))
+  if (auto *InitExprVal = Env.getValueStrict(*InitExpr))
 Env.setValue(Loc, *InitExprVal);
 
   if (Env.getValue(Loc) == nullptr) {
@@ -443,7 +460,7 @@ class TransferVisitor : public 
ConstStmtVisitor {
 }
 case UO_LNot: {
   auto *SubExprVal =
-  dyn_cast_or_null(Env.getValue(*SubExpr, SkipPast::None));
+  dyn_cast_or_null(Env.getValueStrict(*SubExpr));
   if (SubExprVal == nullptr)
 break;
 
@@ -653,19 +670,13 @@ class TransferVisitor : public 
ConstStmtVisitor {
   const Expr *SubExpr = S->getSubExpr();
   assert(SubExpr != nullptr);
 
-  auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);

[clang] 96b22e1 - [clang][dataflow] Use `Strict` accessors in SignAnalysisTest.cpp.

2023-05-21 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-05-22T06:51:13Z
New Revision: 96b22e1c378a93a26cd8fc8051bfc7b90f65b665

URL: 
https://github.com/llvm/llvm-project/commit/96b22e1c378a93a26cd8fc8051bfc7b90f65b665
DIFF: 
https://github.com/llvm/llvm-project/commit/96b22e1c378a93a26cd8fc8051bfc7b90f65b665.diff

LOG: [clang][dataflow] Use `Strict` accessors in SignAnalysisTest.cpp.

This patch is part of the ongoing migration to strict handling of value 
categories (see https://discourse.llvm.org/t/70086 for details).

Depends On D150656

Reviewed By: sammccall, ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D150657

Added: 


Modified: 
clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp

Removed: 




diff  --git a/clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp
index 325ffe1af9914..fe4fdda888bf5 100644
--- a/clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp
@@ -114,12 +114,10 @@ getValueAndSignProperties(const UnaryOperator *UO,
 return {nullptr, {}, {}};
 
   // Value of the unary op.
-  auto *UnaryOpValue = State.Env.getValue(*UO, SkipPast::None);
+  auto *UnaryOpValue = State.Env.getValueStrict(*UO);
   if (!UnaryOpValue) {
-auto &Loc = State.Env.createStorageLocation(*UO);
-State.Env.setStorageLocation(*UO, Loc);
 UnaryOpValue = &State.Env.makeAtomicBoolValue();
-State.Env.setValue(Loc, *UnaryOpValue);
+State.Env.setValueStrict(*UO, *UnaryOpValue);
   }
 
   // Properties for the operand (sub expression).
@@ -133,22 +131,17 @@ getValueAndSignProperties(const UnaryOperator *UO,
 
 void transferBinary(const BinaryOperator *BO, const MatchFinder::MatchResult 
&M,
 LatticeTransferState &State) {
-  StorageLocation *Loc = State.Env.getStorageLocation(*BO, SkipPast::None);
-  if (!Loc) {
-Loc = &State.Env.createStorageLocation(*BO);
-State.Env.setStorageLocation(*BO, *Loc);
-  }
-  BoolValue *Comp = cast_or_null(State.Env.getValue(*Loc));
+  BoolValue *Comp = cast_or_null(State.Env.getValueStrict(*BO));
   if (!Comp) {
 Comp = &State.Env.makeAtomicBoolValue();
-State.Env.setValue(*Loc, *Comp);
+State.Env.setValueStrict(*BO, *Comp);
   }
 
   // FIXME Use this as well:
   // auto *NegatedComp = &State.Env.makeNot(*Comp);
 
-  auto *LHS = State.Env.getValue(*BO->getLHS(), SkipPast::None);
-  auto *RHS = State.Env.getValue(*BO->getRHS(), SkipPast::None);
+  auto *LHS = State.Env.getValueStrict(*BO->getLHS());
+  auto *RHS = State.Env.getValueStrict(*BO->getRHS());
 
   if (!LHS || !RHS)
 return;
@@ -244,19 +237,43 @@ void transferUnaryNot(const UnaryOperator *UO,
   }
 }
 
+// Returns the `Value` associated with `E` (which may be either a prvalue or
+// glvalue). Creates a `Value` or `StorageLocation` as needed if `E` does not
+// have either of these associated with it yet.
+//
+// If this functionality turns out to be needed in more cases, this function
+// should be moved to a more central location.
+Value *getOrCreateValue(const Expr *E, Environment &Env) {
+  Value *Val = nullptr;
+  if (E->isGLValue()) {
+StorageLocation *Loc = Env.getStorageLocationStrict(*E);
+if (!Loc) {
+  Loc = &Env.createStorageLocation(*E);
+  Env.setStorageLocationStrict(*E, *Loc);
+}
+Val = Env.getValue(*Loc);
+if (!Val) {
+  Val = Env.createValue(E->getType());
+  Env.setValue(*Loc, *Val);
+}
+  } else {
+Val = Env.getValueStrict(*E);
+if (!Val) {
+  Val = Env.createValue(E->getType());
+  Env.setValueStrict(*E, *Val);
+}
+  }
+  assert(Val != nullptr);
+
+  return Val;
+}
+
 void transferExpr(const Expr *E, const MatchFinder::MatchResult &M,
   LatticeTransferState &State) {
   const ASTContext &Context = *M.Context;
-  StorageLocation *Loc = State.Env.getStorageLocation(*E, SkipPast::None);
-  if (!Loc) {
-Loc = &State.Env.createStorageLocation(*E);
-State.Env.setStorageLocation(*E, *Loc);
-  }
-  Value *Val = State.Env.getValue(*Loc);
-  if (!Val) {
-Val = State.Env.createValue(Context.IntTy);
-State.Env.setValue(*Loc, *Val);
-  }
+
+  Value *Val = getOrCreateValue(E, State.Env);
+
   // The sign symbolic values have been initialized already.
   if (Val->getProperty("neg"))
 return;



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 8bc8fc6 - [clang][dataflow] Use `Strict` accessors in TypeErasedDataflowAnalysis.cpp.

2023-05-21 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-05-22T06:51:12Z
New Revision: 8bc8fc65c9b20de6ffad63d7ce6734c145265cc2

URL: 
https://github.com/llvm/llvm-project/commit/8bc8fc65c9b20de6ffad63d7ce6734c145265cc2
DIFF: 
https://github.com/llvm/llvm-project/commit/8bc8fc65c9b20de6ffad63d7ce6734c145265cc2.diff

LOG: [clang][dataflow] Use `Strict` accessors in TypeErasedDataflowAnalysis.cpp.

This patch is part of the ongoing migration to strict handling of value 
categories (see https://discourse.llvm.org/t/70086 for details).

Depends On D150655

Reviewed By: sammccall, ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D150656

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp 
b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
index 2e9893e78fa7..4fc8f27ffc9b 100644
--- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
+++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
@@ -123,13 +123,10 @@ class TerminatorVisitor
 private:
   TerminatorVisitorRetTy extendFlowCondition(const Expr &Cond) {
 // The terminator sub-expression might not be evaluated.
-if (Env.getStorageLocation(Cond, SkipPast::None) == nullptr)
+if (Env.getValueStrict(Cond) == nullptr)
   transfer(StmtToEnv, Cond, Env);
 
-// FIXME: The flow condition must be an r-value, so `SkipPast::None` should
-// suffice.
-auto *Val =
-cast_or_null(Env.getValue(Cond, SkipPast::Reference));
+auto *Val = cast_or_null(Env.getValueStrict(Cond));
 // Value merging depends on flow conditions from 
diff erent environments
 // being mutually exclusive -- that is, they cannot both be true in their
 // entirety (even if they may share some clauses). So, we need *some* value
@@ -303,18 +300,14 @@ builtinTransferInitializer(const CFGInitializer &Elt,
   auto *InitStmt = Init->getInit();
   assert(InitStmt != nullptr);
 
-  auto *InitStmtLoc = Env.getStorageLocation(*InitStmt, SkipPast::Reference);
-  if (InitStmtLoc == nullptr)
-return;
-
-  auto *InitStmtVal = Env.getValue(*InitStmtLoc);
-  if (InitStmtVal == nullptr)
-return;
-
   if (Member->getType()->isReferenceType()) {
+auto *InitStmtLoc = Env.getStorageLocationStrict(*InitStmt);
+if (InitStmtLoc == nullptr)
+  return;
+
 auto &MemberLoc = ThisLoc.getChild(*Member);
 Env.setValue(MemberLoc, Env.create(*InitStmtLoc));
-  } else {
+  } else if (auto *InitStmtVal = Env.getValueStrict(*InitStmt)) {
 auto &MemberLoc = ThisLoc.getChild(*Member);
 Env.setValue(MemberLoc, *InitStmtVal);
   }



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 3bc1ea5 - [clang][dataflow] Fix a bug in handling of `operator->` for optional checker.

2023-05-21 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-05-22T06:51:15Z
New Revision: 3bc1ea5b0ac90e04e7b935a5d964613f8fbad4bf

URL: 
https://github.com/llvm/llvm-project/commit/3bc1ea5b0ac90e04e7b935a5d964613f8fbad4bf
DIFF: 
https://github.com/llvm/llvm-project/commit/3bc1ea5b0ac90e04e7b935a5d964613f8fbad4bf.diff

LOG: [clang][dataflow] Fix a bug in handling of `operator->` for optional 
checker.

Prior to this patch, `operator->` was being handled like `operator*`: It was
associating a `Value` of type `T` with the expression result (where `T` is the
template argument of the `optional`). This is correct for `operator*`, which
returns a reference (of some flavor) to `T`, so that the result of the
`CXXOperatorCallExpr` is a glvalue of type `T`. However, `operator*` returns a
`T*`, so the result of the `CXXOperatorCallExpr` is a prvalue `T*`, which should
therefore be associated with `PointerValue` that in turn refers to a `T`.

I noticed this issue while working on the migration to strict handling of
value categories (see https://discourse.llvm.org/t/70086). The current behavior
also seems problematic more generally because it's plausible that the framework
may at some point introduce behavior that assumes an `Expr` of pointer type is
always associated with a `PointerValue`.

As it turns out, this patch fixes an existing FIXME in the test
`OptionalValueInitialization`.

Depends On D150657

Reviewed By: ymandel

Differential Revision: https://reviews.llvm.org/D150775

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp

Removed: 




diff  --git 
a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp 
b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
index 24a3682f438cb..7d30473ea5226 100644
--- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
@@ -399,6 +399,18 @@ void transferUnwrapCall(const Expr *UnwrapExpr, const Expr 
*ObjectExpr,
   }
 }
 
+void transferArrowOpCall(const Expr *UnwrapExpr, const Expr *ObjectExpr,
+ LatticeTransferState &State) {
+  if (auto *OptionalVal =
+  getValueBehindPossiblePointer(*ObjectExpr, State.Env)) {
+if (auto *Loc = maybeInitializeOptionalValueMember(
+UnwrapExpr->getType()->getPointeeType(), *OptionalVal, State.Env)) 
{
+  State.Env.setValueStrict(*UnwrapExpr,
+   State.Env.create(*Loc));
+}
+  }
+}
+
 void transferMakeOptionalCall(const CallExpr *E,
   const MatchFinder::MatchResult &,
   LatticeTransferState &State) {
@@ -774,25 +786,22 @@ auto buildTransferMatchSwitch() {
 transferUnwrapCall(E, E->getImplicitObjectArgument(), State);
   })
 
-  // optional::operator*, optional::operator->
-  // FIXME: This does something slightly strange for `operator->`.
-  // `transferUnwrapCall()` may create a new value of type `T` for the
-  // `optional`, and it associates that value with `E`. In the case of
-  // `operator->`, `E` is a pointer. As a result, we associate an
-  // expression of pointer type with a storage location of non-pointer type
-  // `T`. This can confound other code that expects expressions of
-  // pointer type to be associated with `PointerValue`s, such as the
-  // centrally provided accessors `getImplicitObjectLocation()` and
-  // `getBaseObjectLocation()`, and this is the reason we need to use our
-  // own 'maybeSkipPointer()` and `getValueBehindPossiblePointer()` instead
-  // of these accessors.
-  .CaseOfCFGStmt(valueOperatorCall(std::nullopt),
+  // optional::operator*
+  .CaseOfCFGStmt(isOptionalOperatorCallWithName("*"),
[](const CallExpr *E,
   const MatchFinder::MatchResult &,
   LatticeTransferState &State) {
  transferUnwrapCall(E, E->getArg(0), State);
})
 
+  // optional::operator->
+  .CaseOfCFGStmt(isOptionalOperatorCallWithName("->"),
+   [](const CallExpr *E,
+  const MatchFinder::MatchResult &,
+  LatticeTransferState &State) {
+ transferArrowOpCall(E, E->getArg(0), State);
+   })
+
   // optional::has_value
   .CaseOfCFGStmt(
   isOptionalMemberCallWithName("has_value"),

diff  --git 
a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
index a9d235

[clang] a9e90f7 - [clang][dataflow] Fix a null pointer crash in `computeBlockInputState()`.

2023-05-22 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-05-22T12:19:55Z
New Revision: a9e90f7994222dde987154ed009504afbf3c2166

URL: 
https://github.com/llvm/llvm-project/commit/a9e90f7994222dde987154ed009504afbf3c2166
DIFF: 
https://github.com/llvm/llvm-project/commit/a9e90f7994222dde987154ed009504afbf3c2166.diff

LOG: [clang][dataflow] Fix a null pointer crash in `computeBlockInputState()`.

The crash was due to unconditionally calling
`Block.succ_begin()->getReachableBlock()->hasNoReturnElement()`, but
`getReachableBlock()` can return null now that we have turned
`PruneTriviallyFalseEdges` on.

This patch adds two tests that crash without the fix.

Reviewed By: ymandel

Differential Revision: https://reviews.llvm.org/D151071

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp 
b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
index 4fc8f27ffc9b2..37dd7081ae986 100644
--- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
+++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
@@ -216,7 +216,8 @@ computeBlockInputState(const CFGBlock &Block, 
AnalysisContext &AC) {
 // operator includes a branch that contains a noreturn destructor call.
 //
 // See `NoreturnDestructorTest` for concrete examples.
-if (Block.succ_begin()->getReachableBlock()->hasNoReturnElement()) {
+if (Block.succ_begin()->getReachableBlock() != nullptr &&
+Block.succ_begin()->getReachableBlock()->hasNoReturnElement()) {
   auto &StmtToBlock = AC.CFCtx.getStmtToBlock();
   auto StmtBlock = StmtToBlock.find(Block.getTerminatorStmt());
   assert(StmtBlock != StmtToBlock.end());

diff  --git 
a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
index 30aef86e7a26e..5bfb9e53778b0 100644
--- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
@@ -296,6 +296,22 @@ TEST_F(NoreturnDestructorTest, 
ConditionalOperatorLeftBranchReturns) {
  UnorderedElementsAre("foo"));
 }
 
+TEST_F(NoreturnDestructorTest,
+   ConditionalOperatorConstantCondition_LeftBranchReturns) {
+  std::string Code = R"(
+#include "noreturn_destructor_test_defs.h"
+
+void target() {
+  int value = true ? foo() : Fatal().bar();
+  (void)0;
+  // [[p]]
+}
+  )";
+  runDataflow(Code, UnorderedElementsAre(IsStringMapEntry(
+"p", HoldsFunctionCallLattice(HasCalledFunctions(
+ UnorderedElementsAre("foo"));
+}
+
 TEST_F(NoreturnDestructorTest, ConditionalOperatorRightBranchReturns) {
   std::string Code = R"(
 #include "noreturn_destructor_test_defs.h"
@@ -311,6 +327,22 @@ TEST_F(NoreturnDestructorTest, 
ConditionalOperatorRightBranchReturns) {
  UnorderedElementsAre("foo"));
 }
 
+TEST_F(NoreturnDestructorTest,
+   ConditionalOperatorConstantCondition_RightBranchReturns) {
+  std::string Code = R"(
+#include "noreturn_destructor_test_defs.h"
+
+void target() {
+  int value = false ? Fatal().bar() : foo();
+  (void)0;
+  // [[p]]
+}
+  )";
+  runDataflow(Code, UnorderedElementsAre(IsStringMapEntry(
+"p", HoldsFunctionCallLattice(HasCalledFunctions(
+ UnorderedElementsAre("foo"));
+}
+
 TEST_F(NoreturnDestructorTest, ConditionalOperatorNestedBranchesDoNotReturn) {
   std::string Code = R"(
 #include "noreturn_destructor_test_defs.h"



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 68baaca - [clang][dataflow] Use `Strict` accessors in comma operator and no-op cast.

2023-05-23 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-05-23T11:58:00Z
New Revision: 68baaca61dfad1179a61d99cbf0fe23a6894849d

URL: 
https://github.com/llvm/llvm-project/commit/68baaca61dfad1179a61d99cbf0fe23a6894849d
DIFF: 
https://github.com/llvm/llvm-project/commit/68baaca61dfad1179a61d99cbf0fe23a6894849d.diff

LOG: [clang][dataflow] Use `Strict` accessors in comma operator and no-op cast.

This patch is part of the ongoing migration to strict handling of value
categories (see https://discourse.llvm.org/t/70086 for details).

Depends On D150775

Reviewed By: gribozavr2

Differential Revision: https://reviews.llvm.org/D150776

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Transfer.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index 838ad934b5fbd..9658f5bcd6a0e 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -224,8 +224,7 @@ class TransferVisitor : public 
ConstStmtVisitor {
   break;
 }
 case BO_Comma: {
-  if (auto *Loc = Env.getStorageLocation(*RHS, SkipPast::None))
-Env.setStorageLocation(*S, *Loc);
+  propagateValueOrStorageLocation(*RHS, *S, Env);
   break;
 }
 default:
@@ -397,13 +396,9 @@ class TransferVisitor : public 
ConstStmtVisitor {
   // CK_ConstructorConversion, and CK_UserDefinedConversion.
 case CK_NoOp: {
   // FIXME: Consider making `Environment::getStorageLocation` skip noop
-  // expressions (this and other similar expressions in the file) instead 
of
-  // assigning them storage locations.
-  auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
-  if (SubExprLoc == nullptr)
-break;
-
-  Env.setStorageLocation(*S, *SubExprLoc);
+  // expressions (this and other similar expressions in the file) instead
+  // of assigning them storage locations.
+  propagateValueOrStorageLocation(*SubExpr, *S, Env);
   break;
 }
 case CK_NullToPointer:



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 246626a - [clang][dataflow] Add a `ControlFlowContext::build()` overload taking a `FunctionDecl`.

2023-05-25 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-05-25T07:19:12Z
New Revision: 246626a8cfd3d4f910baadeff4d5aa544b9d4550

URL: 
https://github.com/llvm/llvm-project/commit/246626a8cfd3d4f910baadeff4d5aa544b9d4550
DIFF: 
https://github.com/llvm/llvm-project/commit/246626a8cfd3d4f910baadeff4d5aa544b9d4550.diff

LOG: [clang][dataflow] Add a `ControlFlowContext::build()` overload taking a 
`FunctionDecl`.

This is the most common use case, so it makes sense to have a specific overload 
for it.

Reviewed By: xazax.hun

Differential Revision: https://reviews.llvm.org/D151183

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
clang/unittests/Analysis/FlowSensitive/TestingSupport.h
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h 
b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
index b51e2cb23634d..f327011766069 100644
--- a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
+++ b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
@@ -31,6 +31,11 @@ namespace dataflow {
 /// analysis.
 class ControlFlowContext {
 public:
+  /// Builds a ControlFlowContext from a `FunctionDecl`.
+  /// `Func.hasBody()` must be true, and `Func.isTemplated()` must be false.
+  static llvm::Expected build(const FunctionDecl &Func,
+  ASTContext &C);
+
   /// Builds a ControlFlowContext from an AST node. `D` is the function in 
which
   /// `S` resides. `D.isTemplated()` must be false.
   static llvm::Expected build(const Decl &D, Stmt &S,

diff  --git a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp 
b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
index 4556787d10a8e..c62bff33524cf 100644
--- a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
@@ -67,6 +67,16 @@ static llvm::BitVector findReachableBlocks(const CFG &Cfg) {
   return BlockReachable;
 }
 
+llvm::Expected
+ControlFlowContext::build(const FunctionDecl &Func, ASTContext &C) {
+  if (!Func.hasBody())
+return llvm::createStringError(
+std::make_error_code(std::errc::invalid_argument),
+"Cannot analyze function without a body");
+
+  return build(Func, *Func.getBody(), C);
+}
+
 llvm::Expected
 ControlFlowContext::build(const Decl &D, Stmt &S, ASTContext &C) {
   if (D.isTemplated())

diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
index 73428ac250ad3..32612397ec024 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
@@ -210,8 +210,8 @@ DataflowAnalysisContext::getControlFlowContext(const 
FunctionDecl *F) {
   if (It != FunctionContexts.end())
 return &It->second;
 
-  if (Stmt *Body = F->getBody()) {
-auto CFCtx = ControlFlowContext::build(*F, *Body, F->getASTContext());
+  if (F->hasBody()) {
+auto CFCtx = ControlFlowContext::build(*F, F->getASTContext());
 // FIXME: Handle errors.
 assert(CFCtx);
 auto Result = FunctionContexts.insert({F, std::move(*CFCtx)});

diff  --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h 
b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
index ff7d27d6540cc..d5591bee12dc2 100644
--- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
+++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
@@ -241,8 +241,7 @@ checkDataflow(AnalysisInputs AI,
   llvm::errc::invalid_argument, "Could not find the target function.");
 
 // Build the control flow graph for the target function.
-auto MaybeCFCtx =
-ControlFlowContext::build(*Target, *Target->getBody(), Context);
+auto MaybeCFCtx = ControlFlowContext::build(*Target, Context);
 if (!MaybeCFCtx) return MaybeCFCtx.takeError();
 auto &CFCtx = *MaybeCFCtx;
 

diff  --git 
a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
index 5bfb9e53778b0..84b10c87f6b19 100644
--- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
@@ -67,8 +67,8 @@ runAnalysis(llvm::StringRef Code, AnalysisT 
(*MakeAnalysis)(ASTContext &)) {
   Stmt *Body = Func->getBody();
   assert(Body != nullptr);
 
-  auto CFCtx = llvm::cantFail(
-  ControlFlowContext::build(*Func, *Body, AST->getASTContext()));
+  auto CFCtx =
+  llvm::cantFail(ControlFlowContext::build(*Func, AST->getASTContext()));
 
   AnalysisT Anal

[clang] 6441358 - [clang][dataflow] Add support for return values of reference type.

2023-05-25 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-05-25T08:38:33Z
New Revision: 64413584dacba1fccffa345f69043b3509ee1745

URL: 
https://github.com/llvm/llvm-project/commit/64413584dacba1fccffa345f69043b3509ee1745
DIFF: 
https://github.com/llvm/llvm-project/commit/64413584dacba1fccffa345f69043b3509ee1745.diff

LOG: [clang][dataflow] Add support for return values of reference type.

This patch changes the way `Environment::ReturnLoc` is set: Whereas previously 
it was set by the caller, it is now set by the callee (obviously, as we 
otherwise would not be able to return references).

The patch also introduces `Environment::ReturnVal`, which is used for 
non-reference-type return values. This allows these to be handled with the 
correct value category semantics; see also https://discourse.llvm.org/t/70086, 
which describes the ongoing migration to strict value category semantics.

Depends On D150776

Reviewed By: ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D151194

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index 6f2f7f4004f84..a31f5ec116425 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -192,7 +192,8 @@ class Environment {
 
   /// Moves gathered information back into `this` from a `CalleeEnv` created 
via
   /// `pushCall`.
-  void popCall(const Environment &CalleeEnv);
+  void popCall(const CallExpr *Call, const Environment &CalleeEnv);
+  void popCall(const CXXConstructExpr *Call, const Environment &CalleeEnv);
 
   /// Returns true if and only if the environment is equivalent to `Other`, i.e
   /// the two environments:
@@ -323,8 +324,51 @@ class Environment {
   /// in the environment.
   StorageLocation *getThisPointeeStorageLocation() const;
 
-  /// Returns the storage location of the return value or null, if unset.
-  StorageLocation *getReturnStorageLocation() const;
+  /// Returns the return value of the current function. This can be null if:
+  /// - The function has a void return type
+  /// - No return value could be determined for the function, for example
+  ///   because it calls a function without a body.
+  ///
+  /// Requirements:
+  ///  The current function must have a non-reference return type.
+  Value *getReturnValue() const {
+assert(getCurrentFunc() != nullptr &&
+   !getCurrentFunc()->getReturnType()->isReferenceType());
+return ReturnVal;
+  }
+
+  /// Returns the storage location for the reference returned by the current
+  /// function. This can be null if function doesn't return a single consistent
+  /// reference.
+  ///
+  /// Requirements:
+  ///  The current function must have a reference return type.
+  StorageLocation *getReturnStorageLocation() const {
+assert(getCurrentFunc() != nullptr &&
+   getCurrentFunc()->getReturnType()->isReferenceType());
+return ReturnLoc;
+  }
+
+  /// Sets the return value of the current function.
+  ///
+  /// Requirements:
+  ///  The current function must have a non-reference return type.
+  void setReturnValue(Value *Val) {
+assert(getCurrentFunc() != nullptr &&
+   !getCurrentFunc()->getReturnType()->isReferenceType());
+ReturnVal = Val;
+  }
+
+  /// Sets the storage location for the reference returned by the current
+  /// function.
+  ///
+  /// Requirements:
+  ///  The current function must have a reference return type.
+  void setReturnStorageLocation(StorageLocation *Loc) {
+assert(getCurrentFunc() != nullptr &&
+   getCurrentFunc()->getReturnType()->isReferenceType());
+ReturnLoc = Loc;
+  }
 
   /// Returns a pointer value that represents a null pointer. Calls with
   /// `PointeeType` that are canonically equivalent will return the same 
result.
@@ -472,6 +516,12 @@ class Environment {
   /// returns null.
   const DeclContext *getDeclCtx() const { return CallStack.back(); }
 
+  /// Returns the function currently being analyzed, or null if the code being
+  /// analyzed isn't part of a function.
+  const FunctionDecl *getCurrentFunc() const {
+return dyn_cast(getDeclCtx());
+  }
+
   /// Returns whether this `Environment` can be extended to analyze the given
   /// `Callee` (i.e. if `pushCall` can be used), with recursion disallowed and 
a
   /// given `MaxDepth`.
@@ -515,16 +565,18 @@ class Environment {
   // `DACtx` is not null and not owned by this object.
   DataflowAnalysisContext *DACtx;
 
-
-  // FIXME: move the fields `CallStack`, `ReturnLoc` and `ThisPointeeLoc` into 
a
-  // 

[clang] 49946df - [clang][dataflow][NFC] Remove unused variable.

2023-05-25 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-05-25T12:09:52Z
New Revision: 49946df8211e9d36f0b3755e64b55bc28c0a4247

URL: 
https://github.com/llvm/llvm-project/commit/49946df8211e9d36f0b3755e64b55bc28c0a4247
DIFF: 
https://github.com/llvm/llvm-project/commit/49946df8211e9d36f0b3755e64b55bc28c0a4247.diff

LOG: [clang][dataflow][NFC] Remove unused variable.

Thanks to chapuni to pointing this out on
https://reviews.llvm.org/D151183.

Differential Revision: https://reviews.llvm.org/D151430

Added: 


Modified: 
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp

Removed: 




diff  --git 
a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
index 84b10c87f6b1..1d94b69cfce8 100644
--- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
@@ -64,9 +64,6 @@ runAnalysis(llvm::StringRef Code, AnalysisT 
(*MakeAnalysis)(ASTContext &)) {
 AST->getASTContext()));
   assert(Func != nullptr);
 
-  Stmt *Body = Func->getBody();
-  assert(Body != nullptr);
-
   auto CFCtx =
   llvm::cantFail(ControlFlowContext::build(*Func, AST->getASTContext()));
 



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 7f6c3a9 - [clang][dataflow] Fix a crash in `getLogicOperatorSubExprValue()`.

2023-05-25 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-05-25T14:47:03Z
New Revision: 7f6c3a9033b6409ada46609f5f4b650e8556f56d

URL: 
https://github.com/llvm/llvm-project/commit/7f6c3a9033b6409ada46609f5f4b650e8556f56d
DIFF: 
https://github.com/llvm/llvm-project/commit/7f6c3a9033b6409ada46609f5f4b650e8556f56d.diff

LOG: [clang][dataflow] Fix a crash in `getLogicOperatorSubExprValue()`.

This patch adds a test that crashes without the fix.

Reviewed By: ymandel

Differential Revision: https://reviews.llvm.org/D151201

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index a67f9ceed82e..8547e5049261 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -194,24 +194,13 @@ class TransferVisitor : public 
ConstStmtVisitor {
   auto &Loc = Env.createStorageLocation(*S);
   Env.setStorageLocation(*S, Loc);
 
-  BoolValue *LHSVal = getLogicOperatorSubExprValue(*LHS);
-  // If the LHS was not reachable, this BinaryOperator would also not be
-  // reachable, and we would never get here.
-  assert(LHSVal != nullptr);
-  BoolValue *RHSVal = getLogicOperatorSubExprValue(*RHS);
-  if (RHSVal == nullptr) {
-// If the RHS isn't reachable and we evaluate this BinaryOperator,
-// then the value of the LHS must have triggered the short-circuit
-// logic. This implies that the value of the entire expression must be
-// equal to the value of the LHS.
-Env.setValue(Loc, *LHSVal);
-break;
-  }
+  BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS);
+  BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS);
 
   if (S->getOpcode() == BO_LAnd)
-Env.setValue(Loc, Env.makeAnd(*LHSVal, *RHSVal));
+Env.setValue(Loc, Env.makeAnd(LHSVal, RHSVal));
   else
-Env.setValue(Loc, Env.makeOr(*LHSVal, *RHSVal));
+Env.setValue(Loc, Env.makeOr(LHSVal, RHSVal));
   break;
 }
 case BO_NE:
@@ -805,35 +794,29 @@ class TransferVisitor : public 
ConstStmtVisitor {
   }
 
 private:
-  /// If `SubExpr` is reachable, returns a non-null pointer to the value for
-  /// `SubExpr`. If `SubExpr` is not reachable, returns nullptr.
-  BoolValue *getLogicOperatorSubExprValue(const Expr &SubExpr) {
+  /// Returns the value for the sub-expression `SubExpr` of a logic operator.
+  BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) {
 // `SubExpr` and its parent logic operator might be part of 
diff erent basic
 // blocks. We try to access the value that is assigned to `SubExpr` in the
 // corresponding environment.
-const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr);
-if (!SubExprEnv)
-  return nullptr;
-
-if (auto *Val =
-dyn_cast_or_null(SubExprEnv->getValueStrict(SubExpr)))
-  return Val;
-
-if (Env.getValueStrict(SubExpr) == nullptr) {
-  // Sub-expressions that are logic operators are not added in basic blocks
-  // (e.g. see CFG for `bool d = a && (b || c);`). If `SubExpr` is a logic
-  // operator, it may not have been evaluated and assigned a value yet. In
-  // that case, we need to first visit `SubExpr` and then try to get the
-  // value that gets assigned to it.
+if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr))
+  if (auto *Val =
+  dyn_cast_or_null(SubExprEnv->getValueStrict(SubExpr)))
+return *Val;
+
+// The sub-expression may lie within a basic block that isn't reachable,
+// even if we need it to evaluate the current (reachable) expression
+// (see https://discourse.llvm.org/t/70775). In this case, visit `SubExpr`
+// within the current environment and then try to get the value that gets
+// assigned to it.
+if (Env.getValueStrict(SubExpr) == nullptr)
   Visit(&SubExpr);
-}
-
 if (auto *Val = dyn_cast_or_null(Env.getValueStrict(SubExpr)))
-  return Val;
+  return *Val;
 
 // If the value of `SubExpr` is still unknown, we create a fresh symbolic
 // boolean value for it.
-return &Env.makeAtomicBoolValue();
+return Env.makeAtomicBoolValue();
   }
 
   // If context sensitivity is enabled, try to analyze the body of the callee

diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 726f2b7bbdcc..1a2442f0b12d 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -5140,6 +5140,26 @@ TEST(TransferTest, UnnamedBitfieldInitializer) {
   });
 }
 
+// Repro for a crash that used to occur with chained short-circuiting logical
+// 

[clang] 5ddb623 - [clang][dataflow] Remove unnecessary `ASTContext` parameter from `ControlFlowContext::build` overload.

2023-05-30 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-05-30T07:05:35Z
New Revision: 5ddb623952cacba0a3933dacd4c70439ca95c70d

URL: 
https://github.com/llvm/llvm-project/commit/5ddb623952cacba0a3933dacd4c70439ca95c70d
DIFF: 
https://github.com/llvm/llvm-project/commit/5ddb623952cacba0a3933dacd4c70439ca95c70d.diff

LOG: [clang][dataflow] Remove unnecessary `ASTContext` parameter from 
`ControlFlowContext::build` overload.

When introducing this new overload in https://reviews.llvm.org/D151183, I 
didn't consider that the `ASTContext` parameter was unnecessary because it 
could also be obtained from the `FunctionDecl`.

Reviewed By: gribozavr2, xazax.hun

Differential Revision: https://reviews.llvm.org/D151549

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
clang/unittests/Analysis/FlowSensitive/TestingSupport.h
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h 
b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
index f327011766069..bb36ed237c1e3 100644
--- a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
+++ b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
@@ -33,8 +33,7 @@ class ControlFlowContext {
 public:
   /// Builds a ControlFlowContext from a `FunctionDecl`.
   /// `Func.hasBody()` must be true, and `Func.isTemplated()` must be false.
-  static llvm::Expected build(const FunctionDecl &Func,
-  ASTContext &C);
+  static llvm::Expected build(const FunctionDecl &Func);
 
   /// Builds a ControlFlowContext from an AST node. `D` is the function in 
which
   /// `S` resides. `D.isTemplated()` must be false.

diff  --git a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp 
b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
index c62bff33524cf..c80525dc4f34f 100644
--- a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
@@ -68,13 +68,13 @@ static llvm::BitVector findReachableBlocks(const CFG &Cfg) {
 }
 
 llvm::Expected
-ControlFlowContext::build(const FunctionDecl &Func, ASTContext &C) {
+ControlFlowContext::build(const FunctionDecl &Func) {
   if (!Func.hasBody())
 return llvm::createStringError(
 std::make_error_code(std::errc::invalid_argument),
 "Cannot analyze function without a body");
 
-  return build(Func, *Func.getBody(), C);
+  return build(Func, *Func.getBody(), Func.getASTContext());
 }
 
 llvm::Expected

diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
index 32612397ec024..27ec15adc5350 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
@@ -211,7 +211,7 @@ DataflowAnalysisContext::getControlFlowContext(const 
FunctionDecl *F) {
 return &It->second;
 
   if (F->hasBody()) {
-auto CFCtx = ControlFlowContext::build(*F, F->getASTContext());
+auto CFCtx = ControlFlowContext::build(*F);
 // FIXME: Handle errors.
 assert(CFCtx);
 auto Result = FunctionContexts.insert({F, std::move(*CFCtx)});

diff  --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h 
b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
index d5591bee12dc2..aa2b2a241b224 100644
--- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
+++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h
@@ -241,7 +241,7 @@ checkDataflow(AnalysisInputs AI,
   llvm::errc::invalid_argument, "Could not find the target function.");
 
 // Build the control flow graph for the target function.
-auto MaybeCFCtx = ControlFlowContext::build(*Target, Context);
+auto MaybeCFCtx = ControlFlowContext::build(*Target);
 if (!MaybeCFCtx) return MaybeCFCtx.takeError();
 auto &CFCtx = *MaybeCFCtx;
 

diff  --git 
a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
index 1d94b69cfce81..473750ad7a6cb 100644
--- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
@@ -65,7 +65,7 @@ runAnalysis(llvm::StringRef Code, AnalysisT 
(*MakeAnalysis)(ASTContext &)) {
   assert(Func != nullptr);
 
   auto CFCtx =
-  llvm::cantFail(ControlFlowContext::build(*Func, AST->getASTContext()));
+  llvm::cantFail(ControlFlowContext::build(*Func));
 
   AnalysisT Analysis = MakeAnalysis(AST->getASTContext());
   DataflowAnalysisContext DACtx(std::make_unique());



___

[clang] bfbe137 - [clang][dataflow] Eliminate intermediate `ReferenceValue`s from `Environment::DeclToLoc`.

2023-05-04 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-05-04T20:57:30Z
New Revision: bfbe137888151dfd506df6b3319d08c4de0e00f5

URL: 
https://github.com/llvm/llvm-project/commit/bfbe137888151dfd506df6b3319d08c4de0e00f5
DIFF: 
https://github.com/llvm/llvm-project/commit/bfbe137888151dfd506df6b3319d08c4de0e00f5.diff

LOG: [clang][dataflow] Eliminate intermediate `ReferenceValue`s from 
`Environment::DeclToLoc`.

For the wider context of this change, see the RFC at
https://discourse.llvm.org/t/70086.

After this change, global and local variables of reference type are associated
directly with the `StorageLocation` of the referenced object instead of the
`StorageLocation` of a `ReferenceValue`.

Some tests that explicitly check for an existence of `ReferenceValue` for a
variable of reference type have been modified accordingly.

As discussed in the RFC, I have added an assertion to `Environment::join()` to
check that if both environments contain an entry for the same declaration in
`DeclToLoc`, they both map to the same `StorageLocation`. As discussed in
https://discourse.llvm.org/t/70086/5, this also necessitates removing
declarations from `DeclToLoc` when they go out of scope.

In the RFC, I proposed a gradual migration for this change, but it appears
that all of the callers of `Environment::setStorageLocation(const ValueDecl &,
SkipPast` are in the dataflow framework itself, and that there are only a few of
them.

As this is the function whose semantics are changing in a way that callers
potentially need to adapt to, I've decided to change the semantics of the
function directly.

The semantics of `getStorageLocation(const ValueDecl &, SkipPast SP` now no
longer depend on the behavior of the `SP` parameter. (There don't appear to be
any callers that use `SkipPast::ReferenceThenPointer`, so I've added an
assertion that forbids this usage.)

This patch adds a default argument for the `SP` parameter and removes the
explicit `SP` argument at the callsites that are touched by this change. A
followup patch will remove the argument from the remaining callsites,
allowing the `SkipPast` parameter to be removed entirely. (I don't want to do
that in this patch so that semantics-changing changes can be reviewed separately
from semantics-neutral changes.)

Reviewed By: ymandel, xazax.hun, gribozavr2

Differential Revision: https://reviews.llvm.org/D149144

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index 9c027ef4552ee..cd1703be0507b 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -269,13 +269,24 @@ class Environment {
   ///
   /// Requirements:
   ///
-  ///  `D` must not be assigned a storage location in the environment.
+  ///  `D` must not already have a storage location in the environment.
+  ///
+  ///  If `D` has reference type, `Loc` must refer directly to the referenced
+  ///  object (if any), not to a `ReferenceValue`, and it is not permitted to
+  ///  later change `Loc` to refer to a `ReferenceValue.`
   void setStorageLocation(const ValueDecl &D, StorageLocation &Loc);
 
-  /// Returns the storage location assigned to `D` in the environment, applying
-  /// the `SP` policy for skipping past indirections, or null if `D` isn't
-  /// assigned a storage location in the environment.
-  StorageLocation *getStorageLocation(const ValueDecl &D, SkipPast SP) const;
+  /// Returns the storage location assigned to `D` in the environment, or null
+  /// if `D` isn't assigned a storage location in the environment.
+  ///
+  /// Note that if `D` has reference type, the storage location that is 
returned
+  /// refers directly to the referenced object, not a `ReferenceValue`.
+  ///
+  /// The `SP` parameter is deprecated and has no effect. In addition, it is
+  /// not permitted to pass `SkipPast::ReferenceThenPointer` for this 
parameter.
+  /// New uses of this function should use the default argument for `SP`.
+  StorageLocation *getStorageLocation(const ValueDecl &D,
+  SkipPast SP = SkipPast::None) const;
 
   /// Assigns `Loc` as the storage location of `E` in the environment.
   ///
@@ -320,7 +331,11 @@ class Environment {
 
   /// Equivalent to `getValue(getStorageLocation(D, SP), SkipPast::None)` if 
`D`
   /// is assigned a storage location in the environment, otherwise returns 
null.
-  Value *getValue(const ValueDecl &D, SkipPast SP) const;
+  ///
+  /// The `SP` par

cfe-commits@lists.llvm.org

2023-05-08 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-05-08T07:10:44Z
New Revision: 9940fac7539597c08f03381527011e1280cd7489

URL: 
https://github.com/llvm/llvm-project/commit/9940fac7539597c08f03381527011e1280cd7489
DIFF: 
https://github.com/llvm/llvm-project/commit/9940fac7539597c08f03381527011e1280cd7489.diff

LOG: [clang][dataflow][NFC] Remove `SkipPast` parameter from 
`getStorageLocation(const ValueDecl &).

This parameter was already a no-op, so removing it doesn't change behavior.

Depends On D149144

Reviewed By: ymandel, xazax.hun, gribozavr2

Differential Revision: https://reviews.llvm.org/D149151

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index cd1703be0507b..58b1d8b172b3d 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -281,12 +281,7 @@ class Environment {
   ///
   /// Note that if `D` has reference type, the storage location that is 
returned
   /// refers directly to the referenced object, not a `ReferenceValue`.
-  ///
-  /// The `SP` parameter is deprecated and has no effect. In addition, it is
-  /// not permitted to pass `SkipPast::ReferenceThenPointer` for this 
parameter.
-  /// New uses of this function should use the default argument for `SP`.
-  StorageLocation *getStorageLocation(const ValueDecl &D,
-  SkipPast SP = SkipPast::None) const;
+  StorageLocation *getStorageLocation(const ValueDecl &D) const;
 
   /// Assigns `Loc` as the storage location of `E` in the environment.
   ///

diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index a4d3768b8b189..479aa12d191ee 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -245,7 +245,7 @@ void Environment::initFieldsGlobalsAndFuncs(const 
FunctionDecl *FuncDecl) {
   DACtx->addModeledFields(Fields);
 
   for (const VarDecl *D : Vars) {
-if (getStorageLocation(*D, SkipPast::None) != nullptr)
+if (getStorageLocation(*D) != nullptr)
   continue;
 auto &Loc = createStorageLocation(D->getType().getNonReferenceType());
 setStorageLocation(*D, Loc);
@@ -254,7 +254,7 @@ void Environment::initFieldsGlobalsAndFuncs(const 
FunctionDecl *FuncDecl) {
   }
 
   for (const FunctionDecl *FD : Funcs) {
-if (getStorageLocation(*FD, SkipPast::None) != nullptr)
+if (getStorageLocation(*FD) != nullptr)
   continue;
 auto &Loc = createStorageLocation(FD->getType());
 setStorageLocation(*FD, Loc);
@@ -605,10 +605,7 @@ void Environment::setStorageLocation(const ValueDecl &D, 
StorageLocation &Loc) {
   DeclToLoc[&D] = &Loc;
 }
 
-StorageLocation *Environment::getStorageLocation(const ValueDecl &D,
- SkipPast SP) const {
-  assert(SP != SkipPast::ReferenceThenPointer);
-
+StorageLocation *Environment::getStorageLocation(const ValueDecl &D) const {
   auto It = DeclToLoc.find(&D);
   if (It == DeclToLoc.end())
 return nullptr;
@@ -686,7 +683,7 @@ Value *Environment::getValue(const StorageLocation &Loc) 
const {
 Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const {
   assert(SP != SkipPast::ReferenceThenPointer);
 
-  auto *Loc = getStorageLocation(D, SP);
+  auto *Loc = getStorageLocation(D);
   if (Loc == nullptr)
 return nullptr;
   return getValue(*Loc);

diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index ddabf352fd111..50eb7e9011bda 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -219,7 +219,7 @@ class TransferVisitor : public 
ConstStmtVisitor {
   void VisitDeclRefExpr(const DeclRefExpr *S) {
 const ValueDecl *VD = S->getDecl();
 assert(VD != nullptr);
-auto *DeclLoc = Env.getStorageLocation(*VD, SkipPast::None);
+auto *DeclLoc = Env.getStorageLocation(*VD);
 if (DeclLoc == nullptr)
   return;
 
@@ -533,7 +533,7 @@ class TransferVisitor : public 
ConstStmtVisitor {
 
 if (auto *D = dyn_cast(Member)) {
   if (D->hasGlobalStorage()) {
-auto *VarDeclLoc = Env.getStorageLocation(*D, SkipPast::None);
+auto *VarDeclLoc = Env.

cfe-commits@lists.llvm.org

2023-05-09 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-05-09T07:42:20Z
New Revision: 0c852dc88e9276b74532fd7d233dd23ec1bbed6f

URL: 
https://github.com/llvm/llvm-project/commit/0c852dc88e9276b74532fd7d233dd23ec1bbed6f
DIFF: 
https://github.com/llvm/llvm-project/commit/0c852dc88e9276b74532fd7d233dd23ec1bbed6f.diff

LOG: [clang][dataflow][NFC] Remove `SkipPast` param from `getValue(const 
ValueDecl &)`.

This parameter was already a no-op, so removing it doesn't change behavior.

Reviewed By: ymandel

Differential Revision: https://reviews.llvm.org/D150137

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp
clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
clang/unittests/Analysis/FlowSensitive/SignAnalysisTest.cpp
clang/unittests/Analysis/FlowSensitive/TestingSupport.h
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index 7f24755d9923a..c23e0db7f82d3 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -314,11 +314,7 @@ class Environment {
 
   /// Equivalent to `getValue(getStorageLocation(D, SP), SkipPast::None)` if 
`D`
   /// is assigned a storage location in the environment, otherwise returns 
null.
-  ///
-  /// The `SP` parameter is deprecated and has no effect. In addition, it is
-  /// not permitted to pass `SkipPast::ReferenceThenPointer` for this 
parameter.
-  /// New uses of this function should use the default argument for `SP`.
-  Value *getValue(const ValueDecl &D, SkipPast SP = SkipPast::None) const;
+  Value *getValue(const ValueDecl &D) const;
 
   /// Equivalent to `getValue(getStorageLocation(E, SP), SkipPast::None)` if 
`E`
   /// is assigned a storage location in the environment, otherwise returns 
null.

diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index 479aa12d191ee..0d269f503f4eb 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -680,9 +680,7 @@ Value *Environment::getValue(const StorageLocation &Loc) 
const {
   return It == LocToVal.end() ? nullptr : It->second;
 }
 
-Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const {
-  assert(SP != SkipPast::ReferenceThenPointer);
-
+Value *Environment::getValue(const ValueDecl &D) const {
   auto *Loc = getStorageLocation(D);
   if (Loc == nullptr)
 return nullptr;

diff  --git a/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp
index 86feca486ec7c..f88a179f93a45 100644
--- a/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/ChromiumCheckModelTest.cpp
@@ -158,7 +158,7 @@ TEST(ChromiumCheckModelTest, 
CheckSuccessImpliesConditionHolds) {
 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
 ASSERT_THAT(FooDecl, NotNull());
 
-auto *FooVal = cast(Env.getValue(*FooDecl, SkipPast::None));
+auto *FooVal = cast(Env.getValue(*FooDecl));
 
 EXPECT_TRUE(Env.flowConditionImplies(*FooVal));
   };
@@ -189,7 +189,7 @@ TEST(ChromiumCheckModelTest, UnrelatedCheckIgnored) {
 const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
 ASSERT_THAT(FooDecl, NotNull());
 
-auto *FooVal = cast(Env.getValue(*FooDecl, SkipPast::None));
+auto *FooVal = cast(Env.getValue(*FooDecl));
 
 EXPECT_FALSE(Env.flowConditionImplies(*FooVal));
   };

diff  --git 
a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
index 2f874b44c49bf..1c78dd380c774 100644
--- a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
@@ -124,7 +124,7 @@ TEST_F(EnvironmentTest, InitGlobalVarsFun) {
 
   // Verify the global variable is populated when we analyze `Target`.
   Environment Env(DAContext, *Fun);
-  EXPECT_THAT(Env.getValue(*Var, SkipPast::None), NotNull());
+  EXPECT_THAT(Env.getValue(*Var), NotNull());
 }
 
 // Tests that fields mentioned only in default member initializers are included
@@ -255,7 +255,7 @@ TEST_F(EnvironmentTest, InitGlobalVarsConstructor) {
 
   // Verify the global variable is populated when we analyze `Target`.
   Environment Env(DAContext, *Ctor);
-  EXPECT_THAT(En

[clang] 48bc715 - [clang][dataflow] Eliminate `SkipPast::ReferenceThenPointer`.

2023-05-14 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-05-15T04:33:29Z
New Revision: 48bc71505e03694caac6afb2431ff1157a2382a8

URL: 
https://github.com/llvm/llvm-project/commit/48bc71505e03694caac6afb2431ff1157a2382a8
DIFF: 
https://github.com/llvm/llvm-project/commit/48bc71505e03694caac6afb2431ff1157a2382a8.diff

LOG: [clang][dataflow] Eliminate `SkipPast::ReferenceThenPointer`.

As a replacement, we provide the accessors `getImplicitObjectLocation()` and
`getBaseObjectLocation()`, which are higher-level constructs that cover the use
cases in which `SkipPast::ReferenceThenPointer` was typically used.

Unfortunately, it isn't possible to use these accessors in
UncheckedOptionalAccessModel.cpp; I've added a FIXME to the code explaining the
details. I initially attempted to resolve the issue as part of this patch, but
it turned out to be non-trivial to fix. Instead, I have therefore added a
lower-level replacement for `SkipPast::ReferenceThenPointer` that is used only
within this file.

The wider context of this change is that `SkipPast` will be going away entirely.
See also the RFC at https://discourse.llvm.org/t/70086.

Reviewed By: ymandel, gribozavr2

Differential Revision: https://reviews.llvm.org/D149838

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index c23e0db7f82d3..d734ae5c66fe8 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -46,9 +46,6 @@ enum class SkipPast {
   None,
   /// An optional reference should be skipped past.
   Reference,
-  /// An optional reference should be skipped past, then an optional pointer
-  /// should be skipped past.
-  ReferenceThenPointer,
 };
 
 /// Indicates the result of a tentative comparison.
@@ -477,6 +474,19 @@ class Environment {
   AtomicBoolValue *FlowConditionToken;
 };
 
+/// Returns the storage location for the implicit object of a
+/// `CXXMemberCallExpr`, or null if none is defined in the environment.
+/// Dereferences the pointer if the member call expression was written using
+/// `->`.
+AggregateStorageLocation *
+getImplicitObjectLocation(const CXXMemberCallExpr &MCE, const Environment 
&Env);
+
+/// Returns the storage location for the base object of a `MemberExpr`, or null
+/// if none is defined in the environment. Dereferences the pointer if the
+/// member expression was written using `->`.
+AggregateStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
+const Environment &Env);
+
 } // namespace dataflow
 } // namespace clang
 

diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index 0d269f503f4eb..7b1944f273cf0 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -782,11 +782,6 @@ StorageLocation &Environment::skip(StorageLocation &Loc, 
SkipPast SP) const {
 if (auto *Val = dyn_cast_or_null(getValue(Loc)))
   return Val->getReferentLoc();
 return Loc;
-  case SkipPast::ReferenceThenPointer:
-StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference);
-if (auto *Val = dyn_cast_or_null(getValue(LocPastRef)))
-  return Val->getPointeeLoc();
-return LocPastRef;
   }
   llvm_unreachable("bad SkipPast kind");
 }
@@ -828,5 +823,39 @@ void Environment::dump() const {
   dump(llvm::dbgs());
 }
 
+AggregateStorageLocation *
+getImplicitObjectLocation(const CXXMemberCallExpr &MCE,
+  const Environment &Env) {
+  Expr *ImplicitObject = MCE.getImplicitObjectArgument();
+  if (ImplicitObject == nullptr)
+return nullptr;
+  StorageLocation *Loc =
+  Env.getStorageLocation(*ImplicitObject, SkipPast::Reference);
+  if (Loc == nullptr)
+return nullptr;
+  if (ImplicitObject->getType()->isPointerType()) {
+if (auto *Val = cast_or_null(Env.getValue(*Loc)))
+  return &cast(Val->getPointeeLoc());
+return nullptr;
+  }
+  return cast(Loc);
+}
+
+AggregateStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
+const Environment &Env) {
+  Expr *Base = ME.getBase();
+  if (Base == nullptr)
+return nullptr;
+  StorageLocation *Loc = Env.getStorageLocation(*Base, SkipPast::Reference);
+  if (Loc == nullptr)
+return nullptr;
+  if (ME.isArrow()) {
+if (auto *Val = cast_or_null(Env.

[clang] 1a42f79 - [clang][dataflow] Don't analyze templated declarations.

2023-05-15 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-05-15T11:04:51Z
New Revision: 1a42f795587b9d57291d009989aace6efd0a7a7f

URL: 
https://github.com/llvm/llvm-project/commit/1a42f795587b9d57291d009989aace6efd0a7a7f
DIFF: 
https://github.com/llvm/llvm-project/commit/1a42f795587b9d57291d009989aace6efd0a7a7f.diff

LOG: [clang][dataflow] Don't analyze templated declarations.

Attempting to analyze templated code doesn't have a good cost-benefit ratio. We
have so far done a best-effort attempt at this, but maintaining this support has
an ongoing high maintenance cost because the AST for templates can violate a lot
of the invariants that otherwise hold for the AST of concrete code. As just one
example, in concrete code the operand of a UnaryOperator '*' is always a prvalue
(https://godbolt.org/z/s3e5xxMd1), but in templates this isn't true
(https://godbolt.org/z/6W9xxGvoM).

Further rationale for not analyzing templates:

* The semantics of a template itself are weakly defined; semantics can depend
  strongly on the concrete template arguments. Analyzing the template itself (as
  opposed to an instantiation) therefore has limited value.

* Analyzing templates requires a lot of special-case code that isn't necessary
  for concrete code because dependent types are hard to deal with and the AST
  violates invariants that otherwise hold for concrete code (see above).

* There's precedent in that neither Clang Static Analyzer nor the flow-sensitive
  warnings in Clang (such as uninitialized variables) support analyzing
  templates.

Reviewed By: gribozavr2, xazax.hun

Differential Revision: https://reviews.llvm.org/D150352

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/TestingSupport.h
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h 
b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
index 3495bdfc538cb..b51e2cb23634d 100644
--- a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
+++ b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
@@ -32,7 +32,13 @@ namespace dataflow {
 class ControlFlowContext {
 public:
   /// Builds a ControlFlowContext from an AST node. `D` is the function in 
which
-  /// `S` resides and must not be null.
+  /// `S` resides. `D.isTemplated()` must be false.
+  static llvm::Expected build(const Decl &D, Stmt &S,
+  ASTContext &C);
+
+  /// Builds a ControlFlowContext from an AST node. `D` is the function in 
which
+  /// `S` resides. `D` must not be null and `D->isTemplated()` must be false.
+  LLVM_DEPRECATED("Use the version that takes a const Decl & instead", "")
   static llvm::Expected build(const Decl *D, Stmt &S,
   ASTContext &C);
 

diff  --git a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp 
b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
index 5520633da68ae..4556787d10a8e 100644
--- a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
@@ -68,7 +68,12 @@ static llvm::BitVector findReachableBlocks(const CFG &Cfg) {
 }
 
 llvm::Expected
-ControlFlowContext::build(const Decl *D, Stmt &S, ASTContext &C) {
+ControlFlowContext::build(const Decl &D, Stmt &S, ASTContext &C) {
+  if (D.isTemplated())
+return llvm::createStringError(
+std::make_error_code(std::errc::invalid_argument),
+"Cannot analyze templated declarations");
+
   CFG::BuildOptions Options;
   Options.PruneTriviallyFalseEdges = true;
   Options.AddImplicitDtors = true;
@@ -79,7 +84,7 @@ ControlFlowContext::build(const Decl *D, Stmt &S, ASTContext 
&C) {
   // Ensure that all sub-expressions in basic blocks are evaluated.
   Options.setAllAlwaysAdd();
 
-  auto Cfg = CFG::buildCFG(D, &S, &C, Options);
+  auto Cfg = CFG::buildCFG(&D, &S, &C, Options);
   if (Cfg == nullptr)
 return llvm::createStringError(
 std::make_error_code(std::errc::invalid_argument),
@@ -90,9 +95,19 @@ ControlFlowContext::build(const Decl *D, Stmt &S, ASTContext 
&C) {
 
   llvm::BitVector BlockReachable = findReachableBlocks(*Cfg);
 
-  return ControlFlowContext(D, std::move(Cfg), std::move(StmtToBlock),
+  return ControlFlowContext(&D, std::move(Cfg), std::move(StmtToBlock),
 std::move(BlockReachable));
 }
 
+llvm::Expected
+ControlFlowContext::build(const Decl *D, Stmt &S, ASTContext &C) {
+  if (D == nullptr)
+return llvm::createStringError(
+std::mak

[clang] 080ee85 - [clang][dataflow] Add `Strict` versions of `Value` and `StorageLocation` accessors.

2023-05-17 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-05-17T09:30:47Z
New Revision: 080ee850c639be96b8bea8008088f2b036ff0f15

URL: 
https://github.com/llvm/llvm-project/commit/080ee850c639be96b8bea8008088f2b036ff0f15
DIFF: 
https://github.com/llvm/llvm-project/commit/080ee850c639be96b8bea8008088f2b036ff0f15.diff

LOG: [clang][dataflow] Add `Strict` versions of `Value` and `StorageLocation` 
accessors.

This is part of the gradual migration to strict handling of value categories, 
as described in the RFC at https://discourse.llvm.org/t/70086.

This patch migrates some representative calls of the newly deprecated accessors 
to the new `Strict` functions. Followup patches will migrate the remaining 
callers.  (There are a large number of callers, with some subtlety involved in 
some of them, so it makes sense to split this up into multiple patches rather 
than migrating all callers in one go.)

The `Strict` accessors as implemented here have some differences in semantics 
compared to the semantics originally proposed in the RFC; specifically:

*  `setStorageLocationStrict()`: The RFC proposes to create an intermediate
   `ReferenceValue` that then refers to the `StorageLocation` for the glvalue.
   It turns out though that, even today, most places in the code are not doing
   this but are instead associating glvalues directly with their
   `StorageLocation`. It therefore didn't seem to make sense to introduce new
   `ReferenceValue`s where there were none previously, so I have chosen to
   instead make `setStorageLocationStrict()` simply call through to
   `setStorageLocation(const Expr &, StorageLocation &)` and merely add the
   assertion that the expression must be a glvalue.

*  `getStorageLocationStrict()`: The RFC proposes that this should assert that
   the storage location for the glvalue expression is associated with an
   intermediate `ReferenceValue`, but, as explained, this is often not true.
   The current state is inconsistent: Sometimes the intermediate
   `ReferenceValue` is there, sometimes it isn't. For this reason,
   `getStorageLocationStrict()` skips past a `ReferenceValue` if it is there but
   otherwise directly returns the storage location associated with the
   expression. This behavior is equivalent to the existing behavior of
   `SkipPast::Reference`.

*  `setValueStrict()`: The RFC proposes that this should always create the same
   `StorageLocation` for a given `Value`, but, in fact, the transfer functions
   that exist today don't guarantee this; almost all transfer functions
   unconditionally create a new `StorageLocation` when associating an expression
   with a `Value`.

   There appears to be one special case:
   `TerminatorVisitor::extendFlowCondition()` checks whether the expression is
   already associated with a `StorageLocation` and, if so, reuses the existing
   `StorageLocation` instead of creating a new one.

   For this reason, `setValueStrict()` implements this logic (preserve an
   existing `StorageLocation`) but makes no attempt to always associate the same
   `StorageLocation` with a given `Value`, as nothing in the framework appers to
   require this.

   As `TerminatorVisitor::extendFlowCondition()` is an interesting special case,
   the `setValue()` call there is among the ones that this patch migrates to
   `setValueStrict()`.

Reviewed By: sammccall, ymandel, xazax.hun

Differential Revision: https://reviews.llvm.org/D150653

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index d734ae5c66fe8..6f2f7f4004f84 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -270,16 +270,54 @@ class Environment {
 
   /// Assigns `Loc` as the storage location of `E` in the environment.
   ///
+  /// This function is deprecated; prefer `setStorageLocationStrict()`.
+  /// For details, see https://discourse.llvm.org/t/70086.
+  ///
   /// Requirements:
   ///
   ///  `E` must not be assigned a storage location in the environment.
   void setStorageLocation(const Expr &E, StorageLocation &Loc);
 
+  /// Assigns `Loc` as the storage location of the glvalue `E` in the
+  /// environment.
+  ///
+  /// This function is the preferred alternative to
+  /// `setStorageLocation(const Expr &, StorageLocation &)`. Once the migration
+  /// to strict handling of value categories is complete (see
+  /// https://discourse.llvm.org/t/70086), `setStorageLocation()` will be
+  /// removed and this function will be renamed to `setStorageLocation()`.
+

[clang] 6a81e69 - [clang][dataflow] Remove unused parameter from `diagnoseUnwrapCall()`.

2023-05-17 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-05-17T14:27:58Z
New Revision: 6a81e694ab806d257e43cbc2e32c06099d70cbd8

URL: 
https://github.com/llvm/llvm-project/commit/6a81e694ab806d257e43cbc2e32c06099d70cbd8
DIFF: 
https://github.com/llvm/llvm-project/commit/6a81e694ab806d257e43cbc2e32c06099d70cbd8.diff

LOG: [clang][dataflow] Remove unused parameter from `diagnoseUnwrapCall()`.

Reviewed By: sammccall

Differential Revision: https://reviews.llvm.org/D150756

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp

Removed: 




diff  --git 
a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp 
b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
index 680c4d11a23b7..24a3682f438cb 100644
--- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
@@ -864,8 +864,7 @@ auto buildTransferMatchSwitch() {
   .Build();
 }
 
-std::vector diagnoseUnwrapCall(const Expr *UnwrapExpr,
-   const Expr *ObjectExpr,
+std::vector diagnoseUnwrapCall(const Expr *ObjectExpr,
const Environment &Env) {
   if (auto *OptionalVal = getValueBehindPossiblePointer(*ObjectExpr, Env)) {
 auto *Prop = OptionalVal->getProperty("has_value");
@@ -893,16 +892,16 @@ auto buildDiagnoseMatchSwitch(
   valueCall(IgnorableOptional),
   [](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &,
  const Environment &Env) {
-return diagnoseUnwrapCall(E, E->getImplicitObjectArgument(), Env);
+return diagnoseUnwrapCall(E->getImplicitObjectArgument(), Env);
   })
 
   // optional::operator*, optional::operator->
-  .CaseOfCFGStmt(
-  valueOperatorCall(IgnorableOptional),
-  [](const CallExpr *E, const MatchFinder::MatchResult &,
- const Environment &Env) {
-return diagnoseUnwrapCall(E, E->getArg(0), Env);
-  })
+  .CaseOfCFGStmt(valueOperatorCall(IgnorableOptional),
+   [](const CallExpr *E,
+  const MatchFinder::MatchResult &,
+  const Environment &Env) {
+ return diagnoseUnwrapCall(E->getArg(0), Env);
+   })
   .Build();
 }
 



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 6ab900f - [clang][dataflow] Add support for new expressions.

2023-04-17 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-04-18T04:11:43Z
New Revision: 6ab900f8746e7d8e24afafb5886a40801f6799f4

URL: 
https://github.com/llvm/llvm-project/commit/6ab900f8746e7d8e24afafb5886a40801f6799f4
DIFF: 
https://github.com/llvm/llvm-project/commit/6ab900f8746e7d8e24afafb5886a40801f6799f4.diff

LOG: [clang][dataflow] Add support for new expressions.

Reviewed By: xazax.hun, gribozavr2

Differential Revision: https://reviews.llvm.org/D147698

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index aa8fe907b167..1d273e77ef0b 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -469,6 +469,20 @@ class TransferVisitor : public 
ConstStmtVisitor {
 Env.setValue(Loc, Env.create(*ThisPointeeLoc));
   }
 
+  void VisitCXXNewExpr(const CXXNewExpr *S) {
+auto &Loc = Env.createStorageLocation(*S);
+Env.setStorageLocation(*S, Loc);
+if (Value *Val = Env.createValue(S->getType()))
+  Env.setValue(Loc, *Val);
+  }
+
+  void VisitCXXDeleteExpr(const CXXDeleteExpr *S) {
+// Empty method.
+// We consciously don't do anything on deletes.  Diagnosing double deletes
+// (for example) should be done by a specific analysis, not by the
+// framework.
+  }
+
   void VisitReturnStmt(const ReturnStmt *S) {
 if (!Env.getAnalysisOptions().ContextSensitiveOpts)
   return;

diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 1bb772a93bda..8f02161834dc 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -5170,4 +5170,66 @@ TEST(TransferTest, 
NoReturnFunctionInsideShortCircuitedBooleanOp) {
   });
 }
 
+TEST(TransferTest, NewExpressions) {
+  std::string Code = R"(
+void target() {
+  int *p = new int(42);
+  // [[after_new]]
+}
+  )";
+  runDataflow(
+  Code,
+  [](const llvm::StringMap> &Results,
+ ASTContext &ASTCtx) {
+const Environment &Env =
+getEnvironmentAtAnnotation(Results, "after_new");
+
+auto &P = getValueForDecl(ASTCtx, Env, "p");
+
+EXPECT_THAT(Env.getValue(P.getPointeeLoc()), NotNull());
+  });
+}
+
+TEST(TransferTest, NewExpressions_Structs) {
+  std::string Code = R"(
+struct Inner {
+  int InnerField;
+};
+
+struct Outer {
+  Inner OuterField;
+};
+
+void target() {
+  Outer *p = new Outer;
+  // Access the fields to make sure the analysis actually generates 
children
+  // for them in the `AggregateStorageLoc` and `StructValue`.
+  p->OuterField.InnerField;
+  // [[after_new]]
+}
+  )";
+  runDataflow(
+  Code,
+  [](const llvm::StringMap> &Results,
+ ASTContext &ASTCtx) {
+const Environment &Env =
+getEnvironmentAtAnnotation(Results, "after_new");
+
+const ValueDecl *OuterField = findValueDecl(ASTCtx, "OuterField");
+const ValueDecl *InnerField = findValueDecl(ASTCtx, "InnerField");
+
+auto &P = getValueForDecl(ASTCtx, Env, "p");
+
+auto &OuterLoc = cast(P.getPointeeLoc());
+auto &OuterFieldLoc =
+cast(OuterLoc.getChild(*OuterField));
+auto &InnerFieldLoc = OuterFieldLoc.getChild(*InnerField);
+
+// Values for the struct and all fields exist after the new.
+EXPECT_THAT(Env.getValue(OuterLoc), NotNull());
+EXPECT_THAT(Env.getValue(OuterFieldLoc), NotNull());
+EXPECT_THAT(Env.getValue(InnerFieldLoc), NotNull());
+  });
+}
+
 } // namespace



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] d9e7173 - [clang][dataflow] Associate `FunctionToPointerDecay` nodes with a value.

2023-04-18 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-04-18T07:15:29Z
New Revision: d9e717338f8042664177250315364094262c7073

URL: 
https://github.com/llvm/llvm-project/commit/d9e717338f8042664177250315364094262c7073
DIFF: 
https://github.com/llvm/llvm-project/commit/d9e717338f8042664177250315364094262c7073.diff

LOG: [clang][dataflow] Associate `FunctionToPointerDecay` nodes with a value.

To ensure that we have a pointee for the `PointerValue`, we also create
storage locations for `FunctionDecl`s referenced in the function under analysis.

Reviewed By: gribozavr2

Differential Revision: https://reviews.llvm.org/D148006

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h 
b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index 97ea6a573cffd..4e65d974133a6 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -492,9 +492,9 @@ class Environment {
   void pushCallInternal(const FunctionDecl *FuncDecl,
 ArrayRef Args);
 
-  /// Assigns storage locations and values to all global variables and fields
-  /// referenced in `FuncDecl`. `FuncDecl` must have a body.
-  void initFieldsAndGlobals(const FunctionDecl *FuncDecl);
+  /// Assigns storage locations and values to all global variables, fields
+  /// and functions referenced in `FuncDecl`. `FuncDecl` must have a body.
+  void initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl);
 
   // `DACtx` is not null and not owned by this object.
   DataflowAnalysisContext *DACtx;

diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp 
b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index 680036b6a5b39..9f5b3adc8b1b1 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -162,10 +162,19 @@ static void insertIfGlobal(const Decl &D,
   Vars.insert(V);
 }
 
-static void getFieldsAndGlobalVars(const Decl &D,
-   llvm::DenseSet &Fields,
-   llvm::DenseSet &Vars) {
+static void insertIfFunction(const Decl &D,
+ llvm::DenseSet &Funcs) {
+  if (auto *FD = dyn_cast(&D))
+Funcs.insert(FD);
+}
+
+static void
+getFieldsGlobalsAndFuncs(const Decl &D,
+ llvm::DenseSet &Fields,
+ llvm::DenseSet &Vars,
+ llvm::DenseSet &Funcs) {
   insertIfGlobal(D, Vars);
+  insertIfFunction(D, Funcs);
   if (const auto *Decomp = dyn_cast(&D))
 for (const auto *B : Decomp->bindings())
   if (auto *ME = dyn_cast_or_null(B->getBinding()))
@@ -174,27 +183,32 @@ static void getFieldsAndGlobalVars(const Decl &D,
   Fields.insert(FD);
 }
 
-/// Traverses `S` and inserts into `Vars` any global storage values that are
-/// declared in or referenced from sub-statements.
-static void getFieldsAndGlobalVars(const Stmt &S,
-   llvm::DenseSet &Fields,
-   llvm::DenseSet &Vars) {
+/// Traverses `S` and inserts into `Fields`, `Vars` and `Funcs` any fields,
+/// global variables and functions that are declared in or referenced from
+/// sub-statements.
+static void
+getFieldsGlobalsAndFuncs(const Stmt &S,
+ llvm::DenseSet &Fields,
+ llvm::DenseSet &Vars,
+ llvm::DenseSet &Funcs) {
   for (auto *Child : S.children())
 if (Child != nullptr)
-  getFieldsAndGlobalVars(*Child, Fields, Vars);
+  getFieldsGlobalsAndFuncs(*Child, Fields, Vars, Funcs);
 
   if (auto *DS = dyn_cast(&S)) {
 if (DS->isSingleDecl())
-  getFieldsAndGlobalVars(*DS->getSingleDecl(), Fields, Vars);
+  getFieldsGlobalsAndFuncs(*DS->getSingleDecl(), Fields, Vars, Funcs);
 else
   for (auto *D : DS->getDeclGroup())
-  getFieldsAndGlobalVars(*D, Fields, Vars);
+getFieldsGlobalsAndFuncs(*D, Fields, Vars, Funcs);
   } else if (auto *E = dyn_cast(&S)) {
 insertIfGlobal(*E->getDecl(), Vars);
+insertIfFunction(*E->getDecl(), Funcs);
   } else if (auto *E = dyn_cast(&S)) {
 // FIXME: should we be using `E->getFoundDecl()`?
 const ValueDecl *VD = E->getMemberDecl();
 insertIfGlobal(*VD, Vars);
+insertIfFunction(*VD, Funcs);
 if (const auto *FD = dyn_cast(VD))
   Fields.insert(FD);
   }
@@ -202,11 +216,12 @@ static void getFieldsAndGlobalVars(const Stmt &S,
 
 // FIXME: Add support for resetting globals after function calls to enable
 // the implementatio

[clang] 6b85cc1 - [clang][dataflow] Use existing accessors to check for copy and move assignment ops.

2023-04-24 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-04-24T14:32:09Z
New Revision: 6b85cc18eb7be0fdc01b8586347750e65e56a4c3

URL: 
https://github.com/llvm/llvm-project/commit/6b85cc18eb7be0fdc01b8586347750e65e56a4c3
DIFF: 
https://github.com/llvm/llvm-project/commit/6b85cc18eb7be0fdc01b8586347750e65e56a4c3.diff

LOG: [clang][dataflow] Use existing accessors to check for copy and move 
assignment ops.

Reviewed By: gribozavr2

Differential Revision: https://reviews.llvm.org/D148612

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Transfer.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index 2d85e7b90f73..0814257d5cd3 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -646,9 +646,12 @@ class TransferVisitor : public 
ConstStmtVisitor {
   assert(Arg1 != nullptr);
 
   // Evaluate only copy and move assignment operators.
-  auto *Arg0Type = Arg0->getType()->getUnqualifiedDesugaredType();
-  auto *Arg1Type = Arg1->getType()->getUnqualifiedDesugaredType();
-  if (Arg0Type != Arg1Type)
+  const auto *Method =
+  dyn_cast_or_null(S->getDirectCallee());
+  if (!Method)
+return;
+  if (!Method->isCopyAssignmentOperator() &&
+  !Method->isMoveAssignmentOperator())
 return;
 
   auto *ObjectLoc = Env.getStorageLocation(*Arg0, SkipPast::Reference);



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 791b0fd - [clang][dataflow] Change PruneTriviallyFalseEdges for building CFG

2023-05-03 Thread Martin Braenne via cfe-commits

Author: Kinuko Yasuda
Date: 2023-05-03T18:42:15Z
New Revision: 791b0fd02668fd0fcf07788d4e16bb468434f4bf

URL: 
https://github.com/llvm/llvm-project/commit/791b0fd02668fd0fcf07788d4e16bb468434f4bf
DIFF: 
https://github.com/llvm/llvm-project/commit/791b0fd02668fd0fcf07788d4e16bb468434f4bf.diff

LOG: [clang][dataflow] Change PruneTriviallyFalseEdges for building CFG

Keeping this false could end up with extra iterations on a lot of loops
that aren't real ones (e.g. they could be a do-while-false for macros),
and makes the analyses very slow.

This patch changes the default for
CFG::BuildOptions.PruneTriviallyFalseEdges to true to avoid it.

Reviewed By: ymandel, xazax.hun, gribozavr2

Differential Revision: https://reviews.llvm.org/D149640

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp 
b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
index 6699a0fc9d79e..5520633da68ae 100644
--- a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
@@ -70,7 +70,7 @@ static llvm::BitVector findReachableBlocks(const CFG &Cfg) {
 llvm::Expected
 ControlFlowContext::build(const Decl *D, Stmt &S, ASTContext &C) {
   CFG::BuildOptions Options;
-  Options.PruneTriviallyFalseEdges = false;
+  Options.PruneTriviallyFalseEdges = true;
   Options.AddImplicitDtors = true;
   Options.AddTemporaryDtors = true;
   Options.AddInitializers = true;

diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 750d095af451a..c8161c8f40fc9 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -2644,7 +2644,7 @@ TEST(TransferTest, VarDeclInDoWhile) {
 void target(int *Foo) {
   do {
 int Bar = *Foo;
-  } while (true);
+  } while (false);
   (void)0;
   /*[[p]]*/
 }
@@ -2675,6 +2675,24 @@ TEST(TransferTest, VarDeclInDoWhile) {
   });
 }
 
+TEST(TransferTest, UnreachableAfterWhileTrue) {
+  std::string Code = R"(
+void target() {
+  while (true) {}
+  (void)0;
+  /*[[p]]*/
+}
+  )";
+  runDataflow(
+  Code,
+  [](const llvm::StringMap> &Results,
+ ASTContext &ASTCtx) {
+// The node after the while-true is pruned because it is trivially
+// known to be unreachable.
+ASSERT_TRUE(Results.empty());
+  });
+}
+
 TEST(TransferTest, AggregateInitialization) {
   std::string BracesCode = R"(
 struct A {



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] c8f81ee - [clang-tidy] bugprone-use-after-move: Ctor arguments should be sequenced if ctor call is written as list-initialization.

2023-05-04 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-05-04T12:05:39Z
New Revision: c8f81ee1da325760a4bbd83c8c54ecc9645f8e20

URL: 
https://github.com/llvm/llvm-project/commit/c8f81ee1da325760a4bbd83c8c54ecc9645f8e20
DIFF: 
https://github.com/llvm/llvm-project/commit/c8f81ee1da325760a4bbd83c8c54ecc9645f8e20.diff

LOG: [clang-tidy] bugprone-use-after-move: Ctor arguments should be sequenced 
if ctor call is written as list-initialization.

See

https://timsong-cpp.github.io/cppwp/n4868/dcl.init#list-4

This eliminates a false positive in bugprone-use-after-move; this newly added
test used to be falsely classified as a use-after-move:

```
A a;
S3 s3{a.getInt(), std::move(a)};
```

Reviewed By: PiotrZSL

Differential Revision: https://reviews.llvm.org/D148110

Added: 


Modified: 
clang-tools-extra/clang-tidy/utils/ExprSequence.cpp
clang-tools-extra/docs/ReleaseNotes.rst
clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp

Removed: 




diff  --git a/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp 
b/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp
index f9555be57e738..50df451ecfa26 100644
--- a/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp
+++ b/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp
@@ -131,6 +131,16 @@ const Stmt *ExprSequence::getSequenceSuccessor(const Stmt 
*S) const {
   }
 }
   }
+} else if (const auto *ConstructExpr = dyn_cast(Parent)) 
{
+  // Constructor arguments are sequenced if the constructor call is written
+  // as list-initialization.
+  if (ConstructExpr->isListInitialization()) {
+for (unsigned I = 1; I < ConstructExpr->getNumArgs(); ++I) {
+  if (ConstructExpr->getArg(I - 1) == S) {
+return ConstructExpr->getArg(I);
+  }
+}
+  }
 } else if (const auto *Compound = dyn_cast(Parent)) {
   // Compound statement: Each sub-statement is sequenced after the
   // statements that precede it.

diff  --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index e4220b3134714..98f18cc539faf 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -229,8 +229,9 @@ Changes in existing checks
   to ``std::forward``.
 
 - Improved :doc:`bugprone-use-after-move
-  ` check to also cover constructor
-  initializers.
+  ` check. Detect uses and moves in
+  constructor initializers. Correctly handle constructor arguments as being
+  sequenced when constructor call is written as list-initialization.
 
 - Deprecated :doc:`cert-dcl21-cpp
   ` check.

diff  --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp
index 1e0831048dbd4..00b1da1e727e4 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/use-after-move.cpp
@@ -1160,42 +1160,63 @@ void commaOperatorSequences() {
   }
 }
 
+namespace InitializerListSequences {
+
+struct S1 {
+  int i;
+  A a;
+};
+
+struct S2 {
+  A a;
+  int i;
+};
+
+struct S3 {
+  S3() {}
+  S3(int, A) {}
+  S3(A, int) {}
+};
+
 // An initializer list sequences its initialization clauses.
 void initializerListSequences() {
   {
-struct S1 {
-  int i;
-  A a;
-};
-{
-  A a;
-  S1 s1{a.getInt(), std::move(a)};
-}
-{
-  A a;
-  S1 s1{.i = a.getInt(), .a = std::move(a)};
-}
+A a;
+S1 s1{a.getInt(), std::move(a)};
   }
   {
-struct S2 {
-  A a;
-  int i;
-};
-{
-  A a;
-  S2 s2{std::move(a), a.getInt()};
-  // CHECK-NOTES: [[@LINE-1]]:27: warning: 'a' used after it was moved
-  // CHECK-NOTES: [[@LINE-2]]:13: note: move occurred here
-}
-{
-  A a;
-  S2 s2{.a = std::move(a), .i = a.getInt()};
-  // CHECK-NOTES: [[@LINE-1]]:37: warning: 'a' used after it was moved
-  // CHECK-NOTES: [[@LINE-2]]:13: note: move occurred here
-}
+A a;
+S1 s1{.i = a.getInt(), .a = std::move(a)};
+  }
+  {
+A a;
+S2 s2{std::move(a), a.getInt()};
+// CHECK-NOTES: [[@LINE-1]]:25: warning: 'a' used after it was moved
+// CHECK-NOTES: [[@LINE-2]]:11: note: move occurred here
+  }
+  {
+A a;
+S2 s2{.a = std::move(a), .i = a.getInt()};
+// CHECK-NOTES: [[@LINE-1]]:35: warning: 'a' used after it was moved
+// CHECK-NOTES: [[@LINE-2]]:11: note: move occurred here
+  }
+  {
+// Check the case where the constructed type has a constructor and the
+// initializer list therefore manifests as a `CXXConstructExpr` instead of
+// an `InitListExpr`.
+A a;
+S3 s3{a.getInt(), std::move(a)};
+  }
+  {
+A a;
+S3 s3{std::move(a), a.getInt()};
+// CHECK-NOTES: [[@LINE-1]]:25: warning: 'a' used after it was moved
+// CHECK-NOTES: [[@LINE-2]]:11: note: mov

[clang] c849843 - [clang][dataflow][NFC] Eliminate unnecessary helper `stripReference()`.

2023-05-04 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-05-04T13:14:04Z
New Revision: c849843c3ef73a1cae9040620c4b37e2240f86af

URL: 
https://github.com/llvm/llvm-project/commit/c849843c3ef73a1cae9040620c4b37e2240f86af
DIFF: 
https://github.com/llvm/llvm-project/commit/c849843c3ef73a1cae9040620c4b37e2240f86af.diff

LOG: [clang][dataflow][NFC] Eliminate unnecessary helper `stripReference()`.

`QualType::getNonReferenceType()` does the same thing.

Reviewed By: sammccall

Differential Revision: https://reviews.llvm.org/D149744

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp

Removed: 




diff  --git 
a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp 
b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
index 9745cd8a48311..e306b55753752 100644
--- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
@@ -276,12 +276,6 @@ BoolValue *getHasValue(Environment &Env, Value 
*OptionalVal) {
   return nullptr;
 }
 
-/// If `Type` is a reference type, returns the type of its pointee. Otherwise,
-/// returns `Type` itself.
-QualType stripReference(QualType Type) {
-  return Type->isReferenceType() ? Type->getPointeeType() : Type;
-}
-
 /// Returns true if and only if `Type` is an optional type.
 bool isOptionalType(QualType Type) {
   if (!Type->isRecordType())
@@ -339,7 +333,7 @@ StorageLocation 
*maybeInitializeOptionalValueMember(QualType Q,
 return &ValueLoc;
   }
 
-  auto Ty = stripReference(Q);
+  auto Ty = Q.getNonReferenceType();
   auto *ValueVal = Env.createValue(Ty);
   if (ValueVal == nullptr)
 return nullptr;
@@ -493,11 +487,13 @@ BoolValue &valueOrConversionHasValue(const FunctionDecl 
&F, const Expr &E,
   assert(F.getTemplateSpecializationArgs() != nullptr);
   assert(F.getTemplateSpecializationArgs()->size() > 0);
 
-  const int TemplateParamOptionalWrappersCount = countOptionalWrappers(
-  *MatchRes.Context,
-  stripReference(F.getTemplateSpecializationArgs()->get(0).getAsType()));
-  const int ArgTypeOptionalWrappersCount =
-  countOptionalWrappers(*MatchRes.Context, stripReference(E.getType()));
+  const int TemplateParamOptionalWrappersCount =
+  countOptionalWrappers(*MatchRes.Context, 
F.getTemplateSpecializationArgs()
+   ->get(0)
+   .getAsType()
+   .getNonReferenceType());
+  const int ArgTypeOptionalWrappersCount = countOptionalWrappers(
+  *MatchRes.Context, E.getType().getNonReferenceType());
 
   // Check if this is a constructor/assignment call for `optional` with
   // argument of type `U` such that `T` is constructible from `U`.



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] af22be3 - [clang][dataflow] Use a `PointerValue` for `value` property in optional checker.

2023-06-05 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-06-05T12:52:51Z
New Revision: af22be39038a9c464474410c3a8b3cb428d8b25a

URL: 
https://github.com/llvm/llvm-project/commit/af22be39038a9c464474410c3a8b3cb428d8b25a
DIFF: 
https://github.com/llvm/llvm-project/commit/af22be39038a9c464474410c3a8b3cb428d8b25a.diff

LOG: [clang][dataflow] Use a `PointerValue` for `value` property in optional 
checker.

The `ReferenceValue` class will be eliminated as part of the ongoing migration
to strict handling of value categories (see https://discourse.llvm.org/t/70086
for details).

Reviewed By: gribozavr2

Differential Revision: https://reviews.llvm.org/D152144

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp

Removed: 




diff  --git 
a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp 
b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
index 7d30473ea5226..1095fd49e8600 100644
--- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
@@ -307,12 +307,12 @@ StorageLocation 
*maybeInitializeOptionalValueMember(QualType Q,
 Environment &Env) {
   // The "value" property represents a synthetic field. As such, it needs
   // `StorageLocation`, like normal fields (and other variables). So, we model
-  // it with a `ReferenceValue`, since that includes a storage location.  Once
+  // it with a `PointerValue`, since that includes a storage location.  Once
   // the property is set, it will be shared by all environments that access the
   // `Value` representing the optional (here, `OptionalVal`).
   if (auto *ValueProp = OptionalVal.getProperty("value")) {
-auto *ValueRef = clang::cast(ValueProp);
-auto &ValueLoc = ValueRef->getReferentLoc();
+auto *ValuePtr = clang::cast(ValueProp);
+auto &ValueLoc = ValuePtr->getPointeeLoc();
 if (Env.getValue(ValueLoc) == nullptr) {
   // The property was previously set, but the value has been lost. This can
   // happen, for example, because of an environment merge (where the two
@@ -339,8 +339,8 @@ StorageLocation 
*maybeInitializeOptionalValueMember(QualType Q,
 return nullptr;
   auto &ValueLoc = Env.createStorageLocation(Ty);
   Env.setValue(ValueLoc, *ValueVal);
-  auto &ValueRef = Env.create(ValueLoc);
-  OptionalVal.setProperty("value", ValueRef);
+  auto &ValuePtr = Env.create(ValueLoc);
+  OptionalVal.setProperty("value", ValuePtr);
   return &ValueLoc;
 }
 



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] bbeda83 - [clang][dataflow][NFC] Expand comments on losing values in optional checker.

2023-06-12 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-06-12T08:46:34Z
New Revision: bbeda83090adcb3609f9c1331b2345e7fa547f90

URL: 
https://github.com/llvm/llvm-project/commit/bbeda83090adcb3609f9c1331b2345e7fa547f90
DIFF: 
https://github.com/llvm/llvm-project/commit/bbeda83090adcb3609f9c1331b2345e7fa547f90.diff

LOG: [clang][dataflow][NFC] Expand comments on losing values in optional 
checker.

While working on the ongoing migration to strict handling of value
categories (see https://discourse.llvm.org/t/70086), I ran into issues related
to losing the value associated with an optional.

This issue is hinted at in the existing comments, but the issue didn't become
sufficiently clear to me from those, so I thought it would be worth capturing
more details, along with ideas for how this issue might be fixed.

Reviewed By: ymandel

Differential Revision: https://reviews.llvm.org/D152369

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp

Removed: 




diff  --git 
a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp 
b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
index 1095fd49e8600..a239d54674e96 100644
--- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
@@ -315,11 +315,16 @@ StorageLocation 
*maybeInitializeOptionalValueMember(QualType Q,
 auto &ValueLoc = ValuePtr->getPointeeLoc();
 if (Env.getValue(ValueLoc) == nullptr) {
   // The property was previously set, but the value has been lost. This can
-  // happen, for example, because of an environment merge (where the two
-  // environments mapped the property to 
diff erent values, which resulted in
-  // them both being discarded), or when two blocks in the CFG, with 
neither
-  // a dominator of the other, visit the same optional value, or even when 
a
-  // block is revisited during testing to collect per-statement state.
+  // happen in various situations, for example:
+  // - Because of an environment merge (where the two environments mapped
+  //   the property to 
diff erent values, which resulted in them both being
+  //   discarded).
+  // - When two blocks in the CFG, with neither a dominator of the other,
+  //   visit the same optional value. (FIXME: This is something we can and
+  //   should fix -- see also the lengthy FIXME below.)
+  // - Or even when a block is revisited during testing to collect
+  //   per-statement state.
+  //
   // FIXME: This situation means that the optional contents are not shared
   // between branches and the like. Practically, this lack of sharing
   // reduces the precision of the model when the contents are relevant to
@@ -340,6 +345,51 @@ StorageLocation 
*maybeInitializeOptionalValueMember(QualType Q,
   auto &ValueLoc = Env.createStorageLocation(Ty);
   Env.setValue(ValueLoc, *ValueVal);
   auto &ValuePtr = Env.create(ValueLoc);
+  // FIXME:
+  // The change we make to the `value` property below may become visible to
+  // other blocks that aren't successors of the current block and therefore
+  // don't see the change we made above mapping `ValueLoc` to `ValueVal`. For
+  // example:
+  //
+  //   void target(optional oo, bool b) {
+  // // `oo` is associated with a `StructValue` here, which we will call
+  // // `OptionalVal`.
+  //
+  // // The `has_value` property is set on `OptionalVal` (but not the
+  // // `value` property yet).
+  // if (!oo.has_value()) return;
+  //
+  // if (b) {
+  //   // Let's assume we transfer the `if` branch first.
+  //   //
+  //   // This causes us to call `maybeInitializeOptionalValueMember()`,
+  //   // which causes us to set the `value` property on `OptionalVal`
+  //   // (which had not been set until this point). This `value` property
+  //   // refers to a `PointerValue`, which in turn refers to a
+  //   // StorageLocation` that is associated to an `IntegerValue`.
+  //   oo.value();
+  // } else {
+  //   // Let's assume we transfer the `else` branch after the `if` branch.
+  //   //
+  //   // We see the `value` property that the `if` branch set on
+  //   // `OptionalVal`, but in the environment for this block, the
+  //   // `StorageLocation` in the `PointerValue` is not associated with 
any
+  //   // `Value`.
+  //   oo.value();
+  // }
+  //   }
+  //
+  // This situation is currently "saved" by the code above that checks whether
+  // the `value` property is already set, and if, the `ValueLoc` is not
+  // associated with a `ValueVal`, creates a new `ValueVal`.
+  //
+  // However, what we should really do is to make sure that the change to the
+  // `value` property does not "leak" to other blocks that are not succ

[clang] 3f31d32 - [clang][dataflow] Model pointer value for builtin functions.

2023-06-12 Thread Martin Braenne via cfe-commits

Author: Martin Braenne
Date: 2023-06-12T12:23:18Z
New Revision: 3f31d3204bd2726fa8e5c56ea27c8bba0074790e

URL: 
https://github.com/llvm/llvm-project/commit/3f31d3204bd2726fa8e5c56ea27c8bba0074790e
DIFF: 
https://github.com/llvm/llvm-project/commit/3f31d3204bd2726fa8e5c56ea27c8bba0074790e.diff

LOG: [clang][dataflow] Model pointer value for builtin functions.

This fixes a false positive in the Crubit nullability verification.

Reviewed By: gribozavr2

Differential Revision: https://reviews.llvm.org/D152683

Added: 


Modified: 
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 




diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index 8547e5049261f..e0cb872cfa372 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -400,7 +400,8 @@ class TransferVisitor : public 
ConstStmtVisitor {
   Env.setValue(Loc, NullPointerVal);
   break;
 }
-case CK_FunctionToPointerDecay: {
+case CK_FunctionToPointerDecay:
+case CK_BuiltinFnToFnPtr: {
   StorageLocation *PointeeLoc =
   Env.getStorageLocation(*SubExpr, SkipPast::Reference);
   if (PointeeLoc == nullptr)

diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 1a2442f0b12db..7077f7344a858 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -5327,4 +5327,37 @@ TEST(TransferTest, FunctionToPointerDecayHasValue) {
   });
 }
 
+// Check that the pointer that a builtin function decays to is associated with
+// a value.
+TEST(TransferTest, BuiltinFunctionModeled) {
+  std::string Code = R"(
+void target() {
+  __builtin_expect(0, 0);
+  // [[p]]
+}
+  )";
+  runDataflow(
+  Code,
+  [](const llvm::StringMap> &Results,
+ ASTContext &ASTCtx) {
+using ast_matchers::selectFirst;
+using ast_matchers::match;
+using ast_matchers::traverse;
+using ast_matchers::implicitCastExpr;
+using ast_matchers::hasCastKind;
+
+const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+
+auto *ImplicitCast = selectFirst(
+"implicit_cast",
+match(traverse(TK_AsIs,
+   implicitCastExpr(hasCastKind(CK_BuiltinFnToFnPtr))
+   .bind("implicit_cast")),
+  ASTCtx));
+
+ASSERT_THAT(ImplicitCast, NotNull());
+EXPECT_THAT(Env.getValueStrict(*ImplicitCast), NotNull());
+  });
+}
+
 } // namespace



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits