[clang] [llvm] [AMDGPU] Adding the amdgpu-num-work-groups function attribute (PR #79035)

2024-03-07 Thread Matt Arsenault via cfe-commits


@@ -137,6 +137,12 @@ Removed Compiler Flags
 
 Attribute Changes in Clang
 --
+- Introduced a new function attribute 
``__attribute__((amdgpu_max_num_work_groups(x, y, z)))`` or

arsenm wrote:

I think some of the AMDGPUUsage work-groups are actually wrong based on the 
actual code.

https://github.com/llvm/llvm-project/pull/79035
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [NFC] [C++20] [Modules] [P1689] [Scanner] Don't use thread pool in P1689 per file mode (PR #84285)

2024-03-07 Thread Chuanqi Xu via cfe-commits

https://github.com/ChuanqiXu9 created 
https://github.com/llvm/llvm-project/pull/84285


I suddenly found that the clang scan deps may use all concurrent threads to 
scan the files. It makes sense in the batch mode. But in P1689 per file mode, 
it simply wastes times and resources.

This patch itself should be a NFC patch. It simply moves codes.

>From 8f3060da8059dc300152a1a1bc297cffcba51a61 Mon Sep 17 00:00:00 2001
From: Chuanqi Xu 
Date: Thu, 7 Mar 2024 15:19:28 +0800
Subject: [PATCH] [NFC] [C++20] [Modules] [P1689] [Scanner] Don't use thread
 pool in P1689 per file mode

I suddenly found that the clang scan deps may use all concurrent threads
to scan the files. It makes sense in the batch mode. But in P1689
per file mode, it simply wastes times.
---
 clang/tools/clang-scan-deps/ClangScanDeps.cpp | 204 +-
 1 file changed, 108 insertions(+), 96 deletions(-)

diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp 
b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index d042fecc3dbe63..843816a8ed6515 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -744,6 +744,9 @@ getCompilationDataBase(int argc, char **argv, std::string 
&ErrorMessage) {
 return nullptr;
   }
 
+  // Only 1 threads is required if P1689 per file mode.
+  NumThreads = 1;
+
   // There might be multiple jobs for a compilation. Extract the specified
   // output filename from the last job.
   auto LastCmd = C->getJobs().end();
@@ -867,13 +870,6 @@ int clang_scan_deps_main(int argc, char **argv, const 
llvm::ToolContext &) {
   // Print out the dependency results to STDOUT by default.
   SharedStream DependencyOS(llvm::outs());
 
-  DependencyScanningService Service(ScanMode, Format, OptimizeArgs,
-EagerLoadModules);
-  llvm::DefaultThreadPool Pool(llvm::hardware_concurrency(NumThreads));
-  std::vector> WorkerTools;
-  for (unsigned I = 0; I < Pool.getMaxConcurrency(); ++I)
-WorkerTools.push_back(std::make_unique(Service));
-
   std::vector Inputs =
   AdjustingCompilations->getAllCompileCommands();
 
@@ -893,102 +889,118 @@ int clang_scan_deps_main(int argc, char **argv, const 
llvm::ToolContext &) {
   if (Format == ScanningOutputFormat::Full)
 FD.emplace(ModuleName.empty() ? Inputs.size() : 0);
 
-  if (Verbose) {
-llvm::outs() << "Running clang-scan-deps on " << Inputs.size()
- << " files using " << Pool.getMaxConcurrency() << " 
workers\n";
-  }
-
-  llvm::Timer T;
-  T.startTimer();
-
-  for (unsigned I = 0; I < Pool.getMaxConcurrency(); ++I) {
-Pool.async([&, I]() {
-  llvm::DenseSet AlreadySeenModules;
-  while (auto MaybeInputIndex = GetNextInputIndex()) {
-size_t LocalIndex = *MaybeInputIndex;
-const tooling::CompileCommand *Input = &Inputs[LocalIndex];
-std::string Filename = std::move(Input->Filename);
-std::string CWD = std::move(Input->Directory);
-
-std::optional MaybeModuleName;
-if (!ModuleName.empty())
-  MaybeModuleName = ModuleName;
-
-std::string OutputDir(ModuleFilesDir);
-if (OutputDir.empty())
-  OutputDir = getModuleCachePath(Input->CommandLine);
-auto LookupOutput = [&](const ModuleID &MID, ModuleOutputKind MOK) {
-  return ::lookupModuleOutput(MID, MOK, OutputDir);
-};
-
-// Run the tool on it.
-if (Format == ScanningOutputFormat::Make) {
-  auto MaybeFile =
-  WorkerTools[I]->getDependencyFile(Input->CommandLine, CWD);
-  if (handleMakeDependencyToolResult(Filename, MaybeFile, DependencyOS,
- Errs))
-HadErrors = true;
-} else if (Format == ScanningOutputFormat::P1689) {
-  // It is useful to generate the make-format dependency output during
-  // the scanning for P1689. Otherwise the users need to scan again for
-  // it. We will generate the make-format dependency output if we find
-  // `-MF` in the command lines.
-  std::string MakeformatOutputPath;
-  std::string MakeformatOutput;
-
-  auto MaybeRule = WorkerTools[I]->getP1689ModuleDependencyFile(
-  *Input, CWD, MakeformatOutput, MakeformatOutputPath);
-
-  if (handleP1689DependencyToolResult(Filename, MaybeRule, PD, Errs))
-HadErrors = true;
+  std::vector> WorkerTools;
 
-  if (!MakeformatOutputPath.empty() && !MakeformatOutput.empty() &&
-  !HadErrors) {
-static std::mutex Lock;
-// With compilation database, we may open different files
-// concurrently or we may write the same file concurrently. So we
-// use a map here to allow multiple compile commands to write to 
the
-// same file. Also we need a lock here to avoid data race.
-static llvm::StringMap OSs;
-std::unique_lock LockGuard(Lock);
-

[clang] [NFC] [C++20] [Modules] [P1689] [Scanner] Don't use thread pool in P1689 per file mode (PR #84285)

2024-03-07 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang-modules

Author: Chuanqi Xu (ChuanqiXu9)


Changes


I suddenly found that the clang scan deps may use all concurrent threads to 
scan the files. It makes sense in the batch mode. But in P1689 per file mode, 
it simply wastes times and resources.

This patch itself should be a NFC patch. It simply moves codes.

---
Full diff: https://github.com/llvm/llvm-project/pull/84285.diff


1 Files Affected:

- (modified) clang/tools/clang-scan-deps/ClangScanDeps.cpp (+108-96) 


``diff
diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp 
b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index d042fecc3dbe63..843816a8ed6515 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -744,6 +744,9 @@ getCompilationDataBase(int argc, char **argv, std::string 
&ErrorMessage) {
 return nullptr;
   }
 
+  // Only 1 threads is required if P1689 per file mode.
+  NumThreads = 1;
+
   // There might be multiple jobs for a compilation. Extract the specified
   // output filename from the last job.
   auto LastCmd = C->getJobs().end();
@@ -867,13 +870,6 @@ int clang_scan_deps_main(int argc, char **argv, const 
llvm::ToolContext &) {
   // Print out the dependency results to STDOUT by default.
   SharedStream DependencyOS(llvm::outs());
 
-  DependencyScanningService Service(ScanMode, Format, OptimizeArgs,
-EagerLoadModules);
-  llvm::DefaultThreadPool Pool(llvm::hardware_concurrency(NumThreads));
-  std::vector> WorkerTools;
-  for (unsigned I = 0; I < Pool.getMaxConcurrency(); ++I)
-WorkerTools.push_back(std::make_unique(Service));
-
   std::vector Inputs =
   AdjustingCompilations->getAllCompileCommands();
 
@@ -893,102 +889,118 @@ int clang_scan_deps_main(int argc, char **argv, const 
llvm::ToolContext &) {
   if (Format == ScanningOutputFormat::Full)
 FD.emplace(ModuleName.empty() ? Inputs.size() : 0);
 
-  if (Verbose) {
-llvm::outs() << "Running clang-scan-deps on " << Inputs.size()
- << " files using " << Pool.getMaxConcurrency() << " 
workers\n";
-  }
-
-  llvm::Timer T;
-  T.startTimer();
-
-  for (unsigned I = 0; I < Pool.getMaxConcurrency(); ++I) {
-Pool.async([&, I]() {
-  llvm::DenseSet AlreadySeenModules;
-  while (auto MaybeInputIndex = GetNextInputIndex()) {
-size_t LocalIndex = *MaybeInputIndex;
-const tooling::CompileCommand *Input = &Inputs[LocalIndex];
-std::string Filename = std::move(Input->Filename);
-std::string CWD = std::move(Input->Directory);
-
-std::optional MaybeModuleName;
-if (!ModuleName.empty())
-  MaybeModuleName = ModuleName;
-
-std::string OutputDir(ModuleFilesDir);
-if (OutputDir.empty())
-  OutputDir = getModuleCachePath(Input->CommandLine);
-auto LookupOutput = [&](const ModuleID &MID, ModuleOutputKind MOK) {
-  return ::lookupModuleOutput(MID, MOK, OutputDir);
-};
-
-// Run the tool on it.
-if (Format == ScanningOutputFormat::Make) {
-  auto MaybeFile =
-  WorkerTools[I]->getDependencyFile(Input->CommandLine, CWD);
-  if (handleMakeDependencyToolResult(Filename, MaybeFile, DependencyOS,
- Errs))
-HadErrors = true;
-} else if (Format == ScanningOutputFormat::P1689) {
-  // It is useful to generate the make-format dependency output during
-  // the scanning for P1689. Otherwise the users need to scan again for
-  // it. We will generate the make-format dependency output if we find
-  // `-MF` in the command lines.
-  std::string MakeformatOutputPath;
-  std::string MakeformatOutput;
-
-  auto MaybeRule = WorkerTools[I]->getP1689ModuleDependencyFile(
-  *Input, CWD, MakeformatOutput, MakeformatOutputPath);
-
-  if (handleP1689DependencyToolResult(Filename, MaybeRule, PD, Errs))
-HadErrors = true;
+  std::vector> WorkerTools;
 
-  if (!MakeformatOutputPath.empty() && !MakeformatOutput.empty() &&
-  !HadErrors) {
-static std::mutex Lock;
-// With compilation database, we may open different files
-// concurrently or we may write the same file concurrently. So we
-// use a map here to allow multiple compile commands to write to 
the
-// same file. Also we need a lock here to avoid data race.
-static llvm::StringMap OSs;
-std::unique_lock LockGuard(Lock);
-
-auto OSIter = OSs.find(MakeformatOutputPath);
-if (OSIter == OSs.end()) {
-  std::error_code EC;
-  OSIter = OSs.try_emplace(MakeformatOutputPath,
-   MakeformatOutputPath, EC)
-   .first;
-  if (EC)
-llvm::errs()
- 

[clang] 99500e8 - [Clang][C++23] Implement P2448R2: Relaxing some constexpr restrictions (#77753)

2024-03-07 Thread via cfe-commits

Author: Mariya Podchishchaeva
Date: 2024-03-07T09:36:50+01:00
New Revision: 99500e8c08a4d941acb8a7eb00523296fb2acf7a

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

LOG: [Clang][C++23] Implement P2448R2: Relaxing some constexpr restrictions 
(#77753)

Per
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2448r2.html
function/constructor/destructor can be marked `constexpr` even though it
never produces a constant expression.
Non-literal types as return types and parameter types of functions
marked `constexpr` are also allowed.
Since this is not a DR, the diagnostic messages are still preserved for
C++ standards older than C++23.

Added: 
clang/test/SemaCXX/cxx23-invalid-constexpr.cpp

Modified: 
clang/docs/ReleaseNotes.rst
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/AST/DeclCXX.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/test/AST/Interp/cxx23.cpp
clang/test/CXX/class/class.compare/class.compare.default/p3.cpp
clang/test/CXX/class/class.compare/class.compare.default/p4.cpp
clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/dtor.cpp
clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3-2b.cpp
clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp
clang/test/CXX/drs/dr13xx.cpp
clang/test/CXX/drs/dr14xx.cpp
clang/test/CXX/drs/dr15xx.cpp
clang/test/CXX/drs/dr16xx.cpp
clang/test/CXX/drs/dr6xx.cpp
clang/test/CXX/expr/expr.const/p5-26.cpp
clang/test/CXX/special/class.copy/p13-0x.cpp
clang/test/SemaCXX/constant-expression-cxx11.cpp
clang/test/SemaCXX/constant-expression-cxx14.cpp
clang/test/SemaCXX/constant-expression-cxx2b.cpp
clang/test/SemaCXX/cxx2a-consteval.cpp
clang/test/SemaCXX/deduced-return-type-cxx14.cpp
clang/test/SemaOpenCLCXX/addrspace-constructors.clcpp
clang/www/cxx_status.html

Removed: 




diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8300a8484585ae..1b901a27fd19d1 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -97,6 +97,8 @@ C++23 Feature Support
 - Implemented `P2718R0: Lifetime extension in range-based for loops 
`_. Also
   materialize temporary object which is a prvalue in discarded-value 
expression.
 
+- Implemented `P2448R2: Relaxing some constexpr restrictions 
`_.
+
 C++2c Feature Support
 ^
 

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 5a90e631a894c9..c8dfdc08f5ea07 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9607,13 +9607,10 @@ def err_defaulted_copy_assign_not_ref : Error<
   "the parameter for an explicitly-defaulted copy assignment operator must be 
an "
   "lvalue reference type">;
 def err_incorrect_defaulted_constexpr : Error<
-  "defaulted definition of %sub{select_special_member_kind}0 "
-  "is not constexpr">;
+  "defaulted definition of %sub{select_special_member_kind}0 cannot be marked 
%select{constexpr|consteval}1 "
+  "before C++23">;
 def err_incorrect_defaulted_constexpr_with_vb: Error<
   "%sub{select_special_member_kind}0 cannot be 'constexpr' in a class with 
virtual base class">;
-def err_incorrect_defaulted_consteval : Error<
-  "defaulted declaration of %sub{select_special_member_kind}0 "
-  "cannot be consteval because implicit definition is not constexpr">;
 def warn_defaulted_method_deleted : Warning<
   "explicitly defaulted %sub{select_special_member_kind}0 is implicitly "
   "deleted">, InGroup;
@@ -9724,21 +9721,12 @@ def 
note_defaulted_comparison_cannot_deduce_undeduced_auto : Note<
   "%select{|member|base class}0 %1 declared here">;
 def note_defaulted_comparison_cannot_deduce_callee : Note<
   "selected 'operator<=>' for %select{|member|base class}0 %1 declared here">;
-def ext_defaulted_comparison_constexpr_mismatch : Extension<
+def err_defaulted_comparison_constexpr_mismatch : Error<
   "defaulted definition of %select{%sub{select_defaulted_comparison_kind}1|"
-  "three-way comparison operator}0 that is "
-  "declared %select{constexpr|consteval}2 but"
-  "%select{|for which the corresponding implicit 'operator==' }0 "
-  "invokes a non-constexpr comparison function is a C++23 extension">,
-  InGroup>;
-def warn_cxx23_compat_defaulted_comparison_constexpr_mismatch : Warning<
-  "defaulted definition of %select{%sub{select_defaulted_comparison_kind}1|"
-  "three-way comparison operator}0 that is "
-  "declared %select{constexpr|consteval}2 but"
-  "%select{|for which the corresponding implicit 'operator==' }0 "
- 

[clang] [Clang][C++23] Implement P2448R2: Relaxing some constexpr restrictions (PR #77753)

2024-03-07 Thread Mariya Podchishchaeva via cfe-commits

https://github.com/Fznamznon closed 
https://github.com/llvm/llvm-project/pull/77753
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][NFC] Remove '--' separator in the linker wrapper usage (PR #84253)

2024-03-07 Thread Fangrui Song via cfe-commits

MaskRay wrote:

If a LLVMOption users needs to parse `--`, DashDashParsing from 
https://reviews.llvm.org/D152286 is better :)

https://github.com/llvm/llvm-project/pull/84253
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][NFC] Remove '--' separator in the linker wrapper usage (PR #84253)

2024-03-07 Thread Fangrui Song via cfe-commits

https://github.com/MaskRay approved this pull request.


https://github.com/llvm/llvm-project/pull/84253
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][NFC] Remove '--' separator in the linker wrapper usage (PR #84253)

2024-03-07 Thread Fangrui Song via cfe-commits

MaskRay wrote:

> [NFC]

>From a strict interpretation, this is not NFC as this changes clang driver 
>behavior. The overall behavior combining clang + clang-linker-wrapper may not 
>change, though...

https://github.com/llvm/llvm-project/pull/84253
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Implement CTAD for type alias template. (PR #77890)

2024-03-07 Thread Haojian Wu via cfe-commits


@@ -96,6 +96,10 @@ C++20 Feature Support
   behavior can use the flag '-Xclang -fno-skip-odr-check-in-gmf'.
   (`#79240 `_).
 
+- Initial support for class template argument deduciton (CTAD) for type alias

hokein wrote:

Done.

https://github.com/llvm/llvm-project/pull/77890
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Implement CTAD for type alias template. (PR #77890)

2024-03-07 Thread Haojian Wu via cfe-commits


@@ -10598,10 +10598,38 @@ QualType 
Sema::DeduceTemplateSpecializationFromInitializer(
   if (TemplateName.isDependent())
 return SubstAutoTypeDependent(TSInfo->getType());
 
-  // We can only perform deduction for class templates.
+  // We can only perform deduction for class templates or alias templates.
   auto *Template =
   dyn_cast_or_null(TemplateName.getAsTemplateDecl());
+  TemplateDecl* LookupTemplateDecl = Template;
   if (!Template) {
+if (auto *AliasTemplate = dyn_cast_or_null(
+TemplateName.getAsTemplateDecl())) {
+  Diag(Kind.getLocation(),
+   diag::warn_cxx17_compat_ctad_for_alias_templates);
+  LookupTemplateDecl = AliasTemplate;
+  auto UnderlyingType = AliasTemplate->getTemplatedDecl()
+->getUnderlyingType()
+.getCanonicalType();
+  // C++ [over.match.class.deduct#3]: ..., the defining-type-id of A must 
be
+  // of the form
+  //   [typename] [nested-name-specifier] [template] simple-template-id
+  if (const auto *TST =
+  UnderlyingType->getAs()) {
+Template = dyn_cast_or_null(
+TST->getTemplateName().getAsTemplateDecl());
+  } else if (const auto *RT = UnderlyingType->getAs()) {
+// Cases where template arguments in the RHS of the alias are not
+// dependent. e.g.
+//   using AliasFoo = Foo;
+if (const auto *CTSD = llvm::dyn_cast(
+RT->getAsCXXRecordDecl()))
+  Template = CTSD->getSpecializedTemplate();
+  }
+}
+  }
+  if (!Template) {
+// FIXME: update the diagnostic message to include C++20 alias templates

hokein wrote:

Sure, please take a look on the new change. I also rename the diagnostic to 
`err_deduced_non_class_or_alias_template_specialization_type`.

https://github.com/llvm/llvm-project/pull/77890
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Implement CTAD for type alias template. (PR #77890)

2024-03-07 Thread Haojian Wu via cfe-commits

https://github.com/hokein edited https://github.com/llvm/llvm-project/pull/77890
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Implement CTAD for type alias template. (PR #77890)

2024-03-07 Thread Haojian Wu via cfe-commits


@@ -96,6 +96,10 @@ C++20 Feature Support
   behavior can use the flag '-Xclang -fno-skip-odr-check-in-gmf'.
   (`#79240 `_).
 
+- Initial support for class template argument deduciton (CTAD) for type alias
+  templates (`P1814R0 `_).

hokein wrote:

Done.

https://github.com/llvm/llvm-project/pull/77890
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at indeterminate file position. (PR #84191)

2024-03-07 Thread Balázs Kéri via cfe-commits

https://github.com/balazske updated 
https://github.com/llvm/llvm-project/pull/84191

From dbaf3348510582c013254ed48b69663b42816be0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= 
Date: Wed, 6 Mar 2024 16:01:01 +0100
Subject: [PATCH] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at
 indeterminate file position.

These functions should not be allowed if the file position is indeterminate
(they return the file position).
This condition is now checked, and tests are improved to check it.
---
 .../StaticAnalyzer/Checkers/StreamChecker.cpp | 91 ---
 clang/test/Analysis/stream-error.c| 27 +-
 2 files changed, 80 insertions(+), 38 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index 2ec47bf55df76b..10972158f39862 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -307,64 +307,64 @@ class StreamChecker : public Checker FnTestDescriptions = {
   {{{"StreamTesterChecker_make_feof_stream"}, 1},
{nullptr,
-std::bind(&StreamChecker::evalSetFeofFerror, _1, _2, _3, _4, 
ErrorFEof),
+std::bind(&StreamChecker::evalSetFeofFerror, _1, _2, _3, _4, ErrorFEof,
+  false),
 0}},
   {{{"StreamTesterChecker_make_ferror_stream"}, 1},
{nullptr,
 std::bind(&StreamChecker::evalSetFeofFerror, _1, _2, _3, _4,
-  ErrorFError),
+  ErrorFError, false),
+0}},
+  {{{"StreamTesterChecker_make_ferror_indeterminate_stream"}, 1},
+   {nullptr,
+std::bind(&StreamChecker::evalSetFeofFerror, _1, _2, _3, _4,
+  ErrorFError, true),
 0}},
   };
 
@@ -415,8 +421,11 @@ class StreamChecker : public CheckerStreamArgNo), C,
@@ -865,11 +873,6 @@ void StreamChecker::preReadWrite(const FnDescription *Desc,
   if (!State)
 return;
 
-  if (!IsRead) {
-C.addTransition(State);
-return;
-  }
-
   SymbolRef Sym = StreamVal.getAsSymbol();
   if (Sym && State->get(Sym)) {
 const StreamState *SS = State->get(Sym);
@@ -880,6 +883,24 @@ void StreamChecker::preReadWrite(const FnDescription *Desc,
   }
 }
 
+void StreamChecker::preWrite(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
+  SVal StreamVal = getStreamArg(Desc, Call);
+  State = ensureStreamNonNull(StreamVal, Call.getArgExpr(Desc->StreamArgNo), C,
+  State);
+  if (!State)
+return;
+  State = ensureStreamOpened(StreamVal, C, State);
+  if (!State)
+return;
+  State = ensureNoFilePositionIndeterminate(StreamVal, C, State);
+  if (!State)
+return;
+
+  C.addTransition(State);
+}
+
 void StreamChecker::evalFreadFwrite(const FnDescription *Desc,
 const CallEvent &Call, CheckerContext &C,
 bool IsFread) const {
@@ -1496,14 +1517,16 @@ void StreamChecker::preDefault(const FnDescription 
*Desc, const CallEvent &Call,
 
 void StreamChecker::evalSetFeofFerror(const FnDescription *Desc,
   const CallEvent &Call, CheckerContext &C,
-  const StreamErrorState &ErrorKind) const 
{
+  const StreamErrorState &ErrorKind,
+  bool Indeterminate) const {
   ProgramStateRef State = C.getState();
   SymbolRef StreamSym = getStreamArg(Desc, Call).getAsSymbol();
   assert(StreamSym && "Operation not permitted on non-symbolic stream value.");
   const StreamState *SS = State->get(StreamSym);
   assert(SS && "Stream should be tracked by the checker.");
   State = State->set(
-  StreamSym, StreamState::getOpened(SS->LastOperation, ErrorKind));
+  StreamSym,
+  StreamState::getOpened(SS->LastOperation, ErrorKind, Indeterminate));
   C.addTransition(State);
 }
 
diff --git a/clang/test/Analysis/stream-error.c 
b/clang/test/Analysis/stream-error.c
index ac31083bfc691f..88f7de4234ffb4 100644
--- a/clang/test/Analysis/stream-error.c
+++ b/clang/test/Analysis/stream-error.c
@@ -11,6 +11,7 @@ void clang_analyzer_dump(int);
 void clang_analyzer_warnIfReached(void);
 void StreamTesterChecker_make_feof_stream(FILE *);
 void StreamTesterChecker_make_ferror_stream(FILE *);
+void StreamTesterChecker_make_ferror_indeterminate_stream(FILE *);
 
 void error_fopen(void) {
   FILE *F = fopen("file", "r");
@@ -52,6 +53,8 @@ void stream_error_feof(void) {
   clearerr(F);
   clang_analyzer_eval(feof(F));   // expected-warning {{FALSE}}
   clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
+  StreamTesterChecker_make_ferror_indeterminate_stream(F);
+  clang_analyzer_eval(feof(F));   // expected-warning {{FALSE}}
   fclose(F);
 }
 
@@ -65,6 +68,8 @@ void stream_error_ferror(void) {
   clearerr(F);
   

[clang] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at indeterminate file position. (PR #84191)

2024-03-07 Thread Balázs Kéri via cfe-commits


@@ -880,6 +883,24 @@ void StreamChecker::preReadWrite(const FnDescription *Desc,
   }
 }
 
+void StreamChecker::preWrite(const FnDescription *Desc, const CallEvent &Call,

balazske wrote:

The `CallDescriptionMap` was uncomfortable to handle because too many 
`std::bind` functions.

https://github.com/llvm/llvm-project/pull/84191
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][analyzer] Model more getline/getdelim pre and postconditions (PR #83027)

2024-03-07 Thread Alejandro Álvarez Ayllón via cfe-commits


@@ -1158,6 +1173,123 @@ void StreamChecker::evalUngetc(const FnDescription 
*Desc, const CallEvent &Call,
   C.addTransition(StateFailed);
 }
 
+ProgramStateRef
+StreamChecker::ensurePtrNotNull(SVal PtrVal, const Expr *PtrExpr,
+CheckerContext &C, ProgramStateRef State,
+const StringRef PtrDescr) const {
+  const auto Ptr = PtrVal.getAs();
+  if (!Ptr)
+return nullptr;
+
+  assert(PtrExpr && "Expected an argument");
+
+  const auto [PtrNotNull, PtrNull] = State->assume(*Ptr);
+  if (!PtrNotNull && PtrNull) {
+if (ExplodedNode *N = C.generateErrorNode(PtrNull)) {
+  SmallString<256> buf;
+  llvm::raw_svector_ostream os(buf);
+  os << PtrDescr << " pointer might be NULL.";
+
+  auto R = std::make_unique(BT_SizeNull, buf, N);
+  bugreporter::trackExpressionValue(N, PtrExpr, *R);
+  C.emitReport(std::move(R));
+}
+return nullptr;
+  }
+
+  return PtrNotNull;
+}
+
+ProgramStateRef StreamChecker::ensureSizeZeroIfLineNull(
+SVal LinePtrPtrSVal, SVal SizePtrSVal, const Expr *LinePtrPtrExpr,
+const Expr *SizePtrExpr, CheckerContext &C, ProgramStateRef State) const {
+  static constexpr char SizeNotZeroMsg[] =
+  "Line pointer might be null while n value is not zero";
+
+  // We have a pointer to a pointer to the buffer, and a pointer to the size.
+  // We want what they point at.
+  auto LinePtrSVal = getPointeeDefVal(LinePtrPtrSVal, State);
+  auto NSVal = getPointeeDefVal(SizePtrSVal, State);
+  if (!LinePtrSVal || !NSVal)
+return nullptr;
+
+  assert(LinePtrPtrExpr &&
+ "Expected an argument with a pointer to a pointer to the buffer.");
+  assert(SizePtrExpr &&
+ "Expected an argument with a pointer to the buffer size.");
+
+  // If the line pointer is null, and n is > 0, there is UB.
+  const auto [LinePtrNotNull, LinePtrNull] = State->assume(*LinePtrSVal);
+  if (LinePtrNull && !LinePtrNotNull) {
+const auto [NIsNotZero, NIsZero] = LinePtrNull->assume(*NSVal);
+if (NIsNotZero && !NIsZero) {
+  if (ExplodedNode *N = C.generateErrorNode(NIsNotZero)) {
+auto R = std::make_unique(BT_SizeNotZero,
+  SizeNotZeroMsg, N);
+bugreporter::trackExpressionValue(N, SizePtrExpr, *R);
+bugreporter::trackExpressionValue(N, LinePtrPtrExpr, *R);
+C.emitReport(std::move(R));
+  }
+  return nullptr;
+}
+return NIsZero;
+  }
+  return LinePtrNotNull;
+}
+
+void StreamChecker::preGetdelim(const FnDescription *Desc,
+const CallEvent &Call,
+CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
+  SVal StreamVal = getStreamArg(Desc, Call);
+
+  auto AddTransitionOnReturn = llvm::make_scope_exit([&] {
+if (State != nullptr) {
+  C.addTransition(State);
+}
+  });
+
+  State = ensureStreamNonNull(StreamVal, Call.getArgExpr(Desc->StreamArgNo), C,
+  State);
+  if (!State)
+return;
+  State = ensureStreamOpened(StreamVal, C, State);
+  if (!State)
+return;
+  State = ensureNoFilePositionIndeterminate(StreamVal, C, State);
+  if (!State)
+return;
+
+  // n must not be NULL

alejandro-alvarez-sonarsource wrote:

I went through them, capitalized, quoted, and punctuated. I hope I did not miss 
any.

https://github.com/llvm/llvm-project/pull/83027
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][analyzer] Model more getline/getdelim pre and postconditions (PR #83027)

2024-03-07 Thread Alejandro Álvarez Ayllón via cfe-commits

https://github.com/alejandro-alvarez-sonarsource updated 
https://github.com/llvm/llvm-project/pull/83027

From 997501888aacdbae59ace767e085922c9aa96a22 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alejandro=20=C3=81lvarez=20Ayll=C3=B3n?=
 
Date: Wed, 21 Feb 2024 14:46:01 +0100
Subject: [PATCH 1/2] [clang][analyzer] Model getline/getdelim preconditions

1. lineptr, n and stream can not be NULL
2. if *lineptr is NULL, *n must be 0
---
 .../Core/PathSensitive/CheckerHelpers.h   |   6 +
 .../StaticAnalyzer/Checkers/StreamChecker.cpp | 155 -
 .../StaticAnalyzer/Core/CheckerHelpers.cpp|   9 +
 clang/test/Analysis/getline-stream.c  | 327 ++
 4 files changed, 495 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/Analysis/getline-stream.c

diff --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h
index 65982457ad8393..60421e5437d82f 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h
@@ -13,6 +13,9 @@
 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERHELPERS_H
 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERHELPERS_H
 
+#include "ProgramState_Fwd.h"
+#include "SVals.h"
+
 #include "clang/AST/OperationKinds.h"
 #include "clang/AST/Stmt.h"
 #include "clang/Basic/OperatorKinds.h"
@@ -110,6 +113,9 @@ class OperatorKind {
 OperatorKind operationKindFromOverloadedOperator(OverloadedOperatorKind OOK,
  bool IsBinary);
 
+std::optional getPointeeDefVal(SVal PtrSVal,
+ProgramStateRef State);
+
 } // namespace ento
 
 } // namespace clang
diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index 2ec47bf55df76b..bacac7613f880c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -21,6 +21,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/Sequence.h"
 #include 
 #include 
@@ -234,6 +235,9 @@ class StreamChecker : public Checker();
+  if (!Ptr)
+return nullptr;
+
+  assert(PtrExpr && "Expected an argument");
+
+  const auto [PtrNotNull, PtrNull] = State->assume(*Ptr);
+  if (!PtrNotNull && PtrNull) {
+if (ExplodedNode *N = C.generateErrorNode(PtrNull)) {
+  SmallString<256> buf;
+  llvm::raw_svector_ostream os(buf);
+  os << PtrDescr << " pointer might be NULL.";
+
+  auto R = std::make_unique(BT_SizeNull, buf, N);
+  bugreporter::trackExpressionValue(N, PtrExpr, *R);
+  C.emitReport(std::move(R));
+}
+return nullptr;
+  }
+
+  return PtrNotNull;
+}
+
+ProgramStateRef StreamChecker::ensureSizeZeroIfLineNull(
+SVal LinePtrPtrSVal, SVal SizePtrSVal, const Expr *LinePtrPtrExpr,
+const Expr *SizePtrExpr, CheckerContext &C, ProgramStateRef State) const {
+  static constexpr char SizeNotZeroMsg[] =
+  "Line pointer might be null while n value is not zero";
+
+  // We have a pointer to a pointer to the buffer, and a pointer to the size.
+  // We want what they point at.
+  auto LinePtrSVal = getPointeeDefVal(LinePtrPtrSVal, State);
+  auto NSVal = getPointeeDefVal(SizePtrSVal, State);
+  if (!LinePtrSVal || !NSVal)
+return nullptr;
+
+  assert(LinePtrPtrExpr &&
+ "Expected an argument with a pointer to a pointer to the buffer.");
+  assert(SizePtrExpr &&
+ "Expected an argument with a pointer to the buffer size.");
+
+  // If the line pointer is null, and n is > 0, there is UB.
+  const auto [LinePtrNotNull, LinePtrNull] = State->assume(*LinePtrSVal);
+  if (LinePtrNull && !LinePtrNotNull) {
+const auto [NIsNotZero, NIsZero] = LinePtrNull->assume(*NSVal);
+if (NIsNotZero && !NIsZero) {
+  if (ExplodedNode *N = C.generateErrorNode(NIsNotZero)) {
+auto R = std::make_unique(BT_SizeNotZero,
+  SizeNotZeroMsg, N);
+bugreporter::trackExpressionValue(N, SizePtrExpr, *R);
+bugreporter::trackExpressionValue(N, LinePtrPtrExpr, *R);
+C.emitReport(std::move(R));
+  }
+  return nullptr;
+}
+return NIsZero;
+  }
+  return LinePtrNotNull;
+}
+
+void StreamChecker::preGetdelim(const FnDescription *Desc,
+const CallEvent &Call,
+CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
+  SVal StreamVal = getStreamArg(Desc, Call);
+
+  auto AddTransitionOnReturn = llvm::make_scope_exit([&] {
+if (State != nullptr) {
+  C.addTransition(State);
+}
+  });
+
+  State = 

[clang] [clang][analyzer] Model more getline/getdelim pre and postconditions (PR #83027)

2024-03-07 Thread Alejandro Álvarez Ayllón via cfe-commits


@@ -13,6 +13,9 @@
 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERHELPERS_H
 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERHELPERS_H
 
+#include "ProgramState_Fwd.h"
+#include "SVals.h"
+

alejandro-alvarez-sonarsource wrote:

Removed.

https://github.com/llvm/llvm-project/pull/83027
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][analyzer] Model more getline/getdelim pre and postconditions (PR #83027)

2024-03-07 Thread Alejandro Álvarez Ayllón via cfe-commits


@@ -0,0 +1,327 @@
+// RUN: %clang_analyze_cc1 
-analyzer-checker=core,alpha.unix.Stream,debug.ExprInspection -verify %s
+
+#include "Inputs/system-header-simulator.h"
+#include "Inputs/system-header-simulator-for-malloc.h"
+#include "Inputs/system-header-simulator-for-valist.h"
+
+void clang_analyzer_eval(int);
+void clang_analyzer_dump_int(int);
+extern void clang_analyzer_dump_ptr(void*);
+extern void clang_analyzer_warnIfReached();

alejandro-alvarez-sonarsource wrote:

Removed them for consistency.

https://github.com/llvm/llvm-project/pull/83027
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Implement CTAD for type alias template. (PR #77890)

2024-03-07 Thread Vlad Serebrennikov via cfe-commits

https://github.com/Endilll commented:

`Sema.h` changes look good.

https://github.com/llvm/llvm-project/pull/77890
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [libcxx] [clang] Enable sized deallocation by default in C++14 onwards (PR #83774)

2024-03-07 Thread Fangrui Song via cfe-commits

https://github.com/MaskRay requested changes to this pull request.

This needs sign-off from Apple reviewers whether the version table in 
Darwin.cpp is correct.

https://github.com/llvm/llvm-project/pull/83774
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [libcxx] [clang] Enable sized deallocation by default in C++14 onwards (PR #83774)

2024-03-07 Thread Fangrui Song via cfe-commits


@@ -7105,10 +7105,15 @@ void Clang::ConstructJob(Compilation &C, const 
JobAction &JA,
   Args.addOptInFlag(CmdArgs, options::OPT_frelaxed_template_template_args,
 options::OPT_fno_relaxed_template_template_args);
 
-  // -fsized-deallocation is off by default, as it is an ABI-breaking change 
for
-  // most platforms.
-  Args.addOptInFlag(CmdArgs, options::OPT_fsized_deallocation,
-options::OPT_fno_sized_deallocation);
+  // -fsized-deallocation is on by default in C++14 onwards and otherwise off
+  // by default.
+  if (Arg *A = Args.getLastArg(options::OPT_fsized_deallocation,

MaskRay wrote:

We only need `-fno-sized-deallocation` for CC1Option. When neither option is 
specified, assume implicit `-fsized-deallocation`.

The code change in Darwin.cpp should be changed to a function that decides 
whether the default is yes or no.

https://github.com/llvm/llvm-project/pull/83774
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [libcxx] [clang] Enable sized deallocation by default in C++14 onwards (PR #83774)

2024-03-07 Thread Fangrui Song via cfe-commits

https://github.com/MaskRay edited 
https://github.com/llvm/llvm-project/pull/83774
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Factor out OpenACC part of `Sema` (PR #84184)

2024-03-07 Thread Vlad Serebrennikov via cfe-commits

https://github.com/Endilll updated 
https://github.com/llvm/llvm-project/pull/84184

>From 23f4208fb9978370f59cae16db0747acb3e2c906 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov 
Date: Wed, 6 Mar 2024 18:01:35 +0300
Subject: [PATCH 1/4] [clang] Factor out OpenACC part of `Sema`

This patch moves OpenACC parts of `Sema` into a separate class `SemaOpenACC` 
that is placed in a separate header `Sema/SemaOpenACC.h`. This patch is 
intended to be a model of factoring things out of `Sema`, so I picked a small 
OpenACC part.

Goals are the following:
1) Split `Sema` into manageable parts.
2) Make dependencies between parts visible.
3) Improve Clang development cycle by avoiding recompiling unrelated parts of 
the compiler.
4) Avoid compile-time regressions.
5) Avoid notational regressions in the code that uses Sema.
---
 clang/include/clang/Sema/Sema.h| 77 --
 clang/include/clang/Sema/SemaOpenACC.h | 68 +++
 clang/lib/Parse/ParseOpenACC.cpp   | 22 
 clang/lib/Sema/Sema.cpp|  4 +-
 clang/lib/Sema/SemaOpenACC.cpp | 44 ---
 clang/lib/Sema/TreeTransform.h | 11 ++--
 6 files changed, 137 insertions(+), 89 deletions(-)
 create mode 100644 clang/include/clang/Sema/SemaOpenACC.h

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index f3d3a57104ee07..932676c52b1f30 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -183,6 +183,7 @@ class Preprocessor;
 class PseudoDestructorTypeStorage;
 class PseudoObjectExpr;
 class QualType;
+class SemaOpenACC;
 class StandardConversionSequence;
 class Stmt;
 class StringLiteral;
@@ -466,9 +467,8 @@ class Sema final {
   // 37. Name Lookup for RISC-V Vector Intrinsic (SemaRISCVVectorLookup.cpp)
   // 38. CUDA (SemaCUDA.cpp)
   // 39. HLSL Constructs (SemaHLSL.cpp)
-  // 40. OpenACC Constructs (SemaOpenACC.cpp)
-  // 41. OpenMP Directives and Clauses (SemaOpenMP.cpp)
-  // 42. SYCL Constructs (SemaSYCL.cpp)
+  // 40. OpenMP Directives and Clauses (SemaOpenMP.cpp)
+  // 41. SYCL Constructs (SemaSYCL.cpp)
 
   /// \name Semantic Analysis
   /// Implementations are in Sema.cpp
@@ -1200,6 +1200,27 @@ class Sema final {
   //
   //
 
+  /// \name Sema Components
+  /// Parts of Sema
+  ///@{
+
+  // Just in this section, private members are followed by public, because
+  // C++ requires us to create (private) objects before (public) references.
+
+private:
+  std::unique_ptr OpenACCPtr;
+
+public:
+  SemaOpenACC &OpenACC;
+
+  ///@}
+
+  //
+  //
+  // -
+  //
+  //
+
   /// \name C++ Access Control
   /// Implementations are in SemaAccess.cpp
   ///@{
@@ -13309,56 +13330,6 @@ class Sema final {
   //
   //
 
-  /// \name OpenACC Constructs
-  /// Implementations are in SemaOpenACC.cpp
-  ///@{
-
-public:
-  /// Called after parsing an OpenACC Clause so that it can be checked.
-  bool ActOnOpenACCClause(OpenACCClauseKind ClauseKind,
-  SourceLocation StartLoc);
-
-  /// Called after the construct has been parsed, but clauses haven't been
-  /// parsed.  This allows us to diagnose not-implemented, as well as set up 
any
-  /// state required for parsing the clauses.
-  void ActOnOpenACCConstruct(OpenACCDirectiveKind K, SourceLocation StartLoc);
-
-  /// Called after the directive, including its clauses, have been parsed and
-  /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES
-  /// happen before any associated declarations or statements have been parsed.
-  /// This function is only called when we are parsing a 'statement' context.
-  bool ActOnStartOpenACCStmtDirective(OpenACCDirectiveKind K,
-  SourceLocation StartLoc);
-
-  /// Called after the directive, including its clauses, have been parsed and
-  /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES
-  /// happen before any associated declarations or statements have been parsed.
-  /// This function is only called when we are parsing a 'Decl' context.
-  bool ActOnStartOpenACCDeclDirective(OpenACCDirectiveKind K,
-  SourceLocation StartLoc);
-  /// Called when we encounter an associated statement for our construct, this
-  /// should check legality of the statement as it appertains to this 
Construct.
-  StmtResult ActOnOpenACCAssociatedStmt(OpenACCDirectiveKind K,
-StmtResult AssocStmt);
-
-  /// Called after the directive has been completely parsed, including the
-  /// declaration group or associated statement.
-  StmtResult ActOnEndOpenACCStmtDirective(OpenACCDirectiveKind K,
-  SourceLocation StartLoc,
-  SourceLocation EndLoc,
-  StmtResult AssocStmt);
-  /// Called after the directive has 

[clang] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at indeterminate file position. (PR #84191)

2024-03-07 Thread Balazs Benics via cfe-commits


@@ -880,6 +883,24 @@ void StreamChecker::preReadWrite(const FnDescription *Desc,
   }
 }
 
+void StreamChecker::preWrite(const FnDescription *Desc, const CallEvent &Call,

steakhal wrote:

Let me share my experience with `std::bind` and with this checker.
Unfortunately, we also have/had a couple (<10) conflicting patches to this 
checker, and I had to rebase 16 times to clang-18. This is fine, but when I 
this many `std::binds`, and sometimes changes where the railing "bool" flag 
meaning was changed, I really had to be on my toes when resolving syntactic & 
semantic conflicts.
I feel the `std::bind` usage got out of hand here, and I now regret not pushing 
back.

The bottom line is, that I think having dedicated handlers dispatching to 
common implementations, or just copy-pasting their implementation while 
specializing it leads to cleaner code than using `std::bind` and directly 
binding to the generic implementation.

https://github.com/llvm/llvm-project/pull/84191
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 7ce1cfe - [alpha.webkit.UncountedLocalVarsChecker] Allow uncounted object references within trivial statements (#82229)

2024-03-07 Thread via cfe-commits

Author: Ryosuke Niwa
Date: 2024-03-07T01:06:20-08:00
New Revision: 7ce1cfed9a11735f0f4ee8a3a8bebfa87ee76d07

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

LOG: [alpha.webkit.UncountedLocalVarsChecker] Allow uncounted object references 
within trivial statements (#82229)

This PR makes alpha.webkit.UncountedLocalVarsChecker ignore raw
references and pointers to a ref counted type which appears within
"trival" statements. To do this, this PR extends TrivialFunctionAnalysis
so that it can also analyze "triviality" of statements as well as that
of functions Each Visit* function is now augmented with
withCachedResult, which is responsible for looking up and updating the
cache for each Visit* functions.

As this PR dramatically improves the false positive rate of the checker,
it also deletes the code to ignore raw pointers and references within if
and for statements.

Added: 


Modified: 
clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp
clang/test/Analysis/Checkers/WebKit/mock-types.h
clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp

Removed: 




diff  --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index 01b191ab0eeaf4..287f6a52870056 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -253,6 +253,19 @@ class TrivialFunctionAnalysisVisitor
 return true;
   }
 
+  template 
+  bool WithCachedResult(const Stmt *S, CheckFunction Function) {
+// If the statement isn't in the cache, conservatively assume that
+// it's not trivial until analysis completes. Insert false to the cache
+// first to avoid infinite recursion.
+auto [It, IsNew] = Cache.insert(std::make_pair(S, false));
+if (!IsNew)
+  return It->second;
+bool Result = Function();
+Cache[S] = Result;
+return Result;
+  }
+
 public:
   using CacheTy = TrivialFunctionAnalysis::CacheTy;
 
@@ -267,7 +280,7 @@ class TrivialFunctionAnalysisVisitor
   bool VisitCompoundStmt(const CompoundStmt *CS) {
 // A compound statement is allowed as long each individual sub-statement
 // is trivial.
-return VisitChildren(CS);
+return WithCachedResult(CS, [&]() { return VisitChildren(CS); });
   }
 
   bool VisitReturnStmt(const ReturnStmt *RS) {
@@ -279,17 +292,36 @@ class TrivialFunctionAnalysisVisitor
 
   bool VisitDeclStmt(const DeclStmt *DS) { return VisitChildren(DS); }
   bool VisitDoStmt(const DoStmt *DS) { return VisitChildren(DS); }
-  bool VisitIfStmt(const IfStmt *IS) { return VisitChildren(IS); }
+  bool VisitIfStmt(const IfStmt *IS) {
+return WithCachedResult(IS, [&]() { return VisitChildren(IS); });
+  }
+  bool VisitForStmt(const ForStmt *FS) {
+return WithCachedResult(FS, [&]() { return VisitChildren(FS); });
+  }
+  bool VisitCXXForRangeStmt(const CXXForRangeStmt *FS) {
+return WithCachedResult(FS, [&]() { return VisitChildren(FS); });
+  }
+  bool VisitWhileStmt(const WhileStmt *WS) {
+return WithCachedResult(WS, [&]() { return VisitChildren(WS); });
+  }
   bool VisitSwitchStmt(const SwitchStmt *SS) { return VisitChildren(SS); }
   bool VisitCaseStmt(const CaseStmt *CS) { return VisitChildren(CS); }
   bool VisitDefaultStmt(const DefaultStmt *DS) { return VisitChildren(DS); }
 
   bool VisitUnaryOperator(const UnaryOperator *UO) {
 // Operator '*' and '!' are allowed as long as the operand is trivial.
-if (UO->getOpcode() == UO_Deref || UO->getOpcode() == UO_AddrOf ||
-UO->getOpcode() == UO_LNot)
+auto op = UO->getOpcode();
+if (op == UO_Deref || op == UO_AddrOf || op == UO_LNot)
   return Visit(UO->getSubExpr());
 
+if (UO->isIncrementOp() || UO->isDecrementOp()) {
+  // Allow increment or decrement of a POD type.
+  if (auto *RefExpr = dyn_cast(UO->getSubExpr())) {
+if (auto *Decl = dyn_cast(RefExpr->getDecl()))
+  return Decl->isLocalVarDeclOrParm() &&
+ Decl->getType().isPODType(Decl->getASTContext());
+  }
+}
 // Other operators are non-trivial.
 return false;
   }
@@ -304,22 +336,6 @@ class TrivialFunctionAnalysisVisitor
 return VisitChildren(CO);
   }
 
-  bool VisitDeclRefExpr(const DeclRefExpr *DRE) {
-if (auto *decl = DRE->getDecl()) {
-  if (isa(decl))
-return true;
-  if (isa(decl))
-return true;
-  if (auto *VD = dyn_cast(decl)) {
-if (VD->hasConstantInitialization() && VD->getEvaluatedValue())
-  return true;
-auto *Init = VD->getInit();
-

[clang] [alpha.webkit.UncountedLocalVarsChecker] Allow uncounted object references within trivial statements (PR #82229)

2024-03-07 Thread Ryosuke Niwa via cfe-commits

https://github.com/rniwa closed https://github.com/llvm/llvm-project/pull/82229
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at indeterminate file position. (PR #84191)

2024-03-07 Thread via cfe-commits


@@ -880,6 +883,24 @@ void StreamChecker::preReadWrite(const FnDescription *Desc,
   }
 }
 
+void StreamChecker::preWrite(const FnDescription *Desc, const CallEvent &Call,

NagyDonat wrote:

I agree that `std::bind` is hard to follow, and dedicated handlers dispatching 
to common implementations is a better model.

The "Copy-pasting their implementation while specializing it" could be even 
better if the common parts are lifted out into helper functions; but I strongly 
suggest that we should avoid code duplication.

https://github.com/llvm/llvm-project/pull/84191
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at indeterminate file position. (PR #84191)

2024-03-07 Thread via cfe-commits

https://github.com/NagyDonat edited 
https://github.com/llvm/llvm-project/pull/84191
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][analyzer] Fix StreamChecker `ftell` and `fgetpos` at indeterminate file position. (PR #84191)

2024-03-07 Thread via cfe-commits

https://github.com/NagyDonat edited 
https://github.com/llvm/llvm-project/pull/84191
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][analyzer] Model more getline/getdelim pre and postconditions (PR #83027)

2024-03-07 Thread Alejandro Álvarez Ayllón via cfe-commits

https://github.com/alejandro-alvarez-sonarsource updated 
https://github.com/llvm/llvm-project/pull/83027

From 5c919832f9176d4b1af1312a4ee7cf30b788958a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alejandro=20=C3=81lvarez=20Ayll=C3=B3n?=
 
Date: Wed, 21 Feb 2024 14:46:01 +0100
Subject: [PATCH 1/2] [clang][analyzer] Model getline/getdelim preconditions

1. lineptr, n and stream can not be NULL
2. if *lineptr is NULL, *n must be 0
---
 .../StaticAnalyzer/Checkers/StreamChecker.cpp | 155 -
 clang/test/Analysis/getline-stream.c  | 327 ++
 2 files changed, 480 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/Analysis/getline-stream.c

diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index 2ec47bf55df76b..bacac7613f880c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -21,6 +21,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/Sequence.h"
 #include 
 #include 
@@ -234,6 +235,9 @@ class StreamChecker : public Checker();
+  if (!Ptr)
+return nullptr;
+
+  assert(PtrExpr && "Expected an argument");
+
+  const auto [PtrNotNull, PtrNull] = State->assume(*Ptr);
+  if (!PtrNotNull && PtrNull) {
+if (ExplodedNode *N = C.generateErrorNode(PtrNull)) {
+  SmallString<256> buf;
+  llvm::raw_svector_ostream os(buf);
+  os << PtrDescr << " pointer might be NULL.";
+
+  auto R = std::make_unique(BT_SizeNull, buf, N);
+  bugreporter::trackExpressionValue(N, PtrExpr, *R);
+  C.emitReport(std::move(R));
+}
+return nullptr;
+  }
+
+  return PtrNotNull;
+}
+
+ProgramStateRef StreamChecker::ensureSizeZeroIfLineNull(
+SVal LinePtrPtrSVal, SVal SizePtrSVal, const Expr *LinePtrPtrExpr,
+const Expr *SizePtrExpr, CheckerContext &C, ProgramStateRef State) const {
+  static constexpr char SizeNotZeroMsg[] =
+  "Line pointer might be null while n value is not zero";
+
+  // We have a pointer to a pointer to the buffer, and a pointer to the size.
+  // We want what they point at.
+  auto LinePtrSVal = getPointeeDefVal(LinePtrPtrSVal, State);
+  auto NSVal = getPointeeDefVal(SizePtrSVal, State);
+  if (!LinePtrSVal || !NSVal)
+return nullptr;
+
+  assert(LinePtrPtrExpr &&
+ "Expected an argument with a pointer to a pointer to the buffer.");
+  assert(SizePtrExpr &&
+ "Expected an argument with a pointer to the buffer size.");
+
+  // If the line pointer is null, and n is > 0, there is UB.
+  const auto [LinePtrNotNull, LinePtrNull] = State->assume(*LinePtrSVal);
+  if (LinePtrNull && !LinePtrNotNull) {
+const auto [NIsNotZero, NIsZero] = LinePtrNull->assume(*NSVal);
+if (NIsNotZero && !NIsZero) {
+  if (ExplodedNode *N = C.generateErrorNode(NIsNotZero)) {
+auto R = std::make_unique(BT_SizeNotZero,
+  SizeNotZeroMsg, N);
+bugreporter::trackExpressionValue(N, SizePtrExpr, *R);
+bugreporter::trackExpressionValue(N, LinePtrPtrExpr, *R);
+C.emitReport(std::move(R));
+  }
+  return nullptr;
+}
+return NIsZero;
+  }
+  return LinePtrNotNull;
+}
+
+void StreamChecker::preGetdelim(const FnDescription *Desc,
+const CallEvent &Call,
+CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
+  SVal StreamVal = getStreamArg(Desc, Call);
+
+  auto AddTransitionOnReturn = llvm::make_scope_exit([&] {
+if (State != nullptr) {
+  C.addTransition(State);
+}
+  });
+
+  State = ensureStreamNonNull(StreamVal, Call.getArgExpr(Desc->StreamArgNo), C,
+  State);
+  if (!State)
+return;
+  State = ensureStreamOpened(StreamVal, C, State);
+  if (!State)
+return;
+  State = ensureNoFilePositionIndeterminate(StreamVal, C, State);
+  if (!State)
+return;
+
+  // n must not be NULL
+  SVal SizePtrSval = Call.getArgSVal(1);
+  State = ensurePtrNotNull(SizePtrSval, Call.getArgExpr(1), C, State, "Size");
+  if (!State)
+return;
+
+  // lineptr must not be NULL
+  SVal LinePtrPtrSVal = Call.getArgSVal(0);
+  State =
+  ensurePtrNotNull(LinePtrPtrSVal, Call.getArgExpr(0), C, State, "Line");
+  if (!State)
+return;
+
+  // If lineptr points to a NULL pointer, *n must be 0
+  State =
+  ensureSizeZeroIfLineNull(LinePtrPtrSVal, SizePtrSval, Call.getArgExpr(0),
+   Call.getArgExpr(1), C, State);
+  if (!State)
+return;
+
+  SymbolRef Sym = StreamVal.getAsSymbol();
+  if (Sym && State->get(Sym)) {
+const StreamState *SS = State->get(Sym);
+if (SS->ErrorState & ErrorFEof)
+  reportFEofWarning(Sym, C, State);
+  } else 

[clang] [clang][analyzer] Model more getline/getdelim pre and postconditions (PR #83027)

2024-03-07 Thread Alejandro Álvarez Ayllón via cfe-commits

alejandro-alvarez-sonarsource wrote:

Rebased on top of main to solve conflicts.

https://github.com/llvm/llvm-project/pull/83027
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [dataflow][nfc] Fix u8 string usage with c++20 (PR #84291)

2024-03-07 Thread Vincent Lee via cfe-commits

https://github.com/thevinster created 
https://github.com/llvm/llvm-project/pull/84291

Clang returns an error when compiling this file with c++20
```
error: ISO C++20 does not permit initialization of char array with UTF-8 string 
literal
```
It seems like c++20 treats u8strings differently than strings (probably needs 
char8_t). 
Make this a string to fix the error. 

>From 17a6d9dbdb07631b174d89fa2e95f28244e15e8f Mon Sep 17 00:00:00 2001
From: Vincent Lee 
Date: Thu, 7 Mar 2024 01:14:07 -0800
Subject: [PATCH] [dataflow][nfc] Fix u8 string usage with c++20

---
 clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp 
b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
index ff4e18de2c70f1..d9f40d28859f5e 100644
--- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
+++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
@@ -500,7 +500,7 @@ class HTMLLogger : public Logger {
 for (unsigned I = 0; I < CFG.getNumBlockIDs(); ++I) {
   std::string Name = blockID(I);
   // Rightwards arrow, vertical line
-  char ConvergenceMarker[] = u8"\\n\u2192\u007c";
+  char ConvergenceMarker[] = "\\n\u2192\u007c";
   if (BlockConverged[I])
 Name += ConvergenceMarker;
   GraphS << "  " << blockID(I) << " [id=" << blockID(I) << " label=\""

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


[clang] [dataflow][nfc] Fix u8 string usage with c++20 (PR #84291)

2024-03-07 Thread via cfe-commits

llvmbot wrote:



@llvm/pr-subscribers-clang-analysis

@llvm/pr-subscribers-clang

Author: Vincent Lee (thevinster)


Changes

Clang returns an error when compiling this file with c++20
```
error: ISO C++20 does not permit initialization of char array with UTF-8 string 
literal
```
It seems like c++20 treats u8strings differently than strings (probably needs 
char8_t). 
Make this a string to fix the error. 

---
Full diff: https://github.com/llvm/llvm-project/pull/84291.diff


1 Files Affected:

- (modified) clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp (+1-1) 


``diff
diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp 
b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
index ff4e18de2c70f1..d9f40d28859f5e 100644
--- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
+++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
@@ -500,7 +500,7 @@ class HTMLLogger : public Logger {
 for (unsigned I = 0; I < CFG.getNumBlockIDs(); ++I) {
   std::string Name = blockID(I);
   // Rightwards arrow, vertical line
-  char ConvergenceMarker[] = u8"\\n\u2192\u007c";
+  char ConvergenceMarker[] = "\\n\u2192\u007c";
   if (BlockConverged[I])
 Name += ConvergenceMarker;
   GraphS << "  " << blockID(I) << " [id=" << blockID(I) << " label=\""

``




https://github.com/llvm/llvm-project/pull/84291
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [alpha.webkit.UncountedCallArgsChecker] Don't assume local variables are safe & treat guarded local variable as safe function arguments (PR #82305)

2024-03-07 Thread Ryosuke Niwa via cfe-commits

https://github.com/rniwa closed https://github.com/llvm/llvm-project/pull/82305
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][ExprConst] Can't be past an invalid LValue designator (PR #84293)

2024-03-07 Thread Timm Baeder via cfe-commits

https://github.com/tbaederr created 
https://github.com/llvm/llvm-project/pull/84293

For the test case in C, both `LV.getLValueOffset()` and 
`Ctx.getTypeSizeInChars(Ty)` are zero, so we return `true` from 
`isOnePastTheEndOfCompleteObject()` and ultimately diagnose this as being one 
past the end, but the diagnostic doesn't make sense.

>From e393a6a7ae875eab1154762b1d5bb673adfb9f2b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= 
Date: Thu, 7 Mar 2024 10:14:03 +0100
Subject: [PATCH] [clang][ExprConst] Can't be past an invalid LValue designator

---
 clang/lib/AST/ExprConstant.cpp|  7 ++-
 clang/test/Sema/const-eval.c  |  3 +--
 clang/test/Sema/constexpr-void-cast.c | 14 ++
 3 files changed, 21 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/Sema/constexpr-void-cast.c

diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index d8ca35740fbc35..bc8de9d08542cd 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -9211,7 +9211,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr 
*E) {
Info.getLangOpts().CPlusPlus26)) {
 // Permitted.
   } else {
-if (SubExpr->getType()->isVoidPointerType()) {
+if (SubExpr->getType()->isVoidPointerType() &&
+Info.getLangOpts().CPlusPlus) {
   if (HasValidResult)
 CCEDiag(E, diag::note_constexpr_invalid_void_star_cast)
 << SubExpr->getType() << Info.getLangOpts().CPlusPlus26
@@ -12899,6 +12900,10 @@ static bool isOnePastTheEndOfCompleteObject(const 
ASTContext &Ctx,
   if (Ty->isIncompleteType())
 return true;
 
+  // Can't be past the end of an invalid object.
+  if (LV.getLValueDesignator().Invalid)
+return false;
+
   // We're a past-the-end pointer if we point to the byte after the object,
   // no matter what our type or path is.
   auto Size = Ctx.getTypeSizeInChars(Ty);
diff --git a/clang/test/Sema/const-eval.c b/clang/test/Sema/const-eval.c
index 2e38d5e23c208a..e358aceaad5a43 100644
--- a/clang/test/Sema/const-eval.c
+++ b/clang/test/Sema/const-eval.c
@@ -134,8 +134,7 @@ void PR21945(void) { int i = (({}), 0l); }
 
 void PR24622(void);
 struct PR24622 {} pr24622;
-EVAL_EXPR(52, &pr24622 == (void *)&PR24622); // expected-error {{not an 
integer constant expression}}
- // expected-note@-1 {{past the 
end}}
+EVAL_EXPR(52, &pr24622 == (void *)&PR24622);
 
 // We evaluate these by providing 2s' complement semantics in constant
 // expressions, like we do for integers.
diff --git a/clang/test/Sema/constexpr-void-cast.c 
b/clang/test/Sema/constexpr-void-cast.c
new file mode 100644
index 00..c5caa3b9e58feb
--- /dev/null
+++ b/clang/test/Sema/constexpr-void-cast.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -x c -fsyntax-only %s -verify=c
+// RUN: %clang_cc1 -x c -fsyntax-only %s -pedantic -verify=c-pedantic
+//
+// RUN: %clang_cc1 -x c++ -fsyntax-only %s -verify=cxx
+// RUN: %clang_cc1 -x c++ -fsyntax-only %s -pedantic -verify=cxx-pedantic
+
+// c-no-diagnostics
+// cxx-no-diagnostics
+
+void f(void);
+struct S {char c;} s;
+_Static_assert(&s != (void *)&f, ""); // c-pedantic-warning {{not an integer 
constant expression}} \
+  // c-pedantic-note {{this conversion is 
not allowed in a constant expression}} \
+  // cxx-pedantic-warning 
{{'_Static_assert' is a C11 extension}}

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


[clang] [clang][ExprConst] Can't be past an invalid LValue designator (PR #84293)

2024-03-07 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)


Changes

For the test case in C, both `LV.getLValueOffset()` and 
`Ctx.getTypeSizeInChars(Ty)` are zero, so we return `true` from 
`isOnePastTheEndOfCompleteObject()` and ultimately diagnose this as being one 
past the end, but the diagnostic doesn't make sense.

---
Full diff: https://github.com/llvm/llvm-project/pull/84293.diff


3 Files Affected:

- (modified) clang/lib/AST/ExprConstant.cpp (+6-1) 
- (modified) clang/test/Sema/const-eval.c (+1-2) 
- (added) clang/test/Sema/constexpr-void-cast.c (+14) 


``diff
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index d8ca35740fbc35..bc8de9d08542cd 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -9211,7 +9211,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr 
*E) {
Info.getLangOpts().CPlusPlus26)) {
 // Permitted.
   } else {
-if (SubExpr->getType()->isVoidPointerType()) {
+if (SubExpr->getType()->isVoidPointerType() &&
+Info.getLangOpts().CPlusPlus) {
   if (HasValidResult)
 CCEDiag(E, diag::note_constexpr_invalid_void_star_cast)
 << SubExpr->getType() << Info.getLangOpts().CPlusPlus26
@@ -12899,6 +12900,10 @@ static bool isOnePastTheEndOfCompleteObject(const 
ASTContext &Ctx,
   if (Ty->isIncompleteType())
 return true;
 
+  // Can't be past the end of an invalid object.
+  if (LV.getLValueDesignator().Invalid)
+return false;
+
   // We're a past-the-end pointer if we point to the byte after the object,
   // no matter what our type or path is.
   auto Size = Ctx.getTypeSizeInChars(Ty);
diff --git a/clang/test/Sema/const-eval.c b/clang/test/Sema/const-eval.c
index 2e38d5e23c208a..e358aceaad5a43 100644
--- a/clang/test/Sema/const-eval.c
+++ b/clang/test/Sema/const-eval.c
@@ -134,8 +134,7 @@ void PR21945(void) { int i = (({}), 0l); }
 
 void PR24622(void);
 struct PR24622 {} pr24622;
-EVAL_EXPR(52, &pr24622 == (void *)&PR24622); // expected-error {{not an 
integer constant expression}}
- // expected-note@-1 {{past the 
end}}
+EVAL_EXPR(52, &pr24622 == (void *)&PR24622);
 
 // We evaluate these by providing 2s' complement semantics in constant
 // expressions, like we do for integers.
diff --git a/clang/test/Sema/constexpr-void-cast.c 
b/clang/test/Sema/constexpr-void-cast.c
new file mode 100644
index 00..c5caa3b9e58feb
--- /dev/null
+++ b/clang/test/Sema/constexpr-void-cast.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -x c -fsyntax-only %s -verify=c
+// RUN: %clang_cc1 -x c -fsyntax-only %s -pedantic -verify=c-pedantic
+//
+// RUN: %clang_cc1 -x c++ -fsyntax-only %s -verify=cxx
+// RUN: %clang_cc1 -x c++ -fsyntax-only %s -pedantic -verify=cxx-pedantic
+
+// c-no-diagnostics
+// cxx-no-diagnostics
+
+void f(void);
+struct S {char c;} s;
+_Static_assert(&s != (void *)&f, ""); // c-pedantic-warning {{not an integer 
constant expression}} \
+  // c-pedantic-note {{this conversion is 
not allowed in a constant expression}} \
+  // cxx-pedantic-warning 
{{'_Static_assert' is a C11 extension}}

``




https://github.com/llvm/llvm-project/pull/84293
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [dataflow][nfc] Fix u8 string usage with c++20 (PR #84291)

2024-03-07 Thread via cfe-commits

https://github.com/martinboehme approved this pull request.

Thanks, and sorry for the breeakage!

https://github.com/llvm/llvm-project/pull/84291
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [dataflow][nfc] Fix u8 string usage with c++20 (PR #84291)

2024-03-07 Thread via cfe-commits

https://github.com/martinboehme closed 
https://github.com/llvm/llvm-project/pull/84291
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 6e79f77 - [dataflow][nfc] Fix u8 string usage with c++20 (#84291)

2024-03-07 Thread via cfe-commits

Author: Vincent Lee
Date: 2024-03-07T10:46:36+01:00
New Revision: 6e79f77adbbd338848ea770f2f2b110bc57a3990

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

LOG: [dataflow][nfc] Fix u8 string usage with c++20 (#84291)

Clang returns an error when compiling this file with c++20
```
error: ISO C++20 does not permit initialization of char array with UTF-8 string 
literal
```
It seems like c++20 treats u8strings differently than strings (probably
needs char8_t).
Make this a string to fix the error.

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 ff4e18de2c70f1..d9f40d28859f5e 100644
--- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
+++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
@@ -500,7 +500,7 @@ class HTMLLogger : public Logger {
 for (unsigned I = 0; I < CFG.getNumBlockIDs(); ++I) {
   std::string Name = blockID(I);
   // Rightwards arrow, vertical line
-  char ConvergenceMarker[] = u8"\\n\u2192\u007c";
+  char ConvergenceMarker[] = "\\n\u2192\u007c";
   if (BlockConverged[I])
 Name += ConvergenceMarker;
   GraphS << "  " << blockID(I) << " [id=" << blockID(I) << " label=\""



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


[clang] [Clang][Sema] Allow access to a public template alias declaration that refers to friend's private nested type (PR #83847)

2024-03-07 Thread Qizhi Hu via cfe-commits

https://github.com/jcsxky updated 
https://github.com/llvm/llvm-project/pull/83847

>From a38ad9098c7f4dcffaa22b269bc2a36b5eb0fc4e Mon Sep 17 00:00:00 2001
From: huqizhi 
Date: Mon, 4 Mar 2024 21:51:07 +0800
Subject: [PATCH] [Clang][Sema] Allow access to a public template alias
 declaration that refers to friend's private nested type

---
 clang/docs/ReleaseNotes.rst |  3 +++
 clang/lib/Sema/SemaAccess.cpp   |  6 ++
 clang/test/SemaTemplate/PR25708.cpp | 23 +++
 3 files changed, 32 insertions(+)
 create mode 100644 clang/test/SemaTemplate/PR25708.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8300a8484585ae..945a21f61abc61 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -239,6 +239,9 @@ Bug Fixes in This Version
   for variables created through copy initialization having side-effects in 
C++17 and later.
   Fixes (#GH64356) (#GH79518).
 
+- Allow access to a public template alias declaration that refers to friend's
+  private nested type (`#25708 
`).
+
 Bug Fixes to Compiler Builtins
 ^^
 
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index 4af3c0f30a8e8a..ab4580b39a3ae8 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -1481,6 +1481,12 @@ static Sema::AccessResult CheckAccess(Sema &S, 
SourceLocation Loc,
   }
 
   EffectiveContext EC(S.CurContext);
+  auto &Active = S.CodeSynthesisContexts.back();
+  if (Active.Entity)
+if (auto *RD =
+dyn_cast_or_null(Active.Entity->getDeclContext()))
+  EC.Records.push_back(RD);
+
   switch (CheckEffectiveAccess(S, EC, Loc, Entity)) {
   case AR_accessible: return Sema::AR_accessible;
   case AR_inaccessible: return Sema::AR_inaccessible;
diff --git a/clang/test/SemaTemplate/PR25708.cpp 
b/clang/test/SemaTemplate/PR25708.cpp
new file mode 100644
index 00..cc2e7551a6abaa
--- /dev/null
+++ b/clang/test/SemaTemplate/PR25708.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+// RUN: %clang_cc1 -std=c++14 -verify %s
+// RUN: %clang_cc1 -std=c++17 -verify %s
+// RUN: %clang_cc1 -std=c++20 -verify %s
+// expected-no-diagnostics
+
+struct FooAccessor
+{
+template 
+using Foo = typename T::Foo;
+};
+
+class Type
+{
+friend struct FooAccessor;
+
+using Foo = int;
+};
+
+int main()
+{
+FooAccessor::Foo t;
+}

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


[clang] [X86] Finally handle target of __builtin_ia32_cmp[p|s][s|d] from avx into sse/sse2/avx (PR #84136)

2024-03-07 Thread Simon Pilgrim via cfe-commits

https://github.com/RKSimon edited 
https://github.com/llvm/llvm-project/pull/84136
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] 6f54a54 - [FMV] Remove duplicate features from mangled name. (#84165)

2024-03-07 Thread via cfe-commits

Author: Alexandros Lamprineas
Date: 2024-03-07T10:33:26Z
New Revision: 6f54a54c6f5f644b4f4c79882154fd9737568c8e

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

LOG: [FMV] Remove duplicate features from mangled name. (#84165)

ACLE suggests: https://github.com/ARM-software/acle/pull/308. GCC emits
diagnostics for attribute strings which contain duplicate features, but
for now let's follow the SPEC in regards to mangling rules and we can
change the semantic behavior of the compiler later if there's value to
it.

Added: 


Modified: 
clang/lib/CodeGen/Targets/AArch64.cpp
clang/test/CodeGen/attr-target-version.c

Removed: 




diff  --git a/clang/lib/CodeGen/Targets/AArch64.cpp 
b/clang/lib/CodeGen/Targets/AArch64.cpp
index 725e8a70fddfe6..85117366de0ee8 100644
--- a/clang/lib/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CodeGen/Targets/AArch64.cpp
@@ -886,9 +886,11 @@ void AArch64ABIInfo::appendAttributeMangling(StringRef 
AttrStr,
 return LHS.compare(RHS) < 0;
   });
 
+  llvm::SmallDenseSet UniqueFeats;
   for (auto &Feat : Features)
 if (auto Ext = llvm::AArch64::parseArchExtension(Feat))
-  Out << 'M' << Ext->Name;
+  if (UniqueFeats.insert(Ext->Name).second)
+Out << 'M' << Ext->Name;
 }
 
 std::unique_ptr

diff  --git a/clang/test/CodeGen/attr-target-version.c 
b/clang/test/CodeGen/attr-target-version.c
index ae1a8772f6cc07..b7112c783da913 100644
--- a/clang/test/CodeGen/attr-target-version.c
+++ b/clang/test/CodeGen/attr-target-version.c
@@ -273,7 +273,7 @@ int hoo(void) {
 // CHECK-NEXT:[[TMP3:%.*]] = and i1 true, [[TMP2]]
 // CHECK-NEXT:br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label 
[[RESOLVER_ELSE:%.*]]
 // CHECK:   resolver_return:
-// CHECK-NEXT:ret ptr @fmv_inline._MfcmaMfp16Mfp16MrdmMsme
+// CHECK-NEXT:ret ptr @fmv_inline._MfcmaMfp16MrdmMsme
 // CHECK:   resolver_else:
 // CHECK-NEXT:[[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8
 // CHECK-NEXT:[[TMP5:%.*]] = and i64 [[TMP4]], 864726312827224064
@@ -582,7 +582,7 @@ int hoo(void) {
 //
 //
 // CHECK: Function Attrs: noinline nounwind optnone
-// CHECK-LABEL: define {{[^@]+}}@fmv_inline._MfcmaMfp16Mfp16MrdmMsme
+// CHECK-LABEL: define {{[^@]+}}@fmv_inline._MfcmaMfp16MrdmMsme
 // CHECK-SAME: () #[[ATTR13:[0-9]+]] {
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:ret i32 2



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


[clang] [FMV] Remove duplicate features from mangled name. (PR #84165)

2024-03-07 Thread Alexandros Lamprineas via cfe-commits

https://github.com/labrinea closed 
https://github.com/llvm/llvm-project/pull/84165
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [dataflow][nfc] Fix u8 string usage with c++20 (PR #84291)

2024-03-07 Thread Simon Pilgrim via cfe-commits


@@ -500,7 +500,7 @@ class HTMLLogger : public Logger {
 for (unsigned I = 0; I < CFG.getNumBlockIDs(); ++I) {
   std::string Name = blockID(I);
   // Rightwards arrow, vertical line
-  char ConvergenceMarker[] = u8"\\n\u2192\u007c";
+  char ConvergenceMarker[] = "\\n\u2192\u007c";

RKSimon wrote:

@thevinster @martinboehme This change now fails on MSVC builds:

`warning C4566: character represented by universal-character-name '\u2192' 
cannot be represented in the current code page (1252)`

Maybe try this instead?
```c
const char *ConvergenceMarker = (const char*)u8"\\n\u2192\u007c";
```

https://github.com/llvm/llvm-project/pull/84291
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang-tidy][dataflow] Add `bugprone-null-check-after-dereference` check (PR #84166)

2024-03-07 Thread via cfe-commits


@@ -0,0 +1,625 @@
+//===-- NullPointerAnalysisModel.cpp *- 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
+//
+//===--===//
+//
+// This file defines a generic null-pointer analysis model, used for finding
+// pointer null-checks after the pointer has already been dereferenced.
+//
+// Only a limited set of operations are currently recognized. Notably, pointer
+// arithmetic, null-pointer assignments and _nullable/_nonnull attributes are
+// missing as of yet.
+//
+//===--===//
+
+#include "clang/Analysis/FlowSensitive/Models/NullPointerAnalysisModel.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Stmt.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/FlowSensitive/CFGMatchSwitch.h"
+#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
+#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
+#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
+#include "clang/Analysis/FlowSensitive/MapLattice.h"
+#include "clang/Analysis/FlowSensitive/NoopLattice.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+
+namespace clang::dataflow {
+
+namespace {
+using namespace ast_matchers;
+
+constexpr char kCond[] = "condition";
+constexpr char kVar[] = "var";
+constexpr char kValue[] = "value";
+constexpr char kIsNonnull[] = "is-nonnull";
+constexpr char kIsNull[] = "is-null";
+
+enum class SatisfiabilityResult {
+  // Returned when the value was not initialized yet.
+  Nullptr,
+  // Special value that signals that the boolean value can be anything.
+  // It signals that the underlying formulas are too complex to be calculated
+  // efficiently.
+  Top,
+  // Equivalent to the literal True in the current environment.
+  True,
+  // Equivalent to the literal False in the current environment.
+  False,
+  // Both True and False values could be produced with an appropriate set of
+  // conditions.
+  Unknown
+};
+
+using SR = SatisfiabilityResult;
+
+// FIXME: These AST matchers should also be exported via the
+// NullPointerAnalysisModel class, for tests
+auto ptrToVar(llvm::StringRef VarName = kVar) {
+  return traverse(TK_IgnoreUnlessSpelledInSource,
+  declRefExpr(hasType(isAnyPointer())).bind(VarName));
+}
+
+auto derefMatcher() {
+  return traverse(
+  TK_IgnoreUnlessSpelledInSource,
+  unaryOperator(hasOperatorName("*"), hasUnaryOperand(ptrToVar(;
+}
+
+auto arrowMatcher() {
+  return traverse(
+  TK_IgnoreUnlessSpelledInSource,
+  memberExpr(allOf(isArrow(), hasObjectExpression(ptrToVar();
+}
+
+auto castExprMatcher() {
+  return castExpr(hasCastKind(CK_PointerToBoolean),
+  hasSourceExpression(ptrToVar()))
+  .bind(kCond);
+}
+
+auto nullptrMatcher() {
+  return castExpr(hasCastKind(CK_NullToPointer)).bind(kVar);
+}
+
+auto addressofMatcher() {
+  return unaryOperator(hasOperatorName("&")).bind(kVar);
+}
+
+auto functionCallMatcher() {
+  return callExpr(hasDeclaration(functionDecl(returns(isAnyPointer()
+  .bind(kVar);
+}
+
+auto assignMatcher() {
+  return binaryOperation(isAssignmentOperator(), hasLHS(ptrToVar()),
+ hasRHS(expr().bind(kValue)));
+}
+
+auto anyPointerMatcher() { return expr(hasType(isAnyPointer())).bind(kVar); }
+
+// Only computes simple comparisons against the literals True and False in the
+// environment. Faster, but produces many Unknown values.
+SatisfiabilityResult shallowComputeSatisfiability(BoolValue *Val,
+  const Environment &Env) {
+  if (!Val)
+return SR::Nullptr;
+
+  if (isa(Val))
+return SR::Top;
+
+  if (Val == &Env.getBoolLiteralValue(true))
+return SR::True;
+
+  if (Val == &Env.getBoolLiteralValue(false))
+return SR::False;
+
+  return SR::Unknown;
+}
+
+// Computes satisfiability by using the flow condition. Slower, but more
+// precise.
+SatisfiabilityResult computeSatisfiability(BoolValue *Val,
+   const Environment &Env) {
+  // Early return with the fast compute values.
+  if (SatisfiabilityResult ShallowResult =
+  shallowComputeSatisfiability(Val, Env);
+  ShallowResult != SR::Unknown) {
+return ShallowResult;
+  }
+
+  if (Env.proves(Val->formula()))
+return SR::True;
+
+  if (Env.proves(Env.arena().makeNot(Val->formula(
+return SR::False;
+
+  return SR::Unknown;
+}
+
+inline BoolValue &getVal(llvm::StringRef Name, Value &RootValue) {
+  return *cast(RootValue.getProperty(Name));
+}
+
+// Assign

[clang] [clang-tools-extra] [clang-tidy][dataflow] Add `bugprone-null-check-after-dereference` check (PR #84166)

2024-03-07 Thread via cfe-commits


@@ -0,0 +1,162 @@
+.. title:: clang-tidy - bugprone-null-check-after-dereference
+
+bugprone-null-check-after-dereference
+=
+
+.. note::
+
+   This check uses a flow-sensitive static analysis to produce its
+   results. Therefore, it may be more resource intensive (RAM, CPU) than the
+   average clang-tidy check.
+
+This check identifies redundant pointer null-checks, by finding cases where the
+pointer cannot be null at the location of the null-check.
+
+Redundant null-checks can signal faulty assumptions about the current value of
+a pointer at different points in the program. Either the null-check is
+redundant, or there could be a null-pointer dereference earlier in the program.
+
+.. code-block:: c++
+
+   int f(int *ptr) {
+ *ptr = 20; // note: one of the locations where the pointer's value cannot 
be null
+ // ...
+ if (ptr) { // bugprone: pointer is checked even though it cannot be null 
at this point
+   return *ptr;
+ }
+ return 0;
+   }
+
+Supported pointer operations
+
+
+Pointer null-checks
+---
+
+The checker currently supports null-checks on pointers that use
+``operator bool``, such as when being used as the condition
+for an `if` statement.

martinboehme wrote:

Is `p != nullptr` supported too? This is a common construct (and is mandated 
over `operator bool` by some style guides)l

https://github.com/llvm/llvm-project/pull/84166
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang-tidy][dataflow] Add `bugprone-null-check-after-dereference` check (PR #84166)

2024-03-07 Thread via cfe-commits


@@ -0,0 +1,171 @@
+//===--- NullCheckAfterDereferenceCheck.cpp - 
clang-tidy---===//
+//
+// 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
+//
+//===--===//
+
+#include "NullCheckAfterDereferenceCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
+#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
+#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
+#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
+#include "clang/Analysis/FlowSensitive/Models/NullPointerAnalysisModel.h"
+#include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/Any.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Error.h"
+#include 
+#include 
+
+namespace clang::tidy::bugprone {
+
+using ast_matchers::MatchFinder;
+using dataflow::NullCheckAfterDereferenceDiagnoser;
+using dataflow::NullPointerAnalysisModel;
+
+static constexpr llvm::StringLiteral FuncID("fun");
+
+struct ExpandedResult {
+  SourceLocation WarningLoc;
+  std::optional DerefLoc;
+};
+
+using ExpandedResultType =
+std::pair, std::vector>;
+
+static std::optional
+analyzeFunction(const FunctionDecl &FuncDecl) {
+  using dataflow::ControlFlowContext;
+  using dataflow::DataflowAnalysisState;
+  using llvm::Expected;
+
+  ASTContext &ASTCtx = FuncDecl.getASTContext();
+
+  if (FuncDecl.getBody() == nullptr) {
+return std::nullopt;
+  }
+
+  Expected Context =
+  ControlFlowContext::build(FuncDecl, *FuncDecl.getBody(), ASTCtx);
+  if (!Context)
+return std::nullopt;
+
+  dataflow::DataflowAnalysisContext AnalysisContext(
+  std::make_unique());
+  dataflow::Environment Env(AnalysisContext, FuncDecl);
+  NullPointerAnalysisModel Analysis(ASTCtx);
+  NullCheckAfterDereferenceDiagnoser Diagnoser;
+  NullCheckAfterDereferenceDiagnoser::ResultType Diagnostics;
+
+  using LatticeState = 
DataflowAnalysisState;
+  using DetailMaybeLatticeStates = std::vector>;
+
+  auto DiagnoserImpl = [&ASTCtx, &Diagnoser,
+&Diagnostics](const CFGElement &Elt,
+  const LatticeState &S) mutable -> void {
+auto EltDiagnostics = Diagnoser.diagnose(ASTCtx, &Elt, S.Env);
+llvm::move(EltDiagnostics.first, std::back_inserter(Diagnostics.first));
+llvm::move(EltDiagnostics.second, std::back_inserter(Diagnostics.second));
+  };
+
+  Expected BlockToOutputState =
+  dataflow::runDataflowAnalysis(*Context, Analysis, Env, DiagnoserImpl);
+
+  if (llvm::Error E = BlockToOutputState.takeError()) {
+llvm::dbgs() << "Dataflow analysis failed: " << 
llvm::toString(std::move(E))
+ << ".\n";
+return std::nullopt;
+  }
+
+  ExpandedResultType ExpandedDiagnostics;
+
+  llvm::transform(Diagnostics.first,
+  std::back_inserter(ExpandedDiagnostics.first),
+  [&](SourceLocation WarningLoc) -> ExpandedResult {
+if (auto Val = Diagnoser.WarningLocToVal[WarningLoc];
+auto DerefExpr = Diagnoser.ValToDerefLoc[Val]) {
+  return {WarningLoc, DerefExpr->getBeginLoc()};
+}
+
+return {WarningLoc, std::nullopt};
+  });
+
+  llvm::transform(Diagnostics.second,
+  std::back_inserter(ExpandedDiagnostics.second),
+  [&](SourceLocation WarningLoc) -> ExpandedResult {
+if (auto Val = Diagnoser.WarningLocToVal[WarningLoc];
+auto DerefExpr = Diagnoser.ValToDerefLoc[Val]) {
+  return {WarningLoc, DerefExpr->getBeginLoc()};
+}
+
+return {WarningLoc, std::nullopt};
+  });
+
+  return ExpandedDiagnostics;
+}
+
+void NullCheckAfterDereferenceCheck::registerMatchers(MatchFinder *Finder) {
+  using namespace ast_matchers;
+
+  auto hasPointerValue =
+  hasDescendant(NullPointerAnalysisModel::ptrValueMatcher());
+  Finder->addMatcher(
+  decl(anyOf(functionDecl(unless(isExpansionInSystemHeader()),
+  // FIXME: Remove the filter below when lambdas 
are
+  // well supported by the check.
+  
unless(hasDeclContext(cxxRecordDecl(isLambda(,
+  hasBody(hasPointerValue)),
+ cxxConstructorDecl(hasAnyConstructorInitializer(
+ withInitializer(hasPointerValue)
+  .bind(Fu

[clang] [clang-tools-extra] [clang-tidy][dataflow] Add `bugprone-null-check-after-dereference` check (PR #84166)

2024-03-07 Thread via cfe-commits


@@ -0,0 +1,162 @@
+.. title:: clang-tidy - bugprone-null-check-after-dereference
+
+bugprone-null-check-after-dereference
+=
+
+.. note::
+
+   This check uses a flow-sensitive static analysis to produce its
+   results. Therefore, it may be more resource intensive (RAM, CPU) than the
+   average clang-tidy check.
+
+This check identifies redundant pointer null-checks, by finding cases where the
+pointer cannot be null at the location of the null-check.
+
+Redundant null-checks can signal faulty assumptions about the current value of
+a pointer at different points in the program. Either the null-check is
+redundant, or there could be a null-pointer dereference earlier in the program.
+
+.. code-block:: c++
+
+   int f(int *ptr) {
+ *ptr = 20; // note: one of the locations where the pointer's value cannot 
be null
+ // ...
+ if (ptr) { // bugprone: pointer is checked even though it cannot be null 
at this point
+   return *ptr;
+ }
+ return 0;
+   }
+
+Supported pointer operations
+
+
+Pointer null-checks
+---
+
+The checker currently supports null-checks on pointers that use
+``operator bool``, such as when being used as the condition
+for an `if` statement.
+
+.. code-block:: c++
+
+   int f(int *ptr) {
+ if (ptr) {
+   if (ptr) { // bugprone: pointer is re-checked after its null-ness is 
already checked.
+ return *ptr;
+   }
+
+   return ptr ? *ptr : 0; // bugprone: pointer is re-checked after its 
null-ness is already checked.
+ }
+ return 0;
+   }
+
+Pointer dereferences
+
+
+Pointer star- and arrow-dereferences are supported.
+
+.. code-block:: c++
+
+   struct S {
+ int val;
+   };
+
+   void f(int *ptr, S *wrapper) {
+ *ptr = 20;
+ wrapper->val = 15;
+   }
+
+Null-pointer and other value assignments
+
+
+The checker supports assigning various values to pointers, making them *null*
+or *non-null*. The checker also supports passing pointers of a pointer to
+external functions.
+
+.. code-block:: c++
+
+   extern int *external();
+   extern void refresh(int **ptr_ptr);
+   
+   int f() {
+ int *ptr_null = nullptr;
+ if (ptr_null) { // bugprone: pointer is checked where it cannot be 
non-null.
+   return *ptr_null;
+ }
+
+ int *ptr = external();
+ if (ptr) { // safe: external() could return either nullable or nonnull 
pointers.
+   return *ptr;
+ }
+
+ int *ptr2 = external();
+ *ptr2 = 20;
+ refresh(&ptr2);
+ if (ptr2) { // safe: pointer could be changed by refresh().
+   return *ptr2;
+ }
+ return 0;
+   }
+
+Limitations
+~~~
+
+The check only supports C++ due to limitations in the data-flow framework.
+
+The annotations ``_nullable`` and ``_nonnull`` are not supported.

martinboehme wrote:

These annotations should be upper-case (`_Nullable` and `_Nonnull`). The 
lower-case spellings are not supported (they produce a compiler error).

https://github.com/llvm/llvm-project/pull/84166
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang-tidy][dataflow] Add `bugprone-null-check-after-dereference` check (PR #84166)

2024-03-07 Thread via cfe-commits


@@ -0,0 +1,171 @@
+//===--- NullCheckAfterDereferenceCheck.cpp - 
clang-tidy---===//
+//
+// 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
+//
+//===--===//
+
+#include "NullCheckAfterDereferenceCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
+#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
+#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
+#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
+#include "clang/Analysis/FlowSensitive/Models/NullPointerAnalysisModel.h"
+#include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/Any.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Error.h"
+#include 
+#include 
+
+namespace clang::tidy::bugprone {
+
+using ast_matchers::MatchFinder;
+using dataflow::NullCheckAfterDereferenceDiagnoser;
+using dataflow::NullPointerAnalysisModel;
+
+static constexpr llvm::StringLiteral FuncID("fun");
+
+struct ExpandedResult {
+  SourceLocation WarningLoc;
+  std::optional DerefLoc;
+};
+
+using ExpandedResultType =
+std::pair, std::vector>;
+
+static std::optional
+analyzeFunction(const FunctionDecl &FuncDecl) {
+  using dataflow::ControlFlowContext;
+  using dataflow::DataflowAnalysisState;
+  using llvm::Expected;
+
+  ASTContext &ASTCtx = FuncDecl.getASTContext();
+
+  if (FuncDecl.getBody() == nullptr) {
+return std::nullopt;
+  }
+
+  Expected Context =
+  ControlFlowContext::build(FuncDecl, *FuncDecl.getBody(), ASTCtx);
+  if (!Context)
+return std::nullopt;
+
+  dataflow::DataflowAnalysisContext AnalysisContext(
+  std::make_unique());
+  dataflow::Environment Env(AnalysisContext, FuncDecl);
+  NullPointerAnalysisModel Analysis(ASTCtx);
+  NullCheckAfterDereferenceDiagnoser Diagnoser;
+  NullCheckAfterDereferenceDiagnoser::ResultType Diagnostics;
+
+  using LatticeState = 
DataflowAnalysisState;
+  using DetailMaybeLatticeStates = std::vector>;
+
+  auto DiagnoserImpl = [&ASTCtx, &Diagnoser,
+&Diagnostics](const CFGElement &Elt,
+  const LatticeState &S) mutable -> void {
+auto EltDiagnostics = Diagnoser.diagnose(ASTCtx, &Elt, S.Env);
+llvm::move(EltDiagnostics.first, std::back_inserter(Diagnostics.first));
+llvm::move(EltDiagnostics.second, std::back_inserter(Diagnostics.second));
+  };
+
+  Expected BlockToOutputState =
+  dataflow::runDataflowAnalysis(*Context, Analysis, Env, DiagnoserImpl);
+
+  if (llvm::Error E = BlockToOutputState.takeError()) {
+llvm::dbgs() << "Dataflow analysis failed: " << 
llvm::toString(std::move(E))
+ << ".\n";
+return std::nullopt;
+  }

martinboehme wrote:

Consider using `Expected::moveInto()`.

https://github.com/llvm/llvm-project/pull/84166
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang-tidy][dataflow] Add `bugprone-null-check-after-dereference` check (PR #84166)

2024-03-07 Thread via cfe-commits


@@ -0,0 +1,112 @@
+//===-- NullPointerAnalysisModel.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
+//
+//===--===//
+//
+// This file defines a generic null-pointer analysis model, used for finding
+// pointer null-checks after the pointer has already been dereferenced.
+//
+// Only a limited set of operations are currently recognized. Notably, pointer
+// arithmetic, null-pointer assignments and _nullable/_nonnull attributes are
+// missing as of yet.
+//
+//===--===//
+
+#ifndef CLANG_ANALYSIS_FLOWSENSITIVE_MODELS_NULLPOINTERANALYSISMODEL_H
+#define CLANG_ANALYSIS_FLOWSENSITIVE_MODELS_NULLPOINTERANALYSISMODEL_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Stmt.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/FlowSensitive/CFGMatchSwitch.h"
+#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
+#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
+#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
+#include "clang/Analysis/FlowSensitive/MapLattice.h"
+#include "clang/Analysis/FlowSensitive/NoopLattice.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+
+namespace clang::dataflow {
+
+class NullPointerAnalysisModel
+: public DataflowAnalysis {
+public:
+  /// A transparent wrapper around the function arguments of transferBranch().
+  /// Does not outlive the call to transferBranch().
+  struct TransferArgs {

martinboehme wrote:

Why does this need to be public? It doesn't seem to be used outside 
`NullPointerAnalysisModel`?

https://github.com/llvm/llvm-project/pull/84166
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang-tidy][dataflow] Add `bugprone-null-check-after-dereference` check (PR #84166)

2024-03-07 Thread via cfe-commits


@@ -0,0 +1,171 @@
+//===--- NullCheckAfterDereferenceCheck.cpp - 
clang-tidy---===//
+//
+// 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
+//
+//===--===//
+
+#include "NullCheckAfterDereferenceCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
+#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
+#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
+#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
+#include "clang/Analysis/FlowSensitive/Models/NullPointerAnalysisModel.h"
+#include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/Any.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Error.h"
+#include 
+#include 
+
+namespace clang::tidy::bugprone {
+
+using ast_matchers::MatchFinder;
+using dataflow::NullCheckAfterDereferenceDiagnoser;
+using dataflow::NullPointerAnalysisModel;
+
+static constexpr llvm::StringLiteral FuncID("fun");
+
+struct ExpandedResult {
+  SourceLocation WarningLoc;
+  std::optional DerefLoc;
+};
+
+using ExpandedResultType =
+std::pair, std::vector>;
+
+static std::optional
+analyzeFunction(const FunctionDecl &FuncDecl) {
+  using dataflow::ControlFlowContext;
+  using dataflow::DataflowAnalysisState;
+  using llvm::Expected;
+
+  ASTContext &ASTCtx = FuncDecl.getASTContext();
+
+  if (FuncDecl.getBody() == nullptr) {
+return std::nullopt;
+  }
+
+  Expected Context =
+  ControlFlowContext::build(FuncDecl, *FuncDecl.getBody(), ASTCtx);
+  if (!Context)
+return std::nullopt;
+
+  dataflow::DataflowAnalysisContext AnalysisContext(
+  std::make_unique());
+  dataflow::Environment Env(AnalysisContext, FuncDecl);
+  NullPointerAnalysisModel Analysis(ASTCtx);
+  NullCheckAfterDereferenceDiagnoser Diagnoser;
+  NullCheckAfterDereferenceDiagnoser::ResultType Diagnostics;
+
+  using LatticeState = 
DataflowAnalysisState;
+  using DetailMaybeLatticeStates = std::vector>;
+
+  auto DiagnoserImpl = [&ASTCtx, &Diagnoser,
+&Diagnostics](const CFGElement &Elt,
+  const LatticeState &S) mutable -> void {
+auto EltDiagnostics = Diagnoser.diagnose(ASTCtx, &Elt, S.Env);
+llvm::move(EltDiagnostics.first, std::back_inserter(Diagnostics.first));
+llvm::move(EltDiagnostics.second, std::back_inserter(Diagnostics.second));
+  };
+
+  Expected BlockToOutputState =
+  dataflow::runDataflowAnalysis(*Context, Analysis, Env, DiagnoserImpl);
+
+  if (llvm::Error E = BlockToOutputState.takeError()) {
+llvm::dbgs() << "Dataflow analysis failed: " << 
llvm::toString(std::move(E))
+ << ".\n";
+return std::nullopt;
+  }
+
+  ExpandedResultType ExpandedDiagnostics;
+
+  llvm::transform(Diagnostics.first,
+  std::back_inserter(ExpandedDiagnostics.first),
+  [&](SourceLocation WarningLoc) -> ExpandedResult {
+if (auto Val = Diagnoser.WarningLocToVal[WarningLoc];
+auto DerefExpr = Diagnoser.ValToDerefLoc[Val]) {
+  return {WarningLoc, DerefExpr->getBeginLoc()};
+}
+
+return {WarningLoc, std::nullopt};
+  });
+
+  llvm::transform(Diagnostics.second,
+  std::back_inserter(ExpandedDiagnostics.second),
+  [&](SourceLocation WarningLoc) -> ExpandedResult {
+if (auto Val = Diagnoser.WarningLocToVal[WarningLoc];
+auto DerefExpr = Diagnoser.ValToDerefLoc[Val]) {
+  return {WarningLoc, DerefExpr->getBeginLoc()};
+}
+
+return {WarningLoc, std::nullopt};
+  });
+
+  return ExpandedDiagnostics;
+}
+
+void NullCheckAfterDereferenceCheck::registerMatchers(MatchFinder *Finder) {
+  using namespace ast_matchers;
+
+  auto hasPointerValue =
+  hasDescendant(NullPointerAnalysisModel::ptrValueMatcher());

martinboehme wrote:

Where is `NullPointerAnalysisModel::ptrValueMatcher()` defined? (Can't seem to 
find it -- I'm obviously not looking hard enough.)

https://github.com/llvm/llvm-project/pull/84166
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang-tidy][dataflow] Add `bugprone-null-check-after-dereference` check (PR #84166)

2024-03-07 Thread via cfe-commits


@@ -0,0 +1,171 @@
+//===--- NullCheckAfterDereferenceCheck.cpp - 
clang-tidy---===//
+//
+// 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
+//
+//===--===//
+
+#include "NullCheckAfterDereferenceCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
+#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
+#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
+#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
+#include "clang/Analysis/FlowSensitive/Models/NullPointerAnalysisModel.h"
+#include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/Any.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Error.h"
+#include 
+#include 
+
+namespace clang::tidy::bugprone {
+
+using ast_matchers::MatchFinder;
+using dataflow::NullCheckAfterDereferenceDiagnoser;
+using dataflow::NullPointerAnalysisModel;
+
+static constexpr llvm::StringLiteral FuncID("fun");
+
+struct ExpandedResult {
+  SourceLocation WarningLoc;
+  std::optional DerefLoc;
+};
+
+using ExpandedResultType =
+std::pair, std::vector>;
+
+static std::optional
+analyzeFunction(const FunctionDecl &FuncDecl) {
+  using dataflow::ControlFlowContext;
+  using dataflow::DataflowAnalysisState;
+  using llvm::Expected;
+
+  ASTContext &ASTCtx = FuncDecl.getASTContext();
+
+  if (FuncDecl.getBody() == nullptr) {
+return std::nullopt;
+  }
+
+  Expected Context =
+  ControlFlowContext::build(FuncDecl, *FuncDecl.getBody(), ASTCtx);
+  if (!Context)
+return std::nullopt;
+
+  dataflow::DataflowAnalysisContext AnalysisContext(
+  std::make_unique());
+  dataflow::Environment Env(AnalysisContext, FuncDecl);
+  NullPointerAnalysisModel Analysis(ASTCtx);
+  NullCheckAfterDereferenceDiagnoser Diagnoser;
+  NullCheckAfterDereferenceDiagnoser::ResultType Diagnostics;
+
+  using LatticeState = 
DataflowAnalysisState;

martinboehme wrote:

Nit: This isn't just the "lattice state" -- it's the entire state, comprising 
the `Environment` and the lattice. Maybe simply `State`?

https://github.com/llvm/llvm-project/pull/84166
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang-tidy][dataflow] Add `bugprone-null-check-after-dereference` check (PR #84166)

2024-03-07 Thread via cfe-commits


@@ -0,0 +1,330 @@
+// RUN: %check_clang_tidy %s bugprone-null-check-after-dereference %t
+
+struct S {
+  int a;
+};
+
+int warning_deref(int *p) {
+  *p = 42;
+
+  if (p) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point [bugprone-null-check-after-dereference]
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: one of the locations where the 
pointer's value cannot be null
+  // FIXME: If there's a direct path, make the error message more precise, ie. 
remove `one of the locations`
+*p += 20;
+return *p;

martinboehme wrote:

Nit: This line seems to be redundant -- we already have a `*p` in the same 
block. Also, why does this function need to return anything -- just make it 
`void`?

(Generally, try to make tests contain only the minimal amount of code you need 
to test the behavior the test targets. Also applies similarly to other tests 
below.)

https://github.com/llvm/llvm-project/pull/84166
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang-tidy][dataflow] Add `bugprone-null-check-after-dereference` check (PR #84166)

2024-03-07 Thread via cfe-commits


@@ -0,0 +1,330 @@
+// RUN: %check_clang_tidy %s bugprone-null-check-after-dereference %t
+
+struct S {
+  int a;
+};
+
+int warning_deref(int *p) {
+  *p = 42;
+
+  if (p) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point [bugprone-null-check-after-dereference]
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: one of the locations where the 
pointer's value cannot be null
+  // FIXME: If there's a direct path, make the error message more precise, ie. 
remove `one of the locations`
+*p += 20;
+return *p;
+  } else {
+return 0;
+  }
+}
+
+int warning_member(S *q) {
+  q->a = 42;
+
+  if (q) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: one of the locations where the 
pointer's value cannot be null
+q->a += 20;
+return q->a;
+  } else {
+return 0;
+  }
+}
+
+int negative_warning(int *p) {
+  *p = 42;
+
+  if (!p) {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: pointer value is checked even 
though it cannot be null at this point
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: one of the locations where the 
pointer's value cannot be null
+return 0;
+  } else {
+*p += 20;
+return *p;
+  }
+}
+
+int no_warning(int *p, bool b) {
+  if (b) {
+*p = 42;
+  }
+
+  if (p) {
+// CHECK-MESSAGES-NOT: :[[@LINE-1]]:7: warning: pointer value is checked 
even though it cannot be null at this point 
+*p += 20;
+return *p;
+  } else {
+return 0;
+  }
+}
+
+int else_branch_warning(int *p, bool b) {
+  if (b) {
+*p = 42;
+  } else {
+*p = 20;
+  }
+
+  if (p) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point
+// CHECK-MESSAGES: :[[@LINE-7]]:5: note: one of the locations where the 
pointer's value cannot be null
+return 0;
+  } else {
+*p += 20;
+return *p;
+  }
+}
+
+int two_branches_warning(int *p, bool b) {
+  if (b) {
+*p = 42;
+  }
+  
+  if (!b) {
+*p = 20;
+  }
+
+  if (p) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point
+// CHECK-MESSAGES: :[[@LINE-9]]:5: note: one of the locations where the 
pointer's value cannot be null
+return 0;
+  } else {
+*p += 20;
+return *p;
+  }
+}
+
+int two_branches_reversed(int *p, bool b) {
+  if (!b) {
+*p = 42;
+  }
+  
+  if (b) {
+*p = 20;
+  }
+
+  if (p) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point
+// CHECK-MESSAGES: :[[@LINE-9]]:5: note: one of the locations where the 
pointer's value cannot be null
+return 0;
+  } else {
+*p += 20;
+return *p;
+  }
+}
+
+
+int regular_assignment(int *p, int *q) {
+  *p = 42;
+  q = p;
+
+  if (q) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point
+// CHECK-MESSAGES: :[[@LINE-5]]:3: note: one of the locations where the 
pointer's value cannot be null
+*p += 20; 
+return *p;
+  } else {
+return 0;
+  }
+}
+
+int nullptr_assignment(int *nullptr_param, bool b) {
+  *nullptr_param = 42;
+  int *nullptr_assigned;
+
+  if (b) {
+nullptr_assigned = nullptr;
+  } else {
+nullptr_assigned = nullptr_param;
+  }
+
+  if (nullptr_assigned) {
+// CHECK-MESSAGES-NOT: :[[@LINE-1]]:7: warning: pointer value is checked 
even though it cannot be null at this point

martinboehme wrote:

Redundant

https://github.com/llvm/llvm-project/pull/84166
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang-tidy][dataflow] Add `bugprone-null-check-after-dereference` check (PR #84166)

2024-03-07 Thread via cfe-commits


@@ -0,0 +1,330 @@
+// RUN: %check_clang_tidy %s bugprone-null-check-after-dereference %t
+
+struct S {
+  int a;
+};
+
+int warning_deref(int *p) {
+  *p = 42;
+
+  if (p) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point [bugprone-null-check-after-dereference]
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: one of the locations where the 
pointer's value cannot be null
+  // FIXME: If there's a direct path, make the error message more precise, ie. 
remove `one of the locations`
+*p += 20;
+return *p;
+  } else {
+return 0;
+  }
+}
+
+int warning_member(S *q) {
+  q->a = 42;
+
+  if (q) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: one of the locations where the 
pointer's value cannot be null
+q->a += 20;
+return q->a;
+  } else {
+return 0;
+  }
+}
+
+int negative_warning(int *p) {
+  *p = 42;
+
+  if (!p) {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: pointer value is checked even 
though it cannot be null at this point
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: one of the locations where the 
pointer's value cannot be null
+return 0;
+  } else {
+*p += 20;
+return *p;
+  }
+}
+
+int no_warning(int *p, bool b) {
+  if (b) {
+*p = 42;
+  }
+
+  if (p) {
+// CHECK-MESSAGES-NOT: :[[@LINE-1]]:7: warning: pointer value is checked 
even though it cannot be null at this point 
+*p += 20;
+return *p;
+  } else {
+return 0;
+  }
+}
+
+int else_branch_warning(int *p, bool b) {
+  if (b) {
+*p = 42;
+  } else {
+*p = 20;
+  }
+
+  if (p) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point
+// CHECK-MESSAGES: :[[@LINE-7]]:5: note: one of the locations where the 
pointer's value cannot be null
+return 0;
+  } else {
+*p += 20;
+return *p;
+  }
+}
+
+int two_branches_warning(int *p, bool b) {
+  if (b) {
+*p = 42;
+  }
+  
+  if (!b) {
+*p = 20;
+  }
+
+  if (p) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point
+// CHECK-MESSAGES: :[[@LINE-9]]:5: note: one of the locations where the 
pointer's value cannot be null
+return 0;
+  } else {
+*p += 20;
+return *p;
+  }
+}
+
+int two_branches_reversed(int *p, bool b) {

martinboehme wrote:

This test seems borderline redundant -- it's really testing the framework 
itself rather than your check.

https://github.com/llvm/llvm-project/pull/84166
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang-tidy][dataflow] Add `bugprone-null-check-after-dereference` check (PR #84166)

2024-03-07 Thread via cfe-commits


@@ -0,0 +1,330 @@
+// RUN: %check_clang_tidy %s bugprone-null-check-after-dereference %t
+
+struct S {
+  int a;
+};
+
+int warning_deref(int *p) {
+  *p = 42;
+
+  if (p) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point [bugprone-null-check-after-dereference]
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: one of the locations where the 
pointer's value cannot be null
+  // FIXME: If there's a direct path, make the error message more precise, ie. 
remove `one of the locations`
+*p += 20;
+return *p;
+  } else {
+return 0;
+  }
+}
+
+int warning_member(S *q) {
+  q->a = 42;
+
+  if (q) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: one of the locations where the 
pointer's value cannot be null
+q->a += 20;
+return q->a;
+  } else {
+return 0;
+  }
+}
+
+int negative_warning(int *p) {
+  *p = 42;
+
+  if (!p) {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: pointer value is checked even 
though it cannot be null at this point
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: one of the locations where the 
pointer's value cannot be null
+return 0;
+  } else {
+*p += 20;
+return *p;
+  }
+}
+
+int no_warning(int *p, bool b) {
+  if (b) {
+*p = 42;
+  }
+
+  if (p) {
+// CHECK-MESSAGES-NOT: :[[@LINE-1]]:7: warning: pointer value is checked 
even though it cannot be null at this point 

martinboehme wrote:

I think this is redundant. This style of test will fail if there are any 
unexpected diagnostics.

https://github.com/llvm/llvm-project/pull/84166
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang-tidy][dataflow] Add `bugprone-null-check-after-dereference` check (PR #84166)

2024-03-07 Thread via cfe-commits


@@ -0,0 +1,112 @@
+//===-- NullPointerAnalysisModel.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
+//
+//===--===//
+//
+// This file defines a generic null-pointer analysis model, used for finding
+// pointer null-checks after the pointer has already been dereferenced.
+//
+// Only a limited set of operations are currently recognized. Notably, pointer
+// arithmetic, null-pointer assignments and _nullable/_nonnull attributes are
+// missing as of yet.
+//
+//===--===//
+
+#ifndef CLANG_ANALYSIS_FLOWSENSITIVE_MODELS_NULLPOINTERANALYSISMODEL_H
+#define CLANG_ANALYSIS_FLOWSENSITIVE_MODELS_NULLPOINTERANALYSISMODEL_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Stmt.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/FlowSensitive/CFGMatchSwitch.h"
+#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
+#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
+#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
+#include "clang/Analysis/FlowSensitive/MapLattice.h"
+#include "clang/Analysis/FlowSensitive/NoopLattice.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+
+namespace clang::dataflow {
+
+class NullPointerAnalysisModel
+: public DataflowAnalysis {
+public:
+  /// A transparent wrapper around the function arguments of transferBranch().
+  /// Does not outlive the call to transferBranch().
+  struct TransferArgs {
+bool Branch;
+Environment &Env;
+  };
+
+private:
+  CFGMatchSwitch TransferMatchSwitch;
+  ASTMatchSwitch BranchTransferMatchSwitch;
+
+public:
+  explicit NullPointerAnalysisModel(ASTContext &Context);
+
+  static NoopLattice initialElement() { return {}; }
+
+  static ast_matchers::StatementMatcher ptrValueMatcher();
+
+  // Used to initialize the storage locations of function arguments.
+  // Required to merge these values within the environment.
+  void initializeFunctionParameters(const ControlFlowContext &CFCtx,
+Environment &Env);
+
+  void transfer(const CFGElement &E, NoopLattice &State, Environment &Env);
+
+  void transferBranch(bool Branch, const Stmt *E, NoopLattice &State,
+  Environment &Env);
+
+  void join(QualType Type, const Value &Val1, const Environment &Env1,
+const Value &Val2, const Environment &Env2, Value &MergedVal,
+Environment &MergedEnv) override;
+
+  ComparisonResult compare(QualType Type, const Value &Val1,
+   const Environment &Env1, const Value &Val2,
+   const Environment &Env2) override;
+
+  Value *widen(QualType Type, Value &Prev, const Environment &PrevEnv,
+   Value &Current, Environment &CurrentEnv) override;
+};
+
+class NullCheckAfterDereferenceDiagnoser {
+public:
+  struct DiagnoseArgs {
+llvm::DenseMap &ValToDerefLoc;
+llvm::DenseMap &WarningLocToVal;
+const Environment &Env;
+  };
+
+  using ResultType =
+  std::pair, std::vector>;
+
+  // Maps a pointer's Value to a dereference, null-assignment, etc.
+  // This is used later to construct the Note tag.
+  llvm::DenseMap ValToDerefLoc;
+  // Maps Maps a warning's SourceLocation to its relevant Value.
+  llvm::DenseMap WarningLocToVal;
+

martinboehme wrote:

Do these need to be public? They look like internal implementation details of 
the class.

https://github.com/llvm/llvm-project/pull/84166
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang-tidy][dataflow] Add `bugprone-null-check-after-dereference` check (PR #84166)

2024-03-07 Thread via cfe-commits


@@ -0,0 +1,330 @@
+// RUN: %check_clang_tidy %s bugprone-null-check-after-dereference %t
+
+struct S {
+  int a;
+};
+
+int warning_deref(int *p) {
+  *p = 42;
+
+  if (p) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point [bugprone-null-check-after-dereference]
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: one of the locations where the 
pointer's value cannot be null
+  // FIXME: If there's a direct path, make the error message more precise, ie. 
remove `one of the locations`
+*p += 20;
+return *p;
+  } else {
+return 0;
+  }
+}
+
+int warning_member(S *q) {
+  q->a = 42;
+
+  if (q) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: one of the locations where the 
pointer's value cannot be null
+q->a += 20;
+return q->a;
+  } else {
+return 0;
+  }
+}
+
+int negative_warning(int *p) {
+  *p = 42;
+
+  if (!p) {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: pointer value is checked even 
though it cannot be null at this point
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: one of the locations where the 
pointer's value cannot be null
+return 0;
+  } else {
+*p += 20;
+return *p;
+  }
+}
+
+int no_warning(int *p, bool b) {
+  if (b) {
+*p = 42;
+  }
+
+  if (p) {
+// CHECK-MESSAGES-NOT: :[[@LINE-1]]:7: warning: pointer value is checked 
even though it cannot be null at this point 
+*p += 20;
+return *p;
+  } else {
+return 0;
+  }
+}
+
+int else_branch_warning(int *p, bool b) {
+  if (b) {
+*p = 42;
+  } else {
+*p = 20;
+  }
+
+  if (p) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point
+// CHECK-MESSAGES: :[[@LINE-7]]:5: note: one of the locations where the 
pointer's value cannot be null
+return 0;
+  } else {
+*p += 20;
+return *p;
+  }
+}
+
+int two_branches_warning(int *p, bool b) {
+  if (b) {
+*p = 42;
+  }
+  
+  if (!b) {
+*p = 20;
+  }
+
+  if (p) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point
+// CHECK-MESSAGES: :[[@LINE-9]]:5: note: one of the locations where the 
pointer's value cannot be null
+return 0;
+  } else {
+*p += 20;
+return *p;
+  }
+}
+
+int two_branches_reversed(int *p, bool b) {
+  if (!b) {
+*p = 42;
+  }
+  
+  if (b) {
+*p = 20;
+  }
+
+  if (p) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point
+// CHECK-MESSAGES: :[[@LINE-9]]:5: note: one of the locations where the 
pointer's value cannot be null
+return 0;
+  } else {
+*p += 20;
+return *p;
+  }
+}
+
+
+int regular_assignment(int *p, int *q) {
+  *p = 42;
+  q = p;
+
+  if (q) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point
+// CHECK-MESSAGES: :[[@LINE-5]]:3: note: one of the locations where the 
pointer's value cannot be null
+*p += 20; 
+return *p;
+  } else {
+return 0;
+  }
+}
+
+int nullptr_assignment(int *nullptr_param, bool b) {
+  *nullptr_param = 42;
+  int *nullptr_assigned;
+
+  if (b) {
+nullptr_assigned = nullptr;
+  } else {
+nullptr_assigned = nullptr_param;
+  }
+
+  if (nullptr_assigned) {
+// CHECK-MESSAGES-NOT: :[[@LINE-1]]:7: warning: pointer value is checked 
even though it cannot be null at this point
+*nullptr_assigned = 20;
+return *nullptr_assigned;
+  } else {
+return 0;
+  }
+}
+
+extern int *fncall();
+extern void refresh_ref(int *&ptr);
+extern void refresh_ptr(int **ptr);
+
+int fncall_reassignment(int *fncall_reassigned) {
+  *fncall_reassigned = 42;
+
+  fncall_reassigned = fncall();
+
+  if (fncall_reassigned) {
+// CHECK-MESSAGES-NOT: :[[@LINE-1]]:7: warning: pointer value is checked 
even though it cannot be null at this point
+*fncall_reassigned = 42;
+  }
+  
+  fncall_reassigned = fncall();
+
+  *fncall_reassigned = 42;
+
+  if (fncall_reassigned) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: one of the locations where the 
pointer's value cannot be null
+*fncall_reassigned = 42;
+  }
+  
+  refresh_ptr(&fncall_reassigned);
+
+  if (fncall_reassigned) {
+// CHECK-MESSAGES-NOT: :[[@LINE-1]]:7: warning: pointer value is checked 
even though it cannot be null at this point
+*fncall_reassigned = 42;
+  }
+  
+  refresh_ptr(&fncall_reassigned);
+  *fncall_reassigned = 42;
+
+  if (fncall_reassigned) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even 
though it cannot be null at this point
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: one of the locations where the 
pointer'

[clang] [clang-tools-extra] [clang-tidy][dataflow] Add `bugprone-null-check-after-dereference` check (PR #84166)

2024-03-07 Thread via cfe-commits


@@ -0,0 +1,625 @@
+//===-- NullPointerAnalysisModel.cpp *- 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
+//
+//===--===//
+//
+// This file defines a generic null-pointer analysis model, used for finding
+// pointer null-checks after the pointer has already been dereferenced.
+//
+// Only a limited set of operations are currently recognized. Notably, pointer
+// arithmetic, null-pointer assignments and _nullable/_nonnull attributes are
+// missing as of yet.
+//
+//===--===//
+
+#include "clang/Analysis/FlowSensitive/Models/NullPointerAnalysisModel.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Stmt.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/FlowSensitive/CFGMatchSwitch.h"
+#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
+#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
+#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
+#include "clang/Analysis/FlowSensitive/MapLattice.h"
+#include "clang/Analysis/FlowSensitive/NoopLattice.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+
+namespace clang::dataflow {
+
+namespace {
+using namespace ast_matchers;
+
+constexpr char kCond[] = "condition";
+constexpr char kVar[] = "var";
+constexpr char kValue[] = "value";
+constexpr char kIsNonnull[] = "is-nonnull";
+constexpr char kIsNull[] = "is-null";
+
+enum class SatisfiabilityResult {
+  // Returned when the value was not initialized yet.
+  Nullptr,
+  // Special value that signals that the boolean value can be anything.
+  // It signals that the underlying formulas are too complex to be calculated
+  // efficiently.
+  Top,
+  // Equivalent to the literal True in the current environment.
+  True,
+  // Equivalent to the literal False in the current environment.
+  False,
+  // Both True and False values could be produced with an appropriate set of
+  // conditions.
+  Unknown
+};
+
+using SR = SatisfiabilityResult;
+
+// FIXME: These AST matchers should also be exported via the
+// NullPointerAnalysisModel class, for tests
+auto ptrToVar(llvm::StringRef VarName = kVar) {
+  return traverse(TK_IgnoreUnlessSpelledInSource,
+  declRefExpr(hasType(isAnyPointer())).bind(VarName));
+}
+
+auto derefMatcher() {
+  return traverse(
+  TK_IgnoreUnlessSpelledInSource,
+  unaryOperator(hasOperatorName("*"), hasUnaryOperand(ptrToVar(;
+}
+
+auto arrowMatcher() {
+  return traverse(
+  TK_IgnoreUnlessSpelledInSource,
+  memberExpr(allOf(isArrow(), hasObjectExpression(ptrToVar();
+}
+
+auto castExprMatcher() {
+  return castExpr(hasCastKind(CK_PointerToBoolean),
+  hasSourceExpression(ptrToVar()))
+  .bind(kCond);
+}
+
+auto nullptrMatcher() {
+  return castExpr(hasCastKind(CK_NullToPointer)).bind(kVar);
+}
+
+auto addressofMatcher() {
+  return unaryOperator(hasOperatorName("&")).bind(kVar);
+}
+
+auto functionCallMatcher() {
+  return callExpr(hasDeclaration(functionDecl(returns(isAnyPointer()
+  .bind(kVar);
+}
+
+auto assignMatcher() {
+  return binaryOperation(isAssignmentOperator(), hasLHS(ptrToVar()),
+ hasRHS(expr().bind(kValue)));
+}
+
+auto anyPointerMatcher() { return expr(hasType(isAnyPointer())).bind(kVar); }
+
+// Only computes simple comparisons against the literals True and False in the
+// environment. Faster, but produces many Unknown values.
+SatisfiabilityResult shallowComputeSatisfiability(BoolValue *Val,
+  const Environment &Env) {
+  if (!Val)
+return SR::Nullptr;
+
+  if (isa(Val))
+return SR::Top;
+
+  if (Val == &Env.getBoolLiteralValue(true))
+return SR::True;
+
+  if (Val == &Env.getBoolLiteralValue(false))
+return SR::False;
+
+  return SR::Unknown;
+}
+
+// Computes satisfiability by using the flow condition. Slower, but more
+// precise.
+SatisfiabilityResult computeSatisfiability(BoolValue *Val,

martinboehme wrote:

Naming nit: This isn't really computing satisfiability; it's computing whether 
or not the environment proves that a `BoolValue` is necessarily true or false.

I think you could rename this `tryToProve()`, and you could probably do without 
the `SatisfiabilityResult` type entirely (which isn't really an accurate name 
either) and instead return a `BoolValue &` (since that's what the caller ends 
up needing anyway). This would be either a literal true or false (if the 
environment can prove the value true or false) or `*Val` if the environme

[clang] [clang-tools-extra] [clang-tidy][dataflow] Add `bugprone-null-check-after-dereference` check (PR #84166)

2024-03-07 Thread via cfe-commits


@@ -0,0 +1,171 @@
+//===--- NullCheckAfterDereferenceCheck.cpp - 
clang-tidy---===//
+//
+// 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
+//
+//===--===//
+
+#include "NullCheckAfterDereferenceCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
+#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
+#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
+#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
+#include "clang/Analysis/FlowSensitive/Models/NullPointerAnalysisModel.h"
+#include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/Any.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Error.h"
+#include 
+#include 
+
+namespace clang::tidy::bugprone {
+
+using ast_matchers::MatchFinder;
+using dataflow::NullCheckAfterDereferenceDiagnoser;
+using dataflow::NullPointerAnalysisModel;
+
+static constexpr llvm::StringLiteral FuncID("fun");
+
+struct ExpandedResult {
+  SourceLocation WarningLoc;
+  std::optional DerefLoc;
+};
+
+using ExpandedResultType =
+std::pair, std::vector>;
+
+static std::optional
+analyzeFunction(const FunctionDecl &FuncDecl) {
+  using dataflow::ControlFlowContext;
+  using dataflow::DataflowAnalysisState;
+  using llvm::Expected;
+
+  ASTContext &ASTCtx = FuncDecl.getASTContext();
+
+  if (FuncDecl.getBody() == nullptr) {
+return std::nullopt;
+  }
+
+  Expected Context =
+  ControlFlowContext::build(FuncDecl, *FuncDecl.getBody(), ASTCtx);
+  if (!Context)
+return std::nullopt;
+
+  dataflow::DataflowAnalysisContext AnalysisContext(
+  std::make_unique());
+  dataflow::Environment Env(AnalysisContext, FuncDecl);
+  NullPointerAnalysisModel Analysis(ASTCtx);
+  NullCheckAfterDereferenceDiagnoser Diagnoser;
+  NullCheckAfterDereferenceDiagnoser::ResultType Diagnostics;
+
+  using LatticeState = 
DataflowAnalysisState;
+  using DetailMaybeLatticeStates = std::vector>;
+
+  auto DiagnoserImpl = [&ASTCtx, &Diagnoser,
+&Diagnostics](const CFGElement &Elt,
+  const LatticeState &S) mutable -> void {
+auto EltDiagnostics = Diagnoser.diagnose(ASTCtx, &Elt, S.Env);
+llvm::move(EltDiagnostics.first, std::back_inserter(Diagnostics.first));
+llvm::move(EltDiagnostics.second, std::back_inserter(Diagnostics.second));
+  };
+
+  Expected BlockToOutputState =
+  dataflow::runDataflowAnalysis(*Context, Analysis, Env, DiagnoserImpl);
+
+  if (llvm::Error E = BlockToOutputState.takeError()) {
+llvm::dbgs() << "Dataflow analysis failed: " << 
llvm::toString(std::move(E))
+ << ".\n";
+return std::nullopt;
+  }
+
+  ExpandedResultType ExpandedDiagnostics;
+
+  llvm::transform(Diagnostics.first,
+  std::back_inserter(ExpandedDiagnostics.first),
+  [&](SourceLocation WarningLoc) -> ExpandedResult {
+if (auto Val = Diagnoser.WarningLocToVal[WarningLoc];
+auto DerefExpr = Diagnoser.ValToDerefLoc[Val]) {
+  return {WarningLoc, DerefExpr->getBeginLoc()};
+}
+
+return {WarningLoc, std::nullopt};
+  });
+
+  llvm::transform(Diagnostics.second,
+  std::back_inserter(ExpandedDiagnostics.second),
+  [&](SourceLocation WarningLoc) -> ExpandedResult {
+if (auto Val = Diagnoser.WarningLocToVal[WarningLoc];
+auto DerefExpr = Diagnoser.ValToDerefLoc[Val]) {
+  return {WarningLoc, DerefExpr->getBeginLoc()};
+}
+
+return {WarningLoc, std::nullopt};
+  });
+
+  return ExpandedDiagnostics;
+}
+
+void NullCheckAfterDereferenceCheck::registerMatchers(MatchFinder *Finder) {
+  using namespace ast_matchers;
+
+  auto hasPointerValue =

martinboehme wrote:

```suggestion
  auto containsPointerValue =
```

"has" in matchers tends to imply a direct child; "contains" reads more 
naturally to me.

https://github.com/llvm/llvm-project/pull/84166
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [dataflow][nfc] Fix u8 string usage with c++20 (PR #84291)

2024-03-07 Thread via cfe-commits


@@ -500,7 +500,7 @@ class HTMLLogger : public Logger {
 for (unsigned I = 0; I < CFG.getNumBlockIDs(); ++I) {
   std::string Name = blockID(I);
   // Rightwards arrow, vertical line
-  char ConvergenceMarker[] = u8"\\n\u2192\u007c";
+  char ConvergenceMarker[] = "\\n\u2192\u007c";

martinboehme wrote:

Thanks. Will revert and re-land with your suggestion. Sorry for the breakage!

https://github.com/llvm/llvm-project/pull/84291
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Revert "[dataflow][nfc] Fix u8 string usage with c++20" (PR #84301)

2024-03-07 Thread via cfe-commits

https://github.com/martinboehme created 
https://github.com/llvm/llvm-project/pull/84301

Reverts llvm/llvm-project#84291

The patch broke Windows builds.

>From c4eae28f1eb14bb8a588d866aa561d676c6bdd67 Mon Sep 17 00:00:00 2001
From: martinboehme 
Date: Thu, 7 Mar 2024 11:48:25 +0100
Subject: [PATCH] Revert "[dataflow][nfc] Fix u8 string usage with c++20
 (#84291)"

This reverts commit 6e79f77adbbd338848ea770f2f2b110bc57a3990.
---
 clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp 
b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
index d9f40d28859f5e..ff4e18de2c70f1 100644
--- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
+++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
@@ -500,7 +500,7 @@ class HTMLLogger : public Logger {
 for (unsigned I = 0; I < CFG.getNumBlockIDs(); ++I) {
   std::string Name = blockID(I);
   // Rightwards arrow, vertical line
-  char ConvergenceMarker[] = "\\n\u2192\u007c";
+  char ConvergenceMarker[] = u8"\\n\u2192\u007c";
   if (BlockConverged[I])
 Name += ConvergenceMarker;
   GraphS << "  " << blockID(I) << " [id=" << blockID(I) << " label=\""

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


[clang] 5830d1a - Revert "[dataflow][nfc] Fix u8 string usage with c++20" (#84301)

2024-03-07 Thread via cfe-commits

Author: martinboehme
Date: 2024-03-07T11:48:51+01:00
New Revision: 5830d1a2dff24d752459f215a0c8fc366f393596

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

LOG: Revert "[dataflow][nfc] Fix u8 string usage with c++20" (#84301)

Reverts llvm/llvm-project#84291

The patch broke Windows builds.

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 d9f40d28859f5e..ff4e18de2c70f1 100644
--- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
+++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
@@ -500,7 +500,7 @@ class HTMLLogger : public Logger {
 for (unsigned I = 0; I < CFG.getNumBlockIDs(); ++I) {
   std::string Name = blockID(I);
   // Rightwards arrow, vertical line
-  char ConvergenceMarker[] = "\\n\u2192\u007c";
+  char ConvergenceMarker[] = u8"\\n\u2192\u007c";
   if (BlockConverged[I])
 Name += ConvergenceMarker;
   GraphS << "  " << blockID(I) << " [id=" << blockID(I) << " label=\""



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


[clang] Revert "[dataflow][nfc] Fix u8 string usage with c++20" (PR #84301)

2024-03-07 Thread via cfe-commits

https://github.com/martinboehme closed 
https://github.com/llvm/llvm-project/pull/84301
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Revert "[dataflow][nfc] Fix u8 string usage with c++20" (PR #84301)

2024-03-07 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang

Author: None (martinboehme)


Changes

Reverts llvm/llvm-project#84291

The patch broke Windows builds.

---
Full diff: https://github.com/llvm/llvm-project/pull/84301.diff


1 Files Affected:

- (modified) clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp (+1-1) 


``diff
diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp 
b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
index d9f40d28859f5e..ff4e18de2c70f1 100644
--- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
+++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
@@ -500,7 +500,7 @@ class HTMLLogger : public Logger {
 for (unsigned I = 0; I < CFG.getNumBlockIDs(); ++I) {
   std::string Name = blockID(I);
   // Rightwards arrow, vertical line
-  char ConvergenceMarker[] = "\\n\u2192\u007c";
+  char ConvergenceMarker[] = u8"\\n\u2192\u007c";
   if (BlockConverged[I])
 Name += ConvergenceMarker;
   GraphS << "  " << blockID(I) << " [id=" << blockID(I) << " label=\""

``




https://github.com/llvm/llvm-project/pull/84301
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][dataflow] Fix u8 string error with C++20. (PR #84302)

2024-03-07 Thread via cfe-commits

https://github.com/martinboehme created 
https://github.com/llvm/llvm-project/pull/84302

See also discussion on https://github.com/llvm/llvm-project/pull/84291.


>From 66ba3d492bc09b1244d1b0abdee58e1015a19974 Mon Sep 17 00:00:00 2001
From: Martin Braenne 
Date: Thu, 7 Mar 2024 10:50:57 +
Subject: [PATCH] [clang][dataflow] Fix u8 string error with C++20.

See also discussion on https://github.com/llvm/llvm-project/pull/84291.
---
 clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp 
b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
index ff4e18de2c70f1..f2753d962f23a0 100644
--- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
+++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
@@ -500,7 +500,7 @@ class HTMLLogger : public Logger {
 for (unsigned I = 0; I < CFG.getNumBlockIDs(); ++I) {
   std::string Name = blockID(I);
   // Rightwards arrow, vertical line
-  char ConvergenceMarker[] = u8"\\n\u2192\u007c";
+  const char *ConvergenceMarker = (const char*)u8"\\n\u2192\u007c";
   if (BlockConverged[I])
 Name += ConvergenceMarker;
   GraphS << "  " << blockID(I) << " [id=" << blockID(I) << " label=\""

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


[clang] [clang][dataflow] Fix u8 string error with C++20. (PR #84302)

2024-03-07 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang

Author: None (martinboehme)


Changes

See also discussion on https://github.com/llvm/llvm-project/pull/84291.


---
Full diff: https://github.com/llvm/llvm-project/pull/84302.diff


1 Files Affected:

- (modified) clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp (+1-1) 


``diff
diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp 
b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
index ff4e18de2c70f1..f2753d962f23a0 100644
--- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
+++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
@@ -500,7 +500,7 @@ class HTMLLogger : public Logger {
 for (unsigned I = 0; I < CFG.getNumBlockIDs(); ++I) {
   std::string Name = blockID(I);
   // Rightwards arrow, vertical line
-  char ConvergenceMarker[] = u8"\\n\u2192\u007c";
+  const char *ConvergenceMarker = (const char*)u8"\\n\u2192\u007c";
   if (BlockConverged[I])
 Name += ConvergenceMarker;
   GraphS << "  " << blockID(I) << " [id=" << blockID(I) << " label=\""

``




https://github.com/llvm/llvm-project/pull/84302
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][dataflow] Fix u8 string error with C++20. (PR #84302)

2024-03-07 Thread via cfe-commits

github-actions[bot] wrote:




:warning: C/C++ code formatter, clang-format found issues in your code. 
:warning:



You can test this locally with the following command:


``bash
git-clang-format --diff 5830d1a2dff24d752459f215a0c8fc366f393596 
66ba3d492bc09b1244d1b0abdee58e1015a19974 -- 
clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
``





View the diff from clang-format here.


``diff
diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp 
b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
index f2753d962f..6afd66d9dc 100644
--- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
+++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
@@ -500,7 +500,7 @@ private:
 for (unsigned I = 0; I < CFG.getNumBlockIDs(); ++I) {
   std::string Name = blockID(I);
   // Rightwards arrow, vertical line
-  const char *ConvergenceMarker = (const char*)u8"\\n\u2192\u007c";
+  const char *ConvergenceMarker = (const char *)u8"\\n\u2192\u007c";
   if (BlockConverged[I])
 Name += ConvergenceMarker;
   GraphS << "  " << blockID(I) << " [id=" << blockID(I) << " label=\""

``




https://github.com/llvm/llvm-project/pull/84302
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Add CodeGen tests for CWG 5xx issues (PR #84303)

2024-03-07 Thread Vlad Serebrennikov via cfe-commits

https://github.com/Endilll created 
https://github.com/llvm/llvm-project/pull/84303

This patch covers
[CWG519](https://cplusplus.github.io/CWG/issues/519.html) "Null pointer 
preservation in `void*` conversions",
[CWG571](https://cplusplus.github.io/CWG/issues/571.html) "References declared 
const".

>From c9f7b8daadae24ff9673e58ab6d28c40440d6275 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov 
Date: Thu, 7 Mar 2024 13:32:35 +0300
Subject: [PATCH 1/3] [clang] Add CodeGen tests for CWG 5xx issues

This patch covers
[CWG519](https://cplusplus.github.io/CWG/issues/519.html) "Null pointer 
preservation in `void*` conversions ",
[CWG571](https://cplusplus.github.io/CWG/issues/571.html) "References declared 
const".
---
 clang/test/CXX/drs/dr519.cpp | 36 
 clang/test/CXX/drs/dr571.cpp | 21 +
 clang/test/CXX/drs/dr5xx.cpp | 19 ++-
 clang/www/cxx_dr_status.html |  4 ++--
 4 files changed, 61 insertions(+), 19 deletions(-)
 create mode 100644 clang/test/CXX/drs/dr519.cpp
 create mode 100644 clang/test/CXX/drs/dr571.cpp

diff --git a/clang/test/CXX/drs/dr519.cpp b/clang/test/CXX/drs/dr519.cpp
new file mode 100644
index 00..42328f89ba7cdf
--- /dev/null
+++ b/clang/test/CXX/drs/dr519.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -std=c++98 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++11 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++14 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++2c %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+
+namespace dr519 { // dr519: 2.7
+void f() {
+  int *a = 0;
+  void *v = a;
+  bool c1 = v == static_cast(0);
+
+  void *w = 0;
+  int *b = static_cast(w);
+  bool c2 = b == static_cast(0);
+}
+} // namespace dr519
+
+// We're checking that `null`s that were initially stored in `a` and `w`
+// are simply copied over all the way to respective comparisons with `null`.
+
+// CHECK-LABEL: define {{.*}} void dr519::f()()
+// CHECK: store ptr null, ptr [[A:%.+]],
+// CHECK-NEXT:[[TEMP_A:%.+]] = load ptr, ptr [[A]] 
+// CHECK-NEXT:store ptr [[TEMP_A]], ptr [[V:%.+]],
+// CHECK-NEXT:[[TEMP_V:%.+]] = load ptr, ptr [[V]]
+// CHECK-NEXT:{{.+}} = icmp eq ptr [[TEMP_V]], null
+
+// CHECK: store ptr null, ptr [[W:%.+]],
+// CHECK-NEXT:[[TEMP_W:%.+]] = load ptr, ptr [[W]] 
+// CHECK-NEXT:store ptr [[TEMP_W]], ptr [[B:%.+]],
+// CHECK-NEXT:[[TEMP_B:%.+]] = load ptr, ptr [[B]]
+// CHECK-NEXT:{{.+}} = icmp eq ptr [[TEMP_B]], null
+// CHECK-LABEL: }
diff --git a/clang/test/CXX/drs/dr571.cpp b/clang/test/CXX/drs/dr571.cpp
new file mode 100644
index 00..64f143443cddc3
--- /dev/null
+++ b/clang/test/CXX/drs/dr571.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -std=c++98 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++11 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++14 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++2c %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-pr

[clang] [clang] Add CodeGen tests for CWG 5xx issues (PR #84303)

2024-03-07 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang

Author: Vlad Serebrennikov (Endilll)


Changes

This patch covers
[CWG519](https://cplusplus.github.io/CWG/issues/519.html) "Null pointer 
preservation in `void*` conversions",
[CWG571](https://cplusplus.github.io/CWG/issues/571.html) "References declared 
const".

---
Full diff: https://github.com/llvm/llvm-project/pull/84303.diff


4 Files Affected:

- (added) clang/test/CXX/drs/dr519.cpp (+36) 
- (added) clang/test/CXX/drs/dr571.cpp (+20) 
- (modified) clang/test/CXX/drs/dr5xx.cpp (+2-17) 
- (modified) clang/www/cxx_dr_status.html (+2-2) 


``diff
diff --git a/clang/test/CXX/drs/dr519.cpp b/clang/test/CXX/drs/dr519.cpp
new file mode 100644
index 00..67c01d95ef7c6f
--- /dev/null
+++ b/clang/test/CXX/drs/dr519.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -std=c++98 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++11 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++14 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++2c %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+
+namespace dr519 { // dr519: 2.7
+void f() {
+  int *a = 0;
+  void *v = a;
+  bool c1 = v == static_cast(0);
+
+  void *w = 0;
+  int *b = static_cast(w);
+  bool c2 = b == static_cast(0);
+}
+} // namespace dr519
+
+// We're checking that `null`s that were initially stored in `a` and `w`
+// are simply copied over all the way to respective comparisons with `null`.
+
+// CHECK-LABEL: define {{.*}} void @dr519::f()()
+// CHECK: store ptr null, ptr [[A:%.+]],
+// CHECK-NEXT:[[TEMP_A:%.+]] = load ptr, ptr [[A]] 
+// CHECK-NEXT:store ptr [[TEMP_A]], ptr [[V:%.+]],
+// CHECK-NEXT:[[TEMP_V:%.+]] = load ptr, ptr [[V]]
+// CHECK-NEXT:{{.+}} = icmp eq ptr [[TEMP_V]], null
+
+// CHECK: store ptr null, ptr [[W:%.+]],
+// CHECK-NEXT:[[TEMP_W:%.+]] = load ptr, ptr [[W]] 
+// CHECK-NEXT:store ptr [[TEMP_W]], ptr [[B:%.+]],
+// CHECK-NEXT:[[TEMP_B:%.+]] = load ptr, ptr [[B]]
+// CHECK-NEXT:{{.+}} = icmp eq ptr [[TEMP_B]], null
+// CHECK-LABEL: }
diff --git a/clang/test/CXX/drs/dr571.cpp b/clang/test/CXX/drs/dr571.cpp
new file mode 100644
index 00..19a85b7ddc3508
--- /dev/null
+++ b/clang/test/CXX/drs/dr571.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c++98 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++11 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++14 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+// RUN: %clang_cc1 -std=c++2c %s -triple x86_64-linux-gnu -emit-llvm -o - 
-fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s 
--check-prefixes CHECK
+
+namespace dr571 { // dr571: 2.7
+  typedef int &ir;
+  int n;
+  const ir r = n;
+  // expected-warning@-1 {{'const' qualifier on reference type 'ir' (aka 'int 
&') has no effect}}
+  ir r2 = n;
+}
+
+// Entities have external linkage by default.
+
+// CHECK: @dr571::r = constant ptr @dr571::n
+// CHECK: @dr571::r2 = constant ptr @dr571::n
diff --git a/clang/test/CXX/drs/dr5xx.cpp b/clang/test/CXX/drs/dr5xx.cpp
index 0e1de342f6706f..426b368b390ae6 100644
--- a/clang/te

[clang] [clang][dataflow] Fix u8 string error with C++20. (PR #84302)

2024-03-07 Thread via cfe-commits

https://github.com/martinboehme updated 
https://github.com/llvm/llvm-project/pull/84302

>From 66ba3d492bc09b1244d1b0abdee58e1015a19974 Mon Sep 17 00:00:00 2001
From: Martin Braenne 
Date: Thu, 7 Mar 2024 10:50:57 +
Subject: [PATCH 1/2] [clang][dataflow] Fix u8 string error with C++20.

See also discussion on https://github.com/llvm/llvm-project/pull/84291.
---
 clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp 
b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
index ff4e18de2c70f1..f2753d962f23a0 100644
--- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
+++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
@@ -500,7 +500,7 @@ class HTMLLogger : public Logger {
 for (unsigned I = 0; I < CFG.getNumBlockIDs(); ++I) {
   std::string Name = blockID(I);
   // Rightwards arrow, vertical line
-  char ConvergenceMarker[] = u8"\\n\u2192\u007c";
+  const char *ConvergenceMarker = (const char*)u8"\\n\u2192\u007c";
   if (BlockConverged[I])
 Name += ConvergenceMarker;
   GraphS << "  " << blockID(I) << " [id=" << blockID(I) << " label=\""

>From c526138a8e18e846a6ee9c1a1020fe6623893259 Mon Sep 17 00:00:00 2001
From: Martin Braenne 
Date: Thu, 7 Mar 2024 10:57:41 +
Subject: [PATCH 2/2] fixup! [clang][dataflow] Fix u8 string error with C++20.

---
 clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp 
b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
index f2753d962f23a0..6afd66d9dc6ac5 100644
--- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
+++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
@@ -500,7 +500,7 @@ class HTMLLogger : public Logger {
 for (unsigned I = 0; I < CFG.getNumBlockIDs(); ++I) {
   std::string Name = blockID(I);
   // Rightwards arrow, vertical line
-  const char *ConvergenceMarker = (const char*)u8"\\n\u2192\u007c";
+  const char *ConvergenceMarker = (const char *)u8"\\n\u2192\u007c";
   if (BlockConverged[I])
 Name += ConvergenceMarker;
   GraphS << "  " << blockID(I) << " [id=" << blockID(I) << " label=\""

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


[clang] [dataflow][nfc] Fix u8 string usage with c++20 (PR #84291)

2024-03-07 Thread via cfe-commits

martinboehme wrote:

New attempt: https://github.com/llvm/llvm-project/pull/84302

https://github.com/llvm/llvm-project/pull/84291
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][dataflow] Fix u8 string error with C++20. (PR #84302)

2024-03-07 Thread Simon Pilgrim via cfe-commits

https://github.com/RKSimon approved this pull request.

LGTM - cheers

https://github.com/llvm/llvm-project/pull/84302
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Fix crash when declaring invalid lambda member (PR #74110)

2024-03-07 Thread Nikolas Klauser via cfe-commits

https://github.com/philnik777 updated 
https://github.com/llvm/llvm-project/pull/74110

>From 563f86bddc0ec59b63c6aeffee2342f027c09119 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser 
Date: Fri, 1 Dec 2023 18:16:36 +0100
Subject: [PATCH 1/2] [clang] Fix crash when declaring invalid lambda member

---
 clang/lib/AST/DeclCXX.cpp |  7 +++
 clang/test/SemaCXX/lambda-expressions.cpp | 16 +---
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index c944862fcefeee..e9e62fea9fb376 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1526,10 +1526,9 @@ bool CXXRecordDecl::isGenericLambda() const {
 
 #ifndef NDEBUG
 static bool allLookupResultsAreTheSame(const DeclContext::lookup_result &R) {
-  for (auto *D : R)
-if (!declaresSameEntity(D, R.front()))
-  return false;
-  return true;
+  return llvm::all_of(R, [&](NamedDecl *D) {
+return D->isInvalidDecl() || declaresSameEntity(D, R.front());
+  });
 }
 #endif
 
diff --git a/clang/test/SemaCXX/lambda-expressions.cpp 
b/clang/test/SemaCXX/lambda-expressions.cpp
index 1797eef320b865..1921d02b1a9cf8 100644
--- a/clang/test/SemaCXX/lambda-expressions.cpp
+++ b/clang/test/SemaCXX/lambda-expressions.cpp
@@ -1,3 +1,4 @@
+// RUN: %clang_cc1 -std=c++11 -Wno-unused-value -fsyntax-only 
-verify=expected,expected-cxx14,cxx11 -fblocks %s
 // RUN: %clang_cc1 -std=c++14 -Wno-unused-value -fsyntax-only -verify 
-verify=expected-cxx14 -fblocks %s
 // RUN: %clang_cc1 -std=c++17 -Wno-unused-value -verify -ast-dump -fblocks %s 
| FileCheck %s
 
@@ -558,8 +559,8 @@ struct B {
   int x;
   A a = [&] { int y = x; };
   A b = [&] { [&] { [&] { int y = x; }; }; };
-  A d = [&](auto param) { int y = x; };
-  A e = [&](auto param) { [&] { [&](auto param2) { int y = x; }; }; };
+  A d = [&](auto param) { int y = x; }; // cxx11-error {{'auto' not allowed in 
lambda parameter}}
+  A e = [&](auto param) { [&] { [&](auto param2) { int y = x; }; }; }; // 
cxx11-error 2 {{'auto' not allowed in lambda parameter}}
 };
 
 B b;
@@ -589,6 +590,7 @@ struct S1 {
 void foo1() {
   auto s0 = S1{[name=]() {}}; // expected-error 2 {{expected expression}}
   auto s1 = S1{[name=name]() {}}; // expected-error {{use of undeclared 
identifier 'name'; did you mean 'name1'?}}
+  // cxx11-warning@-1 {{initialized lambda 
captures are a C++14 extension}}
 }
 }
 
@@ -604,7 +606,7 @@ namespace PR25627_dont_odr_use_local_consts {
 
 namespace ConversionOperatorDoesNotHaveDeducedReturnType {
   auto x = [](int){};
-  auto y = [](auto &v) -> void { v.n = 0; };
+  auto y = [](auto &v) -> void { v.n = 0; }; // cxx11-error {{'auto' not 
allowed in lambda parameter}} cxx11-note {{candidate function not viable}} 
cxx11-note {{conversion candidate}}
   using T = decltype(x);
   using U = decltype(y);
   using ExpectedTypeT = void (*)(int);
@@ -624,14 +626,14 @@ namespace ConversionOperatorDoesNotHaveDeducedReturnType {
 template
   friend constexpr U::operator ExpectedTypeU() const noexcept;
 #else
-friend auto T::operator()(int) const;
+friend auto T::operator()(int) const; // cxx11-error {{'auto' return 
without trailing return type; deduced return types are a C++14 extension}}
 friend T::operator ExpectedTypeT() const;
 
 template
-  friend void U::operator()(T&) const;
+  friend void U::operator()(T&) const; // cxx11-error {{friend declaration 
of 'operator()' does not match any declaration}}
 // FIXME: This should not match, as above.
 template
-  friend U::operator ExpectedTypeU() const;
+  friend U::operator ExpectedTypeU() const; // cxx11-error {{friend 
declaration of 'operator void (*)(type-parameter-0-0 &)' does not match any 
declaration}}
 #endif
 
   private:
@@ -639,7 +641,7 @@ namespace ConversionOperatorDoesNotHaveDeducedReturnType {
   };
 
   // Should be OK: lambda's call operator is a friend.
-  void use(X &x) { y(x); }
+  void use(X &x) { y(x); } // cxx11-error {{no matching function for call to 
object}}
 
   // This used to crash in return type deduction for the conversion opreator.
   struct A { int n; void f() { +[](decltype(n)) {}; } };

>From 5412ff972af6fdc6c83d9f0b835ff989252ff591 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser 
Date: Thu, 7 Mar 2024 12:47:55 +0100
Subject: [PATCH 2/2] Address comments

---
 clang/docs/ReleaseNotes.rst   | 2 ++
 clang/test/SemaCXX/lambda-expressions.cpp | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 0ce15169d49bcc..db4dcc3ce029fb 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -617,6 +617,8 @@ Bug Fixes in This Version
 - Fix crash during code generation of C++ coroutine initial suspend when the 
return
   type of await_resume is not trivially destructible.
   Fixes (`#63803 `_)

[clang] [flang] [flang][draft] Improve debug info generation. (PR #84202)

2024-03-07 Thread Tom Eccles via cfe-commits

tblah wrote:

Thank you for this patch! I like the approach so far using the existing debug 
pass.

My gut feeling is that I would rather this happen in a pass rather than earlier 
on (lowering or even semantics) because lowering is already too complicated and 
monolithic. In the past it has proven useful to break down complicated lowering 
steps into smaller pieces by self-contained passes (e.g. the transition from 
AST->FIR to AST->HLFIR->FIR). But I don't have any concrete examples - perhaps 
this won't be so difficult as I suspect, so I am open to other approaches.

>  1. Some of the location information is difficult to extract from FIR. For 
> example, the location where derived types and its members are declared in the 
> source is not available (or at least I could not figure out how to get them).
>  2. Things like fortran module is not a first class entity in IR. One can 
> extract its name from the unique name of the type or variable but this is not 
> ideal.

I would lean towards adding the information you need to (HL)FIR.

Location information is just a kind of attribute on an operation. I presume one 
could use additional location attributes to store the information you need in 
(HL)FIR. I'm not super familiar with derived types in FIR, but perhaps 
`fir.type_info` could be used/extended for this?

Similarly, perhaps the solution for a module would be to add a string attribute 
naming the module.

As Kiran said, it would be good to seek a wider discussion on this - either in 
review of a design document and/or in an RFC on 
https://discourse.llvm.org/c/subprojects/flang/33

https://github.com/llvm/llvm-project/pull/84202
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] a11ab13 - [clang][dataflow] Fix u8 string error with C++20. (#84302)

2024-03-07 Thread via cfe-commits

Author: martinboehme
Date: 2024-03-07T12:53:26+01:00
New Revision: a11ab139e4de9cdad41c299f198515c09be6f05d

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

LOG: [clang][dataflow] Fix u8 string error with C++20. (#84302)

See also discussion on https://github.com/llvm/llvm-project/pull/84291.

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 ff4e18de2c70f1..6afd66d9dc6ac5 100644
--- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
+++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
@@ -500,7 +500,7 @@ class HTMLLogger : public Logger {
 for (unsigned I = 0; I < CFG.getNumBlockIDs(); ++I) {
   std::string Name = blockID(I);
   // Rightwards arrow, vertical line
-  char ConvergenceMarker[] = u8"\\n\u2192\u007c";
+  const char *ConvergenceMarker = (const char *)u8"\\n\u2192\u007c";
   if (BlockConverged[I])
 Name += ConvergenceMarker;
   GraphS << "  " << blockID(I) << " [id=" << blockID(I) << " label=\""



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


[clang] [clang][dataflow] Fix u8 string error with C++20. (PR #84302)

2024-03-07 Thread via cfe-commits

https://github.com/martinboehme closed 
https://github.com/llvm/llvm-project/pull/84302
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][CodeGen] Allow memcpy replace with trivial auto var init (PR #84230)

2024-03-07 Thread Antonio Frighetto via cfe-commits

https://github.com/antoniofrighetto updated 
https://github.com/llvm/llvm-project/pull/84230

>From e5af3e3242b34811eb56d91597bfc58e89f9e2db Mon Sep 17 00:00:00 2001
From: Antonio Frighetto 
Date: Wed, 6 Mar 2024 23:49:40 +0100
Subject: [PATCH] [clang][CodeGen] Allow memcpy replace with trivial auto var
 init

With respect to d5934a4112166ce0375295b2347e7d5c43fdf5ed, actually
ensure `memcpy`s can be avoided when `-ftrivial-auto-var-init` is
set.

Fixes: https://github.com/llvm/llvm-project/issues/84178.
---
 clang/lib/CodeGen/CGDecl.cpp  | 43 ++-
 clang/test/CodeGen/aapcs-align.cpp|  4 +--
 clang/test/CodeGen/aapcs64-align.cpp  |  8 ++---
 clang/test/CodeGen/attr-counted-by.c  | 26 --
 clang/test/CodeGenCXX/auto-var-init.cpp   | 27 +++---
 clang/test/CodeGenOpenCL/amdgpu-printf.cl |  9 +
 clang/test/OpenMP/bug54082.c  |  4 +--
 7 files changed, 56 insertions(+), 65 deletions(-)

diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index bbe14ef4c17244..aa9997b87ecfa7 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -1241,27 +1241,38 @@ static void emitStoresForConstant(CodeGenModule &CGM, 
const VarDecl &D,
 return;
   }
 
-  // If the initializer is small, use a handful of stores.
+  // If the initializer is small or trivialAutoVarInit is set, use a handful of
+  // stores.
+  bool IsTrivialAutoVarInitPattern =
+  CGM.getContext().getLangOpts().getTrivialAutoVarInit() ==
+  LangOptions::TrivialAutoVarInitKind::Pattern;
   if (shouldSplitConstantStore(CGM, ConstantSize)) {
 if (auto *STy = dyn_cast(Ty)) {
-  const llvm::StructLayout *Layout =
-  CGM.getDataLayout().getStructLayout(STy);
-  for (unsigned i = 0; i != constant->getNumOperands(); i++) {
-CharUnits CurOff = 
CharUnits::fromQuantity(Layout->getElementOffset(i));
-Address EltPtr = Builder.CreateConstInBoundsByteGEP(
-Loc.withElementType(CGM.Int8Ty), CurOff);
-emitStoresForConstant(CGM, D, EltPtr, isVolatile, Builder,
-  constant->getAggregateElement(i), IsAutoInit);
+  if (STy == Loc.getElementType() ||
+  (STy != Loc.getElementType() && IsTrivialAutoVarInitPattern)) {
+const llvm::StructLayout *Layout =
+CGM.getDataLayout().getStructLayout(STy);
+for (unsigned i = 0; i != constant->getNumOperands(); i++) {
+  CharUnits CurOff =
+  CharUnits::fromQuantity(Layout->getElementOffset(i));
+  Address EltPtr = Builder.CreateConstInBoundsByteGEP(
+  Loc.withElementType(CGM.Int8Ty), CurOff);
+  emitStoresForConstant(CGM, D, EltPtr, isVolatile, Builder,
+constant->getAggregateElement(i), IsAutoInit);
+}
+return;
   }
-  return;
 } else if (auto *ATy = dyn_cast(Ty)) {
-  for (unsigned i = 0; i != ATy->getNumElements(); i++) {
-Address EltPtr = Builder.CreateConstGEP(
-Loc.withElementType(ATy->getElementType()), i);
-emitStoresForConstant(CGM, D, EltPtr, isVolatile, Builder,
-  constant->getAggregateElement(i), IsAutoInit);
+  if (ATy == Loc.getElementType() ||
+  (ATy != Loc.getElementType() && IsTrivialAutoVarInitPattern)) {
+for (unsigned i = 0; i != ATy->getNumElements(); i++) {
+  Address EltPtr = Builder.CreateConstGEP(
+  Loc.withElementType(ATy->getElementType()), i);
+  emitStoresForConstant(CGM, D, EltPtr, isVolatile, Builder,
+constant->getAggregateElement(i), IsAutoInit);
+}
+return;
   }
-  return;
 }
   }
 
diff --git a/clang/test/CodeGen/aapcs-align.cpp 
b/clang/test/CodeGen/aapcs-align.cpp
index 2886a32974b066..4f393d9e6b7f32 100644
--- a/clang/test/CodeGen/aapcs-align.cpp
+++ b/clang/test/CodeGen/aapcs-align.cpp
@@ -134,8 +134,8 @@ void g6() {
   f6m(1, 2, 3, 4, 5, s);
 }
 // CHECK: define{{.*}} void @g6
-// CHECK: call void @f6(i32 noundef 1, [4 x i32] [i32 6, i32 7, i32 0, i32 0])
-// CHECK: call void @f6m(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 
noundef 4, i32 noundef 5, [4 x i32] [i32 6, i32 7, i32 0, i32 0])
+// CHECK: call void @f6(i32 noundef 1, [4 x i32] [i32 6, i32 7, i32 0, i32 
undef])
+// CHECK: call void @f6m(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 
noundef 4, i32 noundef 5, [4 x i32] [i32 6, i32 7, i32 0, i32 undef])
 // CHECK: declare void @f6(i32 noundef, [4 x i32])
 // CHECK: declare void @f6m(i32 noundef, i32 noundef, i32 noundef, i32 
noundef, i32 noundef, [4 x i32])
 }
diff --git a/clang/test/CodeGen/aapcs64-align.cpp 
b/clang/test/CodeGen/aapcs64-align.cpp
index 759413cbc4b56f..de231f2123b975 100644
--- a/clang/test/CodeGen/aapcs64-align.cpp
+++ b/clang/test/CodeGen/aapcs64-align.cpp
@@ -75,8 +75,8 @@ void g4() {
   f4m(1, 2, 3, 4, 5, s);
 }
 // CHECK: define{{.*}}

[clang] [clang][CodeGen] Allow memcpy replace with trivial auto var init (PR #84230)

2024-03-07 Thread Antonio Frighetto via cfe-commits

antoniofrighetto wrote:

Fixed `auto-var-init.cpp` test failures, believe now it should be aligned with 
the original intent.

https://github.com/llvm/llvm-project/pull/84230
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][nullability] Don't discard expression state before end of full-expression. (PR #82611)

2024-03-07 Thread via cfe-commits


@@ -94,6 +94,38 @@ static llvm::BitVector findReachableBlocks(const CFG &Cfg) {
   return BlockReachable;
 }
 
+static llvm::DenseSet
+buildContainsExprConsumedInDifferentBlock(
+const CFG &Cfg,
+const llvm::DenseMap &StmtToBlock) {
+  llvm::DenseSet Result;

martinboehme wrote:

Agree, I'm not sure which way this goes. This feature doesn't appear to be a 
bit performance issue one way or the other, so I'm inclined to keep it as is.

https://github.com/llvm/llvm-project/pull/82611
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy][missing-std-forward]report diagnotics for using forward in lambda body (PR #83930)

2024-03-07 Thread Congcong Cai via cfe-commits

https://github.com/HerrCai0907 closed 
https://github.com/llvm/llvm-project/pull/83930
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][nullability] allow _Nonnull etc on nullable class types (PR #82705)

2024-03-07 Thread Dmitri Gribenko via cfe-commits


@@ -96,8 +146,16 @@ void AssignAndInitNonNullFromFn() {
   void *_Nonnull nonnull;
   nonnull = ReturnNullable(); // expected-warning{{implicit conversion from 
nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * 
_Nonnull'}}
   nonnull = {ReturnNullable()}; // expected-warning{{implicit conversion from 
nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * 
_Nonnull'}}
-
   TakeNonnull(ReturnNullable()); //expected-warning{{implicit conversion from 
nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * 
_Nonnull}}
+
+  SmartPtr _Nonnull s(ReturnSmartNullable()); // expected-warning{{implicit 
conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer 
type 'SmartPtr _Nonnull'}}
+  SmartPtr _Nonnull s2{ReturnSmartNullable()}; // expected-warning{{implicit 
conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer 
type 'SmartPtr _Nonnull'}}
+  SmartPtr _Nonnull s3 = {ReturnSmartNullable()}; // 
expected-warning{{implicit conversion from nullable pointer 'SmartPtr 
_Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}}
+  SmartPtr _Nonnull s4 = ReturnSmartNullable(); // expected-warning{{implicit 
conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer 
type 'SmartPtr _Nonnull'}}
+  SmartPtr _Nonnull s_nonnull;
+  s_nonnull = ReturnSmartNullable(); // expected-warning{{implicit conversion 
from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 
'SmartPtr _Nonnull'}}
+  s_nonnull = {ReturnSmartNullable()};
+  TakeSmartNonnull(ReturnSmartNullable()); //expected-warning{{implicit 
conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer 
type 'SmartPtr _Nonnull}}

gribozavr wrote:

```suggestion
  TakeSmartNonnull(ReturnSmartNullable()); // expected-warning{{implicit 
conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer 
type 'SmartPtr _Nonnull'}}
```

https://github.com/llvm/llvm-project/pull/82705
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][C++23] Implement P1774R8: Portable assumptions (PR #81014)

2024-03-07 Thread via cfe-commits

Sirraide wrote:

I seem to have missed a test that needs to be updated—I suppose that’s what I 
get for only running the Sema and Codegen tests locally instead of the entire 
test suite.

https://github.com/llvm/llvm-project/pull/81014
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][nullability] Don't discard expression state before end of full-expression. (PR #82611)

2024-03-07 Thread via cfe-commits


@@ -94,6 +94,38 @@ static llvm::BitVector findReachableBlocks(const CFG &Cfg) {
   return BlockReachable;
 }
 
+static llvm::DenseSet
+buildContainsExprConsumedInDifferentBlock(
+const CFG &Cfg,
+const llvm::DenseMap &StmtToBlock) {
+  llvm::DenseSet Result;
+
+  auto CheckChildExprs = [&Result, &StmtToBlock](const Stmt *S,
+ const CFGBlock *Block) {
+for (const Stmt *Child : S->children()) {
+  if (!isa(Child))
+continue;
+  const CFGBlock *ChildBlock = StmtToBlock.lookup(Child);
+  if (ChildBlock != Block)
+Result.insert(ChildBlock);
+}
+  };
+
+  for (const CFGBlock *Block : Cfg) {
+if (Block == nullptr)
+  continue;
+
+for (const CFGElement &Element : *Block)

martinboehme wrote:

> Could we early terminate as soon as we found an expression that is consumed 
> in a different block?

That doesn't work, because we insert `ChildBlock`, not `Block`. This block 
might contain expressions from various other blocks, and we want to insert all 
of those blocks into `Result`, so we can't terminate the loop early.

https://github.com/llvm/llvm-project/pull/82611
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][nullability] Don't discard expression state before end of full-expression. (PR #82611)

2024-03-07 Thread via cfe-commits


@@ -307,7 +310,22 @@ computeBlockInputState(const CFGBlock &Block, 
AnalysisContext &AC) {
 }
   }
 
-  JoinedStateBuilder Builder(AC);
+  // If any of the predecessor blocks contains an expression consumed in a
+  // different block, we need to keep expression state.
+  // Note that in this case, we keep expression state for all predecessors,
+  // rather than only those predecessors that actually contain an expression
+  // consumed in a different block. While this is potentially suboptimal, it's
+  // actually likely, if we have control flow within a full expression, that
+  // all predecessors have expression state consumed in a different block.
+  Environment::ExprJoinBehavior ExprBehavior = Environment::DiscardExprState;
+  for (const CFGBlock *Pred : Preds) {
+if (Pred && AC.CFCtx.containsExprConsumedInDifferentBlock(*Pred)) {
+  ExprBehavior = Environment::KeepExprState;
+  break;
+}
+  }

martinboehme wrote:

I'm still not sure this is worth it - this would add additional stored state 
(even if it's non-mutable), and I'm not sure this is worth it for the small 
gain we get. Will commit as-is, and we can discuss whether we want to create a 
followup patch for this.

https://github.com/llvm/llvm-project/pull/82611
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang][Sema] Allow access to a public template alias declaration that refers to friend's private nested type (PR #83847)

2024-03-07 Thread Qizhi Hu via cfe-commits

https://github.com/jcsxky updated 
https://github.com/llvm/llvm-project/pull/83847

>From d60f27e47318b12aac3b462bc074af53ae1296bd Mon Sep 17 00:00:00 2001
From: huqizhi 
Date: Mon, 4 Mar 2024 21:51:07 +0800
Subject: [PATCH] [Clang][Sema] Allow access to a public template alias
 declaration that refers to friend's private nested type

---
 clang/docs/ReleaseNotes.rst |  3 +++
 clang/lib/Sema/SemaAccess.cpp   |  7 +++
 clang/test/SemaTemplate/PR25708.cpp | 23 +++
 3 files changed, 33 insertions(+)
 create mode 100644 clang/test/SemaTemplate/PR25708.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8300a8484585ae..945a21f61abc61 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -239,6 +239,9 @@ Bug Fixes in This Version
   for variables created through copy initialization having side-effects in 
C++17 and later.
   Fixes (#GH64356) (#GH79518).
 
+- Allow access to a public template alias declaration that refers to friend's
+  private nested type (`#25708 
`).
+
 Bug Fixes to Compiler Builtins
 ^^
 
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index 4af3c0f30a8e8a..1bbe0f5b5298d7 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -1481,6 +1481,13 @@ static Sema::AccessResult CheckAccess(Sema &S, 
SourceLocation Loc,
   }
 
   EffectiveContext EC(S.CurContext);
+  auto &Active = S.CodeSynthesisContexts.back();
+  if (Active.Kind == Sema::CodeSynthesisContext::TemplateInstantiation &&
+  Active.Entity)
+if (auto *RD =
+dyn_cast_or_null(Active.Entity->getDeclContext()))
+  EC.Records.push_back(RD);
+
   switch (CheckEffectiveAccess(S, EC, Loc, Entity)) {
   case AR_accessible: return Sema::AR_accessible;
   case AR_inaccessible: return Sema::AR_inaccessible;
diff --git a/clang/test/SemaTemplate/PR25708.cpp 
b/clang/test/SemaTemplate/PR25708.cpp
new file mode 100644
index 00..cc2e7551a6abaa
--- /dev/null
+++ b/clang/test/SemaTemplate/PR25708.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+// RUN: %clang_cc1 -std=c++14 -verify %s
+// RUN: %clang_cc1 -std=c++17 -verify %s
+// RUN: %clang_cc1 -std=c++20 -verify %s
+// expected-no-diagnostics
+
+struct FooAccessor
+{
+template 
+using Foo = typename T::Foo;
+};
+
+class Type
+{
+friend struct FooAccessor;
+
+using Foo = int;
+};
+
+int main()
+{
+FooAccessor::Foo t;
+}

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


[clang] [Clang][Sema] Allow access to a public template alias declaration that refers to friend's private nested type (PR #83847)

2024-03-07 Thread Qizhi Hu via cfe-commits

https://github.com/jcsxky updated 
https://github.com/llvm/llvm-project/pull/83847

>From 52a0191c1e817942dae080b70bd86e48018d4811 Mon Sep 17 00:00:00 2001
From: huqizhi 
Date: Mon, 4 Mar 2024 21:51:07 +0800
Subject: [PATCH] [Clang][Sema] Allow access to a public template alias
 declaration that refers to friend's private nested type

---
 clang/docs/ReleaseNotes.rst |  3 +++
 clang/lib/Sema/SemaAccess.cpp   |  7 +++
 clang/test/SemaTemplate/PR25708.cpp | 23 +++
 3 files changed, 33 insertions(+)
 create mode 100644 clang/test/SemaTemplate/PR25708.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 1b901a27fd19d1..38cbe421fd485c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -241,6 +241,9 @@ Bug Fixes in This Version
   for variables created through copy initialization having side-effects in 
C++17 and later.
   Fixes (#GH64356) (#GH79518).
 
+- Allow access to a public template alias declaration that refers to friend's
+  private nested type (`#25708 
`).
+
 Bug Fixes to Compiler Builtins
 ^^
 
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index 4af3c0f30a8e8a..1bbe0f5b5298d7 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -1481,6 +1481,13 @@ static Sema::AccessResult CheckAccess(Sema &S, 
SourceLocation Loc,
   }
 
   EffectiveContext EC(S.CurContext);
+  auto &Active = S.CodeSynthesisContexts.back();
+  if (Active.Kind == Sema::CodeSynthesisContext::TemplateInstantiation &&
+  Active.Entity)
+if (auto *RD =
+dyn_cast_or_null(Active.Entity->getDeclContext()))
+  EC.Records.push_back(RD);
+
   switch (CheckEffectiveAccess(S, EC, Loc, Entity)) {
   case AR_accessible: return Sema::AR_accessible;
   case AR_inaccessible: return Sema::AR_inaccessible;
diff --git a/clang/test/SemaTemplate/PR25708.cpp 
b/clang/test/SemaTemplate/PR25708.cpp
new file mode 100644
index 00..cc2e7551a6abaa
--- /dev/null
+++ b/clang/test/SemaTemplate/PR25708.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+// RUN: %clang_cc1 -std=c++14 -verify %s
+// RUN: %clang_cc1 -std=c++17 -verify %s
+// RUN: %clang_cc1 -std=c++20 -verify %s
+// expected-no-diagnostics
+
+struct FooAccessor
+{
+template 
+using Foo = typename T::Foo;
+};
+
+class Type
+{
+friend struct FooAccessor;
+
+using Foo = int;
+};
+
+int main()
+{
+FooAccessor::Foo t;
+}

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


[clang] [clang][nullability] Don't discard expression state before end of full-expression. (PR #82611)

2024-03-07 Thread via cfe-commits

martinboehme wrote:

> > Yes, significantly faster, and fewer SAT solver timeouts.
> 
> The Clang Static Analyzer is going one step further. It is pruning the 
> analysis state really aggressively, it is relying on liveness analysis, and 
> whenever the value of a variable is dead (would not be read in future program 
> points), the corresponding symbols will be pruned from the state. For the 
> really deep path sensitive analysis the CSA is doing, it was really 
> beneficial performance-wise. On the other hand, this approach definitely 
> introduced complexity. The CSA is basically doing garbage collection to 
> figure out what part of the program state is unreachable (e.g., can we read a 
> value through some pointers?). Moreover, actually pruning the analysis state 
> is tricky. If we had `x < y` and `y < z` in our constraints, to correctly 
> prune `y`, we would need to have a new set of constraints like `x+1 < z`. 
> Simply dropping everything with `y` would lose information.

Thanks for the input from CSA!

Yes, doing this more broadly would surely be a win -- but also much more 
difficult than for expression evaluation, which makes it easy to determine how 
long a value will be needed. Something to keep in mind for the future.

By the way, we've also been discussing dropping clauses from the flow condition 
when we can prove we no longer need them. Do you happen to know any references 
to similar work, maybe in CSA?

https://github.com/llvm/llvm-project/pull/82611
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Respect field alignment when evaluating layout compatiblity of structs (PR #84313)

2024-03-07 Thread Vlad Serebrennikov via cfe-commits

https://github.com/Endilll created 
https://github.com/llvm/llvm-project/pull/84313

This patch implements 
[CWG2586](https://cplusplus.github.io/CWG/issues/2583.html) "Common initial 
sequence should consider over-alignment". Note that alignment of union members 
doesn't have to match, as layout compatibility of unions is not defined in 
terms of common initial sequence (http://eel.is/c++draft/class.mem.general#25).

>From 491fc16c777aff8b22893da1cdeb8d137cf28871 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov 
Date: Thu, 7 Mar 2024 15:16:35 +0300
Subject: [PATCH] [clang] Respect field alignment when evaluating layout
 compatiblity of structs

This patch implements 
[CWG2586](https://cplusplus.github.io/CWG/issues/2583.html) "Common initial 
sequence should consider over-alignment ". Note that alignment of union members 
doesn't have to match, as layout compatibility of unions is not defined in 
terms of common initial sequence (http://eel.is/c++draft/class.mem.general#25).
---
 clang/docs/ReleaseNotes.rst|  4 
 clang/lib/Sema/SemaChecking.cpp|  9 +++--
 clang/test/CXX/drs/dr25xx.cpp  | 26 ++
 clang/test/SemaCXX/type-traits.cpp | 13 -
 clang/www/cxx_dr_status.html   |  2 +-
 5 files changed, 50 insertions(+), 4 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 1b901a27fd19d1..62cc6aae4ee58b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -115,6 +115,10 @@ Resolutions to C++ Defect Reports
   of two types.
   (`CWG1719: Layout compatibility and cv-qualification revisited 
`_).
 
+- Alignment of members is now respected when evaluating layout compatibility
+  of structs.
+  (`CWG2583: Common initial sequence should consider over-alignment 
`_).
+
 - ``[[no_unique_address]]`` is now respected when evaluating layout
   compatibility of two types.
   (`CWG2759: [[no_unique_address] and common initial sequence  
`_).
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 3597f93a017136..5f607608cf7a53 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -19185,7 +19185,8 @@ static bool isLayoutCompatible(ASTContext &C, EnumDecl 
*ED1, EnumDecl *ED2) {
 
 /// Check if two fields are layout-compatible.
 static bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1,
-   FieldDecl *Field2) {
+   FieldDecl *Field2,
+   bool IgnoreAlignment = false) {
   if (!isLayoutCompatible(C, Field1->getType(), Field2->getType()))
 return false;
 
@@ -19204,6 +19205,10 @@ static bool isLayoutCompatible(ASTContext &C, 
FieldDecl *Field1,
   if (Field1->hasAttr() ||
   Field2->hasAttr())
 return false;
+
+  if (!IgnoreAlignment &&
+  Field1->getMaxAlignment() != Field2->getMaxAlignment())
+return false;
   return true;
 }
 
@@ -19265,7 +19270,7 @@ static bool isLayoutCompatibleUnion(ASTContext &C, 
RecordDecl *RD1,
 E = UnmatchedFields.end();
 
 for ( ; I != E; ++I) {
-  if (isLayoutCompatible(C, Field1, *I)) {
+  if (isLayoutCompatible(C, Field1, *I, /*IgnoreAlignment=*/true)) {
 bool Result = UnmatchedFields.erase(*I);
 (void) Result;
 assert(Result);
diff --git a/clang/test/CXX/drs/dr25xx.cpp b/clang/test/CXX/drs/dr25xx.cpp
index 9fc7cf59485caa..46532486e50e53 100644
--- a/clang/test/CXX/drs/dr25xx.cpp
+++ b/clang/test/CXX/drs/dr25xx.cpp
@@ -211,6 +211,32 @@ namespace dr2565 { // dr2565: 16 open 2023-06-07
 #endif
 }
 
+namespace dr2583 { // dr2583: 19
+#if __cplusplus >= 201103L
+struct A {
+  int i;
+  char c;
+};
+
+struct B {
+  int i;
+  alignas(8) char c;
+};
+
+union U {
+  A a;
+  B b;
+};
+
+union V {
+  A a;
+  alignas(64) B b;
+};
+
+static_assert(!__is_layout_compatible(A, B), "");
+static_assert(__is_layout_compatible(U, V), "");
+#endif
+} // namespace dr2583
 
 namespace dr2598 { // dr2598: 18
 #if __cplusplus >= 201103L
diff --git a/clang/test/SemaCXX/type-traits.cpp 
b/clang/test/SemaCXX/type-traits.cpp
index 23c339ebdf0826..831de2589dcb9e 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -1681,6 +1681,16 @@ union UnionLayout3 {
   [[no_unique_address]] CEmptyStruct d;
 };
 
+union UnionNoOveralignedMembers {
+  int a;
+  double b;
+};
+
+union UnionWithOveralignedMembers {
+  int a;
+  alignas(16) double b;
+};
+
 struct StructWithAnonUnion {
   union {
 int a;
@@ -1771,7 +1781,8 @@ void is_layout_compatible(int n)
   static_assert(__is_layout_compatible(CStruct, CStructNoUniqueAddress) != 
bool(__has_cpp_attribute(no_unique_address)), "");
   static_assert(__is_layout_compatible(CStructNoUniqueAddress, 
CStructNoUniqueAddress2) != bool(__has_cpp_attribute(no_unique_address

[clang] [clang] Respect field alignment when evaluating layout compatiblity of structs (PR #84313)

2024-03-07 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang

Author: Vlad Serebrennikov (Endilll)


Changes

This patch implements 
[CWG2586](https://cplusplus.github.io/CWG/issues/2583.html) "Common initial 
sequence should consider over-alignment". Note that alignment of union members 
doesn't have to match, as layout compatibility of unions is not defined in 
terms of common initial sequence (http://eel.is/c++draft/class.mem.general#25).

---
Full diff: https://github.com/llvm/llvm-project/pull/84313.diff


5 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+4) 
- (modified) clang/lib/Sema/SemaChecking.cpp (+7-2) 
- (modified) clang/test/CXX/drs/dr25xx.cpp (+26) 
- (modified) clang/test/SemaCXX/type-traits.cpp (+12-1) 
- (modified) clang/www/cxx_dr_status.html (+1-1) 


``diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 1b901a27fd19d1..62cc6aae4ee58b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -115,6 +115,10 @@ Resolutions to C++ Defect Reports
   of two types.
   (`CWG1719: Layout compatibility and cv-qualification revisited 
`_).
 
+- Alignment of members is now respected when evaluating layout compatibility
+  of structs.
+  (`CWG2583: Common initial sequence should consider over-alignment 
`_).
+
 - ``[[no_unique_address]]`` is now respected when evaluating layout
   compatibility of two types.
   (`CWG2759: [[no_unique_address] and common initial sequence  
`_).
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 3597f93a017136..5f607608cf7a53 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -19185,7 +19185,8 @@ static bool isLayoutCompatible(ASTContext &C, EnumDecl 
*ED1, EnumDecl *ED2) {
 
 /// Check if two fields are layout-compatible.
 static bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1,
-   FieldDecl *Field2) {
+   FieldDecl *Field2,
+   bool IgnoreAlignment = false) {
   if (!isLayoutCompatible(C, Field1->getType(), Field2->getType()))
 return false;
 
@@ -19204,6 +19205,10 @@ static bool isLayoutCompatible(ASTContext &C, 
FieldDecl *Field1,
   if (Field1->hasAttr() ||
   Field2->hasAttr())
 return false;
+
+  if (!IgnoreAlignment &&
+  Field1->getMaxAlignment() != Field2->getMaxAlignment())
+return false;
   return true;
 }
 
@@ -19265,7 +19270,7 @@ static bool isLayoutCompatibleUnion(ASTContext &C, 
RecordDecl *RD1,
 E = UnmatchedFields.end();
 
 for ( ; I != E; ++I) {
-  if (isLayoutCompatible(C, Field1, *I)) {
+  if (isLayoutCompatible(C, Field1, *I, /*IgnoreAlignment=*/true)) {
 bool Result = UnmatchedFields.erase(*I);
 (void) Result;
 assert(Result);
diff --git a/clang/test/CXX/drs/dr25xx.cpp b/clang/test/CXX/drs/dr25xx.cpp
index 9fc7cf59485caa..46532486e50e53 100644
--- a/clang/test/CXX/drs/dr25xx.cpp
+++ b/clang/test/CXX/drs/dr25xx.cpp
@@ -211,6 +211,32 @@ namespace dr2565 { // dr2565: 16 open 2023-06-07
 #endif
 }
 
+namespace dr2583 { // dr2583: 19
+#if __cplusplus >= 201103L
+struct A {
+  int i;
+  char c;
+};
+
+struct B {
+  int i;
+  alignas(8) char c;
+};
+
+union U {
+  A a;
+  B b;
+};
+
+union V {
+  A a;
+  alignas(64) B b;
+};
+
+static_assert(!__is_layout_compatible(A, B), "");
+static_assert(__is_layout_compatible(U, V), "");
+#endif
+} // namespace dr2583
 
 namespace dr2598 { // dr2598: 18
 #if __cplusplus >= 201103L
diff --git a/clang/test/SemaCXX/type-traits.cpp 
b/clang/test/SemaCXX/type-traits.cpp
index 23c339ebdf0826..831de2589dcb9e 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -1681,6 +1681,16 @@ union UnionLayout3 {
   [[no_unique_address]] CEmptyStruct d;
 };
 
+union UnionNoOveralignedMembers {
+  int a;
+  double b;
+};
+
+union UnionWithOveralignedMembers {
+  int a;
+  alignas(16) double b;
+};
+
 struct StructWithAnonUnion {
   union {
 int a;
@@ -1771,7 +1781,8 @@ void is_layout_compatible(int n)
   static_assert(__is_layout_compatible(CStruct, CStructNoUniqueAddress) != 
bool(__has_cpp_attribute(no_unique_address)), "");
   static_assert(__is_layout_compatible(CStructNoUniqueAddress, 
CStructNoUniqueAddress2) != bool(__has_cpp_attribute(no_unique_address)), "");
   static_assert(__is_layout_compatible(CStruct, CStructAlignment), "");
-  static_assert(__is_layout_compatible(CStruct, CStructAlignedMembers), ""); 
// FIXME: alignment of members impact common initial sequence
+  static_assert(!__is_layout_compatible(CStruct, CStructAlignedMembers), "");
+  static_assert(__is_layout_compatible(UnionNoOveralignedMembers, 
UnionWithOveralignedMembers), "");
   static_assert(__is_layout_compatible(CStructWithBitfelds, 
CStructWithBitfelds), "");
   static_assert(__is_l

[clang] [analyzer] Mention possibility of underflow in array overflow errors (PR #84201)

2024-03-07 Thread Balázs Kéri via cfe-commits


@@ -603,6 +611,8 @@ void ArrayBoundCheckerV2::performCheck(const Expr *E, 
CheckerContext &C) const {
 auto [WithinUpperBound, ExceedsUpperBound] =
 compareValueToThreshold(State, ByteOffset, *KnownSize, SVB);
 
+bool AssumedNonNegative = SUR.assumedNonNegative();

balazske wrote:

The name `AssumedNonNegative` looks misleading (in variable and function 
arguments too). This has meaning like `CanBeNegative` which is a better name 
for this.

https://github.com/llvm/llvm-project/pull/84201
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Respect field alignment when evaluating layout compatibility of structs (PR #84313)

2024-03-07 Thread Vlad Serebrennikov via cfe-commits

https://github.com/Endilll edited 
https://github.com/llvm/llvm-project/pull/84313
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Respect field alignment in layout compatibility of structs (PR #84313)

2024-03-07 Thread Vlad Serebrennikov via cfe-commits

https://github.com/Endilll edited 
https://github.com/llvm/llvm-project/pull/84313
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][nullability] Don't discard expression state before end of full-expression. (PR #82611)

2024-03-07 Thread via cfe-commits

https://github.com/martinboehme closed 
https://github.com/llvm/llvm-project/pull/82611
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] d5aecf0 - [clang][nullability] Don't discard expression state before end of full-expression. (#82611)

2024-03-07 Thread via cfe-commits

Author: martinboehme
Date: 2024-03-07T13:31:23+01:00
New Revision: d5aecf0c19fc8850d7d34ac8c339bcc7e133b5fb

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

LOG: [clang][nullability] Don't discard expression state before end of 
full-expression. (#82611)

In https://github.com/llvm/llvm-project/pull/72985, I made a change to
discard
expression state (`ExprToLoc` and `ExprToVal`) at the beginning of each
basic
block. I did so with the claim that "we never need to access entries
from these
maps outside of the current basic block", noting that there are
exceptions to
this claim when control flow happens inside a full-expression (the
operands of
`&&`, `||`, and the conditional operator live in different basic blocks
than the
operator itself) but that we already have a mechanism for retrieving the
values
of these operands from the environment for the block they are computed
in.

It turns out, however, that the operands of these operators aren't the
only
expressions whose values can be accessed from a different basic block;
when
control flow happens within a full-expression, that control flow can be
"interposed" between an expression and its parent. Here is an example:

```cxx
void f(int*, int);
bool cond();

void target() {
  int i = 0;
  f(&i, cond() ? 1 : 0);
}
```

([godbolt](https://godbolt.org/z/hrbj1Mj3o))

In the CFG[^1] , note how the expression for `&i` is computed in block
B4,
but the parent of this expression (the `CallExpr`) is located in block
B1.
The the argument expression `&i` and the `CallExpr` are essentially
"torn apart"
into different basic blocks by the conditional operator in the second
argument.
In other words, the edge between the `CallExpr` and its argument `&i`
straddles
the boundary between two blocks.

I used to think that this scenario -- where an edge between an
expression and
one of its children straddles a block boundary -- could only happen
between the
expression that triggers the control flow (`&&`, `||`, or the
conditional
operator) and its children, but the example above shows that other
expressions
can be affected as well; the control flow is still triggered by `&&`,
`||` or
the conditional operator, but the expressions affected lie outside these
operators.

Discarding expression state too soon is harmful. For example, an
analysis that
checks the arguments of the `CallExpr` above would not be able to
retrieve a
value for the `&i` argument.

This patch therefore ensures that we don't discard expression state
before the
end of a full-expression. In other cases -- when the evaluation of a
full-expression is complete -- we still want to discard expression state
for the
reasons explained in https://github.com/llvm/llvm-project/pull/72985
(avoid
performing joins on boolean values that are no longer needed, which
unnecessarily extends the flow condition; improve debuggability by
removing
clutter from the expression state).

The impact on performance from this change is about a 1% slowdown in the
Crubit nullability check benchmarks:

```
name  old cpu/op   new cpu/op   delta
BM_PointerAnalysisCopyPointer 71.9µs ± 1%  71.9µs ± 2%~ (p=0.987 
n=15+20)
BM_PointerAnalysisIntLoop  190µs ± 1%   192µs ± 2%  +1.06%  (p=0.000 
n=14+16)
BM_PointerAnalysisPointerLoop  325µs ± 5%   324µs ± 4%~ (p=0.496 
n=18+20)
BM_PointerAnalysisBranch   193µs ± 0%   192µs ± 4%~ (p=0.488 
n=14+18)
BM_PointerAnalysisLoopAndBranch521µs ± 1%   525µs ± 3%  +0.94%  (p=0.017 
n=18+19)
BM_PointerAnalysisTwoLoops 337µs ± 1%   341µs ± 3%  +1.19%  (p=0.004 
n=17+19)
BM_PointerAnalysisJoinFilePath1.62ms ± 2%  1.64ms ± 3%  +0.92%  (p=0.021 
n=20+20)
BM_PointerAnalysisCallInLoop  1.14ms ± 1%  1.15ms ± 4%~ (p=0.135 
n=16+18)
```

[^1]:
```
 [B5 (ENTRY)]
   Succs (1): B4

 [B1]
   1: [B4.9] ? [B2.1] : [B3.1]
   2: [B4.4]([B4.6], [B1.1])
   Preds (2): B2 B3
   Succs (1): B0

 [B2]
   1: 1
   Preds (1): B4
   Succs (1): B1

 [B3]
   1: 0
   Preds (1): B4
   Succs (1): B1

 [B4]
   1: 0
   2: int i = 0;
   3: f
   4: [B4.3] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int *, int))
   5: i
   6: &[B4.5]
   7: cond
   8: [B4.7] (ImplicitCastExpr, FunctionToPointerDecay, _Bool (*)(void))
   9: [B4.8]()
   T: [B4.9] ? ... : ...
   Preds (1): B5
   Succs (2): B2 B3

 [B0 (EXIT)]
   Preds (1): B1
```

Added: 


Modified: 
clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTes

[clang] [Clang][Sema] Allow access to a public template alias declaration that refers to friend's private nested type (PR #83847)

2024-03-07 Thread Qizhi Hu via cfe-commits

https://github.com/jcsxky updated 
https://github.com/llvm/llvm-project/pull/83847

>From 2bb165ac6264b36f72716cb35ed2e1b4f72f3eaa Mon Sep 17 00:00:00 2001
From: huqizhi 
Date: Mon, 4 Mar 2024 21:51:07 +0800
Subject: [PATCH] [Clang][Sema] Allow access to a public template alias
 declaration that refers to friend's private nested type

---
 clang/docs/ReleaseNotes.rst |  3 +++
 clang/lib/Sema/SemaAccess.cpp   |  9 +
 clang/test/SemaTemplate/PR25708.cpp | 23 +++
 3 files changed, 35 insertions(+)
 create mode 100644 clang/test/SemaTemplate/PR25708.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 1b901a27fd19d1..38cbe421fd485c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -241,6 +241,9 @@ Bug Fixes in This Version
   for variables created through copy initialization having side-effects in 
C++17 and later.
   Fixes (#GH64356) (#GH79518).
 
+- Allow access to a public template alias declaration that refers to friend's
+  private nested type (`#25708 
`).
+
 Bug Fixes to Compiler Builtins
 ^^
 
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index 4af3c0f30a8e8a..0c8d15210f439c 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -1481,6 +1481,15 @@ static Sema::AccessResult CheckAccess(Sema &S, 
SourceLocation Loc,
   }
 
   EffectiveContext EC(S.CurContext);
+  if (!S.CodeSynthesisContexts.empty()) {
+auto &Active = S.CodeSynthesisContexts.back();
+if (Active.Kind == Sema::CodeSynthesisContext::TemplateInstantiation &&
+Active.Entity)
+  if (auto *RD =
+  dyn_cast_or_null(Active.Entity->getDeclContext()))
+EC.Records.push_back(RD);
+  }
+
   switch (CheckEffectiveAccess(S, EC, Loc, Entity)) {
   case AR_accessible: return Sema::AR_accessible;
   case AR_inaccessible: return Sema::AR_inaccessible;
diff --git a/clang/test/SemaTemplate/PR25708.cpp 
b/clang/test/SemaTemplate/PR25708.cpp
new file mode 100644
index 00..cc2e7551a6abaa
--- /dev/null
+++ b/clang/test/SemaTemplate/PR25708.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+// RUN: %clang_cc1 -std=c++14 -verify %s
+// RUN: %clang_cc1 -std=c++17 -verify %s
+// RUN: %clang_cc1 -std=c++20 -verify %s
+// expected-no-diagnostics
+
+struct FooAccessor
+{
+template 
+using Foo = typename T::Foo;
+};
+
+class Type
+{
+friend struct FooAccessor;
+
+using Foo = int;
+};
+
+int main()
+{
+FooAccessor::Foo t;
+}

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


[clang] [analyzer] Mention possibility of underflow in array overflow errors (PR #84201)

2024-03-07 Thread via cfe-commits


@@ -603,6 +611,8 @@ void ArrayBoundCheckerV2::performCheck(const Expr *E, 
CheckerContext &C) const {
 auto [WithinUpperBound, ExceedsUpperBound] =
 compareValueToThreshold(State, ByteOffset, *KnownSize, SVB);
 
+bool AssumedNonNegative = SUR.assumedNonNegative();

NagyDonat wrote:

I see your point, but `CanBeNegative` is also somewhat incorrect here because 
at this point (in the most recent `State`) the value of the symbol cannot be 
negative. I think I'll use something like `AlsoMentionUnderflow` with a comment 
that explains its meaning.

https://github.com/llvm/llvm-project/pull/84201
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Respect field alignment in layout compatibility of structs (PR #84313)

2024-03-07 Thread via cfe-commits

https://github.com/cor3ntin edited 
https://github.com/llvm/llvm-project/pull/84313
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Respect field alignment in layout compatibility of structs (PR #84313)

2024-03-07 Thread via cfe-commits

https://github.com/cor3ntin commented:

I only have a comment otherwise LGTM

https://github.com/llvm/llvm-project/pull/84313
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] Respect field alignment in layout compatibility of structs (PR #84313)

2024-03-07 Thread via cfe-commits


@@ -19185,7 +19185,8 @@ static bool isLayoutCompatible(ASTContext &C, EnumDecl 
*ED1, EnumDecl *ED2) {
 
 /// Check if two fields are layout-compatible.
 static bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1,
-   FieldDecl *Field2) {
+   FieldDecl *Field2,
+   bool IgnoreAlignment = false) {

cor3ntin wrote:

I think I would prefer calling that `IsUnionMember` or something like that (and 
reverse the condition everywhere)

https://github.com/llvm/llvm-project/pull/84313
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


  1   2   3   4   5   >