[PATCH] D158842: [include-cleaner] Handle decls/refs to concepts.

2023-08-31 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 closed this revision.
usaxena95 added a comment.

closed by ac2d2652db8de9ea2b750dd2bf1232941039dffe 



Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158842

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


[PATCH] D158842: [include-cleaner] Handle decls/refs to concepts.

2023-08-31 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 554962.
usaxena95 marked 2 inline comments as done.
usaxena95 added a comment.

Addressed comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158842

Files:
  clang-tools-extra/include-cleaner/lib/WalkAST.cpp
  clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp


Index: clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
===
--- clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
+++ clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
@@ -528,5 +528,16 @@
const char* s = "";
auto sx = ^{s};)cpp");
 }
+
+TEST(WalkAST, Concepts) {
+  std::string Concept = "template concept $explicit^Foo = true;";
+  testWalk(Concept, "templateconcept Bar = ^Foo && true;");
+  testWalk(Concept, "template<^Foo T>void func() {}");
+  testWalk(Concept, "template requires ^Foo void func() {}");
+  testWalk(Concept, "template void func() requires ^Foo {}");
+  testWalk(Concept, "void func(^Foo auto x) {}");
+  // FIXME: Foo should be explicitly referenced.
+  testWalk("template concept Foo = true;", "void func() { ^Foo 
auto x = 1; }");
+}
 } // namespace
 } // namespace clang::include_cleaner
Index: clang-tools-extra/include-cleaner/lib/WalkAST.cpp
===
--- clang-tools-extra/include-cleaner/lib/WalkAST.cpp
+++ clang-tools-extra/include-cleaner/lib/WalkAST.cpp
@@ -241,6 +241,11 @@
 return true;
   }
 
+  bool VisitConceptReference(const ConceptReference *CR) {
+report(CR->getConceptNameLoc(), CR->getFoundDecl());
+return true;
+  }
+
   // Report a reference from explicit specializations to the specialized
   // template. Implicit ones are filtered out by RAV and explicit 
instantiations
   // are already traversed through typelocs.


Index: clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
===
--- clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
+++ clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
@@ -528,5 +528,16 @@
const char* s = "";
auto sx = ^{s};)cpp");
 }
+
+TEST(WalkAST, Concepts) {
+  std::string Concept = "template concept $explicit^Foo = true;";
+  testWalk(Concept, "templateconcept Bar = ^Foo && true;");
+  testWalk(Concept, "template<^Foo T>void func() {}");
+  testWalk(Concept, "template requires ^Foo void func() {}");
+  testWalk(Concept, "template void func() requires ^Foo {}");
+  testWalk(Concept, "void func(^Foo auto x) {}");
+  // FIXME: Foo should be explicitly referenced.
+  testWalk("template concept Foo = true;", "void func() { ^Foo auto x = 1; }");
+}
 } // namespace
 } // namespace clang::include_cleaner
Index: clang-tools-extra/include-cleaner/lib/WalkAST.cpp
===
--- clang-tools-extra/include-cleaner/lib/WalkAST.cpp
+++ clang-tools-extra/include-cleaner/lib/WalkAST.cpp
@@ -241,6 +241,11 @@
 return true;
   }
 
+  bool VisitConceptReference(const ConceptReference *CR) {
+report(CR->getConceptNameLoc(), CR->getFoundDecl());
+return true;
+  }
+
   // Report a reference from explicit specializations to the specialized
   // template. Implicit ones are filtered out by RAV and explicit instantiations
   // are already traversed through typelocs.
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158842: [include-cleaner] Handle decls/refs to concepts.

2023-08-31 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 added inline comments.



Comment at: clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp:217
+void $2^func2() requires $Bar4^Bar {}
+  )cpp");
+  Inputs.Code = Code.code();

sammccall wrote:
> to complete the set I think you want
> 
> `void foo(Bar auto x)` (abbreviated template param) and `Bar auto x = 1` 
> (deduced type).
> 
> Though these may not pass yet
For some reason, `Bar auto x = 1` is still failing; investigating.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158842

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


[PATCH] D158842: [include-cleaner] Handle decls/refs to concepts.

2023-08-31 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 554955.
usaxena95 marked 2 inline comments as done.
usaxena95 added a comment.

Rebased over AST changes.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158842

Files:
  clang-tools-extra/include-cleaner/lib/WalkAST.cpp
  clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp


Index: clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
===
--- clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
+++ clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
@@ -198,6 +198,55 @@
   Pair(Code.point("4"), UnorderedElementsAre(MainFile;
 }
 
+TEST_F(WalkUsedTest, Concepts) {
+  llvm::Annotations ConceptHdr(guard(R"cpp(
+template
+concept Foo = true;
+  )cpp"));
+  llvm::Annotations Code(R"cpp(
+#include "concept.h"
+
+template
+concept $Bar1^Bar = $Foo1^Foo && true;
+
+template<$Bar2^Bar T> requires $Bar3^Bar && $Foo2^Foo
+void $1^func1() {}
+
+template<$Foo3^Foo T>
+void $2^func2() requires $Bar4^Bar {}
+
+void $3^func3($Bar5^Bar auto x) {
+  $Foo4^Foo auto $y^y = 1;
+}
+  )cpp");
+  Inputs.Code = Code.code();
+  Inputs.ExtraFiles["concept.h"] = ConceptHdr.code();
+  Inputs.ExtraArgs.push_back("--std=c++20");
+  TestAST AST(Inputs);
+  auto  = AST.sourceManager();
+  const auto *ConceptHdrFile = SM.getFileManager().getFile("concept.h").get();
+  auto MainFile = Header(SM.getFileEntryForID(SM.getMainFileID()));
+
+  EXPECT_THAT(
+  offsetToProviders(AST),
+  UnorderedElementsAre(
+  Pair(Code.point("Foo1"), UnorderedElementsAre(ConceptHdrFile)),
+  Pair(Code.point("Foo2"), UnorderedElementsAre(ConceptHdrFile)),
+  Pair(Code.point("Foo3"), UnorderedElementsAre(ConceptHdrFile)),
+  Pair(Code.point("Bar1"), UnorderedElementsAre(MainFile)),
+  Pair(Code.point("Bar2"), UnorderedElementsAre(MainFile)),
+  Pair(Code.point("Bar3"), UnorderedElementsAre(MainFile)),
+  Pair(Code.point("Bar4"), UnorderedElementsAre(MainFile)),
+  Pair(Code.point("Bar5"), UnorderedElementsAre(MainFile)),
+  // FIXME: Foo4 should be reported.
+  // Pair(Code.point("Foo4"), UnorderedElementsAre(ConceptHdrFile)),
+  Pair(Code.point("1"), UnorderedElementsAre(MainFile)),
+  Pair(Code.point("2"), UnorderedElementsAre(MainFile)),
+  Pair(Code.point("3"), UnorderedElementsAre(MainFile)),
+  Pair(Code.point("y"), UnorderedElementsAre(MainFile
+  << Code.code();
+}
+
 class AnalyzeTest : public testing::Test {
 protected:
   TestInputs Inputs;
@@ -299,7 +348,7 @@
   Results.Unused.push_back(Inc.atLine(4));
 
   EXPECT_EQ(fixIncludes(Results, "d.cc", Code, format::getLLVMStyle()),
-R"cpp(#include "d.h"
+R"cpp(#include "d.h"
 #include "a.h"
 #include "aa.h"
 #include "ab.h"
@@ -310,7 +359,7 @@
   Results.Missing.push_back("\"d.h\"");
   Code = R"cpp(#include "a.h")cpp";
   EXPECT_EQ(fixIncludes(Results, "d.cc", Code, format::getLLVMStyle()),
-R"cpp(#include "d.h"
+R"cpp(#include "d.h"
 #include "a.h")cpp");
 }
 
Index: clang-tools-extra/include-cleaner/lib/WalkAST.cpp
===
--- clang-tools-extra/include-cleaner/lib/WalkAST.cpp
+++ clang-tools-extra/include-cleaner/lib/WalkAST.cpp
@@ -241,6 +241,16 @@
 return true;
   }
 
+  bool VisitConceptDecl(ConceptDecl *CD) {
+report(CD->getLocation(), CD);
+return true;
+  }
+
+  bool VisitConceptReference(const ConceptReference *CR) {
+report(CR->getConceptNameLoc(), CR->getFoundDecl());
+return true;
+  }
+
   // Report a reference from explicit specializations to the specialized
   // template. Implicit ones are filtered out by RAV and explicit 
instantiations
   // are already traversed through typelocs.


Index: clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
===
--- clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
+++ clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
@@ -198,6 +198,55 @@
   Pair(Code.point("4"), UnorderedElementsAre(MainFile;
 }
 
+TEST_F(WalkUsedTest, Concepts) {
+  llvm::Annotations ConceptHdr(guard(R"cpp(
+template
+concept Foo = true;
+  )cpp"));
+  llvm::Annotations Code(R"cpp(
+#include "concept.h"
+
+template
+concept $Bar1^Bar = $Foo1^Foo && true;
+
+template<$Bar2^Bar T> requires $Bar3^Bar && $Foo2^Foo
+void $1^func1() {}
+
+template<$Foo3^Foo T>
+void $2^func2() requires $Bar4^Bar {}
+
+void $3^func3($Bar5^Bar auto x) {
+  $Foo4^Foo auto $y^y = 1;
+}
+  )cpp");
+  Inputs.Code = Code.code();
+  Inputs.ExtraFiles["concept.h"] = ConceptHdr.code();
+  Inputs.ExtraArgs.push_back("--std=c++20");
+  TestAST AST(Inputs);
+  

[PATCH] D158842: [include-cleaner] Handle decls/refs to concepts.

2023-08-25 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 created this revision.
usaxena95 added reviewers: massberg, sammccall.
Herald added a subscriber: kadircet.
Herald added a project: All.
usaxena95 requested review of this revision.
Herald added projects: clang, clang-tools-extra.
Herald added a subscriber: cfe-commits.

This is similar to D155858  and is probably 
more suited to be a followup to it.

Happy to wait if the mentioned revision is ready to land soon. Otherwise we 
could land this first and fix the include-cleaner bug.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D158842

Files:
  clang-tools-extra/include-cleaner/lib/WalkAST.cpp
  clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
  clang/include/clang/AST/RecursiveASTVisitor.h

Index: clang/include/clang/AST/RecursiveASTVisitor.h
===
--- clang/include/clang/AST/RecursiveASTVisitor.h
+++ clang/include/clang/AST/RecursiveASTVisitor.h
@@ -463,15 +463,13 @@
   bool TraverseConceptTypeRequirement(concepts::TypeRequirement *R);
   bool TraverseConceptExprRequirement(concepts::ExprRequirement *R);
   bool TraverseConceptNestedRequirement(concepts::NestedRequirement *R);
+  bool TraverseConceptReference(const ConceptReference );
 
   bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue);
 
 private:
   // These are helper methods used by more than one Traverse* method.
   bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL);
-  /// Traverses the qualifier, name and template arguments of a concept
-  /// reference.
-  bool TraverseConceptReferenceHelper(const ConceptReference );
 
   // Traverses template parameter lists of either a DeclaratorDecl or TagDecl.
   template 
@@ -507,7 +505,7 @@
 bool RecursiveASTVisitor::TraverseTypeConstraint(
 const TypeConstraint *C) {
   if (!getDerived().shouldVisitImplicitCode()) {
-TRY_TO(TraverseConceptReferenceHelper(*C));
+TRY_TO(TraverseConceptReference(*C));
 return true;
   }
   if (Expr *IDC = C->getImmediatelyDeclaredConstraint()) {
@@ -517,7 +515,7 @@
 // if we have an immediately-declared-constraint, otherwise
 // we'll end up visiting the concept and the arguments in
 // the TC twice.
-TRY_TO(TraverseConceptReferenceHelper(*C));
+TRY_TO(TraverseConceptReference(*C));
   }
   return true;
 }
@@ -541,7 +539,7 @@
 }
 
 template 
-bool RecursiveASTVisitor::TraverseConceptReferenceHelper(
+bool RecursiveASTVisitor::TraverseConceptReference(
 const ConceptReference ) {
   TRY_TO(TraverseNestedNameSpecifierLoc(C.getNestedNameSpecifierLoc()));
   TRY_TO(TraverseDeclarationNameInfo(C.getConceptNameInfo()));
@@ -2904,7 +2902,7 @@
 })
 
 DEF_TRAVERSE_STMT(ConceptSpecializationExpr,
-  { TRY_TO(TraverseConceptReferenceHelper(*S)); })
+  { TRY_TO(TraverseConceptReference(*S)); })
 
 DEF_TRAVERSE_STMT(RequiresExpr, {
   TRY_TO(TraverseDecl(S->getBody()));
Index: clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
===
--- clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
+++ clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
@@ -198,6 +198,45 @@
   Pair(Code.point("4"), UnorderedElementsAre(MainFile;
 }
 
+TEST_F(WalkUsedTest, Concepts) {
+  llvm::Annotations ConceptHdr(guard(R"cpp(
+template
+concept Foo = true;
+  )cpp"));
+  llvm::Annotations Code(R"cpp(
+#include "concept.h"
+
+template
+concept $Bar1^Bar = $Foo1^Foo && true;
+
+template<$Bar2^Bar T> requires $Bar3^Bar && $Foo2^Foo
+void $1^func1() {}
+
+template<$Foo3^Foo T>
+void $2^func2() requires $Bar4^Bar {}
+  )cpp");
+  Inputs.Code = Code.code();
+  Inputs.ExtraFiles["concept.h"] = ConceptHdr.code();
+  Inputs.ExtraArgs.push_back("--std=c++20");
+  TestAST AST(Inputs);
+  auto  = AST.sourceManager();
+  const auto *ConceptHdrFile = SM.getFileManager().getFile("concept.h").get();
+  auto MainFile = Header(SM.getFileEntryForID(SM.getMainFileID()));
+
+  EXPECT_THAT(
+  offsetToProviders(AST),
+  UnorderedElementsAre(
+  Pair(Code.point("Foo1"), UnorderedElementsAre(ConceptHdrFile)),
+  Pair(Code.point("Foo2"), UnorderedElementsAre(ConceptHdrFile)),
+  Pair(Code.point("Foo3"), UnorderedElementsAre(ConceptHdrFile)),
+  Pair(Code.point("Bar1"), UnorderedElementsAre(MainFile)),
+  Pair(Code.point("Bar2"), UnorderedElementsAre(MainFile)),
+  Pair(Code.point("Bar3"), UnorderedElementsAre(MainFile)),
+  Pair(Code.point("Bar4"), UnorderedElementsAre(MainFile)),
+  Pair(Code.point("1"), UnorderedElementsAre(MainFile)),
+  Pair(Code.point("2"), UnorderedElementsAre(MainFile;
+}
+
 class AnalyzeTest : public testing::Test {
 protected:
   TestInputs Inputs;
@@ -299,7 +338,7 @@
   Results.Unused.push_back(Inc.atLine(4));
 
   EXPECT_EQ(fixIncludes(Results, "d.cc", Code, 

[PATCH] D155898: [clangd] Fix go-to-type target location

2023-07-21 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 accepted this revision.
usaxena95 added inline comments.
This revision is now accepted and ready to land.



Comment at: clang-tools-extra/clangd/XRefs.cpp:347
+void enhanceLocatedSymbolsFromIndex(
+llvm::MutableArrayRef Result,
+const llvm::DenseMap ,

nit: ResultIndex looks like an implementation detail of this function and the 
callers do not need it. SymbolID is already present as LocatedSymbol::ID so we 
can compute this map in this function itself.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155898

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


[PATCH] D155614: [clangd] Make an include always refer to itself. Background: clang-review expects all referents to have definition, declaration or reference(s).

2023-07-18 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 added inline comments.



Comment at: clang-tools-extra/clangd/XRefs.cpp:1361-1362
   });
-  if (Results.References.empty())
-return std::nullopt;
-

Sorry for the confusion. This looks intentional and somewhat valuable for 
unused headers. We could fix this on clang-review's end as discussed on the 
internal patch. We should also add a comment here explaining the rationale 
behind returning no refs in such cases.

(The check below certainly looks redundant though and could be removed).


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155614

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


[PATCH] D148213: [clangd] Use FileEntryRef for canonicalizing filepaths.

2023-04-13 Thread Utkarsh Saxena via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGed365f464a0a: [clangd] Use FileEntryRef for canonicalizing 
filepaths. (authored by usaxena95).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D148213

Files:
  clang-tools-extra/clangd/Diagnostics.cpp
  clang-tools-extra/clangd/IncludeCleaner.cpp
  clang-tools-extra/clangd/SourceCode.cpp
  clang-tools-extra/clangd/SourceCode.h
  clang-tools-extra/clangd/XRefs.cpp
  clang-tools-extra/clangd/index/Background.cpp
  clang-tools-extra/clangd/index/SymbolCollector.cpp
  clang-tools-extra/clangd/indexer/IndexerMain.cpp
  clang-tools-extra/clangd/refactor/Tweak.cpp

Index: clang-tools-extra/clangd/refactor/Tweak.cpp
===
--- clang-tools-extra/clangd/refactor/Tweak.cpp
+++ clang-tools-extra/clangd/refactor/Tweak.cpp
@@ -104,8 +104,9 @@
 Tweak::Effect::fileEdit(const SourceManager , FileID FID,
 tooling::Replacements Replacements) {
   Edit Ed(SM.getBufferData(FID), std::move(Replacements));
-  if (auto FilePath = getCanonicalPath(SM.getFileEntryForID(FID), SM))
-return std::make_pair(*FilePath, std::move(Ed));
+  if (const auto FE = SM.getFileEntryRefForID(FID))
+if (auto FilePath = getCanonicalPath(*FE, SM))
+  return std::make_pair(*FilePath, std::move(Ed));
   return error("Failed to get absolute path for edited file: {0}",
SM.getFileEntryRefForID(FID)->getName());
 }
Index: clang-tools-extra/clangd/indexer/IndexerMain.cpp
===
--- clang-tools-extra/clangd/indexer/IndexerMain.cpp
+++ clang-tools-extra/clangd/indexer/IndexerMain.cpp
@@ -46,10 +46,10 @@
 SymbolCollector::Options Opts;
 Opts.CountReferences = true;
 Opts.FileFilter = [&](const SourceManager , FileID FID) {
-  const auto *F = SM.getFileEntryForID(FID);
+  const auto F = SM.getFileEntryRefForID(FID);
   if (!F)
 return false; // Skip invalid files.
-  auto AbsPath = getCanonicalPath(F, SM);
+  auto AbsPath = getCanonicalPath(*F, SM);
   if (!AbsPath)
 return false; // Skip files without absolute path.
   std::lock_guard Lock(FilesMu);
Index: clang-tools-extra/clangd/index/SymbolCollector.cpp
===
--- clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -205,11 +205,11 @@
 
   // Returns a canonical URI for the file \p FE.
   // We attempt to make the path absolute first.
-  const std::string (const FileEntry *FE) {
+  const std::string (const FileEntryRef FE) {
 auto R = CacheFEToURI.try_emplace(FE);
 if (R.second) {
   auto CanonPath = getCanonicalPath(FE, SM);
-  R.first->second = (CanonPath ? *CanonPath : FE->getName());
+  R.first->second = (CanonPath ? *CanonPath : FE.getName());
 }
 return *R.first->second;
   }
@@ -218,7 +218,7 @@
   // If the file is in the FileManager, use that to canonicalize the path.
   // We attempt to make the path absolute in any case.
   const std::string (llvm::StringRef Path) {
-if (auto File = SM.getFileManager().getFile(Path))
+if (auto File = SM.getFileManager().getFileRef(Path))
   return toURI(*File);
 return toURIInternal(Path);
   }
@@ -373,7 +373,7 @@
   }
 
   llvm::StringRef getIncludeHeaderUncached(FileID FID) {
-const FileEntry *FE = SM.getFileEntryForID(FID);
+const auto FE = SM.getFileEntryRefForID(FID);
 if (!FE || FE->getName().empty())
   return "";
 llvm::StringRef Filename = FE->getName();
@@ -392,13 +392,13 @@
 // Framework headers are spelled as , not
 // "path/FrameworkName.framework/Headers/Foo.h".
 auto  = PP->getHeaderSearchInfo();
-if (const auto *HFI = HS.getExistingFileInfo(FE, /*WantExternal*/ false))
+if (const auto *HFI = HS.getExistingFileInfo(*FE, /*WantExternal*/ false))
   if (!HFI->Framework.empty())
 if (auto Spelling =
-getFrameworkHeaderIncludeSpelling(FE, HFI->Framework, HS))
+getFrameworkHeaderIncludeSpelling(*FE, HFI->Framework, HS))
   return *Spelling;
 
-if (!tooling::isSelfContainedHeader(FE, PP->getSourceManager(),
+if (!tooling::isSelfContainedHeader(*FE, PP->getSourceManager(),
 PP->getHeaderSearchInfo())) {
   // A .inc or .def file is often included into a real header to define
   // symbols (e.g. LLVM tablegen files).
@@ -409,7 +409,7 @@
   return "";
 }
 // Standard case: just insert the file itself.
-return toURI(FE);
+return toURI(*FE);
   }
 };
 
@@ -417,12 +417,12 @@
 std::optional
 SymbolCollector::getTokenLocation(SourceLocation TokLoc) {
   const auto  = ASTCtx->getSourceManager();
-  auto *FE = 

[PATCH] D148213: [clangd] Use FileEntryRef for canonicalizing filepaths.

2023-04-13 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 513219.
usaxena95 marked 6 inline comments as done.
usaxena95 added a comment.

Addressed comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D148213

Files:
  clang-tools-extra/clangd/Diagnostics.cpp
  clang-tools-extra/clangd/IncludeCleaner.cpp
  clang-tools-extra/clangd/SourceCode.cpp
  clang-tools-extra/clangd/SourceCode.h
  clang-tools-extra/clangd/XRefs.cpp
  clang-tools-extra/clangd/index/Background.cpp
  clang-tools-extra/clangd/index/SymbolCollector.cpp
  clang-tools-extra/clangd/indexer/IndexerMain.cpp
  clang-tools-extra/clangd/refactor/Tweak.cpp

Index: clang-tools-extra/clangd/refactor/Tweak.cpp
===
--- clang-tools-extra/clangd/refactor/Tweak.cpp
+++ clang-tools-extra/clangd/refactor/Tweak.cpp
@@ -104,8 +104,9 @@
 Tweak::Effect::fileEdit(const SourceManager , FileID FID,
 tooling::Replacements Replacements) {
   Edit Ed(SM.getBufferData(FID), std::move(Replacements));
-  if (auto FilePath = getCanonicalPath(SM.getFileEntryForID(FID), SM))
-return std::make_pair(*FilePath, std::move(Ed));
+  if (const auto FE = SM.getFileEntryRefForID(FID))
+if (auto FilePath = getCanonicalPath(*FE, SM))
+  return std::make_pair(*FilePath, std::move(Ed));
   return error("Failed to get absolute path for edited file: {0}",
SM.getFileEntryRefForID(FID)->getName());
 }
Index: clang-tools-extra/clangd/indexer/IndexerMain.cpp
===
--- clang-tools-extra/clangd/indexer/IndexerMain.cpp
+++ clang-tools-extra/clangd/indexer/IndexerMain.cpp
@@ -46,10 +46,10 @@
 SymbolCollector::Options Opts;
 Opts.CountReferences = true;
 Opts.FileFilter = [&](const SourceManager , FileID FID) {
-  const auto *F = SM.getFileEntryForID(FID);
+  const auto F = SM.getFileEntryRefForID(FID);
   if (!F)
 return false; // Skip invalid files.
-  auto AbsPath = getCanonicalPath(F, SM);
+  auto AbsPath = getCanonicalPath(*F, SM);
   if (!AbsPath)
 return false; // Skip files without absolute path.
   std::lock_guard Lock(FilesMu);
Index: clang-tools-extra/clangd/index/SymbolCollector.cpp
===
--- clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -205,11 +205,11 @@
 
   // Returns a canonical URI for the file \p FE.
   // We attempt to make the path absolute first.
-  const std::string (const FileEntry *FE) {
+  const std::string (const FileEntryRef FE) {
 auto R = CacheFEToURI.try_emplace(FE);
 if (R.second) {
   auto CanonPath = getCanonicalPath(FE, SM);
-  R.first->second = (CanonPath ? *CanonPath : FE->getName());
+  R.first->second = (CanonPath ? *CanonPath : FE.getName());
 }
 return *R.first->second;
   }
@@ -218,7 +218,7 @@
   // If the file is in the FileManager, use that to canonicalize the path.
   // We attempt to make the path absolute in any case.
   const std::string (llvm::StringRef Path) {
-if (auto File = SM.getFileManager().getFile(Path))
+if (auto File = SM.getFileManager().getFileRef(Path))
   return toURI(*File);
 return toURIInternal(Path);
   }
@@ -373,7 +373,7 @@
   }
 
   llvm::StringRef getIncludeHeaderUncached(FileID FID) {
-const FileEntry *FE = SM.getFileEntryForID(FID);
+const auto FE = SM.getFileEntryRefForID(FID);
 if (!FE || FE->getName().empty())
   return "";
 llvm::StringRef Filename = FE->getName();
@@ -392,13 +392,13 @@
 // Framework headers are spelled as , not
 // "path/FrameworkName.framework/Headers/Foo.h".
 auto  = PP->getHeaderSearchInfo();
-if (const auto *HFI = HS.getExistingFileInfo(FE, /*WantExternal*/ false))
+if (const auto *HFI = HS.getExistingFileInfo(*FE, /*WantExternal*/ false))
   if (!HFI->Framework.empty())
 if (auto Spelling =
-getFrameworkHeaderIncludeSpelling(FE, HFI->Framework, HS))
+getFrameworkHeaderIncludeSpelling(*FE, HFI->Framework, HS))
   return *Spelling;
 
-if (!tooling::isSelfContainedHeader(FE, PP->getSourceManager(),
+if (!tooling::isSelfContainedHeader(*FE, PP->getSourceManager(),
 PP->getHeaderSearchInfo())) {
   // A .inc or .def file is often included into a real header to define
   // symbols (e.g. LLVM tablegen files).
@@ -409,7 +409,7 @@
   return "";
 }
 // Standard case: just insert the file itself.
-return toURI(FE);
+return toURI(*FE);
   }
 };
 
@@ -417,12 +417,12 @@
 std::optional
 SymbolCollector::getTokenLocation(SourceLocation TokLoc) {
   const auto  = ASTCtx->getSourceManager();
-  auto *FE = SM.getFileEntryForID(SM.getFileID(TokLoc));
+  const auto FE = 

[PATCH] D148213: [clangd] Use FileEntryRef for canonicalizing filepaths.

2023-04-13 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 513168.
usaxena95 added a comment.

Rebase


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D148213

Files:
  clang-tools-extra/clangd/Diagnostics.cpp
  clang-tools-extra/clangd/SourceCode.cpp
  clang-tools-extra/clangd/SourceCode.h
  clang-tools-extra/clangd/XRefs.cpp
  clang-tools-extra/clangd/index/Background.cpp
  clang-tools-extra/clangd/index/SymbolCollector.cpp
  clang-tools-extra/clangd/indexer/IndexerMain.cpp
  clang-tools-extra/clangd/refactor/Tweak.cpp

Index: clang-tools-extra/clangd/refactor/Tweak.cpp
===
--- clang-tools-extra/clangd/refactor/Tweak.cpp
+++ clang-tools-extra/clangd/refactor/Tweak.cpp
@@ -104,8 +104,9 @@
 Tweak::Effect::fileEdit(const SourceManager , FileID FID,
 tooling::Replacements Replacements) {
   Edit Ed(SM.getBufferData(FID), std::move(Replacements));
-  if (auto FilePath = getCanonicalPath(SM.getFileEntryForID(FID), SM))
-return std::make_pair(*FilePath, std::move(Ed));
+  if (const auto FE = SM.getFileEntryRefForID(FID))
+if (auto FilePath = getCanonicalPath(*FE, SM))
+  return std::make_pair(*FilePath, std::move(Ed));
   return error("Failed to get absolute path for edited file: {0}",
SM.getFileEntryRefForID(FID)->getName());
 }
Index: clang-tools-extra/clangd/indexer/IndexerMain.cpp
===
--- clang-tools-extra/clangd/indexer/IndexerMain.cpp
+++ clang-tools-extra/clangd/indexer/IndexerMain.cpp
@@ -46,10 +46,10 @@
 SymbolCollector::Options Opts;
 Opts.CountReferences = true;
 Opts.FileFilter = [&](const SourceManager , FileID FID) {
-  const auto *F = SM.getFileEntryForID(FID);
+  const auto F = SM.getFileEntryRefForID(FID);
   if (!F)
 return false; // Skip invalid files.
-  auto AbsPath = getCanonicalPath(F, SM);
+  auto AbsPath = getCanonicalPath(*F, SM);
   if (!AbsPath)
 return false; // Skip files without absolute path.
   std::lock_guard Lock(FilesMu);
Index: clang-tools-extra/clangd/index/SymbolCollector.cpp
===
--- clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -205,11 +205,11 @@
 
   // Returns a canonical URI for the file \p FE.
   // We attempt to make the path absolute first.
-  const std::string (const FileEntry *FE) {
+  const std::string (const FileEntryRef ) {
 auto R = CacheFEToURI.try_emplace(FE);
 if (R.second) {
   auto CanonPath = getCanonicalPath(FE, SM);
-  R.first->second = (CanonPath ? *CanonPath : FE->getName());
+  R.first->second = (CanonPath ? *CanonPath : FE.getName());
 }
 return *R.first->second;
   }
@@ -218,7 +218,7 @@
   // If the file is in the FileManager, use that to canonicalize the path.
   // We attempt to make the path absolute in any case.
   const std::string (llvm::StringRef Path) {
-if (auto File = SM.getFileManager().getFile(Path))
+if (auto File = SM.getFileManager().getFileRef(Path))
   return toURI(*File);
 return toURIInternal(Path);
   }
@@ -373,7 +373,7 @@
   }
 
   llvm::StringRef getIncludeHeaderUncached(FileID FID) {
-const FileEntry *FE = SM.getFileEntryForID(FID);
+const auto FE = SM.getFileEntryRefForID(FID);
 if (!FE || FE->getName().empty())
   return "";
 llvm::StringRef Filename = FE->getName();
@@ -392,13 +392,15 @@
 // Framework headers are spelled as , not
 // "path/FrameworkName.framework/Headers/Foo.h".
 auto  = PP->getHeaderSearchInfo();
-if (const auto *HFI = HS.getExistingFileInfo(FE, /*WantExternal*/ false))
+if (const auto *HFI = HS.getExistingFileInfo(>getFileEntry(),
+ /*WantExternal*/ false))
   if (!HFI->Framework.empty())
-if (auto Spelling =
-getFrameworkHeaderIncludeSpelling(FE, HFI->Framework, HS))
+if (auto Spelling = getFrameworkHeaderIncludeSpelling(
+>getFileEntry(), HFI->Framework, HS))
   return *Spelling;
 
-if (!tooling::isSelfContainedHeader(FE, PP->getSourceManager(),
+if (!tooling::isSelfContainedHeader(>getFileEntry(),
+PP->getSourceManager(),
 PP->getHeaderSearchInfo())) {
   // A .inc or .def file is often included into a real header to define
   // symbols (e.g. LLVM tablegen files).
@@ -409,7 +411,7 @@
   return "";
 }
 // Standard case: just insert the file itself.
-return toURI(FE);
+return toURI(*FE);
   }
 };
 
@@ -417,12 +419,12 @@
 std::optional
 SymbolCollector::getTokenLocation(SourceLocation TokLoc) {
   const auto  = ASTCtx->getSourceManager();
-  auto *FE = 

[PATCH] D148213: [clangd] Use FileEntryRef for canonicalizing filepaths.

2023-04-13 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 513165.
usaxena95 added a comment.

More refactorings.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D148213

Files:
  clang-tools-extra/clangd/Diagnostics.cpp
  clang-tools-extra/clangd/IncludeCleaner.cpp
  clang-tools-extra/clangd/SourceCode.cpp
  clang-tools-extra/clangd/SourceCode.h
  clang-tools-extra/clangd/XRefs.cpp
  clang-tools-extra/clangd/index/Background.cpp
  clang-tools-extra/clangd/index/SymbolCollector.cpp
  clang-tools-extra/clangd/indexer/IndexerMain.cpp
  clang-tools-extra/clangd/refactor/Tweak.cpp

Index: clang-tools-extra/clangd/refactor/Tweak.cpp
===
--- clang-tools-extra/clangd/refactor/Tweak.cpp
+++ clang-tools-extra/clangd/refactor/Tweak.cpp
@@ -104,8 +104,9 @@
 Tweak::Effect::fileEdit(const SourceManager , FileID FID,
 tooling::Replacements Replacements) {
   Edit Ed(SM.getBufferData(FID), std::move(Replacements));
-  if (auto FilePath = getCanonicalPath(SM.getFileEntryForID(FID), SM))
-return std::make_pair(*FilePath, std::move(Ed));
+  if (const auto FE = SM.getFileEntryRefForID(FID))
+if (auto FilePath = getCanonicalPath(*FE, SM))
+  return std::make_pair(*FilePath, std::move(Ed));
   return error("Failed to get absolute path for edited file: {0}",
SM.getFileEntryRefForID(FID)->getName());
 }
Index: clang-tools-extra/clangd/indexer/IndexerMain.cpp
===
--- clang-tools-extra/clangd/indexer/IndexerMain.cpp
+++ clang-tools-extra/clangd/indexer/IndexerMain.cpp
@@ -46,10 +46,10 @@
 SymbolCollector::Options Opts;
 Opts.CountReferences = true;
 Opts.FileFilter = [&](const SourceManager , FileID FID) {
-  const auto *F = SM.getFileEntryForID(FID);
+  const auto F = SM.getFileEntryRefForID(FID);
   if (!F)
 return false; // Skip invalid files.
-  auto AbsPath = getCanonicalPath(F, SM);
+  auto AbsPath = getCanonicalPath(*F, SM);
   if (!AbsPath)
 return false; // Skip files without absolute path.
   std::lock_guard Lock(FilesMu);
Index: clang-tools-extra/clangd/index/SymbolCollector.cpp
===
--- clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -205,11 +205,11 @@
 
   // Returns a canonical URI for the file \p FE.
   // We attempt to make the path absolute first.
-  const std::string (const FileEntry *FE) {
+  const std::string (const FileEntryRef ) {
 auto R = CacheFEToURI.try_emplace(FE);
 if (R.second) {
   auto CanonPath = getCanonicalPath(FE, SM);
-  R.first->second = (CanonPath ? *CanonPath : FE->getName());
+  R.first->second = (CanonPath ? *CanonPath : FE.getName());
 }
 return *R.first->second;
   }
@@ -218,7 +218,7 @@
   // If the file is in the FileManager, use that to canonicalize the path.
   // We attempt to make the path absolute in any case.
   const std::string (llvm::StringRef Path) {
-if (auto File = SM.getFileManager().getFile(Path))
+if (auto File = SM.getFileManager().getFileRef(Path))
   return toURI(*File);
 return toURIInternal(Path);
   }
@@ -373,7 +373,7 @@
   }
 
   llvm::StringRef getIncludeHeaderUncached(FileID FID) {
-const FileEntry *FE = SM.getFileEntryForID(FID);
+const auto FE = SM.getFileEntryRefForID(FID);
 if (!FE || FE->getName().empty())
   return "";
 llvm::StringRef Filename = FE->getName();
@@ -392,13 +392,15 @@
 // Framework headers are spelled as , not
 // "path/FrameworkName.framework/Headers/Foo.h".
 auto  = PP->getHeaderSearchInfo();
-if (const auto *HFI = HS.getExistingFileInfo(FE, /*WantExternal*/ false))
+if (const auto *HFI = HS.getExistingFileInfo(>getFileEntry(),
+ /*WantExternal*/ false))
   if (!HFI->Framework.empty())
-if (auto Spelling =
-getFrameworkHeaderIncludeSpelling(FE, HFI->Framework, HS))
+if (auto Spelling = getFrameworkHeaderIncludeSpelling(
+>getFileEntry(), HFI->Framework, HS))
   return *Spelling;
 
-if (!tooling::isSelfContainedHeader(FE, PP->getSourceManager(),
+if (!tooling::isSelfContainedHeader(>getFileEntry(),
+PP->getSourceManager(),
 PP->getHeaderSearchInfo())) {
   // A .inc or .def file is often included into a real header to define
   // symbols (e.g. LLVM tablegen files).
@@ -409,7 +411,7 @@
   return "";
 }
 // Standard case: just insert the file itself.
-return toURI(FE);
+return toURI(*FE);
   }
 };
 
@@ -417,12 +419,12 @@
 std::optional
 SymbolCollector::getTokenLocation(SourceLocation TokLoc) {
   const auto  = 

[PATCH] D148213: [clangd] Use FileEntryRef for canonicalizing filepaths.

2023-04-13 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 created this revision.
Herald added subscribers: kadircet, arphaman.
Herald added a project: All.
usaxena95 requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D148213

Files:
  clang-tools-extra/clangd/Diagnostics.cpp
  clang-tools-extra/clangd/IncludeCleaner.cpp
  clang-tools-extra/clangd/SourceCode.cpp
  clang-tools-extra/clangd/SourceCode.h
  clang-tools-extra/clangd/XRefs.cpp
  clang-tools-extra/clangd/index/Background.cpp
  clang-tools-extra/clangd/index/SymbolCollector.cpp
  clang-tools-extra/clangd/indexer/IndexerMain.cpp
  clang-tools-extra/clangd/refactor/Tweak.cpp

Index: clang-tools-extra/clangd/refactor/Tweak.cpp
===
--- clang-tools-extra/clangd/refactor/Tweak.cpp
+++ clang-tools-extra/clangd/refactor/Tweak.cpp
@@ -104,8 +104,9 @@
 Tweak::Effect::fileEdit(const SourceManager , FileID FID,
 tooling::Replacements Replacements) {
   Edit Ed(SM.getBufferData(FID), std::move(Replacements));
-  if (auto FilePath = getCanonicalPath(SM.getFileEntryForID(FID), SM))
-return std::make_pair(*FilePath, std::move(Ed));
+  if (const auto FERef = SM.getFileEntryRefForID(FID))
+if (auto FilePath = getCanonicalPath(*FERef, SM))
+  return std::make_pair(*FilePath, std::move(Ed));
   return error("Failed to get absolute path for edited file: {0}",
SM.getFileEntryRefForID(FID)->getName());
 }
Index: clang-tools-extra/clangd/indexer/IndexerMain.cpp
===
--- clang-tools-extra/clangd/indexer/IndexerMain.cpp
+++ clang-tools-extra/clangd/indexer/IndexerMain.cpp
@@ -46,10 +46,10 @@
 SymbolCollector::Options Opts;
 Opts.CountReferences = true;
 Opts.FileFilter = [&](const SourceManager , FileID FID) {
-  const auto *F = SM.getFileEntryForID(FID);
+  const auto F = SM.getFileEntryRefForID(FID);
   if (!F)
 return false; // Skip invalid files.
-  auto AbsPath = getCanonicalPath(F, SM);
+  auto AbsPath = getCanonicalPath(*F, SM);
   if (!AbsPath)
 return false; // Skip files without absolute path.
   std::lock_guard Lock(FilesMu);
Index: clang-tools-extra/clangd/index/SymbolCollector.cpp
===
--- clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -205,11 +205,11 @@
 
   // Returns a canonical URI for the file \p FE.
   // We attempt to make the path absolute first.
-  const std::string (const FileEntry *FE) {
+  const std::string (const FileEntryRef ) {
 auto R = CacheFEToURI.try_emplace(FE);
 if (R.second) {
   auto CanonPath = getCanonicalPath(FE, SM);
-  R.first->second = (CanonPath ? *CanonPath : FE->getName());
+  R.first->second = (CanonPath ? *CanonPath : FE.getName());
 }
 return *R.first->second;
   }
@@ -218,7 +218,7 @@
   // If the file is in the FileManager, use that to canonicalize the path.
   // We attempt to make the path absolute in any case.
   const std::string (llvm::StringRef Path) {
-if (auto File = SM.getFileManager().getFile(Path))
+if (auto File = SM.getFileManager().getFileRef(Path))
   return toURI(*File);
 return toURIInternal(Path);
   }
@@ -373,7 +373,7 @@
   }
 
   llvm::StringRef getIncludeHeaderUncached(FileID FID) {
-const FileEntry *FE = SM.getFileEntryForID(FID);
+const auto FE = SM.getFileEntryRefForID(FID);
 if (!FE || FE->getName().empty())
   return "";
 llvm::StringRef Filename = FE->getName();
@@ -392,13 +392,15 @@
 // Framework headers are spelled as , not
 // "path/FrameworkName.framework/Headers/Foo.h".
 auto  = PP->getHeaderSearchInfo();
-if (const auto *HFI = HS.getExistingFileInfo(FE, /*WantExternal*/ false))
+if (const auto *HFI = HS.getExistingFileInfo(>getFileEntry(),
+ /*WantExternal*/ false))
   if (!HFI->Framework.empty())
-if (auto Spelling =
-getFrameworkHeaderIncludeSpelling(FE, HFI->Framework, HS))
+if (auto Spelling = getFrameworkHeaderIncludeSpelling(
+>getFileEntry(), HFI->Framework, HS))
   return *Spelling;
 
-if (!tooling::isSelfContainedHeader(FE, PP->getSourceManager(),
+if (!tooling::isSelfContainedHeader(>getFileEntry(),
+PP->getSourceManager(),
 PP->getHeaderSearchInfo())) {
   // A .inc or .def file is often included into a real header to define
   // symbols (e.g. LLVM tablegen files).
@@ -409,7 +411,7 @@
   return "";
 }
 // Standard case: just insert the file itself.
-return toURI(FE);
+return toURI(*FE);
   }
 };
 
@@ -417,12 +419,12 @@
 

[PATCH] D145642: [clang-format] Annotate lambdas with requires clauses.

2023-03-22 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 added a comment.

> starting a line with an opening paren is pretty weird!)

I do not think this is weird. On the contrary, this is more readable to me and 
separates the requires clause from the parameters list. For example this one 
looks so much better:

  // trunk.
  template 
  void func() {
auto x = []
  requires Foo && Foo(T t, U u) requires BarBar && BarBar ||
   BarBar
{
  return u + t;
};
  }

  // patch.
  template  void func() {
auto x = []
  requires Foo && Foo
(T t, U u)
  requires BarBar && BarBar || BarBar
{ return u + t; };
  }

Discussion on wrapping the lambda body with single statement. FWIW: I do not 
think this is a regression and we are fixing things as seen in my first example.

Another point:
While testing this patch, the following still fails to recognise. Might be 
something special with `true`.

  auto y = [&]
  requires true(Callable && callable)
{ static_cast(callable); };




Comment at: clang/unittests/Format/TokenAnnotatorTest.cpp:1352
+
+  // Both at once? Probably not even valid.
+  Tokens = annotate("[]  requires Foo (T t) requires Bar 
{}");

This is valid and is accepted by the compilers https://godbolt.org/z/EPbrWbrsv


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D145642

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


[PATCH] D142384: [C++20] Fix a crash with modules.

2023-03-06 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 added a comment.

This does not seem to be a pressing issue as there are no other reported 
module/cpp20 related crashes which were fixed by this.
Also since it has no tests, it should be fine to postpone it to the next 
release.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D142384

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


[PATCH] D145154: Change ClangTidy unit tests to run in C++20 mode instead of C++11.

2023-03-02 Thread Utkarsh Saxena via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGc396073a0de6: Change ClangTidy unit tests to run in C++20 
mode instead of C++11. (authored by usaxena95).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D145154

Files:
  clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h


Index: clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
===
--- clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
+++ clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
@@ -110,7 +110,7 @@
 Args.push_back("-fobjc-arc");
   }
   if (extension == ".cc" || extension == ".cpp" || extension == ".mm") {
-Args.push_back("-std=c++11");
+Args.push_back("-std=c++20");
   }
   Args.push_back("-Iinclude");
   Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());


Index: clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
===
--- clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
+++ clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
@@ -110,7 +110,7 @@
 Args.push_back("-fobjc-arc");
   }
   if (extension == ".cc" || extension == ".cpp" || extension == ".mm") {
-Args.push_back("-std=c++11");
+Args.push_back("-std=c++20");
   }
   Args.push_back("-Iinclude");
   Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D145154: Change ClangTidy unit tests to run in C++20 mode instead of C++11.

2023-03-02 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 created this revision.
usaxena95 added a reviewer: gribozavr2.
Herald added a project: All.
usaxena95 requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D145154

Files:
  clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h


Index: clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
===
--- clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
+++ clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
@@ -110,7 +110,7 @@
 Args.push_back("-fobjc-arc");
   }
   if (extension == ".cc" || extension == ".cpp" || extension == ".mm") {
-Args.push_back("-std=c++11");
+Args.push_back("-std=c++20");
   }
   Args.push_back("-Iinclude");
   Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());


Index: clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
===
--- clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
+++ clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
@@ -110,7 +110,7 @@
 Args.push_back("-fobjc-arc");
   }
   if (extension == ".cc" || extension == ".cpp" || extension == ".mm") {
-Args.push_back("-std=c++11");
+Args.push_back("-std=c++20");
   }
   Args.push_back("-Iinclude");
   Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D144480: [C++20][ClangTidy] Update the ClangTidy tests to also test in C++20 mode

2023-03-02 Thread Utkarsh Saxena via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGb4d9ac8b453e: [C++20][ClangTidy] Update the ClangTidy tests 
to also test in C++20 mode (authored by usaxena95).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D144480

Files:
  clang-tools-extra/test/clang-tidy/checkers/bugprone/dangling-handle.cpp
  
clang-tools-extra/test/clang-tidy/checkers/bugprone/easily-swappable-parameters-implicits.cpp
  clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp
  clang-tools-extra/test/clang-tidy/checkers/bugprone/signal-handler.cpp
  
clang-tools-extra/test/clang-tidy/checkers/bugprone/unhandled-exception-at-new.cpp
  clang-tools-extra/test/clang-tidy/checkers/cert/throw-exception-type.cpp
  clang-tools-extra/test/clang-tidy/checkers/misc/static-assert.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-copy-initialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type-macros.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability/isolate-declaration-cxx17.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof.cpp
@@ -1,4 +1,5 @@
 // RUN: %check_clang_tidy -std=c++14,c++17 %s readability-use-anyofallof %t -- -- -fexceptions
+// FIXME: Fix the checker to work in C++20 mode.
 
 bool good_any_of() {
   int v[] = {1, 2, 3};
Index: clang-tools-extra/test/clang-tidy/checkers/readability/isolate-declaration-cxx17.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/isolate-declaration-cxx17.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/isolate-declaration-cxx17.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++17 %s readability-isolate-declaration %t
+// RUN: %check_clang_tidy -std=c++17-or-later %s readability-isolate-declaration %t
 
 template 
 struct pair {
Index: clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++14 %s readability-const-return-type %t
+// RUN: %check_clang_tidy -std=c++14-or-later %s readability-const-return-type %t
 
 //  p# = positive test
 //  n# = negative test
Index: clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type-macros.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type-macros.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type-macros.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++14 %s readability-const-return-type %t -- \
+// RUN: %check_clang_tidy -std=c++14-or-later %s readability-const-return-type %t -- \
 // RUN:   -config="{CheckOptions: [{key: readability-const-return-type.IgnoreMacros, value: false}]}"
 
 //  p# = positive test
Index: clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-copy-initialization.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++17 %s performance-unnecessary-copy-initialization %t
+// RUN: %check_clang_tidy -std=c++17-or-later %s performance-unnecessary-copy-initialization %t
 
 template 
 struct Iterator {
Index: clang-tools-extra/test/clang-tidy/checkers/misc/static-assert.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/misc/static-assert.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/misc/static-assert.cpp
@@ -1,5 +1,5 @@
 // RUN: %check_clang_tidy -std=c++11 -check-suffixes=,CXX11 %s misc-static-assert %t
-// RUN: %check_clang_tidy -std=c++17 -check-suffixes=,CXX17 %s misc-static-assert %t
+// RUN: %check_clang_tidy -std=c++17-or-later -check-suffixes=,CXX17 %s misc-static-assert %t
 
 void abort() {}
 #ifdef NDEBUG
Index: clang-tools-extra/test/clang-tidy/checkers/cert/throw-exception-type.cpp
===
--- 

[PATCH] D144480: [C++20][ClangTidy] Update the ClangTidy tests to also test in C++20 mode

2023-03-02 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 501822.
usaxena95 marked 2 inline comments as done.
usaxena95 added a comment.

Addressed comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D144480

Files:
  clang-tools-extra/test/clang-tidy/checkers/bugprone/dangling-handle.cpp
  
clang-tools-extra/test/clang-tidy/checkers/bugprone/easily-swappable-parameters-implicits.cpp
  clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp
  clang-tools-extra/test/clang-tidy/checkers/bugprone/signal-handler.cpp
  
clang-tools-extra/test/clang-tidy/checkers/bugprone/unhandled-exception-at-new.cpp
  clang-tools-extra/test/clang-tidy/checkers/cert/throw-exception-type.cpp
  clang-tools-extra/test/clang-tidy/checkers/misc/static-assert.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-copy-initialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type-macros.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability/isolate-declaration-cxx17.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof.cpp
@@ -1,4 +1,5 @@
 // RUN: %check_clang_tidy -std=c++14,c++17 %s readability-use-anyofallof %t -- -- -fexceptions
+// FIXME: Fix the checker to work in C++20 mode.
 
 bool good_any_of() {
   int v[] = {1, 2, 3};
Index: clang-tools-extra/test/clang-tidy/checkers/readability/isolate-declaration-cxx17.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/isolate-declaration-cxx17.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/isolate-declaration-cxx17.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++17 %s readability-isolate-declaration %t
+// RUN: %check_clang_tidy -std=c++17-or-later %s readability-isolate-declaration %t
 
 template 
 struct pair {
Index: clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++14 %s readability-const-return-type %t
+// RUN: %check_clang_tidy -std=c++14-or-later %s readability-const-return-type %t
 
 //  p# = positive test
 //  n# = negative test
Index: clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type-macros.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type-macros.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type-macros.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++14 %s readability-const-return-type %t -- \
+// RUN: %check_clang_tidy -std=c++14-or-later %s readability-const-return-type %t -- \
 // RUN:   -config="{CheckOptions: [{key: readability-const-return-type.IgnoreMacros, value: false}]}"
 
 //  p# = positive test
Index: clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-copy-initialization.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++17 %s performance-unnecessary-copy-initialization %t
+// RUN: %check_clang_tidy -std=c++17-or-later %s performance-unnecessary-copy-initialization %t
 
 template 
 struct Iterator {
Index: clang-tools-extra/test/clang-tidy/checkers/misc/static-assert.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/misc/static-assert.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/misc/static-assert.cpp
@@ -1,5 +1,5 @@
 // RUN: %check_clang_tidy -std=c++11 -check-suffixes=,CXX11 %s misc-static-assert %t
-// RUN: %check_clang_tidy -std=c++17 -check-suffixes=,CXX17 %s misc-static-assert %t
+// RUN: %check_clang_tidy -std=c++17-or-later -check-suffixes=,CXX17 %s misc-static-assert %t
 
 void abort() {}
 #ifdef NDEBUG
Index: clang-tools-extra/test/clang-tidy/checkers/cert/throw-exception-type.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/cert/throw-exception-type.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/cert/throw-exception-type.cpp
@@ 

[PATCH] D144480: [C++20][ClangTidy] Update the ClangTidy tests to also test in C++20 mode

2023-02-21 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 created this revision.
Herald added subscribers: kbarton, nemanjai.
Herald added a project: All.
usaxena95 requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D144480

Files:
  clang-tools-extra/test/clang-tidy/checkers/bugprone/dangling-handle.cpp
  
clang-tools-extra/test/clang-tidy/checkers/bugprone/easily-swappable-parameters-implicits.cpp
  clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp
  clang-tools-extra/test/clang-tidy/checkers/bugprone/signal-handler.cpp
  
clang-tools-extra/test/clang-tidy/checkers/bugprone/unhandled-exception-at-new.cpp
  clang-tools-extra/test/clang-tidy/checkers/cert/throw-exception-type.cpp
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init-cxx98.cpp
  clang-tools-extra/test/clang-tidy/checkers/misc/static-assert.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-copy-initialization.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type-macros.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability/isolate-declaration-cxx17.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof.cpp
  clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h

Index: clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
===
--- clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
+++ clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
@@ -110,7 +110,7 @@
 Args.push_back("-fobjc-arc");
   }
   if (extension == ".cc" || extension == ".cpp" || extension == ".mm") {
-Args.push_back("-std=c++11");
+Args.push_back("-std=c++20");
   }
   Args.push_back("-Iinclude");
   Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
Index: clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof.cpp
@@ -1,4 +1,5 @@
 // RUN: %check_clang_tidy -std=c++14,c++17 %s readability-use-anyofallof %t -- -- -fexceptions
+// FIXME: Fix the checker to work in C++20 mode.
 
 bool good_any_of() {
   int v[] = {1, 2, 3};
Index: clang-tools-extra/test/clang-tidy/checkers/readability/isolate-declaration-cxx17.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/isolate-declaration-cxx17.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/isolate-declaration-cxx17.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++17 %s readability-isolate-declaration %t
+// RUN: %check_clang_tidy -std=c++17-or-later %s readability-isolate-declaration %t
 
 template 
 struct pair {
Index: clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++14 %s readability-const-return-type %t
+// RUN: %check_clang_tidy -std=c++14-or-later %s readability-const-return-type %t
 
 //  p# = positive test
 //  n# = negative test
Index: clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type-macros.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type-macros.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type-macros.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++14 %s readability-const-return-type %t -- \
+// RUN: %check_clang_tidy -std=c++14-or-later %s readability-const-return-type %t -- \
 // RUN:   -config="{CheckOptions: [{key: readability-const-return-type.IgnoreMacros, value: false}]}"
 
 //  p# = positive test
Index: clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-copy-initialization.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-copy-initialization.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-copy-initialization.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++17 %s performance-unnecessary-copy-initialization %t
+// RUN: %check_clang_tidy -std=c++17-or-later %s performance-unnecessary-copy-initialization %t
 
 template 
 struct Iterator {
Index: clang-tools-extra/test/clang-tidy/checkers/misc/static-assert.cpp
===
--- 

[PATCH] D142384: [C++20] Fix a crash with modules.

2023-02-02 Thread Utkarsh Saxena via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGb6121432da79: [C++20] Fix a crash with modules. (authored by 
usaxena95).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D142384

Files:
  clang/lib/AST/Decl.cpp


Index: clang/lib/AST/Decl.cpp
===
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -4770,7 +4770,10 @@
 RecordDecl::field_iterator RecordDecl::field_begin() const {
   if (hasExternalLexicalStorage() && !hasLoadedFieldsFromExternalStorage())
 LoadFieldsFromExternalStorage();
-
+  // This is necessary for correctness for C++ with modules.
+  // FIXME: Come up with a test case that breaks without definition.
+  if (RecordDecl *D = getDefinition(); D && D != this)
+return D->field_begin();
   return field_iterator(decl_iterator(FirstDecl));
 }
 


Index: clang/lib/AST/Decl.cpp
===
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -4770,7 +4770,10 @@
 RecordDecl::field_iterator RecordDecl::field_begin() const {
   if (hasExternalLexicalStorage() && !hasLoadedFieldsFromExternalStorage())
 LoadFieldsFromExternalStorage();
-
+  // This is necessary for correctness for C++ with modules.
+  // FIXME: Come up with a test case that breaks without definition.
+  if (RecordDecl *D = getDefinition(); D && D != this)
+return D->field_begin();
   return field_iterator(decl_iterator(FirstDecl));
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D142384: [C++20] Fix a crash with modules.

2023-02-02 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 494314.
usaxena95 marked an inline comment as done.
usaxena95 added a comment.

Addressed comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D142384

Files:
  clang/lib/AST/Decl.cpp


Index: clang/lib/AST/Decl.cpp
===
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -4769,7 +4769,10 @@
 RecordDecl::field_iterator RecordDecl::field_begin() const {
   if (hasExternalLexicalStorage() && !hasLoadedFieldsFromExternalStorage())
 LoadFieldsFromExternalStorage();
-
+  // This is necessary for correctness for C++ with modules.
+  // FIXME: Come up with a test case that breaks without definition.
+  if (RecordDecl *D = getDefinition(); D && D != this)
+return D->field_begin();
   return field_iterator(decl_iterator(FirstDecl));
 }
 


Index: clang/lib/AST/Decl.cpp
===
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -4769,7 +4769,10 @@
 RecordDecl::field_iterator RecordDecl::field_begin() const {
   if (hasExternalLexicalStorage() && !hasLoadedFieldsFromExternalStorage())
 LoadFieldsFromExternalStorage();
-
+  // This is necessary for correctness for C++ with modules.
+  // FIXME: Come up with a test case that breaks without definition.
+  if (RecordDecl *D = getDefinition(); D && D != this)
+return D->field_begin();
   return field_iterator(decl_iterator(FirstDecl));
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D142384: [C++20] Fix a crash with modules.

2023-02-01 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 added a comment.

In D142384#4096935 , @ilya-biryukov 
wrote:

> @usaxena95 could you give an example of the code that fails the assertion? Is 
> it some of the tests?

`assert(getDefinition())` fails about 3.6k tests.
`assert(!isa(this) || getDefinition());` fails a handful 23 
tests in ObjC:

  Failed Tests (23):
Clang :: Analysis/CFContainers.mm
Clang :: Analysis/blocks.m
Clang :: Analysis/dtor-array.cpp
Clang :: Analysis/edges-new.mm
Clang :: Analysis/incorrect-checker-names.mm
Clang :: Analysis/malloc.mm
Clang :: Analysis/mig.mm
Clang :: Analysis/retain-release.m
Clang :: Analysis/retain-release.mm
Clang :: Analysis/stack-capture-leak-arc.mm
Clang :: Analysis/stack-capture-leak-no-arc.mm
Clang :: Analysis/taint-tester.cpp
Clang :: CodeGenObjCXX/encode.mm
Clang-Unit :: AST/./ASTTests/0/100
Clang-Unit :: AST/./ASTTests/1/100
Clang-Unit :: AST/./ASTTests/14/100
Clang-Unit :: AST/./ASTTests/16/100
Clang-Unit :: AST/./ASTTests/76/100
Clang-Unit :: AST/./ASTTests/77/100
Clang-Unit :: AST/./ASTTests/78/100
Clang-Unit :: AST/./ASTTests/79/100
Clang-Unit :: AST/./ASTTests/98/100
Clang-Unit :: AST/./ASTTests/99/100

`bin/clang  $SRC/llvm-project/clang/test/CodeGenObjCXX/encode.mm`
Stacktrace: https://pastebin.pl/view/c6f505a7

`assert((!isa(this) || getDefinition() || !FirstDecl) && "Field 
without a CXX definition ?");` works. So if there is no CXX definition then the 
fields are always empty and current callers are fine with that.

I think this is fine, and we should just use the definition when it is 
available without asking the callers to request fields only when definition is 
available.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D142384

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


[PATCH] D142384: [C++20] Fix a crash with modules.

2023-02-01 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 493926.
usaxena95 added a comment.

Moved to RecordDecl::field_begin. Assertion is no more valid in RecordDecl.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D142384

Files:
  clang/lib/AST/Decl.cpp


Index: clang/lib/AST/Decl.cpp
===
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -4769,7 +4769,8 @@
 RecordDecl::field_iterator RecordDecl::field_begin() const {
   if (hasExternalLexicalStorage() && !hasLoadedFieldsFromExternalStorage())
 LoadFieldsFromExternalStorage();
-
+  if (RecordDecl *D = getDefinition(); D && D != this)
+return D->field_begin();
   return field_iterator(decl_iterator(FirstDecl));
 }
 


Index: clang/lib/AST/Decl.cpp
===
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -4769,7 +4769,8 @@
 RecordDecl::field_iterator RecordDecl::field_begin() const {
   if (hasExternalLexicalStorage() && !hasLoadedFieldsFromExternalStorage())
 LoadFieldsFromExternalStorage();
-
+  if (RecordDecl *D = getDefinition(); D && D != this)
+return D->field_begin();
   return field_iterator(decl_iterator(FirstDecl));
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D142384: [C++20] Fix a crash with modules.

2023-01-31 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 493652.
usaxena95 added a comment.

Use definition based field access only for CXXRecordDecl.
Avoid dynamic dispatch.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D142384

Files:
  clang/include/clang/AST/DeclCXX.h


Index: clang/include/clang/AST/DeclCXX.h
===
--- clang/include/clang/AST/DeclCXX.h
+++ clang/include/clang/AST/DeclCXX.h
@@ -554,6 +554,21 @@
 
   bool hasDefinition() const { return DefinitionData || dataPtr(); }
 
+  RecordDecl::field_iterator field_begin() const {
+assert(hasDefinition() && "Definition not available to get fields.");
+return static_cast(getDefinition())->field_begin();
+  }
+
+  RecordDecl::field_iterator field_end() const {
+return field_iterator(decl_iterator());
+  }
+
+  RecordDecl::field_range fields() const {
+return field_range(field_begin(), field_end());
+  }
+
+  bool field_empty() const { return field_begin() == field_end(); }
+
   static CXXRecordDecl *Create(const ASTContext , TagKind TK, DeclContext 
*DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id,


Index: clang/include/clang/AST/DeclCXX.h
===
--- clang/include/clang/AST/DeclCXX.h
+++ clang/include/clang/AST/DeclCXX.h
@@ -554,6 +554,21 @@
 
   bool hasDefinition() const { return DefinitionData || dataPtr(); }
 
+  RecordDecl::field_iterator field_begin() const {
+assert(hasDefinition() && "Definition not available to get fields.");
+return static_cast(getDefinition())->field_begin();
+  }
+
+  RecordDecl::field_iterator field_end() const {
+return field_iterator(decl_iterator());
+  }
+
+  RecordDecl::field_range fields() const {
+return field_range(field_begin(), field_end());
+  }
+
+  bool field_empty() const { return field_begin() == field_end(); }
+
   static CXXRecordDecl *Create(const ASTContext , TagKind TK, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id,
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D142384: [C++20] Fix a crash with modules.

2023-01-31 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 493538.
usaxena95 added a comment.

Moved the use of definition where fields are accessed.
This now resolves several other C++20/Module related crashes as well.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D142384

Files:
  clang/include/clang/AST/Decl.h
  clang/include/clang/AST/DeclCXX.h


Index: clang/include/clang/AST/DeclCXX.h
===
--- clang/include/clang/AST/DeclCXX.h
+++ clang/include/clang/AST/DeclCXX.h
@@ -554,6 +554,11 @@
 
   bool hasDefinition() const { return DefinitionData || dataPtr(); }
 
+  RecordDecl::field_iterator field_begin() const override {
+assert(hasDefinition() && "Definition not available to get fields.");
+return static_cast(getDefinition())->field_begin();
+  }
+
   static CXXRecordDecl *Create(const ASTContext , TagKind TK, DeclContext 
*DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id,
Index: clang/include/clang/AST/Decl.h
===
--- clang/include/clang/AST/Decl.h
+++ clang/include/clang/AST/Decl.h
@@ -4220,7 +4220,7 @@
   using field_range = llvm::iterator_range>;
 
   field_range fields() const { return field_range(field_begin(), field_end()); 
}
-  field_iterator field_begin() const;
+  virtual field_iterator field_begin() const;
 
   field_iterator field_end() const {
 return field_iterator(decl_iterator());


Index: clang/include/clang/AST/DeclCXX.h
===
--- clang/include/clang/AST/DeclCXX.h
+++ clang/include/clang/AST/DeclCXX.h
@@ -554,6 +554,11 @@
 
   bool hasDefinition() const { return DefinitionData || dataPtr(); }
 
+  RecordDecl::field_iterator field_begin() const override {
+assert(hasDefinition() && "Definition not available to get fields.");
+return static_cast(getDefinition())->field_begin();
+  }
+
   static CXXRecordDecl *Create(const ASTContext , TagKind TK, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id,
Index: clang/include/clang/AST/Decl.h
===
--- clang/include/clang/AST/Decl.h
+++ clang/include/clang/AST/Decl.h
@@ -4220,7 +4220,7 @@
   using field_range = llvm::iterator_range>;
 
   field_range fields() const { return field_range(field_begin(), field_end()); }
-  field_iterator field_begin() const;
+  virtual field_iterator field_begin() const;
 
   field_iterator field_end() const {
 return field_iterator(decl_iterator());
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D142384: [C++20] Fix a crash with modules.

2023-01-30 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 493489.
usaxena95 marked an inline comment as done.
usaxena95 added a comment.

Add message in the assertion.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D142384

Files:
  clang/lib/AST/ExprConstant.cpp


Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -6229,6 +6229,8 @@
 return false;
 
   const CXXRecordDecl *RD = Definition->getParent();
+  assert(RD->hasDefinition() && "Definition is needed to read the fields");
+  RD = RD->getDefinition();
   if (RD->getNumVBases()) {
 Info.FFDiag(CallLoc, diag::note_constexpr_virtual_base) << RD;
 return false;


Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -6229,6 +6229,8 @@
 return false;
 
   const CXXRecordDecl *RD = Definition->getParent();
+  assert(RD->hasDefinition() && "Definition is needed to read the fields");
+  RD = RD->getDefinition();
   if (RD->getNumVBases()) {
 Info.FFDiag(CallLoc, diag::note_constexpr_virtual_base) << RD;
 return false;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D142384: [C++20] Fix a crash with modules.

2023-01-24 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 491661.
usaxena95 edited the summary of this revision.
usaxena95 added a comment.

Use `getDefinition`


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D142384

Files:
  clang/lib/AST/ExprConstant.cpp


Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -6229,6 +6229,8 @@
 return false;
 
   const CXXRecordDecl *RD = Definition->getParent();
+  assert(RD->hasDefinition());
+  RD->getDefinition();
   if (RD->getNumVBases()) {
 Info.FFDiag(CallLoc, diag::note_constexpr_virtual_base) << RD;
 return false;


Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -6229,6 +6229,8 @@
 return false;
 
   const CXXRecordDecl *RD = Definition->getParent();
+  assert(RD->hasDefinition());
+  RD->getDefinition();
   if (RD->getNumVBases()) {
 Info.FFDiag(CallLoc, diag::note_constexpr_virtual_base) << RD;
 return false;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D142384: [C++20] Fix a crash with modules.

2023-01-23 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 created this revision.
Herald added a project: All.
usaxena95 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D142384

Files:
  clang/lib/AST/ExprConstant.cpp


Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -6229,6 +6229,8 @@
 return false;
 
   const CXXRecordDecl *RD = Definition->getParent();
+  if (RD->field_empty())
+RD = RD->getMostRecentDecl();
   if (RD->getNumVBases()) {
 Info.FFDiag(CallLoc, diag::note_constexpr_virtual_base) << RD;
 return false;


Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -6229,6 +6229,8 @@
 return false;
 
   const CXXRecordDecl *RD = Definition->getParent();
+  if (RD->field_empty())
+RD = RD->getMostRecentDecl();
   if (RD->getNumVBases()) {
 Info.FFDiag(CallLoc, diag::note_constexpr_virtual_base) << RD;
 return false;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D141818: Add test for an invalid requirement in requires expr.

2023-01-16 Thread Utkarsh Saxena via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG15ad244670a9: Add test for an invalid requirement in 
requires expr. (authored by usaxena95).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D141818

Files:
  clang/test/SemaCXX/invalid-requirement-requires-expr.cpp


Index: clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang -fsyntax-only -std=c++2a -Xclang -verify -ftemplate-depth=5 
-ftemplate-backtrace-limit=4 %s
+
+// RequiresExpr contains invalid requirement. (Eg. Highly recurisive template).
+template
+struct A { static constexpr bool far(); };
+class B {
+bool data_member;
+friend struct A<1>;
+};
+
+template<>
+constexpr bool A<0>::far() { return true; }
+
+template
+constexpr bool A::far() {
+return requires(B b) {
+  b.data_member;
+  requires A::far(); // #Invalid
+  // expected-error@#Invalid {{recursive template instantiation exceeded 
maximum depth}}
+  // expected-note@#Invalid {{in instantiation}}
+  // expected-note@#Invalid 2 {{while}}
+  // expected-note@#Invalid {{contexts in backtrace}}
+  // expected-note@#Invalid {{increase recursive template instantiation 
depth}}
+};
+}
+static_assert(A<1>::far());
+static_assert(!A<6>::far()); // expected-note {{in instantiation of member 
function}}


Index: clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang -fsyntax-only -std=c++2a -Xclang -verify -ftemplate-depth=5 -ftemplate-backtrace-limit=4 %s
+
+// RequiresExpr contains invalid requirement. (Eg. Highly recurisive template).
+template
+struct A { static constexpr bool far(); };
+class B {
+bool data_member;
+friend struct A<1>;
+};
+
+template<>
+constexpr bool A<0>::far() { return true; }
+
+template
+constexpr bool A::far() {
+return requires(B b) {
+  b.data_member;
+  requires A::far(); // #Invalid
+  // expected-error@#Invalid {{recursive template instantiation exceeded maximum depth}}
+  // expected-note@#Invalid {{in instantiation}}
+  // expected-note@#Invalid 2 {{while}}
+  // expected-note@#Invalid {{contexts in backtrace}}
+  // expected-note@#Invalid {{increase recursive template instantiation depth}}
+};
+}
+static_assert(A<1>::far());
+static_assert(!A<6>::far()); // expected-note {{in instantiation of member function}}
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D141818: Add test for an invalid requirement in requires expr.

2023-01-15 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 created this revision.
usaxena95 added reviewers: ilya-biryukov, erichkeane.
Herald added a project: All.
usaxena95 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

The one introduced in D140547  was brittle. 
Fixing max template depth to
a small value would still test the same issue without causing actual
stack exhaustion.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D141818

Files:
  clang/test/SemaCXX/invalid-requirement-requires-expr.cpp


Index: clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang -fsyntax-only -std=c++2a -Xclang -verify -ftemplate-depth=5 
-ftemplate-backtrace-limit=4 %s
+
+// RequiresExpr contains invalid requirement. (Eg. Highly recurisive template).
+template
+struct A { static constexpr bool far(); };
+class B {
+bool data_member;
+friend struct A<1>;
+};
+
+template<>
+constexpr bool A<0>::far() { return true; }
+
+template
+constexpr bool A::far() {
+return requires(B b) {
+  b.data_member;
+  requires A::far(); // #Invalid
+  // expected-error@#Invalid {{recursive template instantiation exceeded 
maximum depth}}
+  // expected-note@#Invalid {{in instantiation}}
+  // expected-note@#Invalid 2 {{while}}
+  // expected-note@#Invalid {{contexts in backtrace}}
+  // expected-note@#Invalid {{increase recursive template instantiation 
depth}}
+};
+}
+static_assert(A<1>::far());
+static_assert(!A<6>::far()); // expected-note {{in instantiation of member 
function}}


Index: clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang -fsyntax-only -std=c++2a -Xclang -verify -ftemplate-depth=5 -ftemplate-backtrace-limit=4 %s
+
+// RequiresExpr contains invalid requirement. (Eg. Highly recurisive template).
+template
+struct A { static constexpr bool far(); };
+class B {
+bool data_member;
+friend struct A<1>;
+};
+
+template<>
+constexpr bool A<0>::far() { return true; }
+
+template
+constexpr bool A::far() {
+return requires(B b) {
+  b.data_member;
+  requires A::far(); // #Invalid
+  // expected-error@#Invalid {{recursive template instantiation exceeded maximum depth}}
+  // expected-note@#Invalid {{in instantiation}}
+  // expected-note@#Invalid 2 {{while}}
+  // expected-note@#Invalid {{contexts in backtrace}}
+  // expected-note@#Invalid {{increase recursive template instantiation depth}}
+};
+}
+static_assert(A<1>::far());
+static_assert(!A<6>::far()); // expected-note {{in instantiation of member function}}
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D140547: Perform access checking to private members in simple requirement.

2023-01-13 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 marked 4 inline comments as done.
usaxena95 added a comment.

I have deleted the test in 
https://github.com/llvm/llvm-project/commit/a3b632ab8772237ae23638f702bdceda028b2016.
It is safe to delete as this is a brittle test trying to generate an invalid 
requirement using very deep template instantiation. I would find a better way 
to test this in another forward patch.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D140547

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


[PATCH] D140547: Perform access checking to private members in simple requirement.

2023-01-11 Thread Utkarsh Saxena via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG9e0474fbb9c5: Perform access checking to private members in 
simple requirement. (authored by usaxena95).

Changed prior to commit:
  https://reviews.llvm.org/D140547?vs=487866=488136#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D140547

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/ExprConcepts.h
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Sema/SemaAccess.cpp
  clang/lib/Sema/SemaConcept.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
  clang/test/SemaCXX/invalid-requirement-requires-expr.cpp

Index: clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 %s -I%S -std=c++2a -verify
+
+// RequiresExpr contains invalid requirement. (Eg. Highly recurisive template).
+template
+struct A { static constexpr bool far(); };
+class B {
+bool data_member;
+friend struct A<1>;
+};
+
+template<>
+constexpr bool A<0>::far() { return true; }
+
+template
+constexpr bool A::far() {
+return requires(B b) {
+  b.data_member;
+  requires A::far(); //expected-note 3{{in instantiation}} // expected-note 6{{while}} expected-note {{contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all}}
+  // expected-error@-1{{recursive template instantiation exceeded maximum depth}}
+};
+}
+static_assert(A<1>::far());
+static_assert(!A<10001>::far()); // expected-note {{in instantiation of member function}}
Index: clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
@@ -104,3 +104,138 @@
 constexpr bool b = requires (X ) { static_cast(nullptr); };
 // expected-error@-1{{constraint variable 'x' cannot be used in an evaluated context}}
 // expected-note@-2{{'x' declared here}}
+
+namespace access_checks {
+namespace in_requires_expression {
+template
+struct A {
+static constexpr bool foo();
+static constexpr bool bar();
+static constexpr bool baz();
+static constexpr bool faz();
+};
+
+class C{};
+
+class B {
+void p() {}
+bool data_member = true;
+static const bool static_member = true;
+friend struct A<0>;
+};
+
+template
+constexpr bool A::foo() {
+return requires(B b) { b.p(); };
+}
+static_assert(!A<1>::foo());
+static_assert(A<0>::foo());
+
+template
+constexpr bool A::bar() {
+return requires() { B::static_member; };
+}
+static_assert(!A<1>::bar());
+static_assert(A<0>::bar());
+
+template
+constexpr bool A::baz() {
+return requires(B b) { b.data_member; };
+}
+static_assert(!A<1>::baz());
+static_assert(A<0>::baz());
+
+template
+constexpr bool A::faz() {
+return requires(B a, B b) { 
+  a.p();
+  b.data_member;
+  B::static_member;
+};
+}
+static_assert(!A<1>::faz());
+static_assert(A<0>::faz());
+} // namespace in_requires_expression
+
+namespace in_concepts {
+// Dependent access does not cause hard errors.
+template class A;
+
+template <> class A<0> {
+  static void f() {}
+};
+template
+concept C1 = requires() { A::f(); };
+static_assert(!C1<0>);
+
+template <> class A<1> {
+public: 
+  static void f() {}
+};
+static_assert(C1<1>);
+
+// Non-dependent access to private member is a hard error.
+class B{
+   static void f() {} // expected-note 2{{implicitly declared private here}}
+};
+template
+concept C2 = requires() { B::f(); }; // expected-error {{'f' is a private member}}
+
+constexpr bool non_template_func() {
+  return requires() {
+  B::f(); // expected-error {{'f' is a private member}}
+  };
+}
+template
+constexpr bool template_func() {
+  return requires() {
+  A::f();
+  };
+}
+static_assert(!template_func<0>());
+static_assert(template_func<1>());
+} // namespace in_concepts
+
+namespace in_trailing_requires {
+template  struct B;
+class A {
+   static void f();
+   friend struct B;
+};
+ 
+template  struct B {
+  static constexpr int index() requires requires{ A::f(); } {
+return 1;
+  }
+  static constexpr int index() {
+return 2;
+  }
+};
+
+static_assert(B::index() == 1);
+static_assert(B::index() == 2);
+
+namespace missing_member_function {
+template  struct Use;
+class X { 
+  int a;
+  static int B;
+  friend struct Use;
+};
+template  struct Use {
+  constexpr static int foo() requires requires(X x) { x.a; } {
+return 1;
+  }
+  constexpr static int bar() requires requires { X::B; } {
+return 1;
+  }
+};
+
+void test() {
+  // FIXME: Propagate diagnostic.
+  

[PATCH] D140547: Perform access checking to private members in simple requirement.

2023-01-10 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 487866.
usaxena95 added a comment.

Remove new lines.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D140547

Files:
  clang/include/clang/AST/ExprConcepts.h
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Sema/SemaAccess.cpp
  clang/lib/Sema/SemaConcept.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
  clang/test/SemaCXX/invalid-requirement-requires-expr.cpp

Index: clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 %s -I%S -std=c++2a -verify
+
+// RequiresExpr contains invalid requirement. (Eg. Highly recurisive template).
+template
+struct A { static constexpr bool far(); };
+class B {
+bool data_member;
+friend struct A<1>;
+};
+
+template<>
+constexpr bool A<0>::far() { return true; }
+
+template
+constexpr bool A::far() {
+return requires(B b) {
+  b.data_member;
+  requires A::far(); //expected-note 3{{in instantiation}} // expected-note 6{{while}} expected-note {{contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all}}
+  // expected-error@-1{{recursive template instantiation exceeded maximum depth}}
+};
+}
+static_assert(A<1>::far());
+static_assert(!A<10001>::far()); // expected-note {{in instantiation of member function}}
Index: clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
@@ -104,3 +104,138 @@
 constexpr bool b = requires (X ) { static_cast(nullptr); };
 // expected-error@-1{{constraint variable 'x' cannot be used in an evaluated context}}
 // expected-note@-2{{'x' declared here}}
+
+namespace access_checks {
+namespace in_requires_expression {
+template
+struct A {
+static constexpr bool foo();
+static constexpr bool bar();
+static constexpr bool baz();
+static constexpr bool faz();
+};
+
+class C{};
+
+class B {
+void p() {}
+bool data_member = true;
+static const bool static_member = true;
+friend struct A<0>;
+};
+
+template
+constexpr bool A::foo() {
+return requires(B b) { b.p(); };
+}
+static_assert(!A<1>::foo());
+static_assert(A<0>::foo());
+
+template
+constexpr bool A::bar() {
+return requires() { B::static_member; };
+}
+static_assert(!A<1>::bar());
+static_assert(A<0>::bar());
+
+template
+constexpr bool A::baz() {
+return requires(B b) { b.data_member; };
+}
+static_assert(!A<1>::baz());
+static_assert(A<0>::baz());
+
+template
+constexpr bool A::faz() {
+return requires(B a, B b) { 
+  a.p();
+  b.data_member;
+  B::static_member;
+};
+}
+static_assert(!A<1>::faz());
+static_assert(A<0>::faz());
+} // namespace in_requires_expression
+
+namespace in_concepts {
+// Dependent access does not cause hard errors.
+template class A;
+
+template <> class A<0> {
+  static void f() {}
+};
+template
+concept C1 = requires() { A::f(); };
+static_assert(!C1<0>);
+
+template <> class A<1> {
+public: 
+  static void f() {}
+};
+static_assert(C1<1>);
+
+// Non-dependent access to private member is a hard error.
+class B{
+   static void f() {} // expected-note 2{{implicitly declared private here}}
+};
+template
+concept C2 = requires() { B::f(); }; // expected-error {{'f' is a private member}}
+
+constexpr bool non_template_func() {
+  return requires() {
+  B::f(); // expected-error {{'f' is a private member}}
+  };
+}
+template
+constexpr bool template_func() {
+  return requires() {
+  A::f();
+  };
+}
+static_assert(!template_func<0>());
+static_assert(template_func<1>());
+} // namespace in_concepts
+
+namespace in_trailing_requires {
+template  struct B;
+class A {
+   static void f();
+   friend struct B;
+};
+ 
+template  struct B {
+  static constexpr int index() requires requires{ A::f(); } {
+return 1;
+  }
+  static constexpr int index() {
+return 2;
+  }
+};
+
+static_assert(B::index() == 1);
+static_assert(B::index() == 2);
+
+namespace missing_member_function {
+template  struct Use;
+class X { 
+  int a;
+  static int B;
+  friend struct Use;
+};
+template  struct Use {
+  constexpr static int foo() requires requires(X x) { x.a; } {
+return 1;
+  }
+  constexpr static int bar() requires requires { X::B; } {
+return 1;
+  }
+};
+
+void test() {
+  // FIXME: Propagate diagnostic.
+  Use::foo(); //expected-error {{invalid reference to function 'foo': constraints not satisfied}}
+  static_assert(Use::foo() == 1);
+}
+} // namespace missing_member_function
+} // namespace in_trailing_requires
+} // namespace access_check
Index: 

[PATCH] D140547: Perform access checking to private members in simple requirement.

2023-01-10 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 added inline comments.



Comment at: clang/lib/Sema/SemaTemplateInstantiate.cpp:1375
+if (Trap.hasErrorOccurred())
+  TransReq.getAs()->setSatisfied(false);
+  }

ilya-biryukov wrote:
> ilya-biryukov wrote:
> > `TransReq` may be `ExprError` and this will cause a crash. Worth adding a 
> > test too.
> Could you please add `assert(!TransReq || *TransReq != E)`.
> The common optimization in TreeTransform is to avoid rebuilding the AST nodes 
> if nothing changes. There is no optimization like this for `RequireExpr` 
> right now, but it would not be unexpected if this gets implemented in the 
> future.
> 
> In those situations, the current code can potentially change value of 
> `isSatisfied` for an existing expression rather than for a newly created, 
> which seems like asking for trouble. It would be nice to give an early 
> warning to implementors of this optimization that they should think how to 
> handle this case.
Thanks for spotting. Adding a test with invalid requirement which caused a 
crash.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D140547

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


[PATCH] D140547: Perform access checking to private members in simple requirement.

2023-01-10 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 487865.
usaxena95 marked 6 inline comments as done.
usaxena95 added a comment.

Addressed comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D140547

Files:
  clang/include/clang/AST/ExprConcepts.h
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Sema/SemaAccess.cpp
  clang/lib/Sema/SemaConcept.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
  clang/test/SemaCXX/invalid-requirement-requires-expr.cpp

Index: clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
@@ -0,0 +1,24 @@
+
+// RUN: %clang_cc1 %s -I%S -std=c++2a -verify
+
+// RequiresExpr contains invalid requirement. (Eg. Highly recurisive template).
+template
+struct A { static constexpr bool far(); };
+class B {
+bool data_member;
+friend struct A<1>;
+};
+
+template<>
+constexpr bool A<0>::far() { return true; }
+
+template
+constexpr bool A::far() {
+return requires(B b) {
+  b.data_member;
+  requires A::far(); //expected-note 3{{in instantiation}} // expected-note 6{{while}} expected-note {{contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all}}
+  // expected-error@-1{{recursive template instantiation exceeded maximum depth}}
+};
+}
+static_assert(A<1>::far());
+static_assert(!A<10001>::far()); // expected-note {{in instantiation of member function}}
Index: clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
@@ -104,3 +104,138 @@
 constexpr bool b = requires (X ) { static_cast(nullptr); };
 // expected-error@-1{{constraint variable 'x' cannot be used in an evaluated context}}
 // expected-note@-2{{'x' declared here}}
+
+namespace access_checks {
+namespace in_requires_expression {
+template
+struct A {
+static constexpr bool foo();
+static constexpr bool bar();
+static constexpr bool baz();
+static constexpr bool faz();
+};
+
+class C{};
+
+class B {
+void p() {}
+bool data_member = true;
+static const bool static_member = true;
+friend struct A<0>;
+};
+
+template
+constexpr bool A::foo() {
+return requires(B b) { b.p(); };
+}
+static_assert(!A<1>::foo());
+static_assert(A<0>::foo());
+
+template
+constexpr bool A::bar() {
+return requires() { B::static_member; };
+}
+static_assert(!A<1>::bar());
+static_assert(A<0>::bar());
+
+template
+constexpr bool A::baz() {
+return requires(B b) { b.data_member; };
+}
+static_assert(!A<1>::baz());
+static_assert(A<0>::baz());
+
+template
+constexpr bool A::faz() {
+return requires(B a, B b) { 
+  a.p();
+  b.data_member;
+  B::static_member;
+};
+}
+static_assert(!A<1>::faz());
+static_assert(A<0>::faz());
+} // namespace in_requires_expression
+
+namespace in_concepts {
+// Dependent access does not cause hard errors.
+template class A;
+
+template <> class A<0> {
+  static void f() {}
+};
+template
+concept C1 = requires() { A::f(); };
+static_assert(!C1<0>);
+
+template <> class A<1> {
+public: 
+  static void f() {}
+};
+static_assert(C1<1>);
+
+// Non-dependent access to private member is a hard error.
+class B{
+   static void f() {} // expected-note 2{{implicitly declared private here}}
+};
+template
+concept C2 = requires() { B::f(); }; // expected-error {{'f' is a private member}}
+
+constexpr bool non_template_func() {
+  return requires() {
+  B::f(); // expected-error {{'f' is a private member}}
+  };
+}
+template
+constexpr bool template_func() {
+  return requires() {
+  A::f();
+  };
+}
+static_assert(!template_func<0>());
+static_assert(template_func<1>());
+} // namespace in_concepts
+
+namespace in_trailing_requires {
+template  struct B;
+class A {
+   static void f();
+   friend struct B;
+};
+ 
+template  struct B {
+  static constexpr int index() requires requires{ A::f(); } {
+return 1;
+  }
+  static constexpr int index() {
+return 2;
+  }
+};
+
+static_assert(B::index() == 1);
+static_assert(B::index() == 2);
+
+namespace missing_member_function {
+template  struct Use;
+class X { 
+  int a;
+  static int B;
+  friend struct Use;
+};
+template  struct Use {
+  constexpr static int foo() requires requires(X x) { x.a; } {
+return 1;
+  }
+  constexpr static int bar() requires requires { X::B; } {
+return 1;
+  }
+};
+
+void test() {
+  // FIXME: Propagate diagnostic.
+  Use::foo(); //expected-error {{invalid reference to function 'foo': constraints not satisfied}}
+  static_assert(Use::foo() == 1);
+}
+} // namespace missing_member_function
+} // namespace in_trailing_requires
+} // namespace 

[PATCH] D140547: Perform access checking to private members in simple requirement.

2023-01-05 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 486604.
usaxena95 added a comment.

Use ParsingDeclRAIIObject instead of ContextRAII.

This creates a separate diagnostic pool for diagnositcs associated to the 
RequiresExprBodyDecl.
This is important because dependent diagnostics should not leak to higher 
scopes (Eg. inside a template function or in a trailing requires). These 
dependent diagnstics must be attached to the DeclContext of the parameters of 
RequiresExpr (which is the BodyDecl in this case).
Non dependent diagnostics should not delayed and surfaced as hard errors.

This addresses the previously failing LibCXX failure as well.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D140547

Files:
  clang/include/clang/AST/ExprConcepts.h
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Sema/SemaAccess.cpp
  clang/lib/Sema/SemaConcept.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp

Index: clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
@@ -104,3 +104,138 @@
 constexpr bool b = requires (X ) { static_cast(nullptr); };
 // expected-error@-1{{constraint variable 'x' cannot be used in an evaluated context}}
 // expected-note@-2{{'x' declared here}}
+
+namespace access_checks {
+namespace in_requires_expression {
+template
+struct A {
+static constexpr bool foo();
+static constexpr bool bar();
+static constexpr bool baz();
+static constexpr bool faz();
+};
+
+class C{};
+
+class B {
+void p() {}
+bool data_member = true;
+static const bool static_member = true;
+friend struct A<0>;
+};
+
+template
+constexpr bool A::foo() {
+return requires(B b) { b.p(); };
+}
+static_assert(!A<1>::foo());
+static_assert(A<0>::foo());
+
+template
+constexpr bool A::bar() {
+return requires() { B::static_member; };
+}
+static_assert(!A<1>::bar());
+static_assert(A<0>::bar());
+
+template
+constexpr bool A::baz() {
+return requires(B b) { b.data_member; };
+}
+static_assert(!A<1>::baz());
+static_assert(A<0>::baz());
+
+template
+constexpr bool A::faz() {
+return requires(B a, B b) { 
+  a.p();
+  b.data_member;
+  B::static_member;
+};
+}
+static_assert(!A<1>::faz());
+static_assert(A<0>::faz());
+} // namespace in_requires_expression
+
+namespace in_concepts {
+// Dependent access does not cause hard errors.
+template class A;
+
+template <> class A<0> {
+  static void f() {}
+};
+template
+concept C1 = requires() { A::f(); };
+static_assert(!C1<0>);
+
+template <> class A<1> {
+public: 
+  static void f() {}
+};
+static_assert(C1<1>);
+
+// Non-dependent access to private member is a hard error.
+class B{
+   static void f() {} // expected-note 2{{implicitly declared private here}}
+};
+template
+concept C2 = requires() { B::f(); }; // expected-error {{'f' is a private member}}
+
+constexpr bool non_template_func() {
+  return requires() {
+  B::f(); // expected-error {{'f' is a private member}}
+  };
+}
+template
+constexpr bool template_func() {
+  return requires() {
+  A::f();
+  };
+}
+static_assert(!template_func<0>());
+static_assert(template_func<1>());
+} // namespace in_concepts
+
+namespace in_trailing_requires {
+template  struct B;
+class A {
+   static void f();
+   friend struct B;
+};
+ 
+template  struct B {
+  static constexpr int index() requires requires{ A::f(); } {
+return 1;
+  }
+  static constexpr int index() {
+return 2;
+  }
+};
+
+static_assert(B::index() == 1);
+static_assert(B::index() == 2);
+
+namespace missing_member_function {
+template  struct Use;
+class X { 
+  int a;
+  static int B;
+  friend struct Use;
+};
+template  struct Use {
+  constexpr static int foo() requires requires(X x) { x.a; } {
+return 1;
+  }
+  constexpr static int bar() requires requires { X::B; } {
+return 1;
+  }
+};
+
+void test() {
+  // TODO: Propagate diagnostic.
+  Use::foo(); //expected-error {{invalid reference to function 'foo': constraints not satisfied}}
+  static_assert(Use::foo() == 1);
+}
+} // namespace missing_member_function
+} // namespace in_trailing_requires
+} // namespace access_check
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTLambda.h"
 #include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprConcepts.h"
@@ -1363,7 +1364,17 @@
 
 ExprResult TransformRequiresExpr(RequiresExpr *E) {
   

[PATCH] D140547: Perform access checking to private members in simple requirement.

2023-01-04 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 486357.
usaxena95 added a comment.

Return a valid RequriesExpr instead of a ExprError in case of depenedent 
diagnositcs. 
We would also need to store the diagnositcs in the RequiresExpr for better 
diagnosis.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D140547

Files:
  clang/include/clang/AST/ExprConcepts.h
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Sema/SemaConcept.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp

Index: clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
@@ -104,3 +104,138 @@
 constexpr bool b = requires (X ) { static_cast(nullptr); };
 // expected-error@-1{{constraint variable 'x' cannot be used in an evaluated context}}
 // expected-note@-2{{'x' declared here}}
+
+namespace access_checks {
+namespace in_requires_expression {
+template
+struct A {
+static constexpr bool foo();
+static constexpr bool bar();
+static constexpr bool baz();
+static constexpr bool faz();
+};
+
+class C{};
+
+class B {
+void p() {}
+bool data_member = true;
+static const bool static_member = true;
+friend struct A<0>;
+};
+
+template
+constexpr bool A::foo() {
+return requires(B b) { b.p(); };
+}
+static_assert(!A<1>::foo());
+static_assert(A<0>::foo());
+
+template
+constexpr bool A::bar() {
+return requires() { B::static_member; };
+}
+static_assert(!A<1>::bar());
+static_assert(A<0>::bar());
+
+template
+constexpr bool A::baz() {
+return requires(B b) { b.data_member; };
+}
+static_assert(!A<1>::baz());
+static_assert(A<0>::baz());
+
+template
+constexpr bool A::faz() {
+return requires(B a, B b) { 
+  a.p();
+  b.data_member;
+  B::static_member;
+};
+}
+static_assert(!A<1>::faz());
+static_assert(A<0>::faz());
+} // namespace in_requires_expression
+
+namespace in_concepts {
+// Dependent access does not cause hard errors.
+template class A;
+
+template <> class A<0> {
+  static void f() {}
+};
+template
+concept C1 = requires() { A::f(); };
+static_assert(!C1<0>);
+
+template <> class A<1> {
+public: 
+  static void f() {}
+};
+static_assert(C1<1>);
+
+// Non-dependent access to private member is a hard error.
+class B{
+   static void f() {} // expected-note 2{{implicitly declared private here}}
+};
+template
+concept C2 = requires() { B::f(); }; // expected-error {{'f' is a private member}}
+
+constexpr bool non_template_func() {
+  return requires() {
+  B::f(); // expected-error {{'f' is a private member}}
+  };
+}
+template
+constexpr bool template_func() {
+  return requires() {
+  A::f();
+  };
+}
+static_assert(!template_func<0>());
+static_assert(template_func<1>());
+} // namespace in_concepts
+
+namespace in_trailing_requires {
+template  struct B;
+class A {
+   static void f();
+   friend struct B;
+};
+ 
+template  struct B {
+  static constexpr int index() requires requires{ A::f(); } {
+return 1;
+  }
+  static constexpr int index() {
+return 2;
+  }
+};
+
+static_assert(B::index() == 1);
+static_assert(B::index() == 2);
+
+namespace missing_member_function {
+template  struct Use;
+class X { 
+  int a;
+  static int B;
+  friend struct Use;
+};
+template  struct Use {
+  constexpr static int foo() requires requires(X x) { x.a; } {
+return 1;
+  }
+  constexpr static int bar() requires requires { X::B; } {
+return 1;
+  }
+};
+
+void test() {
+  // TODO: Propagate diagnostic.
+  Use::foo(); //expected-error {{invalid reference to function 'foo': constraints not satisfied}}
+  static_assert(Use::foo() == 1);
+}
+} // namespace missing_member_function
+} // namespace in_trailing_requires
+} // namespace access_check
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTLambda.h"
 #include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprConcepts.h"
@@ -1363,7 +1364,17 @@
 
 ExprResult TransformRequiresExpr(RequiresExpr *E) {
   LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
-  return inherited::TransformRequiresExpr(E);
+  auto TransReq = inherited::TransformRequiresExpr(E);
+  if (E->getBody()->isDependentContext()) {
+Sema::SFINAETrap Trap(SemaRef);
+// We recreate the RequiresExpr body, but not by instantiating it.
+// Produce pending diagnostics for dependent access check.

[PATCH] D140547: Perform access checking to private members in simple requirement.

2023-01-04 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 486313.
usaxena95 marked an inline comment as done.
usaxena95 added a comment.

Added more tests. Still investigating libcxx failure and tests.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D140547

Files:
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp

Index: clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
@@ -104,3 +104,138 @@
 constexpr bool b = requires (X ) { static_cast(nullptr); };
 // expected-error@-1{{constraint variable 'x' cannot be used in an evaluated context}}
 // expected-note@-2{{'x' declared here}}
+
+namespace access_checks {
+namespace in_requires_expression {
+template
+struct A {
+static constexpr bool foo();
+static constexpr bool bar();
+static constexpr bool baz();
+static constexpr bool faz();
+};
+
+class C{};
+
+class B {
+void p() {}
+bool data_member = true;
+static const bool static_member = true;
+friend struct A<0>;
+};
+
+template
+constexpr bool A::foo() {
+return requires(B b) { b.p(); };
+}
+static_assert(!A<1>::foo());
+static_assert(A<0>::foo());
+
+template
+constexpr bool A::bar() {
+return requires() { B::static_member; };
+}
+static_assert(!A<1>::bar());
+static_assert(A<0>::bar());
+
+template
+constexpr bool A::baz() {
+return requires(B b) { b.data_member; };
+}
+static_assert(!A<1>::baz());
+static_assert(A<0>::baz());
+
+template
+constexpr bool A::faz() {
+return requires(B a, B b) { 
+  a.p();
+  b.data_member;
+  B::static_member;
+};
+}
+static_assert(!A<1>::faz());
+static_assert(A<0>::faz());
+} // namespace in_requires_expression
+
+namespace in_concepts {
+// Dependent access does not cause hard errors.
+template class A;
+
+template <> class A<0> {
+  static void f() {}
+};
+template
+concept C1 = requires() { A::f(); };
+static_assert(!C1<0>);
+
+template <> class A<1> {
+public: 
+  static void f() {}
+};
+static_assert(C1<1>);
+
+// Non-dependent access to private member is a hard error.
+class B{
+   static void f() {} // expected-note 2{{implicitly declared private here}}
+};
+template
+concept C2 = requires() { B::f(); }; // expected-error {{'f' is a private member}}
+
+constexpr bool non_template_func() {
+  return requires() {
+  B::f(); // expected-error {{'f' is a private member}}
+  };
+}
+template
+constexpr bool template_func() {
+  return requires() {
+  A::f();
+  };
+}
+static_assert(!template_func<0>());
+static_assert(template_func<1>());
+} // namespace in_concepts
+
+namespace in_trailing_requires {
+template  struct B;
+class A {
+   static void f();
+   friend struct B;
+};
+ 
+template  struct B {
+  static constexpr int index() requires requires{ A::f(); } {
+return 1;
+  }
+  static constexpr int index() {
+return 2;
+  }
+};
+
+static_assert(B::index() == 1);
+static_assert(B::index() == 2);
+
+namespace missing_member_function {
+template  struct Use;
+class X { 
+  int a;
+  static int B;
+  friend struct Use;
+};
+template  struct Use {
+  constexpr static int foo() requires requires(X x) { x.a; } {
+return 1;
+  }
+  constexpr static int bar() requires requires { X::B; } {
+return 1;
+  }
+};
+
+void test() {
+  // FIXME: This should be an error.
+  Use::foo();
+  static_assert(Use::foo() == 1);
+}
+} // namespace missing_member_function
+} // namespace in_trailing_requires
+} // namespace access_check
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTLambda.h"
 #include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprConcepts.h"
@@ -1363,7 +1364,16 @@
 
 ExprResult TransformRequiresExpr(RequiresExpr *E) {
   LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
-  return inherited::TransformRequiresExpr(E);
+  auto TransReq = inherited::TransformRequiresExpr(E);
+  if (E->getBody()->isDependentContext()) {
+Sema::SFINAETrap Trap(SemaRef);
+// We recreate the RequiresExpr body, but not by instantiating it.
+// Produce pending diagnostics for dependent access check.
+SemaRef.PerformDependentDiagnostics(E->getBody(), TemplateArgs);
+if (Trap.hasErrorOccurred())
+  return ExprError();
+  }
+  return TransReq;
 }
 
 bool 

[PATCH] D140547: Perform access checking to private members in simple requirement.

2023-01-04 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 marked an inline comment as done.
usaxena95 added inline comments.



Comment at: clang/lib/Sema/SemaTemplateInstantiate.cpp:1367
+  if (E->getBody()->isDependentContext()) {
+Sema::SFINAETrap Trap(SemaRef);
+// We recreate the RequiresExpr body, but not by instantiating it.

ilya-biryukov wrote:
> Other uses of `PerformDependentDiagnostics` do not add an explicit 
> `SFINAETrap` AFAICS.
> Why is `RequiresExpr` special? Because it should "eat" the errors and only 
> return a value?
Yes. Precisely. 



Comment at: 
clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp:157
+static_assert(A<0>::faz());
+}

ilya-biryukov wrote:
> Could you add a check that in the following case we mention access check in 
> the note to the `no matching function to call` error?
> 
> ```
> template  struct Use;
> 
> class X { int a; friend struct Use; };
> 
> template  struct Use {
>   static void foo() requires (requires (X x) { x.a; }) {
>   }
> };
> 
> void test() {
> Use::foo();
> }
> ```
Added. This does not produce any diagnostics. Investigating!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D140547

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


[PATCH] D140876: [clang][C++20] Non-dependent access checks in requires expression.

2023-01-04 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 abandoned this revision.
usaxena95 marked an inline comment as done.
usaxena95 added a comment.

Moving the changes to https://reviews.llvm.org/D140547


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D140876

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


[PATCH] D140547: Perform access checking to private members in simple requirement.

2023-01-04 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 486255.
usaxena95 marked 3 inline comments as done.
usaxena95 added a comment.

Adding access check related changes from https://reviews.llvm.org/D140876


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D140547

Files:
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp

Index: clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
@@ -104,3 +104,129 @@
 constexpr bool b = requires (X ) { static_cast(nullptr); };
 // expected-error@-1{{constraint variable 'x' cannot be used in an evaluated context}}
 // expected-note@-2{{'x' declared here}}
+
+namespace access_checks {
+template
+struct A {
+static constexpr bool foo();
+static constexpr bool bar();
+static constexpr bool baz();
+static constexpr bool faz();
+};
+
+class C{};
+
+class B {
+void p() {}
+bool data_member = true;
+static const bool static_member = true;
+friend struct A<0>;
+};
+
+template
+constexpr bool A::foo() {
+return requires(B b) { b.p(); };
+}
+static_assert(!A<1>::foo());
+static_assert(A<0>::foo());
+
+template
+constexpr bool A::bar() {
+return requires() { B::static_member; };
+}
+static_assert(!A<1>::bar());
+static_assert(A<0>::bar());
+
+template
+constexpr bool A::baz() {
+return requires(B b) { b.data_member; };
+}
+static_assert(!A<1>::baz());
+static_assert(A<0>::baz());
+
+template
+constexpr bool A::faz() {
+return requires(B a, B b) { 
+  a.p();
+  b.data_member;
+  B::static_member;
+};
+}
+static_assert(!A<1>::faz());
+static_assert(A<0>::faz());
+}
+
+namespace access_check_in_concepts {
+// Dependent access does not cause hard errors.
+template class A;
+
+template <> class A<0> {
+  static void f() {}
+};
+template
+concept C1 = requires() { A::f(); };
+static_assert(!C1<0>);
+
+template <> class A<1> {
+public: 
+  static void f() {}
+};
+static_assert(C1<1>);
+
+// Non-dependent access to private member is a hard error.
+class B{
+   static void f() {} // expected-note 2{{implicitly declared private here}}
+};
+template
+concept C2 = requires() { B::f(); }; // expected-error {{'f' is a private member}}
+
+constexpr bool non_template_func() {
+  return requires() {
+  B::f(); // expected-error {{'f' is a private member}}
+  };
+}
+template
+constexpr bool template_func() {
+  return requires() {
+  A::f();
+  };
+}
+static_assert(!template_func<0>());
+static_assert(template_func<1>());
+
+namespace access_check_in_trailing_requires {
+template  struct B;
+class A {
+   static void f();
+   friend struct B;
+};
+ 
+template  struct B {
+static constexpr int index() requires requires{ A::f(); } {
+return 1;
+}
+static constexpr int index() {
+return 2;
+}
+};
+
+static_assert(B::index() == 1);
+static_assert(B::index() == 2);
+
+namespace missing_member_function {
+template  struct Use;
+class X { int a; friend struct Use; };
+template  struct Use {
+  constexpr static int foo() requires requires(X x) { x.a; } {
+return 1;
+  }
+};
+
+void test() {
+  // FIXME: This should be an error.
+  Use::foo();
+  static_assert(Use::foo() == 1);
+}
+}
+}
+}
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTLambda.h"
 #include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprConcepts.h"
@@ -1363,7 +1364,16 @@
 
 ExprResult TransformRequiresExpr(RequiresExpr *E) {
   LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
-  return inherited::TransformRequiresExpr(E);
+  auto TransReq = inherited::TransformRequiresExpr(E);
+  if (E->getBody()->isDependentContext()) {
+Sema::SFINAETrap Trap(SemaRef);
+// We recreate the RequiresExpr body, but not by instantiating it.
+// Produce pending diagnostics for dependent access check.
+SemaRef.PerformDependentDiagnostics(E->getBody(), TemplateArgs);
+if (Trap.hasErrorOccurred())
+  return ExprError();
+  }
+  return TransReq;
 }
 
 bool TransformRequiresExprRequirements(
Index: clang/lib/Parse/ParseExprCXX.cpp
===
--- clang/lib/Parse/ParseExprCXX.cpp
+++ clang/lib/Parse/ParseExprCXX.cpp
@@ -3507,6 +3507,7 @@
   //   Expressions appearing within 

[PATCH] D140876: [clang][C++20] Non-dependent access checks in requires expression.

2023-01-04 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 marked an inline comment as done.
usaxena95 added a comment.

In D140876#4023286 , @ilya-biryukov 
wrote:

> Should access checks should happen in the context where `concept` is written 
> or where it's used?
> If access-checking should happen where concept is defined, having a hard 
> error seems fine because of the wording you quoted:

As Roy indicated, this is a wording issue. For the time being, concepts are not 
evaluated in the scope of its use (as the result of atomic constraints should 
be same at all points of program). An independent requires clause on the other 
hand considers the scope where it is written.

>> If the substitution of template arguments into a requirement would always 
>> result in a substitution failure, the program is ill-formed; no diagnostic 
>> required.
>
> The program is ill-formed and we show the diagnostic even though it's not 
> required.

Are you suggesting to drop the diagnostic in this case ? I think

> I poked around and found an interesting case where GCC seems to be doing the 
> wrong thing:
>
>   template  struct B;
>   class A {
>  static void f();
>  friend struct B;
>   };
>
>   template  struct B {
>   static constexpr int index() requires requires{ A::f(); } {
>   return 1;
>   }
>   static constexpr int index() {
>   return 2;
>   }
>   };
>   
>   static_assert(B::index() == 1); // GCC picks 1, MSVC picks 1.
>   static_assert(B::index() == 2);   // GCC (incorrectly?) picks 1, MSVC 
> picks 2!
>
> Is this related to this change? Could we add a test that validates Clang is 
> doing the right thing?

This is an interesting test case. Clang does the right thing here and it is 
related to both this change and the base change 
https://reviews.llvm.org/D140547.
The test case mentioned on that patch also needs both the changes and also 
something else.

I will squash both these patches into one for a better review/commit.




Comment at: clang/lib/Parse/ParseExprCXX.cpp:3510
   Actions, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::ContextRAII SaveContext(Actions, Actions.CurContext);
 

ilya-biryukov wrote:
> Could you explain how this changes behaviour and how it leads to fixing the 
> issue?
> 
> I'm sure there is quite a bit of thought and debugging behind this one-line 
> change, but it's not evident by just looking at it how it solves the issue.
Sorry for not providing more context here. I agree this makes things work quite 
unexpectedly. 

The main issue here is the delaying of the diagnostics. Eg in 
`Parser::ParseTemplateDeclarationOrSpecialization` through 
`ParsingDeclRAIIObject ParsingTemplateParams`. Diagnostics in 
`ParseConceptDefinition` are attached to  Diagnostics pool of 
`ParsingTemplateParams` which are never flushed. Creating a new context does 
not delay the diagnostics. 


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D140876

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


[PATCH] D140876: [clang][C++20] Non-dependent access checks in requires expression.

2023-01-03 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 485939.
usaxena95 added a comment.

More tests.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D140876

Files:
  clang/lib/Parse/ParseExprCXX.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp


Index: clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
@@ -155,3 +155,42 @@
 static_assert(!A<1>::faz());
 static_assert(A<0>::faz());
 }
+
+namespace non_dependent_access_check_hard_errors {
+// Dependent access does not cause hard errors.
+template class A;
+
+template <> class A<0> {
+  static void f() {}
+};
+template
+concept C1 = requires() { A::f(); };
+static_assert(!C1<0>);
+
+template <> class A<1> {
+public: 
+  static void f() {}
+};
+static_assert(C1<1>);
+
+// Non-dependent access to private member is a hard error.
+class B{
+   static void f() {} // expected-note 2{{implicitly declared private here}}
+};
+template
+concept C2 = requires() { B::f(); }; // expected-error {{'f' is a private 
member}}
+
+constexpr bool non_template_func() {
+  return requires() {
+  B::f(); // expected-error {{'f' is a private member}}
+  };
+}
+template
+constexpr bool template_func() {
+  return requires() {
+  A::f();
+  };
+}
+static_assert(!template_func<0>());
+static_assert(template_func<1>());
+}
Index: clang/lib/Parse/ParseExprCXX.cpp
===
--- clang/lib/Parse/ParseExprCXX.cpp
+++ clang/lib/Parse/ParseExprCXX.cpp
@@ -3507,6 +3507,7 @@
   //   Expressions appearing within a requirement-body are unevaluated 
operands.
   EnterExpressionEvaluationContext Ctx(
   Actions, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::ContextRAII SaveContext(Actions, Actions.CurContext);
 
   ParseScope BodyScope(this, Scope::DeclScope);
   RequiresExprBodyDecl *Body = Actions.ActOnStartRequiresExpr(


Index: clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
@@ -155,3 +155,42 @@
 static_assert(!A<1>::faz());
 static_assert(A<0>::faz());
 }
+
+namespace non_dependent_access_check_hard_errors {
+// Dependent access does not cause hard errors.
+template class A;
+
+template <> class A<0> {
+  static void f() {}
+};
+template
+concept C1 = requires() { A::f(); };
+static_assert(!C1<0>);
+
+template <> class A<1> {
+public: 
+  static void f() {}
+};
+static_assert(C1<1>);
+
+// Non-dependent access to private member is a hard error.
+class B{
+   static void f() {} // expected-note 2{{implicitly declared private here}}
+};
+template
+concept C2 = requires() { B::f(); }; // expected-error {{'f' is a private member}}
+
+constexpr bool non_template_func() {
+  return requires() {
+  B::f(); // expected-error {{'f' is a private member}}
+  };
+}
+template
+constexpr bool template_func() {
+  return requires() {
+  A::f();
+  };
+}
+static_assert(!template_func<0>());
+static_assert(template_func<1>());
+}
Index: clang/lib/Parse/ParseExprCXX.cpp
===
--- clang/lib/Parse/ParseExprCXX.cpp
+++ clang/lib/Parse/ParseExprCXX.cpp
@@ -3507,6 +3507,7 @@
   //   Expressions appearing within a requirement-body are unevaluated operands.
   EnterExpressionEvaluationContext Ctx(
   Actions, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::ContextRAII SaveContext(Actions, Actions.CurContext);
 
   ParseScope BodyScope(this, Scope::DeclScope);
   RequiresExprBodyDecl *Body = Actions.ActOnStartRequiresExpr(
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D140876: [clang][C++20] Non-dependent access checks in requires expression.

2023-01-03 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 created this revision.
Herald added a project: All.
usaxena95 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Access to members in a non-dependent context would always yield an
invalid expression. When it appears in a requires-expression, then this
is a hard error as this would always result in a substitution failure.

https://eel.is/c++draft/expr.prim.req#general-note-1
Note 1: If a requires-expression contains invalid types or expressions in its 
requirements, and it does not appear within the declaration of a templated 
entity, then the program is ill-formed. — end note]
If the substitution of template arguments into a requirement would always 
result in a substitution failure, the program is ill-formed; no diagnostic 
required.

Fixes: https://github.com/llvm/llvm-project/issues/53334


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D140876

Files:
  clang/lib/Parse/ParseExprCXX.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp


Index: clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
@@ -155,3 +155,28 @@
 static_assert(!A<1>::faz());
 static_assert(A<0>::faz());
 }
+
+namespace non_dependent_access_check_hard_errors {
+// Dependent access does not cause hard errors.
+template class A;
+
+template <> class A<0> {
+  static void f() {}
+};
+template
+concept C1 = requires() { A::f(); };
+static_assert(!C1<0>);
+
+template <> class A<1> {
+public: 
+  static void f() {}
+};
+static_assert(C1<1>);
+
+// Non-dependent access to private member is a hard error.
+class B{
+   static void f() {} // expected-note {{implicitly declared private here}}
+};
+template
+concept C2 = requires() { B::f(); }; // expected-error {{'f' is a private 
member}}
+}
Index: clang/lib/Parse/ParseExprCXX.cpp
===
--- clang/lib/Parse/ParseExprCXX.cpp
+++ clang/lib/Parse/ParseExprCXX.cpp
@@ -3507,6 +3507,7 @@
   //   Expressions appearing within a requirement-body are unevaluated 
operands.
   EnterExpressionEvaluationContext Ctx(
   Actions, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::ContextRAII SaveContext(Actions, Actions.CurContext);
 
   ParseScope BodyScope(this, Scope::DeclScope);
   RequiresExprBodyDecl *Body = Actions.ActOnStartRequiresExpr(


Index: clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
@@ -155,3 +155,28 @@
 static_assert(!A<1>::faz());
 static_assert(A<0>::faz());
 }
+
+namespace non_dependent_access_check_hard_errors {
+// Dependent access does not cause hard errors.
+template class A;
+
+template <> class A<0> {
+  static void f() {}
+};
+template
+concept C1 = requires() { A::f(); };
+static_assert(!C1<0>);
+
+template <> class A<1> {
+public: 
+  static void f() {}
+};
+static_assert(C1<1>);
+
+// Non-dependent access to private member is a hard error.
+class B{
+   static void f() {} // expected-note {{implicitly declared private here}}
+};
+template
+concept C2 = requires() { B::f(); }; // expected-error {{'f' is a private member}}
+}
Index: clang/lib/Parse/ParseExprCXX.cpp
===
--- clang/lib/Parse/ParseExprCXX.cpp
+++ clang/lib/Parse/ParseExprCXX.cpp
@@ -3507,6 +3507,7 @@
   //   Expressions appearing within a requirement-body are unevaluated operands.
   EnterExpressionEvaluationContext Ctx(
   Actions, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::ContextRAII SaveContext(Actions, Actions.CurContext);
 
   ParseScope BodyScope(this, Scope::DeclScope);
   RequiresExprBodyDecl *Body = Actions.ActOnStartRequiresExpr(
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D140547: Perform access checking to private members in simple requirement.

2022-12-30 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 485726.
usaxena95 added a comment.

Improved comment and added comment.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D140547

Files:
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp


Index: clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
@@ -104,3 +104,54 @@
 constexpr bool b = requires (X ) { static_cast(nullptr); };
 // expected-error@-1{{constraint variable 'x' cannot be used in an evaluated 
context}}
 // expected-note@-2{{'x' declared here}}
+
+namespace access_checks {
+template
+struct A {
+static constexpr bool foo();
+static constexpr bool bar();
+static constexpr bool baz();
+static constexpr bool faz();
+};
+
+class C{};
+
+class B {
+void p() {}
+bool data_member = true;
+static const bool static_member = true;
+friend struct A<0>;
+};
+
+template
+constexpr bool A::foo() {
+return requires(B b) { b.p(); };
+}
+static_assert(!A<1>::foo());
+static_assert(A<0>::foo());
+
+template
+constexpr bool A::bar() {
+return requires() { B::static_member; };
+}
+static_assert(!A<1>::bar());
+static_assert(A<0>::bar());
+
+template
+constexpr bool A::baz() {
+return requires(B b) { b.data_member; };
+}
+static_assert(!A<1>::baz());
+static_assert(A<0>::baz());
+
+template
+constexpr bool A::faz() {
+return requires(B a, B b) { 
+  a.p();
+  b.data_member;
+  B::static_member;
+};
+}
+static_assert(!A<1>::faz());
+static_assert(A<0>::faz());
+}
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTLambda.h"
 #include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprConcepts.h"
@@ -1362,6 +1363,14 @@
 }
 
 ExprResult TransformRequiresExpr(RequiresExpr *E) {
+  if (E->getBody()->isDependentContext()) {
+Sema::SFINAETrap Trap(SemaRef);
+// We recreate the RequiresExpr body, but not by instantiating it.
+// Produce pending diagnostics for dependent access check.
+SemaRef.PerformDependentDiagnostics(E->getBody(), TemplateArgs);
+if (Trap.hasErrorOccurred())
+  return ExprError();
+  }
   LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
   return inherited::TransformRequiresExpr(E);
 }


Index: clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
@@ -104,3 +104,54 @@
 constexpr bool b = requires (X ) { static_cast(nullptr); };
 // expected-error@-1{{constraint variable 'x' cannot be used in an evaluated context}}
 // expected-note@-2{{'x' declared here}}
+
+namespace access_checks {
+template
+struct A {
+static constexpr bool foo();
+static constexpr bool bar();
+static constexpr bool baz();
+static constexpr bool faz();
+};
+
+class C{};
+
+class B {
+void p() {}
+bool data_member = true;
+static const bool static_member = true;
+friend struct A<0>;
+};
+
+template
+constexpr bool A::foo() {
+return requires(B b) { b.p(); };
+}
+static_assert(!A<1>::foo());
+static_assert(A<0>::foo());
+
+template
+constexpr bool A::bar() {
+return requires() { B::static_member; };
+}
+static_assert(!A<1>::bar());
+static_assert(A<0>::bar());
+
+template
+constexpr bool A::baz() {
+return requires(B b) { b.data_member; };
+}
+static_assert(!A<1>::baz());
+static_assert(A<0>::baz());
+
+template
+constexpr bool A::faz() {
+return requires(B a, B b) { 
+  a.p();
+  b.data_member;
+  B::static_member;
+};
+}
+static_assert(!A<1>::faz());
+static_assert(A<0>::faz());
+}
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTLambda.h"
 #include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprConcepts.h"
@@ -1362,6 +1363,14 @@
 }
 
 ExprResult TransformRequiresExpr(RequiresExpr *E) {
+  if 

[PATCH] D140547: Perform access checking to private members in simple requirement.

2022-12-30 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 485725.
usaxena95 added a comment.

Perform access-dependent checks after transforming requires clause.
This is more generic and less invasive than the previous version which changed 
`RebuildMemberExpr` and also produced duplicate diagnostics.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D140547

Files:
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp


Index: clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
@@ -104,3 +104,54 @@
 constexpr bool b = requires (X ) { static_cast(nullptr); };
 // expected-error@-1{{constraint variable 'x' cannot be used in an evaluated 
context}}
 // expected-note@-2{{'x' declared here}}
+
+namespace access_checks {
+template
+struct A {
+static constexpr bool foo();
+static constexpr bool bar();
+static constexpr bool baz();
+static constexpr bool faz();
+};
+
+class C{};
+
+class B {
+void p() {}
+bool data_member = true;
+static const bool static_member = true;
+friend struct A<0>;
+};
+
+template
+constexpr bool A::foo() {
+return requires(B b) { b.p(); };
+}
+static_assert(!A<1>::foo());
+static_assert(A<0>::foo());
+
+template
+constexpr bool A::bar() {
+return requires() { B::static_member; };
+}
+static_assert(!A<1>::bar());
+static_assert(A<0>::bar());
+
+template
+constexpr bool A::baz() {
+return requires(B b) { b.data_member; };
+}
+static_assert(!A<1>::baz());
+static_assert(A<0>::baz());
+
+template
+constexpr bool A::faz() {
+return requires(B a, B b) { 
+  a.p();
+  b.data_member;
+  B::static_member;
+};
+}
+static_assert(!A<1>::faz());
+static_assert(A<0>::faz());
+}
\ No newline at end of file
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTLambda.h"
 #include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprConcepts.h"
@@ -1363,7 +1364,19 @@
 
 ExprResult TransformRequiresExpr(RequiresExpr *E) {
   LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
-  return inherited::TransformRequiresExpr(E);
+  ExprResult TransReq = inherited::TransformRequiresExpr(E);
+  {
+if (TransReq.isInvalid() || !E->getBody()->isDependentContext())
+  return TransReq;
+Sema::SFINAETrap Trap(SemaRef);
+// We recreated parameters, but not by instantiating them. There may be
+// pending access-dependent diagnostics to produce.
+// RequiresExpr Body serves as the DeclContext for the parameters.
+SemaRef.PerformDependentDiagnostics(E->getBody(), TemplateArgs);
+if (Trap.hasErrorOccurred())
+  return ExprError();
+  }
+  return TransReq;
 }
 
 bool TransformRequiresExprRequirements(


Index: clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
@@ -104,3 +104,54 @@
 constexpr bool b = requires (X ) { static_cast(nullptr); };
 // expected-error@-1{{constraint variable 'x' cannot be used in an evaluated context}}
 // expected-note@-2{{'x' declared here}}
+
+namespace access_checks {
+template
+struct A {
+static constexpr bool foo();
+static constexpr bool bar();
+static constexpr bool baz();
+static constexpr bool faz();
+};
+
+class C{};
+
+class B {
+void p() {}
+bool data_member = true;
+static const bool static_member = true;
+friend struct A<0>;
+};
+
+template
+constexpr bool A::foo() {
+return requires(B b) { b.p(); };
+}
+static_assert(!A<1>::foo());
+static_assert(A<0>::foo());
+
+template
+constexpr bool A::bar() {
+return requires() { B::static_member; };
+}
+static_assert(!A<1>::bar());
+static_assert(A<0>::bar());
+
+template
+constexpr bool A::baz() {
+return requires(B b) { b.data_member; };
+}
+static_assert(!A<1>::baz());
+static_assert(A<0>::baz());
+
+template
+constexpr bool A::faz() {
+return requires(B a, B b) { 
+  a.p();
+  b.data_member;
+  B::static_member;
+};
+}
+static_assert(!A<1>::faz());
+static_assert(A<0>::faz());
+}
\ No newline at end of file
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp

[PATCH] D140547: Perform access checking to private members in simple requirement.

2022-12-22 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 created this revision.
Herald added a project: All.
usaxena95 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D140547

Files:
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/lib/Sema/TreeTransform.h
  clang/test/CXX/class.access/p4.cpp
  clang/test/CXX/drs/dr6xx.cpp
  clang/test/CXX/temp/temp.decls/temp.friend/p1.cpp
  clang/test/SemaCXX/access.cpp

Index: clang/test/SemaCXX/access.cpp
===
--- clang/test/SemaCXX/access.cpp
+++ clang/test/SemaCXX/access.cpp
@@ -115,13 +115,13 @@
 namespace N {
 class Y {
   template friend struct X;
-  int t; // expected-note {{here}}
+  int t; // expected-note 2 {{here}}
 };
 }
 template struct X {
-  X() { (void)N::Y().t; } // expected-error {{private}}
+  X() { (void)N::Y().t; } // expected-error 2 {{private}}
 };
-X x;
+X x; // expected-note {{in instantiation of member function}}
   }
   namespace comment2 {
 struct X;
Index: clang/test/CXX/temp/temp.decls/temp.friend/p1.cpp
===
--- clang/test/CXX/temp/temp.decls/temp.friend/p1.cpp
+++ clang/test/CXX/temp/temp.decls/temp.friend/p1.cpp
@@ -97,17 +97,17 @@
 friend class User;
 friend bool transform<>(Bool, bool);
 
-bool value; // expected-note 2 {{declared private here}}
+bool value; // expected-note 4 {{declared private here}}
   };
 
   template  class User {
 static T compute(Bool b) {
-  return b.value; // expected-error {{'value' is a private member of 'test3::Bool'}}
+  return b.value; // expected-error 2 {{'value' is a private member of 'test3::Bool'}}
 }
   };
 
   template  T transform(Bool b, T value) {
-if (b.value) // expected-error {{'value' is a private member of 'test3::Bool'}}
+if (b.value) // expected-error 2 {{'value' is a private member of 'test3::Bool'}}
   return value;
 return value + 1;
   }
@@ -222,7 +222,7 @@
   template  A bar(const T*, const A&);
   template  class A {
   private:
-void foo(); // expected-note {{declared private here}}
+void foo(); // expected-note 2 {{declared private here}}
 friend A bar<>(const T*, const A&);
   };
 
@@ -231,7 +231,7 @@
 l1.foo();
 
 A l2;
-l2.foo(); // expected-error {{'foo' is a private member of 'test10::A'}}
+l2.foo(); // expected-error 2 {{'foo' is a private member of 'test10::A'}}
 
 return l1;
   }
Index: clang/test/CXX/drs/dr6xx.cpp
===
--- clang/test/CXX/drs/dr6xx.cpp
+++ clang/test/CXX/drs/dr6xx.cpp
@@ -882,11 +882,17 @@
 friend int dr674::g(int);
 friend int dr674::h<>(int);
 int n; // expected-note 2{{private}}
+#if __cplusplus  >= 201103L
+  // expected-note@-2 {{private}}
+#endif
   };
 
   template int f(T) { return X().n; }
   int g(int) { return X().n; }
   template int g(T) { return X().n; } // expected-error {{private}}
+  #if __cplusplus  >= 201103L
+// expected-error@-2 {{private}}
+  #endif
   int h(int) { return X().n; } // expected-error {{private}}
   template int h(T) { return X().n; }
 
@@ -910,11 +916,17 @@
 friend int Y::g(int);
 friend int Y::h<>(int);
 int n; // expected-note 2{{private}}
+#if __cplusplus >= 201103L
+  // expected-note@-2 {{private}}
+#endif
   };
 
   template int Y::f(T) { return Z().n; }
   int Y::g(int) { return Z().n; }
   template int Y::g(T) { return Z().n; } // expected-error {{private}}
+  #if __cplusplus  >= 201103L
+// expected-error@-2 {{private}}
+  #endif
   int Y::h(int) { return Z().n; } // expected-error {{private}}
   template int Y::h(T) { return Z().n; }
 
Index: clang/test/CXX/class.access/p4.cpp
===
--- clang/test/CXX/class.access/p4.cpp
+++ clang/test/CXX/class.access/p4.cpp
@@ -503,26 +503,26 @@
 namespace test15 {
   template  class A {
   private:
-int private_foo; // expected-note {{declared private here}}
-static int private_sfoo; // expected-note {{declared private here}}
+int private_foo; // expected-note 2 {{declared private here}}
+static int private_sfoo; // expected-note 2 {{declared private here}}
   protected:
-int protected_foo; // expected-note 3 {{declared protected here}} // expected-note {{can only access this member on an object of type 'test15::B'}}
-static int protected_sfoo; // expected-note 3 {{declared protected here}}
+int protected_foo; // expected-note 6 {{declared protected here}} // expected-note 2 {{can only access this member on an object of type 'test15::B'}}
+static int protected_sfoo; // expected-note 6 {{declared protected here}}
 
 int test1(A ) {
-  return a.private_foo; // expected-error {{private member}}
+  return a.private_foo; 

[PATCH] D138914: Make evaluation of nested requirement consistent with requires expr.

2022-12-21 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 marked an inline comment as done.
usaxena95 added inline comments.



Comment at: clang/lib/Sema/SemaTemplateInstantiate.cpp:2339
+Req->getConstraintExpr()->getSourceRange(), Satisfaction))
+  TransConstraint = Result[0];
+assert(!Trap.hasErrorOccurred() && "Substitution failures must be handled "

rtrieu wrote:
> I have found a crash here when it access vector `Result` without checking the 
> size first, leading to out of bounds memory access.  CReduce gave the 
> following testcase:
> 
> ```
> template  struct b;
> template  using d = b;
> template  using f = d<__is_same(a, e)>;
> template 
> concept g = f::h;
> template 
> concept i = g;
> template  class j {
>   template 
>   requires requires { requires i; }
>   j();
> };
> template <> j();
> ```
> 
> `clang reduce.ii --std=c++20`
> 
> ```
> assertion failed at llvm/include/llvm/ADT/SmallVector.h:294 in reference 
> llvm::SmallVectorTemplateCommon::operator[](size_type) [T = 
> clang::Expr *]: idx < size()
> ...
> ...
> (anonymous 
> namespace)::TemplateInstantiator::TransformNestedRequirement(clang::concepts::NestedRequirement*)
>  clang/lib/Sema/SemaTemplateInstantiate.cpp:2339:25
> ...
> ...
> ```
Thanks for noticing and sorry for the trouble. I have fixed this forward in 
https://github.com/llvm/llvm-project/commit/8c0aa53b07caa604d58a0d83dc571d8fcb004972.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D138914

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


[PATCH] D138914: Make evaluation of nested requirement consistent with requires expr.

2022-12-19 Thread Utkarsh Saxena via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
usaxena95 marked an inline comment as done.
Closed by commit rGb3ce87285186: Make evaluation of nested requirement 
consistent with requires expr. (authored by usaxena95).

Changed prior to commit:
  https://reviews.llvm.org/D138914?vs=484013=484022#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D138914

Files:
  clang/include/clang/AST/ASTConcept.h
  clang/include/clang/AST/ASTNodeTraverser.h
  clang/include/clang/AST/ExprConcepts.h
  clang/include/clang/AST/RecursiveASTVisitor.h
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/ASTConcept.cpp
  clang/lib/AST/StmtPrinter.cpp
  clang/lib/AST/StmtProfile.cpp
  clang/lib/Sema/SemaConcept.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/lib/Sema/TreeTransform.h
  clang/lib/Serialization/ASTReaderStmt.cpp
  clang/lib/Serialization/ASTWriterStmt.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
  clang/test/PCH/cxx2a-requires-expr.cpp
  clang/tools/libclang/CIndex.cpp

Index: clang/tools/libclang/CIndex.cpp
===
--- clang/tools/libclang/CIndex.cpp
+++ clang/tools/libclang/CIndex.cpp
@@ -1374,7 +1374,7 @@
   }
   case Requirement::RK_Nested: {
 const NestedRequirement  = cast(R);
-if (!NR.isSubstitutionFailure()) {
+if (!NR.hasInvalidConstraint()) {
   if (Visit(NR.getConstraintExpr()))
 return true;
 }
Index: clang/test/PCH/cxx2a-requires-expr.cpp
===
--- clang/test/PCH/cxx2a-requires-expr.cpp
+++ clang/test/PCH/cxx2a-requires-expr.cpp
@@ -12,12 +12,13 @@
 
 template
 bool f() {
-  // CHECK: requires (T t) { t++; { t++ } noexcept -> C; { t++ } -> C2; typename T::a; requires T::val; };
+  // CHECK: requires (T t) { t++; { t++ } noexcept -> C; { t++ } -> C2; typename T::a; requires T::val; requires C || (C || C); };
   return requires (T t) {
 t++;
 { t++ } noexcept -> C;
 { t++ } -> C2;
 typename T::a;
 requires T::val;
+requires C || (C || C);
   };
 }
Index: clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
@@ -51,3 +51,115 @@
   X.next();
 };
 
+namespace SubstitutionFailureNestedRequires {
+template  concept True = true;
+template  concept False = false;
+
+struct S { double value; };
+
+template 
+concept Pipes = requires (T x) {
+   requires True || True || False;
+   requires False || True || True;
+};
+
+template 
+concept Amps1 = requires (T x) {
+   requires True && True && !False; // #Amps1
+};
+template 
+concept Amps2 = requires (T x) {
+   requires True && True;
+};
+
+static_assert(Pipes);
+static_assert(Pipes);
+
+static_assert(Amps1);
+static_assert(!Amps1);
+
+static_assert(Amps2);
+static_assert(!Amps2);
+
+template
+void foo1() requires requires (T x) { // #foo1
+  requires
+  True // #foo1Value
+  && True;
+} {}
+template void fooPipes() requires Pipes {}
+template void fooAmps1() requires Amps1 {} // #fooAmps1
+void foo() {
+  foo1();
+  foo1(); // expected-error {{no matching function for call to 'foo1'}}
+  // expected-note@#foo1Value {{because 'True && True' would be invalid: member reference base type 'int' is not a structure or union}}
+  // expected-note@#foo1 {{candidate template ignored: constraints not satisfied [with T = int]}}
+  fooPipes();
+  fooPipes();
+  fooAmps1();
+  fooAmps1(); // expected-error {{no matching function for call to 'fooAmps1'}}
+  // expected-note@#fooAmps1 {{candidate template ignored: constraints not satisfied [with T = int]}}
+  // expected-note@#fooAmps1 {{because 'int' does not satisfy 'Amps1'}}
+  // expected-note@#Amps1 {{because 'True && True && !False' would be invalid: member reference base type 'int' is not a structure or union}}
+}
+
+template
+concept HasNoValue = requires (T x) {
+  requires !True && True;
+};
+// FIXME: 'int' does not satisfy 'HasNoValue' currently since `!True` is an invalid expression.
+// But, in principle, it should be constant-evaluated to true.
+// This happens also for requires expression and is not restricted to nested requirement.
+static_assert(!HasNoValue);
+static_assert(!HasNoValue);
+
+template constexpr bool NotAConceptTrue = true;
+template 
+concept SFinNestedRequires = requires (T x) {
+// SF in a non-concept specialisation should also be evaluated to false.
+   requires NotAConceptTrue || NotAConceptTrue;
+};
+static_assert(SFinNestedRequires);
+static_assert(SFinNestedRequires);
+template 
+void foo() requires 

[PATCH] D138914: Make evaluation of nested requirement consistent with requires expr.

2022-12-19 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 484013.
usaxena95 added a comment.
Herald added a subscriber: arphaman.

Removed use of SubstitutionDiagnostic from NestedRequirement.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D138914

Files:
  clang/include/clang/AST/ASTConcept.h
  clang/include/clang/AST/ASTNodeTraverser.h
  clang/include/clang/AST/ExprConcepts.h
  clang/include/clang/AST/RecursiveASTVisitor.h
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/ASTConcept.cpp
  clang/lib/AST/StmtPrinter.cpp
  clang/lib/AST/StmtProfile.cpp
  clang/lib/Sema/SemaConcept.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/lib/Sema/TreeTransform.h
  clang/lib/Serialization/ASTReaderStmt.cpp
  clang/lib/Serialization/ASTWriterStmt.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
  clang/test/PCH/cxx2a-requires-expr.cpp
  clang/tools/libclang/CIndex.cpp

Index: clang/tools/libclang/CIndex.cpp
===
--- clang/tools/libclang/CIndex.cpp
+++ clang/tools/libclang/CIndex.cpp
@@ -1374,7 +1374,7 @@
   }
   case Requirement::RK_Nested: {
 const NestedRequirement  = cast(R);
-if (!NR.isSubstitutionFailure()) {
+if (!NR.hasInvalidConstraint()) {
   if (Visit(NR.getConstraintExpr()))
 return true;
 }
Index: clang/test/PCH/cxx2a-requires-expr.cpp
===
--- clang/test/PCH/cxx2a-requires-expr.cpp
+++ clang/test/PCH/cxx2a-requires-expr.cpp
@@ -12,12 +12,13 @@
 
 template
 bool f() {
-  // CHECK: requires (T t) { t++; { t++ } noexcept -> C; { t++ } -> C2; typename T::a; requires T::val; };
+  // CHECK: requires (T t) { t++; { t++ } noexcept -> C; { t++ } -> C2; typename T::a; requires T::val; requires C || (C || C); };
   return requires (T t) {
 t++;
 { t++ } noexcept -> C;
 { t++ } -> C2;
 typename T::a;
 requires T::val;
+requires C || (C || C);
   };
 }
Index: clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
@@ -51,3 +51,115 @@
   X.next();
 };
 
+namespace SubstitutionFailureNestedRequires {
+template  concept True = true;
+template  concept False = false;
+
+struct S { double value; };
+
+template 
+concept Pipes = requires (T x) {
+   requires True || True || False;
+   requires False || True || True;
+};
+
+template 
+concept Amps1 = requires (T x) {
+   requires True && True && !False; // #Amps1
+};
+template 
+concept Amps2 = requires (T x) {
+   requires True && True;
+};
+
+static_assert(Pipes);
+static_assert(Pipes);
+
+static_assert(Amps1);
+static_assert(!Amps1);
+
+static_assert(Amps2);
+static_assert(!Amps2);
+
+template
+void foo1() requires requires (T x) { // #foo1
+  requires
+  True // #foo1Value
+  && True;
+} {}
+template void fooPipes() requires Pipes {}
+template void fooAmps1() requires Amps1 {} // #fooAmps1
+void foo() {
+  foo1();
+  foo1(); // expected-error {{no matching function for call to 'foo1'}}
+  // expected-note@#foo1Value {{because 'True && True' would be invalid: member reference base type 'int' is not a structure or union}}
+  // expected-note@#foo1 {{candidate template ignored: constraints not satisfied [with T = int]}}
+  fooPipes();
+  fooPipes();
+  fooAmps1();
+  fooAmps1(); // expected-error {{no matching function for call to 'fooAmps1'}}
+  // expected-note@#fooAmps1 {{candidate template ignored: constraints not satisfied [with T = int]}}
+  // expected-note@#fooAmps1 {{because 'int' does not satisfy 'Amps1'}}
+  // expected-note@#Amps1 {{because 'True && True && !False' would be invalid: member reference base type 'int' is not a structure or union}}
+}
+
+template
+concept HasNoValue = requires (T x) {
+  requires !True && True;
+};
+// FIXME: 'int' does not satisfy 'HasNoValue' currently since `!True` is an invalid expression.
+// But, in principle, it should be constant-evaluated to true.
+// This happens also for requires expression and is not restricted to nested requirement.
+static_assert(!HasNoValue);
+static_assert(!HasNoValue);
+
+template constexpr bool NotAConceptTrue = true;
+template 
+concept SFinNestedRequires = requires (T x) {
+// SF in a non-concept specialisation should also be evaluated to false.
+   requires NotAConceptTrue || NotAConceptTrue;
+};
+static_assert(SFinNestedRequires);
+static_assert(SFinNestedRequires);
+template 
+void foo() requires SFinNestedRequires {}
+void bar() {
+  foo();
+  foo();
+}
+namespace ErrorExpressions_NotSF {
+template struct X { static constexpr bool value = T::value; }; // #X_Value
+struct True { static constexpr bool value = true; 

[PATCH] D138914: Make evaluation of nested requirement consistent with requires expr.

2022-11-29 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 478819.
usaxena95 added a comment.

Remove unintended whitespaces and new lines.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D138914

Files:
  clang/include/clang/AST/ASTConcept.h
  clang/include/clang/AST/ExprConcepts.h
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/AST/StmtPrinter.cpp
  clang/lib/Sema/SemaConcept.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/lib/Sema/TreeTransform.h
  clang/lib/Serialization/ASTReaderStmt.cpp
  clang/lib/Serialization/ASTWriterStmt.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
  clang/test/PCH/cxx2a-requires-expr.cpp

Index: clang/test/PCH/cxx2a-requires-expr.cpp
===
--- clang/test/PCH/cxx2a-requires-expr.cpp
+++ clang/test/PCH/cxx2a-requires-expr.cpp
@@ -12,12 +12,13 @@
 
 template
 bool f() {
-  // CHECK: requires (T t) { t++; { t++ } noexcept -> C; { t++ } -> C2; typename T::a; requires T::val; };
+  // CHECK: requires (T t) { t++; { t++ } noexcept -> C; { t++ } -> C2; typename T::a; requires T::val; requires C || (C || C); };
   return requires (T t) {
 t++;
 { t++ } noexcept -> C;
 { t++ } -> C2;
 typename T::a;
 requires T::val;
+requires C || (C || C);
   };
 }
Index: clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
@@ -51,3 +51,115 @@
   X.next();
 };
 
+namespace SubstitutionFailureNestedRequires {
+template  concept True = true;
+template  concept False = false;
+
+struct S { double value; };
+
+template 
+concept Pipes = requires (T x) {
+   requires True || True || False;
+   requires False || True || True;
+};
+
+template 
+concept Amps1 = requires (T x) {
+   requires True && True && !False; // #Amps1
+};
+template 
+concept Amps2 = requires (T x) {
+   requires True && True;
+};
+
+static_assert(Pipes);
+static_assert(Pipes);
+
+static_assert(Amps1);
+static_assert(!Amps1);
+
+static_assert(Amps2);
+static_assert(!Amps2);
+
+template
+void foo1() requires requires (T x) { // #foo1
+  requires
+  True // #foo1Value
+  && True;
+} {}
+template void fooPipes() requires Pipes {}
+template void fooAmps1() requires Amps1 {} // #fooAmps1
+void foo() {
+  foo1();
+  foo1(); // expected-error {{no matching function for call to 'foo1'}}
+  // expected-note@#foo1Value {{because 'True && True' would be invalid: member reference base type 'int' is not a structure or union}}
+  // expected-note@#foo1 {{candidate template ignored: constraints not satisfied [with T = int]}}
+  fooPipes();
+  fooPipes();
+  fooAmps1();
+  fooAmps1(); // expected-error {{no matching function for call to 'fooAmps1'}}
+  // expected-note@#fooAmps1 {{candidate template ignored: constraints not satisfied [with T = int]}}
+  // expected-note@#fooAmps1 {{because 'int' does not satisfy 'Amps1'}}
+  // expected-note@#Amps1 {{because 'True && True && !False' would be invalid: member reference base type 'int' is not a structure or union}}
+}
+
+template
+concept HasNoValue = requires (T x) {
+  requires !True && True;
+};
+// FIXME: 'int' does not satisfy 'HasNoValue' currently since `!True` is an invalid expression.
+// But, in principle, it should be constant-evaluated to true.
+// This happens also for requires expression and is not restricted to nested requirement.
+static_assert(!HasNoValue);
+static_assert(!HasNoValue);
+
+template constexpr bool NotAConceptTrue = true;
+template 
+concept SFinNestedRequires = requires (T x) {
+// SF in a non-concept specialisation should also be evaluated to false.
+   requires NotAConceptTrue || NotAConceptTrue;
+};
+static_assert(SFinNestedRequires);
+static_assert(SFinNestedRequires);
+template 
+void foo() requires SFinNestedRequires {}
+void bar() {
+  foo();
+  foo();
+}
+namespace ErrorExpressions_NotSF {
+template struct X { static constexpr bool value = T::value; }; // #X_Value
+struct True { static constexpr bool value = true; };
+struct False { static constexpr bool value = false; };
+template concept C = true;
+template concept F = false;
+
+template requires requires(T) { requires C || X::value; } void foo();
+
+template requires requires(T) { requires C && X::value; } void bar(); // #bar
+template requires requires(T) { requires F || (X::value && C); } void baz();
+
+void func() {
+  foo();
+  foo();
+  foo();
+
+  bar();
+  bar();
+  // expected-error@-1 {{no matching function for call to 'bar'}}
+  // expected-note@#bar {{while substituting template arguments into constraint expression here}}
+  // expected-note@#bar {{while checking the satisfaction of nested requirement requested here}}
+  // expected-note@#bar 

[PATCH] D138914: Make evaluation of nested requirement consistent with requires expr.

2022-11-29 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 478818.
usaxena95 added a comment.

Removed extraneous colons from diagnostic.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D138914

Files:
  clang/include/clang/AST/ASTConcept.h
  clang/include/clang/AST/ExprConcepts.h
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/AST/StmtPrinter.cpp
  clang/lib/Sema/SemaConcept.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/lib/Sema/TreeTransform.h
  clang/lib/Serialization/ASTReaderStmt.cpp
  clang/lib/Serialization/ASTWriterStmt.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
  clang/test/PCH/cxx2a-requires-expr.cpp

Index: clang/test/PCH/cxx2a-requires-expr.cpp
===
--- clang/test/PCH/cxx2a-requires-expr.cpp
+++ clang/test/PCH/cxx2a-requires-expr.cpp
@@ -12,12 +12,13 @@
 
 template
 bool f() {
-  // CHECK: requires (T t) { t++; { t++ } noexcept -> C; { t++ } -> C2; typename T::a; requires T::val; };
+  // CHECK: requires (T t) { t++; { t++ } noexcept -> C; { t++ } -> C2; typename T::a; requires T::val; requires C || (C || C); };
   return requires (T t) {
 t++;
 { t++ } noexcept -> C;
 { t++ } -> C2;
 typename T::a;
 requires T::val;
+requires C || (C || C);
   };
 }
Index: clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
@@ -19,7 +19,8 @@
 
 template
 struct X {
-template requires requires (U u) { requires sizeof(u) == sizeof(T); } // expected-note{{because 'sizeof (u) == sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}}
+template requires requires (U u) { requires sizeof(u) == sizeof(T); } 
+// expected-note@-1 {{because 'sizeof (u) == sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}}
 struct r4 {};
 };
 
@@ -51,3 +52,115 @@
   X.next();
 };
 
+namespace SubstitutionFailureNestedRequires {
+template  concept True = true;
+template  concept False = false;
+
+struct S { double value; };
+
+template 
+concept Pipes = requires (T x) {
+   requires True || True || False;
+   requires False || True || True;
+};
+
+template 
+concept Amps1 = requires (T x) {
+   requires True && True && !False; // #Amps1
+};
+template 
+concept Amps2 = requires (T x) {
+   requires True && True;
+};
+
+static_assert(Pipes);
+static_assert(Pipes);
+
+static_assert(Amps1);
+static_assert(!Amps1);
+
+static_assert(Amps2);
+static_assert(!Amps2);
+
+template
+void foo1() requires requires (T x) { // #foo1
+  requires
+  True // #foo1Value
+  && True;
+} {}
+template void fooPipes() requires Pipes {}
+template void fooAmps1() requires Amps1 {} // #fooAmps1
+void foo() {
+  foo1();
+  foo1(); // expected-error {{no matching function for call to 'foo1'}}
+  // expected-note@#foo1Value {{because 'True && True' would be invalid: member reference base type 'int' is not a structure or union}}
+  // expected-note@#foo1 {{candidate template ignored: constraints not satisfied [with T = int]}}
+  fooPipes();
+  fooPipes();
+  fooAmps1();
+  fooAmps1(); // expected-error {{no matching function for call to 'fooAmps1'}}
+  // expected-note@#fooAmps1 {{candidate template ignored: constraints not satisfied [with T = int]}}
+  // expected-note@#fooAmps1 {{because 'int' does not satisfy 'Amps1'}}
+  // expected-note@#Amps1 {{because 'True && True && !False' would be invalid: member reference base type 'int' is not a structure or union}}
+}
+
+template
+concept HasNoValue = requires (T x) {
+  requires !True && True;
+};
+// FIXME: 'int' does not satisfy 'HasNoValue' currently since `!True` is an invalid expression.
+// But, in principle, it should be constant-evaluated to true.
+// This happens also for requires expression and is not restricted to nested requirement.
+static_assert(!HasNoValue);
+static_assert(!HasNoValue);
+
+template constexpr bool NotAConceptTrue = true;
+template 
+concept SFinNestedRequires = requires (T x) {
+// SF in a non-concept specialisation should also be evaluated to false.
+   requires NotAConceptTrue || NotAConceptTrue;
+};
+static_assert(SFinNestedRequires);
+static_assert(SFinNestedRequires);
+template 
+void foo() requires SFinNestedRequires {} 
+void bar() { 
+  foo();
+  foo();
+}
+namespace ErrorExpressions_NotSF {
+template struct X { static constexpr bool value = T::value; }; // #X_Value
+struct True { static constexpr bool value = true; };
+struct False { static constexpr bool value = false; };
+template concept C = true;
+template concept F = false;
+
+template requires requires(T) { requires C || X::value; } void foo();
+
+template requires 

[PATCH] D138914: Make evaluation of nested requirement consistent with requires expr.

2022-11-29 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 added inline comments.



Comment at: clang/include/clang/AST/ExprConcepts.h:428
+  : Requirement(RK_Nested,
+Constraint && Constraint->isInstantiationDependent(),
+Constraint && 
Constraint->containsUnexpandedParameterPack(),

erichkeane wrote:
> erichkeane wrote:
> > I'm a little concerned that we're changing to a situation where the 
> > constraint in a nested-requirement can be null like this.  The other cases 
> > it can be null we consider it a 'substitution failure' (see the 1st 
> > constructor).
> > 
> > It seems to me that we perhaps need a different state here for that.
> I still have this concern, we need to make sure that NestedRequirement is 
> written to consider this type of failure, it likely needs a separate 
> constructor that contains information about the failure.  We probably want at 
> least some sort of stored diagnostic here, sot hat we dont lose the output we 
> have below.
NestedRequirement will no more capture a substitution failure. I am planning to 
remove all references to SubstitutionDiagnostics for it. I have **temporarily** 
added unreachable tags to the references of SubstitutionDiagnostics. 

If this looks fine to you then I would move forward with refactoring it to 
remove all support for SubstitutionDiagnostics in NestedRequirement. WDYT ?



Comment at: clang/lib/Sema/SemaConcept.cpp:172
   //operand is satisfied.
-  return BO.recreateBinOp(S, LHSRes);
+  // LHS is instantiated while RHS is not. Skip creating invalid BinaryOp.
+  return LHSRes;

For context: This is not necessarily invalid but more importantly the BinaryOp 
cannot be constant evaluated as it would have dependent RHS.



Comment at: 
clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp:23
+template requires requires (U u) { requires sizeof(u) == 
sizeof(T); } 
+// expected-note@-1 {{because substituted constraint expression is 
ill-formed: invalid application of 'sizeof' to an incomplete type 'void'}}
 struct r4 {};

erichkeane wrote:
> Losing the extra context here is unfortunate as well... why do we lose this 
> info?
This is now restored.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D138914

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


[PATCH] D138914: Make evaluation of nested requirement consistent with requires expr.

2022-11-29 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 478814.
usaxena95 marked 4 inline comments as done.
usaxena95 added a comment.

Addressed comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D138914

Files:
  clang/include/clang/AST/ASTConcept.h
  clang/include/clang/AST/ExprConcepts.h
  clang/lib/AST/StmtPrinter.cpp
  clang/lib/Sema/SemaConcept.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/lib/Sema/TreeTransform.h
  clang/lib/Serialization/ASTReaderStmt.cpp
  clang/lib/Serialization/ASTWriterStmt.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
  clang/test/PCH/cxx2a-requires-expr.cpp

Index: clang/test/PCH/cxx2a-requires-expr.cpp
===
--- clang/test/PCH/cxx2a-requires-expr.cpp
+++ clang/test/PCH/cxx2a-requires-expr.cpp
@@ -12,12 +12,13 @@
 
 template
 bool f() {
-  // CHECK: requires (T t) { t++; { t++ } noexcept -> C; { t++ } -> C2; typename T::a; requires T::val; };
+  // CHECK: requires (T t) { t++; { t++ } noexcept -> C; { t++ } -> C2; typename T::a; requires T::val; requires C || (C || C); };
   return requires (T t) {
 t++;
 { t++ } noexcept -> C;
 { t++ } -> C2;
 typename T::a;
 requires T::val;
+requires C || (C || C);
   };
 }
Index: clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
@@ -19,7 +19,8 @@
 
 template
 struct X {
-template requires requires (U u) { requires sizeof(u) == sizeof(T); } // expected-note{{because 'sizeof (u) == sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}}
+template requires requires (U u) { requires sizeof(u) == sizeof(T); } 
+// expected-note@-1 {{because 'sizeof (u) == sizeof(T)' would be invalid: : invalid application of 'sizeof' to an incomplete type 'void'}}
 struct r4 {};
 };
 
@@ -41,7 +42,7 @@
   template
   concept C2 = requires (T a) {
   requires sizeof(a) == 4; // OK
-  requires a == 0; // expected-note{{because 'a == 0' would be invalid: constraint variable 'a' cannot be used in an evaluated context}}
+  requires a == 0; // expected-note{{because 'a == 0' would be invalid: : constraint variable 'a' cannot be used in an evaluated context}}
 };
   static_assert(C2); // expected-note{{because 'int' does not satisfy 'C2'}} expected-error{{static assertion failed}}
 }
@@ -51,3 +52,115 @@
   X.next();
 };
 
+namespace SubstitutionFailureNestedRequires {
+template  concept True = true;
+template  concept False = false;
+
+struct S { double value; };
+
+template 
+concept Pipes = requires (T x) {
+   requires True || True || False;
+   requires False || True || True;
+};
+
+template 
+concept Amps1 = requires (T x) {
+   requires True && True && !False; // #Amps1
+};
+template 
+concept Amps2 = requires (T x) {
+   requires True && True;
+};
+
+static_assert(Pipes);
+static_assert(Pipes);
+
+static_assert(Amps1);
+static_assert(!Amps1);
+
+static_assert(Amps2);
+static_assert(!Amps2);
+
+template
+void foo1() requires requires (T x) { // #foo1
+  requires
+  True // #foo1Value
+  && True;
+} {}
+template void fooPipes() requires Pipes {}
+template void fooAmps1() requires Amps1 {} // #fooAmps1
+void foo() {
+  foo1();
+  foo1(); // expected-error {{no matching function for call to 'foo1'}}
+  // expected-note@#foo1Value {{because 'True && True' would be invalid: : member reference base type 'int' is not a structure or union}}
+  // expected-note@#foo1 {{candidate template ignored: constraints not satisfied [with T = int]}}
+  fooPipes();
+  fooPipes();
+  fooAmps1();
+  fooAmps1(); // expected-error {{no matching function for call to 'fooAmps1'}}
+  // expected-note@#fooAmps1 {{candidate template ignored: constraints not satisfied [with T = int]}}
+  // expected-note@#fooAmps1 {{because 'int' does not satisfy 'Amps1'}}
+  // expected-note@#Amps1 {{because 'True && True && !False' would be invalid: : member reference base type 'int' is not a structure or union}}
+}
+
+template
+concept HasNoValue = requires (T x) {
+  requires !True && True;
+};
+// FIXME: 'int' does not satisfy 'HasNoValue' currently since `!True` is an invalid expression.
+// But, in principle, it should be constant-evaluated to true.
+// This happens also for requires expression and is not restricted to nested requirement.
+static_assert(!HasNoValue);
+static_assert(!HasNoValue);
+
+template constexpr bool NotAConceptTrue = true;
+template 
+concept SFinNestedRequires = requires (T x) {
+// SF in a non-concept specialisation should also be evaluated to false.
+   requires NotAConceptTrue || NotAConceptTrue;
+};
+static_assert(SFinNestedRequires);

[PATCH] D138914: Make evaluation of nested requirement consistent with requires expr.

2022-11-29 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 478658.
usaxena95 marked an inline comment as done.
usaxena95 added a comment.

Added tests.
Fixed regressions in diagnositcs.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D138914

Files:
  clang/include/clang/AST/ExprConcepts.h
  clang/lib/Sema/SemaConcept.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
  clang/test/SemaTemplate/instantiate-requires-expr.cpp

Index: clang/test/SemaTemplate/instantiate-requires-expr.cpp
===
--- clang/test/SemaTemplate/instantiate-requires-expr.cpp
+++ clang/test/SemaTemplate/instantiate-requires-expr.cpp
@@ -190,7 +190,7 @@
   template
   struct a {
   template requires
-  (requires { requires sizeof(T::a) == 0; }, false) // expected-note{{because 'requires { requires <>; } , false' evaluated to false}}
+  (requires { requires sizeof(T::a) == 0; }, false) // expected-note{{because 'requires { requires ; } , false' evaluated to false}}
   struct r {};
   };
 
Index: clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
@@ -19,7 +19,8 @@
 
 template
 struct X {
-template requires requires (U u) { requires sizeof(u) == sizeof(T); } // expected-note{{because 'sizeof (u) == sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}}
+template requires requires (U u) { requires sizeof(u) == sizeof(T); } 
+// expected-note@-1 {{because substituted constraint expression is ill-formed: invalid application of 'sizeof' to an incomplete type 'void'}}
 struct r4 {};
 };
 
@@ -41,7 +42,7 @@
   template
   concept C2 = requires (T a) {
   requires sizeof(a) == 4; // OK
-  requires a == 0; // expected-note{{because 'a == 0' would be invalid: constraint variable 'a' cannot be used in an evaluated context}}
+  requires a == 0; // expected-note{{because substituted constraint expression is ill-formed: constraint variable 'a' cannot be used in an evaluated context}}
 };
   static_assert(C2); // expected-note{{because 'int' does not satisfy 'C2'}} expected-error{{static assertion failed}}
 }
@@ -51,3 +52,110 @@
   X.next();
 };
 
+namespace SubstitutionFailureNestedRequires {
+template  concept True = true;
+template  concept False = false;
+
+struct S { double value; };
+
+template 
+concept Pipes = requires (T x) {
+   requires True || True || False;
+   requires False || True || True;
+};
+
+template 
+concept Amps1 = requires (T x) {
+   requires True && True && !False;
+   // expected-note@-1{{because substituted constraint expression is ill-formed: member reference base type 'int' is not a structure or union}}
+};
+template 
+concept Amps2 = requires (T x) {
+   requires True && True;
+};
+
+static_assert(Pipes);
+static_assert(Pipes);
+
+static_assert(Amps1);
+static_assert(!Amps1);
+
+static_assert(Amps2);
+static_assert(!Amps2);
+
+template
+void foo1() requires requires (T x) { // expected-note {{candidate template ignored: constraints not satisfied [with T = int]}}
+  requires
+  True // expected-note {{because substituted constraint expression is ill-formed: member reference base type 'int' is not a structure or union}}
+  && True;
+} {}
+template void fooPipes() requires Pipes {}
+template void fooAmps1() requires Amps1 {}
+// expected-note@-1 {{candidate template ignored: constraints not satisfied [with T = int]}} \
+// expected-note@-1 {{because 'int' does not satisfy 'Amps1'}}
+
+void foo() {
+  foo1();
+  foo1(); // expected-error {{no matching function for call to 'foo1'}}
+  fooPipes();
+  fooPipes();
+  fooAmps1();
+  fooAmps1(); // expected-error {{no matching function for call to 'fooAmps1'}}
+}
+
+template
+concept HasNoValue = requires (T x) {
+  requires !True && True;
+};
+// FIXME: 'int' does not satisfy 'HasNoValue' currently since `!True` is an invalid expression.
+// But, in principle, it should be constant-evaluated to true.
+static_assert(!HasNoValue);
+static_assert(!HasNoValue);
+
+template constexpr bool NotAConceptTrue = true;
+template 
+concept SFinNestedRequires = requires (T x) {
+// SF in a non-concept specialisation should also be evaluated to false.
+   requires NotAConceptTrue || NotAConceptTrue;
+};
+static_assert(SFinNestedRequires);
+static_assert(SFinNestedRequires);
+template 
+void foo() requires SFinNestedRequires {} 
+void bar() { 
+  foo();
+  foo();
+}
+namespace ErrorExpressions_NotSF {
+template struct X { static constexpr bool value = T::value; }; \
+// expected-error {{type 'int' cannot be used prior to '::' because it has no members}}
+struct True { static constexpr bool value 

[PATCH] D137712: Correctly handle Substitution failure in concept specialization.

2022-11-29 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 abandoned this revision.
usaxena95 added a comment.

Second attempt along the lines of the last comment: 
https://reviews.llvm.org/D138914
PTAL.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D137712

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


[PATCH] D138914: Make evaluation of nested requirement consistent with requires expr.

2022-11-29 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 created this revision.
Herald added a project: All.
usaxena95 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Fixes: https://github.com/llvm/llvm-project/issues/45563

  template  concept True = true;
  
  template 
  concept C1 = requires (T) {
 requires True || True;
  };
  
  template 
  constexpr bool foo()
  requires True || True {
  return true;
  }
  static_assert(C1); // Previously failed due to SFINAE error
  static_assert(foo()); // but this works fine.

The issue here is the discrepancy between how a nested requirement is evaluated 

 Vs how a non-nested requirement is evaluated 
.

This patch makes constraint checking consistent for nested requirement
and trailing requires expressions by reusing the same evaluator.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D138914

Files:
  clang/include/clang/AST/ExprConcepts.h
  clang/lib/Sema/SemaConcept.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
  clang/test/SemaTemplate/instantiate-requires-expr.cpp

Index: clang/test/SemaTemplate/instantiate-requires-expr.cpp
===
--- clang/test/SemaTemplate/instantiate-requires-expr.cpp
+++ clang/test/SemaTemplate/instantiate-requires-expr.cpp
@@ -24,8 +24,8 @@
 
 template requires
 false_v; }>
-// expected-note@-1 {{because 'false_v; }>' evaluated to false}}
-// expected-note@-2 {{because 'false_v; }>' evaluated to false}}
+// expected-note@-1 {{because 'false_v; }>' evaluated to false}}
+// expected-note@-2 {{because 'false_v; }>' evaluated to false}}
 struct r1 {};
 
 using r1i1 = r1; // expected-error {{constraints not satisfied for class template 'r1' [with T = int]}}
@@ -35,8 +35,8 @@
 
 template requires
 false_v
-// expected-note@-1 {{because 'false_v'}}
-// expected-note@-2 {{because 'false_v' evaluated to false}}
+// expected-note@-1 {{because 'false_v; }>' evaluated to false}}
+// expected-note@-2 {{because 'false_v; }>' evaluated to false}}
 struct r2 {};
 
 using r2i1 = r2; // expected-error {{constraints not satisfied for class template 'r2' [with Ts = ]}}
@@ -44,8 +44,8 @@
 
 template requires
 false_v<(requires (Ts ts) {requires sizeof(ts) != 0;} && ...)>
-// expected-note@-1 {{because 'false_v' evaluated to false}}
-// expected-note@-2 {{because 'false_v' evaluated to false}}
+// expected-note@-1 {{because 'false_v; } && requires (unsigned short ts) { requires ; }>' evaluated to false}}
+// expected-note@-2 {{because 'false_v; }>' evaluated to false}}
 struct r3 {};
 
 using r3i1 = r3; // expected-error {{constraints not satisfied for class template 'r3' [with Ts = ]}}
@@ -181,7 +181,7 @@
 
 namespace nested_requirement {
   // check that constraint expression is instantiated correctly
-  template requires false_v // expected-note{{because 'false_v' evaluated to false}}
+  template requires false_v // expected-note{{because 'false_v; }>' evaluated to false}}
   struct r1 {};
 
   using r1i = r1; // expected-error{{constraints not satisfied for class template 'r1' [with T = int]}}
@@ -190,7 +190,7 @@
   template
   struct a {
   template requires
-  (requires { requires sizeof(T::a) == 0; }, false) // expected-note{{because 'requires { requires <>; } , false' evaluated to false}}
+  (requires { requires sizeof(T::a) == 0; }, false) // expected-note{{because 'requires { requires ; } , false' evaluated to false}}
   struct r {};
   };
 
@@ -199,7 +199,7 @@
   // Parameter pack inside expr
   template requires
   false_v<(requires { requires sizeof(Ts) == 0; } && ...)>
-  // expected-note@-1 {{because 'false_v' evaluated to false}}
+  // expected-note@-1 {{because 'false_v; } && requires { requires ; }>' evaluated to false}}
   struct r2 {};
 
   using r2i = r2; // expected-error{{constraints not satisfied for class template 'r2' [with Ts = ]}}
@@ -208,14 +208,14 @@
 // Parameter pack inside multiple requirements
 template requires
 false_v<(requires { requires sizeof(Ts) == 0; sizeof(Ts); } && ...)>
-// expected-note@-1 {{because 'false_v' evaluated to false}}
+// expected-note@-1 {{because 'false_v; sizeof(Ts); } && requires { requires ; sizeof(Ts); }>' evaluated to false}}
 struct r4 {};
 
 using r4i = r4; // expected-error{{constraints not satisfied for class template 'r4' [with Ts = ]}}
 
 template requires
 false_v<(requires(Ts t) { requires sizeof(t) == 0; t++; } && ...)>
-// expected-note@-1 {{because 'false_v' evaluated to false}}
+// expected-note@-1 {{because 'false_v; t++; } && requires (short t) { requires ; t++; }>' evaluated to false}}
 struct r5 {};
 
 using r5i = r5; // expected-error{{constraints not satisfied for class template 'r5' [with Ts = ]}}
Index: 

[PATCH] D137712: Correctly handle Substitution failure in concept specialization.

2022-11-13 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 added inline comments.



Comment at: clang/include/clang/AST/ExprConcepts.h:103
 
+  bool hasSubstitutionFailureInArgs() const {
+return ArgsHasSubstitutionFailure;

erichkeane wrote:
> Does this really belong here instead of as a part of the 
> ConceptSpecializationDecl?
I am not aware of the original goals for this. For example, 
`ASTTemplateArgumentListInfo` is part of `ConceptReference` while 
`TemplateArgument` is part of `ImplicitConceptSpecializationDecl`. Both of them 
are invalid in such a case.
I am open to suggestion to where to place this.



Comment at: clang/include/clang/AST/ExprConcepts.h:159
+  // todo: add doc ?
+struct SubstitutionDiagnostic {
+  StringRef SubstitutedEntity;

erichkeane wrote:
> I had a previous patch at something else where I was moving toward doing this 
> change, so I think this is probably something inevitable.  
> 
> However, I'm having a tough time splitting this patch mentally between the 
> 'fix' and the infrastructure changes needed.  A part of me thinks we should 
> split this patch a bit in that direction.
I agree. This is a larger change which probably belongs to a separate change. 
Until then I think it is fine to not provide diagnostic of the exact expression 
of the SubstitutedEntity for which SF occurred.



Comment at: clang/lib/AST/ExprConcepts.cpp:112-113
+  return ConceptSpecializationExpr::Create(
+  C, NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept, nullptr,
+  nullptr, Satisfaction);
+}

shafik wrote:
> I think I got the parameter names correct.
Could you please elaborate what is your suggestion here ?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D137712

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


[PATCH] D137712: Correctly handle Substitution failure in concept specialization.

2022-11-13 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 475054.
usaxena95 marked 3 inline comments as done.
usaxena95 added a comment.

Addressed commented. Added Release notes.
Removed infrastructure changes and deferred them to a future patch.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D137712

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/ExprConcepts.h
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/AST/ComputeDependence.cpp
  clang/lib/AST/ExprConcepts.cpp
  clang/lib/AST/StmtPrinter.cpp
  clang/lib/Sema/SemaConcept.cpp
  clang/lib/Sema/TreeTransform.h
  clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp

Index: clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
===
--- clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
@@ -51,3 +51,80 @@
   X.next();
 };
 
+
+namespace SubstitutionFailureNestedRequires {
+template  concept True = true;
+
+struct S { double value; };
+
+template 
+concept Pipes = requires (T x) {
+   requires True || True;
+   requires True || True;
+};
+
+template 
+concept Amps1 = requires (T x) {
+   requires True && True;
+   // expected-note@-1{{because 'member reference base type 'int' is not a structure or union'}}
+};
+template 
+concept Amps2 = requires (T x) {
+   requires True && True;
+};
+
+static_assert(Pipes);
+static_assert(Pipes);
+
+static_assert(Amps1);
+static_assert(!Amps1);
+
+static_assert(Amps2);
+static_assert(!Amps2);
+
+template
+void foo1() requires requires (T x) { // expected-note {{candidate template ignored: constraints not satisfied [with T = int]}}
+  requires
+  True // expected-note {{because 'member reference base type 'int' is not a structure or union'}}
+  && True;
+} {}
+template void fooPipes() requires Pipes {}
+template void fooAmps1() requires Amps1 {}
+// expected-note@-1 {{candidate template ignored: constraints not satisfied [with T = int]}} \
+// expected-note@-1 {{because 'int' does not satisfy 'Amps1'}}
+
+void foo() {
+  foo1();
+  foo1(); // expected-error {{no matching function for call to 'foo1'}}
+  fooPipes();
+  fooPipes();
+  fooAmps1();
+  fooAmps1(); // expected-error {{no matching function for call to 'fooAmps1'}}
+}
+
+template
+concept HasNoValue = requires (T x) {
+  requires !True && True;
+};
+static_assert(HasNoValue);
+static_assert(!HasNoValue);
+
+template constexpr bool NotAConceptTrue = true;
+template 
+concept SFinNestedRequires = requires (T x) {
+// Only SF in a concept specialisation should be evaluated to false. 
+// Rest is still a SF.
+   requires NotAConceptTrue || NotAConceptTrue;
+   // expected-note@-1 {{because 'NotAConceptTrue || NotAConceptTrue' would be invalid: member reference base type 'int' is not a structure or union}}
+};
+static_assert(!SFinNestedRequires); // Unsatisfied but not a hard error.
+static_assert(SFinNestedRequires);
+template 
+void foo() requires SFinNestedRequires {} 
+// expected-note@-1 {{candidate template ignored: constraints not satisfied [with T = int]}}
+// expected-note@-2 {{because 'int' does not satisfy 'SFinNestedRequires'}}
+void bar() { 
+  foo(); // expected-error {{no matching function for call to 'foo'}}
+  foo();
+}
+}
Index: clang/lib/Sema/TreeTransform.h
===
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -15,6 +15,7 @@
 
 #include "CoroutineStmtBuilder.h"
 #include "TypeLocBuilder.h"
+#include "clang/AST/ASTConcept.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
@@ -37,6 +38,7 @@
 #include "clang/Sema/ScopeInfo.h"
 #include "clang/Sema/SemaDiagnostic.h"
 #include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/TemplateDeduction.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/Support/ErrorHandling.h"
 #include 
@@ -3477,6 +3479,23 @@
 return Result;
   }
 
+  ExprResult RebuildConceptSpecializationSubstitutionFailure(
+  ConceptSpecializationExpr *E,
+  ConstraintSatisfaction::SubstitutionDiagnostic *SubstDiags) {
+ConstraintSatisfaction Satisfaction;
+Satisfaction.IsSatisfied = false;
+Satisfaction.ContainsErrors = false;
+Satisfaction.Details.emplace_back(E, SubstDiags);
+CXXScopeSpec SS;
+SS.Adopt(E->getNestedNameSpecifierLoc());
+return ConceptSpecializationExpr::CreateSubstitutionFailure(
+SemaRef.Context,
+SS.isSet() ? SS.getWithLocInContext(SemaRef.Context)
+   : NestedNameSpecifierLoc{},
+E->getTemplateKWLoc(), E->getConceptNameInfo(), E->getFoundDecl(),
+E->getNamedConcept(), );
+  }
+
   /// \brief Build a new requires expression.
   ///
   /// By default, performs semantic analysis to build the new expression.
@@ -12611,15 

[PATCH] D137712: Correctly handle Substitution failure in concept specialization.

2022-11-11 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 474716.
usaxena95 added a comment.

Moving closer to show diagnostic of entity for which SFNIAE occurred.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D137712

Files:
  clang/include/clang/AST/ASTConcept.h
  clang/include/clang/AST/ExprConcepts.h
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/ASTConcept.cpp
  clang/lib/AST/ComputeDependence.cpp
  clang/lib/AST/ExprConcepts.cpp
  clang/lib/AST/StmtPrinter.cpp
  clang/lib/Sema/SemaConcept.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/lib/Sema/TreeTransform.h
  clang/lib/Serialization/ASTReaderStmt.cpp
  clang/lib/Serialization/ASTWriterStmt.cpp
  clang/test/SemaTemplate/concepts.cpp

Index: clang/test/SemaTemplate/concepts.cpp
===
--- clang/test/SemaTemplate/concepts.cpp
+++ clang/test/SemaTemplate/concepts.cpp
@@ -764,3 +764,53 @@
   __iterator_traits_member_pointer_or_arrow_or_void> f;
 }
 }// namespace InheritedFromPartialSpec
+
+namespace nested_requirements {
+template  concept True = true;
+
+struct S { double value; };
+
+template 
+concept Pipes = requires (T x) {
+   requires True || True;
+   requires True || True;
+};
+template 
+concept Amps1 = requires (T x) {
+   requires True && True;
+   // expected-note@-1{{because 'todo fill me' would be invalid: member reference base type 'int' is not a structure or union}}
+};
+template 
+concept Amps2 = requires (T x) {
+   requires True && True;
+};
+
+static_assert(Pipes);
+static_assert(Pipes);
+
+static_assert(Amps1);
+static_assert(!Amps1);
+
+static_assert(Amps2);
+static_assert(!Amps2);
+
+template
+void foo1() requires requires (T x) { // expected-note {{candidate template ignored: constraints not satisfied [with T = int]}}
+  requires 
+  True // expected-note {{because 'todo fill me' would be invalid: member reference base type 'int' is not a structure or union}}
+  && True;
+} {}
+template void fooPipes() requires Pipes {}
+template void fooAmps1() requires Amps1 {}
+// expected-note@-1 {{candidate template ignored: constraints not satisfied [with T = int]}} \
+// expected-note@-1 {{because 'int' does not satisfy 'Amps1'}}
+
+void foo() {
+  foo1();
+  foo1(); // expected-error {{no matching function for call to 'foo1'}}
+  fooPipes();
+  fooPipes();
+  fooAmps1();
+  fooAmps1(); // expected-error {{no matching function for call to 'fooAmps1'}}
+}
+}
\ No newline at end of file
Index: clang/lib/Serialization/ASTWriterStmt.cpp
===
--- clang/lib/Serialization/ASTWriterStmt.cpp
+++ clang/lib/Serialization/ASTWriterStmt.cpp
@@ -11,6 +11,7 @@
 ///
 //===--===//
 
+#include "clang/AST/ASTConcept.h"
 #include "clang/AST/ExprOpenMP.h"
 #include "clang/Serialization/ASTRecordWriter.h"
 #include "clang/Sema/DeclSpec.h"
@@ -412,19 +413,18 @@
   if (E)
 Record.AddStmt(E);
   else {
-auto *Diag = DetailRecord.second.get *>();
-Record.AddSourceLocation(Diag->first);
-Record.AddString(Diag->second);
+auto *Diag =
+DetailRecord.second.get();
+Record.AddSourceLocation(Diag->DiagLoc);
+Record.AddString(Diag->DiagMessage);
   }
 }
   }
 }
 
 static void
-addSubstitutionDiagnostic(
-ASTRecordWriter ,
-const concepts::Requirement::SubstitutionDiagnostic *D) {
+addSubstitutionDiagnostic(ASTRecordWriter ,
+  const concepts::SubstitutionDiagnostic *D) {
   Record.AddString(D->SubstitutedEntity);
   Record.AddSourceLocation(D->DiagLoc);
   Record.AddString(D->DiagMessage);
@@ -467,8 +467,8 @@
   Record.push_back(ExprReq->getKind());
   Record.push_back(ExprReq->Status);
   if (ExprReq->isExprSubstitutionFailure()) {
-addSubstitutionDiagnostic(Record,
- ExprReq->Value.get());
+addSubstitutionDiagnostic(
+Record, ExprReq->Value.get());
   } else
 Record.AddStmt(ExprReq->Value.get());
   if (ExprReq->getKind() == concepts::Requirement::RK_Compound) {
Index: clang/lib/Serialization/ASTReaderStmt.cpp
===
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -781,9 +781,9 @@
 SourceLocation DiagLocation = Record.readSourceLocation();
 std::string DiagMessage = Record.readString();
 Satisfaction.Details.emplace_back(
-ConstraintExpr, new (Record.getContext())
-ConstraintSatisfaction::SubstitutionDiagnostic{
-DiagLocation, DiagMessage});
+ConstraintExpr,
+new (Record.getContext()) concepts::SubstitutionDiagnostic{
+"todo: fill substituted 

[PATCH] D137712: Correctly handle Substitution failure in concept specialization.

2022-11-09 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 created this revision.
Herald added a project: All.
usaxena95 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D137712

Files:
  clang/include/clang/AST/ExprConcepts.h
  clang/lib/AST/ComputeDependence.cpp
  clang/lib/AST/ExprConcepts.cpp
  clang/lib/Sema/TreeTransform.h
  clang/test/SemaTemplate/concepts.cpp

Index: clang/test/SemaTemplate/concepts.cpp
===
--- clang/test/SemaTemplate/concepts.cpp
+++ clang/test/SemaTemplate/concepts.cpp
@@ -764,3 +764,53 @@
   __iterator_traits_member_pointer_or_arrow_or_void> f;
 }
 }// namespace InheritedFromPartialSpec
+
+namespace nested_requirements {
+template  concept True = true;
+
+struct S { double value; };
+
+template 
+concept Pipes = requires (T x) {
+   requires True || True;
+   requires True || True;
+};
+template 
+concept Amps1 = requires (T x) {
+   requires True && True;
+   // expected-note@-1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+};
+template 
+concept Amps2 = requires (T x) {
+   requires True && True;
+};
+
+static_assert(Pipes);
+static_assert(Pipes);
+
+static_assert(Amps1);
+static_assert(!Amps1);
+
+static_assert(Amps2);
+static_assert(!Amps2);
+
+template
+void foo1() requires requires (T x) { // expected-note {{candidate template ignored: constraints not satisfied [with T = int]}}
+  requires 
+  True // expected-note {{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+  && True;
+} {}
+template void fooPipes() requires Pipes {}
+template void fooAmps1() requires Amps1 {}
+// expected-note@-1 {{candidate template ignored: constraints not satisfied [with T = int]}} \
+// expected-note@-1 {{because 'int' does not satisfy 'Amps1'}}
+
+void foo() {
+  foo1();
+  foo1(); // expected-error {{no matching function for call to 'foo1'}}
+  fooPipes();
+  fooPipes();
+  fooAmps1();
+  fooAmps1(); // expected-error {{no matching function for call to 'fooAmps1'}}
+}
+}
\ No newline at end of file
Index: clang/lib/Sema/TreeTransform.h
===
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -3477,6 +3477,22 @@
 return Result;
   }
 
+  ExprResult RebuildConceptSpecializationExprWithSFINAE(
+  ConceptSpecializationExpr *E, NestedNameSpecifierLoc NNS,
+  SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
+  NamedDecl *FoundDecl, ConceptDecl *NamedConcept) {
+ConstraintSatisfaction Satisfaction;
+Satisfaction.IsSatisfied = false;
+Satisfaction.ContainsErrors = true;
+CXXScopeSpec SS;
+SS.Adopt(NNS);
+return ConceptSpecializationExpr::CreateWithSFINAE(
+SemaRef.Context,
+SS.isSet() ? SS.getWithLocInContext(SemaRef.Context)
+   : NestedNameSpecifierLoc{},
+TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept, );
+  }
+
   /// \brief Build a new requires expression.
   ///
   /// By default, performs semantic analysis to build the new expression.
@@ -12617,9 +12633,20 @@
  ConceptSpecializationExpr *E) {
   const ASTTemplateArgumentListInfo *Old = E->getTemplateArgsAsWritten();
   TemplateArgumentListInfo TransArgs(Old->LAngleLoc, Old->RAngleLoc);
-  if (getDerived().TransformTemplateArguments(Old->getTemplateArgs(),
-  Old->NumTemplateArgs, TransArgs))
-return ExprError();
+  {
+Sema::SFINAETrap Trap(getSema());
+if (getDerived().TransformTemplateArguments(
+Old->getTemplateArgs(), Old->NumTemplateArgs, TransArgs) &&
+!Trap.hasErrorOccurred())
+  return ExprError();
+
+if (Trap.hasErrorOccurred()) {
+  // FIXME: Propogate detailed subtitution falilure diagnostics.
+  return getDerived().RebuildConceptSpecializationExprWithSFINAE(
+  E, E->getNestedNameSpecifierLoc(), E->getTemplateKWLoc(),
+  E->getConceptNameInfo(), E->getFoundDecl(), E->getNamedConcept());
+}
+  }
 
   return getDerived().RebuildConceptSpecializationExpr(
   E->getNestedNameSpecifierLoc(), E->getTemplateKWLoc(),
Index: clang/lib/AST/ExprConcepts.cpp
===
--- clang/lib/AST/ExprConcepts.cpp
+++ clang/lib/AST/ExprConcepts.cpp
@@ -103,6 +103,16 @@
 Dependent, ContainsUnexpandedParameterPack);
 }
 
+ConceptSpecializationExpr *ConceptSpecializationExpr::CreateWithSFINAE(
+const ASTContext , NestedNameSpecifierLoc NNS,
+SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
+NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
+const ConstraintSatisfaction *Satisfaction) {
+  return 

[PATCH] D133052: [clang] Avoid crash when expanding conversion templates in concepts.

2022-10-28 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 added a comment.

Coincidentally 2 of the bugs were just fixed in b9a77b56d8 
.
 I do not completely agree with the approach there though. We should be fixing 
the root cause instead of circumventing the assert in `InsertNode` by 
insert-if-not-present. This is why we still have 44304 and 50891 still 
persistent.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D133052

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


[PATCH] D133052: [clang] Avoid crash when expanding conversion templates in concepts.

2022-10-28 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 added a comment.

My suggestion would be to properly handle cycles in 
`CheckConstraintSatisfaction`. This problem goes beyond cycles introduced by 
conversion. See #53213  and 
#44304  
https://godbolt.org/z/v41ez6eW4. These two bugs are due to an assertion failure 
while inserting entry into SatisfactionCache.

My suggestion would be detect cycles in `CheckConstraintSatisfaction`. We 
already have a way to check "whether we have seen this before ?" in 
`SatisfactionCache` using `FoldingSet` for `ConstraintSatisfaction`. We could 
use a similar set to track the constraints being evaluated. Stop evaluation 
when we detect a cycle. Attach appropriate details to the Satisfaction and fail 
the constraint.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D133052

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


[PATCH] D133052: [clang] Avoid crash when expanding conversion templates in concepts.

2022-10-27 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 added a comment.

Not sure if this has come up already but this would still crash on

  template 
  concept C = requires(T a) { foo(a); };
  struct D1 {
  template  D1(TO);
  };
  struct D2 {
  friend void foo(D1);
  };
  
  static_assert(C);

as we only consider conversion to itself (derived to base).


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D133052

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


[PATCH] D136440: [clang] Do not hide base member using-decls with different template head.

2022-10-27 Thread Utkarsh Saxena via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG56099d242809: [clang] Do not hide base member using-decls 
with different template head. (authored by usaxena95).

Changed prior to commit:
  https://reviews.llvm.org/D136440?vs=471086=471095#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D136440

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaOverload.cpp
  clang/test/SemaTemplate/concepts-using-decl.cpp

Index: clang/test/SemaTemplate/concepts-using-decl.cpp
===
--- /dev/null
+++ clang/test/SemaTemplate/concepts-using-decl.cpp
@@ -0,0 +1,178 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+
+namespace static_methods {
+template concept False = false;
+
+struct Base {
+static void foo(auto);
+};
+struct Derived : public Base {
+using Base::foo;
+static void foo(False auto);
+};
+void func() {
+Derived::foo(42);
+}
+} // namespace static_methods
+
+namespace constrained_members {
+template  struct Opaque {};
+template  void expect(Opaque _) {}
+
+struct Empty{};
+constexpr int EmptySize = sizeof(Empty);
+
+template concept IsEmpty = sizeof(T) == EmptySize;
+
+namespace base_members_not_hidden {
+struct base {
+  template 
+  Opaque<0> foo() { return Opaque<0>(); };
+};
+
+struct bar1 : public base {
+  using base::foo;
+  template  requires IsEmpty 
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+
+struct bar2 : public base {
+  using base::foo;
+  template 
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+
+struct bar3 : public base {
+  using base::foo;
+  template 
+  Opaque<1> foo() requires IsEmpty { return Opaque<1>(); };
+};
+
+void func() {
+  expect<0>(base{}.foo());
+  expect<0>(base{}.foo());
+  expect<1>(bar1{}.foo());
+  expect<0>(bar1{}.foo());
+  expect<1>(bar2{}.foo());
+  expect<0>(bar2{}.foo());
+  expect<1>(bar3{}.foo());
+  expect<0>(bar3{}.foo());
+}
+}
+namespace base_members_hidden {
+struct base1 {
+  template  requires IsEmpty
+  Opaque<0> foo() { return Opaque<0>(); }; // expected-note {{candidate function}}
+};
+struct bar1 : public base1 {
+  using base1::foo;
+  template  requires IsEmpty
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+struct base2 {
+  template 
+  Opaque<0> foo() { return Opaque<0>(); };
+};
+struct bar2 : public base2 {
+  using base2::foo;
+  template 
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+struct baz : public base1 {
+  using base1::foo;
+  template  requires IsEmpty && IsEmpty
+  Opaque<1> foo() { return Opaque<1>(); };  // expected-note {{candidate function}}
+};
+void func() { 
+  expect<0>(base1{}.foo());
+  expect<1>(bar1{}.foo());
+  expect<0>(base2{}.foo());
+  expect<1>(bar2{}.foo());
+  baz{}.foo(); // expected-error {{call to member function 'foo' is ambiguous}}
+}
+} // namespace base_members_hidden
+
+namespace same_contraint_at_different_place {
+struct base {
+  template 
+  void foo1() {}; // expected-note 2 {{candidate function}}
+  template  requires IsEmpty
+  void foo2() {}; // expected-note 2 {{candidate function}}
+  template 
+  void foo3() requires IsEmpty {}; // expected-note 2 {{candidate function}}
+};
+struct bar1 : public base {
+  using base::foo1;
+  using base::foo2;
+  using base::foo3;
+  template  requires IsEmpty
+  void foo1() {}; // expected-note {{candidate function}}
+  template 
+  void foo2() {}; // expected-note {{candidate function}}
+  template 
+  void foo3() {}; // expected-note {{candidate function}}
+};
+struct bar2 : public base {
+  using base::foo1;
+  using base::foo2;
+  using base::foo3;
+  template 
+  void foo1() requires IsEmpty {}; // expected-note {{candidate function}}
+  template 
+  void foo2() requires IsEmpty {}; // expected-note {{candidate function}}
+  template  requires IsEmpty
+  void foo3() {}; // expected-note {{candidate function}}
+};
+void func() {
+  bar1{}.foo1(); // expected-error {{call to member function 'foo1' is ambiguous}}
+  bar1{}.foo2(); // expected-error {{call to member function 'foo2' is ambiguous}}
+  bar1{}.foo3(); // expected-error {{call to member function 'foo3' is ambiguous}}
+  bar2{}.foo1(); // expected-error {{call to member function 'foo1' is ambiguous}}
+  bar2{}.foo2(); // expected-error {{call to member function 'foo2' is ambiguous}}
+  bar2{}.foo3(); // expected-error {{call to member function 'foo3' is ambiguous}}
+}
+} // namespace same_constraint_at_different_place
+
+namespace more_constrained {
+struct base1 { 
+  template  Opaque<0> foo() { return Opaque<0>(); }
+};
+struct derived1 : base1 { 
+  using base1::foo;
+  template  Opaque<1> foo() { return Opaque<1>(); }
+};
+struct base2 { 
+  template  Opaque<0> foo() { return Opaque<0>(); }
+};
+struct derived2 : base2 { 
+  using base2::foo;
+  template  Opaque<1> foo() { return 

[PATCH] D136440: [clang] Do not hide base member using-decls with different template head.

2022-10-27 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 471086.
usaxena95 marked 2 inline comments as done.
usaxena95 added a comment.

Addressed comments. Added release notes.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D136440

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaOverload.cpp
  clang/test/SemaTemplate/concepts-using-decl.cpp

Index: clang/test/SemaTemplate/concepts-using-decl.cpp
===
--- /dev/null
+++ clang/test/SemaTemplate/concepts-using-decl.cpp
@@ -0,0 +1,178 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+
+namespace static_methods {
+template concept False = false;
+
+struct Base {
+static void foo(auto);
+};
+struct Derived : public Base {
+using Base::foo;
+static void foo(False auto);
+};
+void func() {
+Derived::foo(42);
+}
+} // namespace static_methods
+
+namespace constrained_members {
+template  struct Opaque {};
+template  void expect(Opaque _) {}
+
+struct Empty{};
+constexpr int EmptySize = sizeof(Empty);
+
+template concept IsEmpty = sizeof(T) == EmptySize;
+
+namespace base_members_not_hidden {
+struct base {
+  template 
+  Opaque<0> foo() { return Opaque<0>(); };
+};
+
+struct bar1 : public base {
+  using base::foo;
+  template  requires IsEmpty 
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+
+struct bar2 : public base {
+  using base::foo;
+  template 
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+
+struct bar3 : public base {
+  using base::foo;
+  template 
+  Opaque<1> foo() requires IsEmpty { return Opaque<1>(); };
+};
+
+void func() {
+  expect<0>(base{}.foo());
+  expect<0>(base{}.foo());
+  expect<1>(bar1{}.foo());
+  expect<0>(bar1{}.foo());
+  expect<1>(bar2{}.foo());
+  expect<0>(bar2{}.foo());
+  expect<1>(bar3{}.foo());
+  expect<0>(bar3{}.foo());
+}
+}
+namespace base_members_hidden {
+struct base1 {
+  template  requires IsEmpty
+  Opaque<0> foo() { return Opaque<0>(); }; // expected-note {{candidate function}}
+};
+struct bar1 : public base1 {
+  using base1::foo;
+  template  requires IsEmpty
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+struct base2 {
+  template 
+  Opaque<0> foo() { return Opaque<0>(); };
+};
+struct bar2 : public base2 {
+  using base2::foo;
+  template 
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+struct baz : public base1 {
+  using base1::foo;
+  template  requires IsEmpty && IsEmpty
+  Opaque<1> foo() { return Opaque<1>(); };  // expected-note {{candidate function}}
+};
+void func() { 
+  expect<0>(base1{}.foo());
+  expect<1>(bar1{}.foo());
+  expect<0>(base2{}.foo());
+  expect<1>(bar2{}.foo());
+  baz{}.foo(); // expected-error {{call to member function 'foo' is ambiguous}}
+}
+} // namespace base_members_hidden
+
+namespace same_contraint_at_different_place {
+struct base {
+  template 
+  void foo1() {}; // expected-note 2 {{candidate function}}
+  template  requires IsEmpty
+  void foo2() {}; // expected-note 2 {{candidate function}}
+  template 
+  void foo3() requires IsEmpty {}; // expected-note 2 {{candidate function}}
+};
+struct bar1 : public base {
+  using base::foo1;
+  using base::foo2;
+  using base::foo3;
+  template  requires IsEmpty
+  void foo1() {}; // expected-note {{candidate function}}
+  template 
+  void foo2() {}; // expected-note {{candidate function}}
+  template 
+  void foo3() {}; // expected-note {{candidate function}}
+};
+struct bar2 : public base {
+  using base::foo1;
+  using base::foo2;
+  using base::foo3;
+  template 
+  void foo1() requires IsEmpty {}; // expected-note {{candidate function}}
+  template 
+  void foo2() requires IsEmpty {}; // expected-note {{candidate function}}
+  template  requires IsEmpty
+  void foo3() {}; // expected-note {{candidate function}}
+};
+void func() {
+  bar1{}.foo1(); // expected-error {{call to member function 'foo1' is ambiguous}}
+  bar1{}.foo2(); // expected-error {{call to member function 'foo2' is ambiguous}}
+  bar1{}.foo3(); // expected-error {{call to member function 'foo3' is ambiguous}}
+  bar2{}.foo1(); // expected-error {{call to member function 'foo1' is ambiguous}}
+  bar2{}.foo2(); // expected-error {{call to member function 'foo2' is ambiguous}}
+  bar2{}.foo3(); // expected-error {{call to member function 'foo3' is ambiguous}}
+}
+} // namespace same_constraint_at_different_place
+
+namespace more_constrained {
+struct base1 { 
+  template  Opaque<0> foo() { return Opaque<0>(); }
+};
+struct derived1 : base1 { 
+  using base1::foo;
+  template  Opaque<1> foo() { return Opaque<1>(); }
+};
+struct base2 { 
+  template  Opaque<0> foo() { return Opaque<0>(); }
+};
+struct derived2 : base2 { 
+  using base2::foo;
+  template  Opaque<1> foo() { return Opaque<1>(); }
+};
+void func() {
+  expect<0>(derived1{}.foo());
+  expect<1>(derived1{}.foo());
+  expect<0>(derived2{}.foo());
+  expect<1>(derived2{}.foo());
+}
+} // namespace 

[PATCH] D136440: [clang] Do not hide base member using-decls with different template head.

2022-10-25 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 added inline comments.



Comment at: clang/test/SemaTemplate/concepts-using-decl.cpp:112
+  expect<1>(baz{}.foo()); // expected-error {{call to member function 
'foo' is ambiguous}}
+}
+}

ilya-biryukov wrote:
> Could you also check that `requires` clauses and constraints in template 
> parameters do not hide each other?
> ```
> template  ...
> // vs
> template  requires IsEmpty ...
> // vs
> template  void foo() requires IsEmpty ...
> ```
> Should not hide each other.
> 
> Another interesting case (that probably does not yet work):
> ```
> struct base { template  void foo(); };
> struct derived : base { 
>   using base::foo; 
>   template  void foo();
> };
> ```
> ^^ `derived().foo()` will probably produce an ambiguity now (as we 
> don't have an explicit requires clause here). I don't think it's worth fixing 
> now, but keeping a test for it with a FIXME seems reasonable.
The last test case would work though since we perform template head check if 
any template head is contrained. This is not ambiguous as overloading chooses 
the "most contrained" version.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D136440

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


[PATCH] D136440: [clang] Do not hide base member using-decls with different template head.

2022-10-25 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 470505.
usaxena95 marked 3 inline comments as done.
usaxena95 added a comment.

Added more tests.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D136440

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaOverload.cpp
  clang/test/SemaTemplate/concepts-using-decl.cpp

Index: clang/test/SemaTemplate/concepts-using-decl.cpp
===
--- /dev/null
+++ clang/test/SemaTemplate/concepts-using-decl.cpp
@@ -0,0 +1,173 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+
+namespace static_methods {
+template concept False = false;
+
+struct Base {
+static void foo(auto);
+};
+struct Derived : public Base {
+using Base::foo;
+static void foo(False auto);
+};
+void func() {
+Derived::foo(42);
+}
+} // namespace static_methods
+
+namespace constrained_members {
+template  struct Opaque {};
+template  void expect(Opaque _) {}
+
+struct Empty{};
+constexpr int EmptySize = sizeof(Empty);
+
+template concept IsEmpty = sizeof(T) == EmptySize;
+
+namespace base_members_not_hidden {
+struct base {
+  template 
+  Opaque<0> foo() { return Opaque<0>(); };
+};
+
+struct bar1 : public base {
+  using base::foo;
+  template  requires IsEmpty 
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+
+struct bar2 : public base {
+  using base::foo;
+  template 
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+
+struct bar3 : public base {
+  using base::foo;
+  template 
+  Opaque<1> foo() requires IsEmpty { return Opaque<1>(); };
+};
+
+void func() {
+  expect<0>(base{}.foo());
+  expect<0>(base{}.foo());
+  expect<1>(bar1{}.foo());
+  expect<0>(bar1{}.foo());
+  expect<1>(bar2{}.foo());
+  expect<0>(bar2{}.foo());
+  expect<1>(bar3{}.foo());
+  expect<0>(bar3{}.foo());
+}
+}namespace base_members_hidden {
+struct base1 {
+  template  requires IsEmpty
+  Opaque<0> foo() { return Opaque<0>(); }; // expected-note {{candidate function [with T = constrained_members::Empty]}}
+};
+struct bar1 : public base1 {
+  using base1::foo;
+  template  requires IsEmpty
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+struct base2 {
+  template 
+  Opaque<0> foo() { return Opaque<0>(); };
+};
+struct bar2 : public base2 {
+  using base2::foo;
+  template 
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+struct baz : public base1 {
+  using base1::foo;
+  template  requires IsEmpty && IsEmpty
+  Opaque<1> foo() { return Opaque<1>(); };  // expected-note {{candidate function [with T = constrained_members::Empty]}}
+};
+void func() { 
+  expect<0>(base1{}.foo());
+  expect<1>(bar1{}.foo());
+  expect<0>(base2{}.foo());
+  expect<1>(bar2{}.foo());
+  baz{}.foo(); // expected-error {{call to member function 'foo' is ambiguous}}
+}
+}
+namespace same_contraint_at_different_place {
+struct base {
+  template 
+  Opaque<0> foo1() { return Opaque<0>(); }; // expected-note 2 {{candidate function}}
+  template  requires IsEmpty
+  Opaque<0> foo2() { return Opaque<0>(); }; // expected-note 2 {{candidate function}}
+  template 
+  Opaque<0> foo3() requires IsEmpty { return Opaque<0>(); }; // expected-note 2 {{candidate function}}
+};
+struct bar1 : public base {
+  using base::foo1;
+  using base::foo2;
+  using base::foo3;
+  template  requires IsEmpty
+  Opaque<1> foo1() { return Opaque<1>(); }; // expected-note {{candidate function}}
+  template 
+  Opaque<1> foo2() { return Opaque<1>(); }; // expected-note {{candidate function}}
+  template 
+  Opaque<1> foo3() { return Opaque<1>(); }; // expected-note {{candidate function}}
+};
+struct bar2 : public base {
+  using base::foo1;
+  using base::foo2;
+  using base::foo3;
+  template 
+  Opaque<2> foo1() requires IsEmpty { return Opaque<2>(); }; // expected-note {{candidate function}}
+  template 
+  Opaque<2> foo2() requires IsEmpty { return Opaque<2>(); }; // expected-note {{candidate function}}
+  template  requires IsEmpty
+  Opaque<2> foo3() { return Opaque<2>(); }; // expected-note {{candidate function}}
+};void func() {
+  bar1{}.foo1(); // expected-error {{call to member function 'foo1' is ambiguous}}
+  bar1{}.foo2(); // expected-error {{call to member function 'foo2' is ambiguous}}
+  bar1{}.foo3(); // expected-error {{call to member function 'foo3' is ambiguous}}
+  bar2{}.foo1(); // expected-error {{call to member function 'foo1' is ambiguous}}
+  bar2{}.foo2(); // expected-error {{call to member function 'foo2' is ambiguous}}
+  bar2{}.foo3(); // expected-error {{call to member function 'foo3' is ambiguous}}
+}
+} // namespace same_contraint_at_different_place
+
+namespace more_contrained {
+struct base1 { 
+  template  Opaque<0> foo() { return Opaque<0>(); }
+};
+struct derived1 : base1 { 
+  using base1::foo;
+  template  Opaque<1> foo() { return Opaque<1>(); }
+};
+struct base2 { 
+  template  Opaque<0> foo() { return Opaque<0>(); }
+};
+struct derived2 : base2 { 
+  using base2::foo;
+  template 

[PATCH] D136440: [clang] Do not hide base member using-decls with different template head.

2022-10-24 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 470174.
usaxena95 marked 2 inline comments as done.
usaxena95 added a comment.

Addressed comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D136440

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaOverload.cpp
  clang/test/SemaTemplate/concepts-using-decl.cpp

Index: clang/test/SemaTemplate/concepts-using-decl.cpp
===
--- /dev/null
+++ clang/test/SemaTemplate/concepts-using-decl.cpp
@@ -0,0 +1,114 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+
+namespace heads_without_concepts {
+struct base {
+  template 
+  int foo() { return 1; };
+};
+
+struct bar : public base {
+  using base::foo;
+  template  
+  int foo() { return 2; }; // expected-note {{candidate template ignored: substitution failure: too many template arguments for function template 'foo'}}
+};
+
+void func() {
+  bar f;
+  f.foo<10>();
+  // FIXME(GH58571): bar::foo should not hide base::foo.
+  f.foo<10, 10>(); // expected-error {{no matching member function for call to 'foo'}}
+}
+}
+
+namespace static_methods {
+template concept False = false;
+
+struct Base {
+static void foo(auto);
+};
+struct Derived : public Base {
+using Base::foo;
+static void foo(False auto);
+};
+void func() {
+Derived::foo(42);
+}
+}
+
+namespace constrained_members {
+template  struct Opaque {};
+template  void expect(Opaque _) {}
+
+struct Empty{};
+constexpr int EmptySize = sizeof(Empty);
+
+template concept IsEmpty = sizeof(T) == EmptySize;
+
+namespace base_members_not_hidden {
+struct base {
+  template 
+  Opaque<0> foo() { return Opaque<0>(); };
+};
+
+struct bar1 : public base {
+  using base::foo;
+  template  requires IsEmpty 
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+
+struct bar2 : public base {
+  using base::foo;
+  template 
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+
+struct bar3 : public base {
+  using base::foo;
+  template 
+  Opaque<1> foo() requires IsEmpty { return Opaque<1>(); };
+};
+
+void func() {
+  expect<0>(base{}.foo());
+  expect<0>(base{}.foo());
+  expect<1>(bar1{}.foo());
+  expect<0>(bar1{}.foo());
+  expect<1>(bar2{}.foo());
+  expect<0>(bar2{}.foo());
+  expect<1>(bar3{}.foo());
+  expect<0>(bar3{}.foo());
+}
+}
+namespace base_members_hidden {
+struct base1 {
+  template  requires IsEmpty
+  Opaque<0> foo() { return Opaque<0>(); }; // expected-note {{candidate function [with T = constrained_members::Empty]}}
+};
+struct bar1 : public base1 {
+  using base1::foo;
+  template  requires IsEmpty
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+struct base2 {
+  template 
+  Opaque<0> foo() { return Opaque<0>(); };
+};
+struct bar2 : public base2 {
+  using base2::foo;
+  template 
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+struct baz : public base1 {
+  using base1::foo;
+  template  requires IsEmpty && IsEmpty
+  Opaque<1> foo() { return Opaque<1>(); };  // expected-note {{candidate function [with T = constrained_members::Empty]}}
+};
+void func() { 
+  expect<0>(base1{}.foo());
+  expect<1>(bar1{}.foo());
+  expect<0>(base2{}.foo());
+  expect<1>(bar2{}.foo());
+  expect<1>(baz{}.foo()); // expected-error {{call to member function 'foo' is ambiguous}}
+}
+}
+}
Index: clang/lib/Sema/SemaOverload.cpp
===
--- clang/lib/Sema/SemaOverload.cpp
+++ clang/lib/Sema/SemaOverload.cpp
@@ -1280,26 +1280,42 @@
!FunctionParamTypesAreEqual(OldType, NewType)))
 return true;
 
-  // C++ [temp.over.link]p4:
-  //   The signature of a function template consists of its function
-  //   signature, its return type and its template parameter list. The names
-  //   of the template parameters are significant only for establishing the
-  //   relationship between the template parameters and the rest of the
-  //   signature.
-  //
-  // We check the return type and template parameter lists for function
-  // templates first; the remaining checks follow.
-  //
-  // However, we don't consider either of these when deciding whether
-  // a member introduced by a shadow declaration is hidden.
-  if (!UseMemberUsingDeclRules && NewTemplate &&
-  (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
-   OldTemplate->getTemplateParameters(),
-   false, TPL_TemplateMatch) ||
-   !Context.hasSameType(Old->getDeclaredReturnType(),
-New->getDeclaredReturnType(
-return true;
-
+  if (NewTemplate) {
+// C++ [temp.over.link]p4:
+//   The signature of a function template consists of its function
+//   signature, its return type and its template parameter list. The names
+//   of the template parameters are significant only for establishing the
+//   relationship between the template parameters and the 

[PATCH] D136440: [clang] Do not hide base member using-decls with different template head.

2022-10-24 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 marked 4 inline comments as done.
usaxena95 added a comment.

I have switched to a version where we matched template heads only when they are 
constraints. This is for the moment to unblock the existing bugs and not break 
existing code prior to C++20.
Let us continue the discussion over the possibility of introducing an ambiguity 
in  https://github.com/llvm/llvm-project/issues/58571




Comment at: clang/lib/Sema/SemaOverload.cpp:1307
+// C++ [namespace.udecl]p4:
+//   The member from the base class is hidden or overridden by the
+//   implicitly-declared copy/move constructor or assignment operator of 
the

ilya-biryukov wrote:
> How is this related to checking whether the template parameter lists check?
> I seems to be missing the logical connection that goes from the standard 
> wording to the code. Could you explain?
> 
> An example that I have in mind is:
> ```
> struct A {
> template  A(T);
> template  int foo(T);
> };
> struct B : A {
> using A::A;
> template  B(T);
> 
> using A::foo;
> template  int foo(T);
> };
> 
> namespace detail {
> template  int bar(T);
> }
> using detail::bar;
> template  int bar(T);
> 
> int a = bar(10); // this is definitely ambiguous.
> 
> B b(10); // should this be ambiguous?
> int c = b.foo(10); // should this be ambiguous?
> // Should constructors and functions behave differently? Why?
> ```
> 
> I [see](https://gcc.godbolt.org/z/z4Ko1ehPe) that both Clang and GCC treat 
> member declarations differently, but I don't see why they should given that 
> they are supposed to use the same "corresponds" terminology from the 
> standard. What am I missing?
I have filed https://github.com/llvm/llvm-project/issues/58571 to discuss the 
interpretation of the standard.



Comment at: clang/test/SemaTemplate/concepts-using-decl.cpp:110
+  expect<1>(bar2{}.foo());
+  // FIXME: Candidates from using-decls should be dropped in case of ambiguity.
+  expect<1>(baz{}.foo()); // expected-error {{call to member function 
'foo' is ambiguous}}

ilya-biryukov wrote:
> Why should they be dropped? Could you provide pointers from the standard?
I think I misunderstood that using decls should not be introducing ambiguities. 


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D136440

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


[PATCH] D136440: [clang] Do not hide base member using-decls with different template head.

2022-10-21 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 469552.
usaxena95 added a comment.

Added more tests.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D136440

Files:
  clang/lib/Sema/SemaOverload.cpp
  clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp
  clang/test/CXX/drs/dr2xx.cpp
  clang/test/SemaTemplate/concepts-using-decl.cpp

Index: clang/test/SemaTemplate/concepts-using-decl.cpp
===
--- /dev/null
+++ clang/test/SemaTemplate/concepts-using-decl.cpp
@@ -0,0 +1,114 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+
+namespace heads_without_concepts {
+struct base {
+  template 
+  int foo() { return 1; };
+};
+
+struct bar : public base {
+  using base::foo;
+  template  
+  int foo() { return 2; };
+};
+
+void func() {
+  bar f;
+  f.foo<10>();
+  f.foo<10, 10>();
+}
+}
+
+namespace static_methods {
+template concept False = false;
+
+struct Base {
+static void foo(auto);
+};
+struct Derived : public Base {
+using Base::foo;
+static void foo(False auto);
+};
+void func() {
+Derived::foo(42);
+}
+}
+
+namespace members_not_hidden {
+template  struct Opaque {};
+template  void expect(Opaque _) {}
+
+struct Empty{};
+constexpr int EmptySize = sizeof(Empty);
+
+template concept IsEmpty = sizeof(T) == EmptySize;
+
+namespace base_members_not_hidden {
+struct base {
+  template 
+  Opaque<0> foo() { return Opaque<0>(); };
+};
+
+struct bar1 : public base {
+  using base::foo;
+  template  requires IsEmpty 
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+
+struct bar2 : public base {
+  using base::foo;
+  template 
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+
+struct bar3 : public base {
+  using base::foo;
+  template 
+  Opaque<1> foo() requires IsEmpty { return Opaque<1>(); };
+};
+
+void func() {
+  expect<0>(base{}.foo());
+  expect<0>(base{}.foo());
+  expect<1>(bar1{}.foo());
+  expect<0>(bar1{}.foo());
+  expect<1>(bar2{}.foo());
+  expect<0>(bar2{}.foo());
+  expect<1>(bar3{}.foo());
+  expect<0>(bar3{}.foo());
+}
+}
+namespace base_members_hidden {
+struct base1 {
+  template  requires IsEmpty
+  Opaque<0> foo() { return Opaque<0>(); }; // expected-note {{candidate function [with T = members_not_hidden::Empty]}}
+};
+struct bar1 : public base1 {
+  using base1::foo;
+  template  requires IsEmpty
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+struct base2 {
+  template 
+  Opaque<0> foo() { return Opaque<0>(); };
+};
+struct bar2 : public base2 {
+  using base2::foo;
+  template 
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+struct baz : public base1 {
+  using base1::foo;
+  template  requires IsEmpty && IsEmpty
+  Opaque<1> foo() { return Opaque<1>(); };  // expected-note {{candidate function [with T = members_not_hidden::Empty]}}
+};
+void func() { 
+  expect<0>(base1{}.foo());
+  expect<1>(bar1{}.foo());
+  expect<0>(base2{}.foo());
+  expect<1>(bar2{}.foo());
+  // FIXME: Candidates from using-decls should be dropped in case of ambiguity.
+  expect<1>(baz{}.foo()); // expected-error {{call to member function 'foo' is ambiguous}}
+}
+}
+}
Index: clang/test/CXX/drs/dr2xx.cpp
===
--- clang/test/CXX/drs/dr2xx.cpp
+++ clang/test/CXX/drs/dr2xx.cpp
@@ -719,11 +719,11 @@
 using A::g;
 using A::h;
 int (int);
-template int (int); // expected-note {{candidate}}
+template int (int);
 int ();
   } b;
   int  = b.f(0);
-  int  = b.g(0); // expected-error {{no match}}
+  int  = b.g(0); // expected-error {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'void'}}
   int  = b.h();
   float  = const_cast(b).h();
 
Index: clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp
===
--- clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp
+++ clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp
@@ -9,7 +9,7 @@
 //   parameter types in a base class (rather than conflicting).
 
 template  struct Opaque {};
-template  void expect(Opaque _) {} // expected-note 4 {{candidate function template not viable}}
+template  void expect(Opaque _) {}
 
 // PR5727
 // This just shouldn't crash.
@@ -113,35 +113,35 @@
 
   struct Derived1 : Base {
 using Base::foo;
-template  Opaque<2> foo() { return Opaque<2>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'n'}}
+template  Opaque<2> foo() { return Opaque<2>(); }
   };
 
   struct Derived2 : Base {
-template  Opaque<2> foo() { return Opaque<2>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'n'}}
+template  Opaque<2> foo() { return Opaque<2>(); }
 using Base::foo;
   };
 
   struct Derived3 : Base {
 using Base::foo;
-template  Opaque<3> foo() { return Opaque<3>(); } // expected-note {{invalid 

[PATCH] D136440: Do not hide base member using decls with different template head.

2022-10-21 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 created this revision.
Herald added a project: All.
usaxena95 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D136440

Files:
  clang/lib/Sema/SemaOverload.cpp
  clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp
  clang/test/CXX/drs/dr2xx.cpp
  clang/test/SemaTemplate/concepts-using-decl.cpp

Index: clang/test/SemaTemplate/concepts-using-decl.cpp
===
--- /dev/null
+++ clang/test/SemaTemplate/concepts-using-decl.cpp
@@ -0,0 +1,97 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+// expected-no-diagnostics
+
+namespace heads_without_concepts {
+struct base {
+  template 
+  int foo() { return 1; };
+};
+
+struct bar : public base {
+  using base::foo;
+  template  
+  int foo() { return 2; };
+};
+
+void func() {
+  bar f;
+  f.foo<10>();
+  f.foo<10, 10>();
+}
+}
+
+namespace static_methods {
+template concept False = false;
+
+struct Base {
+static void foo(auto);
+};
+struct Derived : public Base {
+using Base::foo;
+static void foo(False auto);
+};
+void func() {
+Derived::foo(42);
+}
+}
+
+namespace members_not_hidden {
+template  struct Opaque {};
+template  void expect(Opaque _) {}
+
+struct Empty{};
+constexpr int EmptySize = sizeof(Empty);
+
+template concept IsEmpty = sizeof(T) == EmptySize;
+
+namespace base_members_not_hidden {
+struct base {
+  template 
+  Opaque<0> foo() { return Opaque<0>(); };
+};
+
+struct bar1 : public base {
+  using base::foo;
+  template  requires IsEmpty 
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+
+struct bar2 : public base {
+  using base::foo;
+  template 
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+
+struct bar3 : public base {
+  using base::foo;
+  template 
+  Opaque<1> foo() requires IsEmpty { return Opaque<1>(); };
+};
+
+void func() {
+  expect<0>(base{}.foo());
+  expect<0>(base{}.foo());
+  expect<1>(bar1{}.foo());
+  expect<0>(bar1{}.foo());
+  expect<1>(bar2{}.foo());
+  expect<0>(bar2{}.foo());
+  expect<1>(bar3{}.foo());
+  expect<0>(bar3{}.foo());
+}
+}
+namespace base_members_hidden {
+struct base {
+  template  requires IsEmpty
+  Opaque<0> foo() { return Opaque<0>(); };
+};
+struct bar : public base {
+  using base::foo;
+  template  requires IsEmpty
+  Opaque<1> foo() { return Opaque<1>(); };
+};
+void func() { 
+  expect<0>(base{}.foo());
+  expect<1>(bar{}.foo());
+}
+}
+}
\ No newline at end of file
Index: clang/test/CXX/drs/dr2xx.cpp
===
--- clang/test/CXX/drs/dr2xx.cpp
+++ clang/test/CXX/drs/dr2xx.cpp
@@ -719,11 +719,11 @@
 using A::g;
 using A::h;
 int (int);
-template int (int); // expected-note {{candidate}}
+template int (int);
 int ();
   } b;
   int  = b.f(0);
-  int  = b.g(0); // expected-error {{no match}}
+  int  = b.g(0); // expected-error {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'void'}}
   int  = b.h();
   float  = const_cast(b).h();
 
Index: clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp
===
--- clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp
+++ clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp
@@ -9,7 +9,7 @@
 //   parameter types in a base class (rather than conflicting).
 
 template  struct Opaque {};
-template  void expect(Opaque _) {} // expected-note 4 {{candidate function template not viable}}
+template  void expect(Opaque _) {}
 
 // PR5727
 // This just shouldn't crash.
@@ -113,35 +113,35 @@
 
   struct Derived1 : Base {
 using Base::foo;
-template  Opaque<2> foo() { return Opaque<2>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'n'}}
+template  Opaque<2> foo() { return Opaque<2>(); }
   };
 
   struct Derived2 : Base {
-template  Opaque<2> foo() { return Opaque<2>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'n'}}
+template  Opaque<2> foo() { return Opaque<2>(); }
 using Base::foo;
   };
 
   struct Derived3 : Base {
 using Base::foo;
-template  Opaque<3> foo() { return Opaque<3>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'T'}}
+template  Opaque<3> foo() { return Opaque<3>(); }
   };
 
   struct Derived4 : Base {
-template  Opaque<3> foo() { return Opaque<3>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'T'}}
+template  Opaque<3> foo() { return Opaque<3>(); }
 using Base::foo;
   };
 
   void test() {
 expect<0>(Base().foo());
 expect<1>(Base().foo<0>());
-expect<0>(Derived1().foo()); // expected-error {{no matching member function for call to 'foo'}} expected-error {{no matching function for call to 'expect'}}
+expect<0>(Derived1().foo());
  

[PATCH] D136259: Fix crash in constraining partial specialization on nested template.

2022-10-20 Thread Utkarsh Saxena via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG4c87e12484b3: Fix crash in constraining partial 
specialization on nested template. (authored by usaxena95).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D136259

Files:
  clang/lib/Sema/SemaTemplateDeduction.cpp
  clang/test/SemaTemplate/concepts-GH53354.cpp


Index: clang/test/SemaTemplate/concepts-GH53354.cpp
===
--- /dev/null
+++ clang/test/SemaTemplate/concepts-GH53354.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+// expected-no-diagnostics
+
+template  class>
+struct S
+{};
+
+template 
+concept C1 = requires
+{
+  typename S;
+};
+
+template 
+requires C1
+struct A {};
+
+template 
+requires C1 && true
+struct A {};
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5803,8 +5803,8 @@
   }
 
   bool TraverseTemplateName(TemplateName Template) {
-if (auto *TTP =
-dyn_cast(Template.getAsTemplateDecl()))
+if (auto *TTP = llvm::dyn_cast_or_null(
+Template.getAsTemplateDecl()))
   if (TTP->getDepth() == Depth)
 Used[TTP->getIndex()] = true;
 RecursiveASTVisitor::


Index: clang/test/SemaTemplate/concepts-GH53354.cpp
===
--- /dev/null
+++ clang/test/SemaTemplate/concepts-GH53354.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+// expected-no-diagnostics
+
+template  class>
+struct S
+{};
+
+template 
+concept C1 = requires
+{
+  typename S;
+};
+
+template 
+requires C1
+struct A {};
+
+template 
+requires C1 && true
+struct A {};
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5803,8 +5803,8 @@
   }
 
   bool TraverseTemplateName(TemplateName Template) {
-if (auto *TTP =
-dyn_cast(Template.getAsTemplateDecl()))
+if (auto *TTP = llvm::dyn_cast_or_null(
+Template.getAsTemplateDecl()))
   if (TTP->getDepth() == Depth)
 Used[TTP->getIndex()] = true;
 RecursiveASTVisitor::
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136259: Fix crash in constraining partial specialization on nested template.

2022-10-19 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 468962.
usaxena95 marked 2 inline comments as done.
usaxena95 added a comment.

Addressed comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D136259

Files:
  clang/lib/Sema/SemaTemplateDeduction.cpp
  clang/test/SemaTemplate/concepts-GH53354.cpp


Index: clang/test/SemaTemplate/concepts-GH53354.cpp
===
--- /dev/null
+++ clang/test/SemaTemplate/concepts-GH53354.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+// expected-no-diagnostics
+
+template  class>
+struct S
+{};
+
+template 
+concept C1 = requires
+{
+  typename S;
+};
+
+template 
+requires C1
+struct A {};
+
+template 
+requires C1 && true
+struct A {};
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5804,8 +5804,8 @@
   }
 
   bool TraverseTemplateName(TemplateName Template) {
-if (auto *TTP =
-dyn_cast(Template.getAsTemplateDecl()))
+if (auto *TTP = llvm::dyn_cast_or_null(
+Template.getAsTemplateDecl()))
   if (TTP->getDepth() == Depth)
 Used[TTP->getIndex()] = true;
 RecursiveASTVisitor::


Index: clang/test/SemaTemplate/concepts-GH53354.cpp
===
--- /dev/null
+++ clang/test/SemaTemplate/concepts-GH53354.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+// expected-no-diagnostics
+
+template  class>
+struct S
+{};
+
+template 
+concept C1 = requires
+{
+  typename S;
+};
+
+template 
+requires C1
+struct A {};
+
+template 
+requires C1 && true
+struct A {};
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5804,8 +5804,8 @@
   }
 
   bool TraverseTemplateName(TemplateName Template) {
-if (auto *TTP =
-dyn_cast(Template.getAsTemplateDecl()))
+if (auto *TTP = llvm::dyn_cast_or_null(
+Template.getAsTemplateDecl()))
   if (TTP->getDepth() == Depth)
 Used[TTP->getIndex()] = true;
 RecursiveASTVisitor::
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136259: Fix crash in constraining partial specialization on nested template.

2022-10-19 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 468925.
usaxena95 added a comment.

Added test.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D136259

Files:
  clang/lib/Sema/SemaTemplateDeduction.cpp
  clang/test/SemaTemplate/concepts-GH53354.cpp


Index: clang/test/SemaTemplate/concepts-GH53354.cpp
===
--- /dev/null
+++ clang/test/SemaTemplate/concepts-GH53354.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+// expected-no-diagnostics
+
+template  class>
+struct S
+{};
+
+template 
+concept C1 = requires
+{
+  typename S;
+};
+
+template 
+requires C1
+struct A {};
+
+template 
+requires C1 and true
+struct A {};
\ No newline at end of file
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5804,10 +5804,10 @@
   }
 
   bool TraverseTemplateName(TemplateName Template) {
-if (auto *TTP =
-dyn_cast(Template.getAsTemplateDecl()))
-  if (TTP->getDepth() == Depth)
-Used[TTP->getIndex()] = true;
+if (TemplateDecl *TD = Template.getAsTemplateDecl())
+  if (auto *TTP = dyn_cast(TD))
+if (TTP->getDepth() == Depth)
+  Used[TTP->getIndex()] = true;
 RecursiveASTVisitor::
 TraverseTemplateName(Template);
 return true;


Index: clang/test/SemaTemplate/concepts-GH53354.cpp
===
--- /dev/null
+++ clang/test/SemaTemplate/concepts-GH53354.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+// expected-no-diagnostics
+
+template  class>
+struct S
+{};
+
+template 
+concept C1 = requires
+{
+  typename S;
+};
+
+template 
+requires C1
+struct A {};
+
+template 
+requires C1 and true
+struct A {};
\ No newline at end of file
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5804,10 +5804,10 @@
   }
 
   bool TraverseTemplateName(TemplateName Template) {
-if (auto *TTP =
-dyn_cast(Template.getAsTemplateDecl()))
-  if (TTP->getDepth() == Depth)
-Used[TTP->getIndex()] = true;
+if (TemplateDecl *TD = Template.getAsTemplateDecl())
+  if (auto *TTP = dyn_cast(TD))
+if (TTP->getDepth() == Depth)
+  Used[TTP->getIndex()] = true;
 RecursiveASTVisitor::
 TraverseTemplateName(Template);
 return true;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136259: Fix crash in constraining partial specialization on nested template.

2022-10-19 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 created this revision.
Herald added a project: All.
usaxena95 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Fixes: https://github.com/llvm/llvm-project/issues/53354


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D136259

Files:
  clang/lib/Sema/SemaTemplateDeduction.cpp


Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5804,10 +5804,10 @@
   }
 
   bool TraverseTemplateName(TemplateName Template) {
-if (auto *TTP =
-dyn_cast(Template.getAsTemplateDecl()))
-  if (TTP->getDepth() == Depth)
-Used[TTP->getIndex()] = true;
+if (TemplateDecl *TD = Template.getAsTemplateDecl())
+  if (auto *TTP = dyn_cast(TD))
+if (TTP->getDepth() == Depth)
+  Used[TTP->getIndex()] = true;
 RecursiveASTVisitor::
 TraverseTemplateName(Template);
 return true;


Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5804,10 +5804,10 @@
   }
 
   bool TraverseTemplateName(TemplateName Template) {
-if (auto *TTP =
-dyn_cast(Template.getAsTemplateDecl()))
-  if (TTP->getDepth() == Depth)
-Used[TTP->getIndex()] = true;
+if (TemplateDecl *TD = Template.getAsTemplateDecl())
+  if (auto *TTP = dyn_cast(TD))
+if (TTP->getDepth() == Depth)
+  Used[TTP->getIndex()] = true;
 RecursiveASTVisitor::
 TraverseTemplateName(Template);
 return true;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D128750: [C++20] Implement P2113R0: Changes to the Partial Ordering of Constrained Functions

2022-10-19 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 added inline comments.



Comment at: clang/test/CXX/over/over.match/over.match.best/p1-2a.cpp:106
   template
-  constexpr int goo(const int b) requires AtLeast2 {
+  constexpr int goo(const int b) requires AtLeast2 { // expected-note 
{{candidate function}}
 return 2;

ychen wrote:
> usaxena95 wrote:
> > Thanks for working on this.
> > 
> > I wanted to bring up related: 
> > https://github.com/llvm/llvm-project/issues/56154
> > Eg.: Removing this `const` still removes the ambiguity but it shouldn't.
> > Since you have more context, does this look related to you ?
> Removing `const` makes the partial ordering compare constraints where 
> `AtLeast2 && true` subsumes `AtLeast2` so it is not ambiguous 
> anymore. Similar reasoning could be made for the original test case of 
> https://github.com/llvm/llvm-project/issues/56154. 56154 exposes an issue in 
> constraints partial ordering which is not related to this patch.
Thanks for the clarification. 


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D128750

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


[PATCH] D128750: [C++20] Implement P2113R0: Changes to the Partial Ordering of Constrained Functions

2022-10-18 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 added inline comments.



Comment at: clang/test/CXX/over/over.match/over.match.best/p1-2a.cpp:106
   template
-  constexpr int goo(const int b) requires AtLeast2 {
+  constexpr int goo(const int b) requires AtLeast2 { // expected-note 
{{candidate function}}
 return 2;

Thanks for working on this.

I wanted to bring up related: https://github.com/llvm/llvm-project/issues/56154
Eg.: Removing this `const` still removes the ambiguity but it shouldn't.
Since you have more context, does this look related to you ?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D128750

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


[PATCH] D134529: [C++20][Clang] P2468R2 The Equality Operator You Are Looking For

2022-10-12 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 added a comment.

In D134529#3853086 , @BertalanD wrote:

> Does it deserve a mention in the Potentially Breaking Changes section of the 
> release notes?

You are right. I was thinking the same after this discussion. I will add this 
to the section.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D134529

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


[PATCH] D134529: [C++20][Clang] P2468R2 The Equality Operator You Are Looking For

2022-10-12 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 added a comment.

In D134529#3852990 , @erichkeane 
wrote:

> Note that @BertalanD  noticed an issue with what I expect to be this patch: 
> https://godbolt.org/z/Wjb9rsEYG
>
> Can someone more knowledgable about this paper please make sure it is an 
> intended change?  It seems to me that the reversing behavior of the equality 
> operators is a little awkward here (note that commenting out != makes that 
> 'work' again).

This is intentional. Example from https://eel.is/c++draft/over.match.oper#4

  struct A {};
  template bool operator==(A, T); // #1
  bool a1 = 0 == A(); // OK, calls reversed #1
  template bool operator!=(A, T);
  bool a2 = 0 == A(); // error, #1 is not a rewrite 
target

Adding a matching `operator!=` disables reversing arguments (C++17 mode). The 
LHS in this case should provide a `operator==`.

The diagnostic might not be the most helpful at this point is. You can choose to

- Remove `operator!=`. Allows assuming `x==y` is equivalent to `y==x` and 
therefore uses the same function with reversed arguments.
- Write `s == c` instead of `c == s`.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D134529

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


[PATCH] D135608: Update implementation status of P2468R2

2022-10-10 Thread Utkarsh Saxena via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGe66cfb63ceed: Update implementation status of P2468R2 
(authored by usaxena95).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D135608

Files:
  clang/www/cxx_status.html


Index: clang/www/cxx_status.html
===
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1432,7 +1432,7 @@
 
   The Equality Operator You Are Looking For
   https://wg21.link/P2468R2;>P2468R2
-  No
+  Clang 16
 
 
   De-deprecating volatile compound operations


Index: clang/www/cxx_status.html
===
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1432,7 +1432,7 @@
 
   The Equality Operator You Are Looking For
   https://wg21.link/P2468R2;>P2468R2
-  No
+  Clang 16
 
 
   De-deprecating volatile compound operations
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D135608: Update implementation status of P2468R2

2022-10-10 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 466571.
usaxena95 marked an inline comment as done.
usaxena95 added a comment.

addressed comments


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D135608

Files:
  clang/www/cxx_status.html


Index: clang/www/cxx_status.html
===
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1432,7 +1432,7 @@
 
   The Equality Operator You Are Looking For
   https://wg21.link/P2468R2;>P2468R2
-  No
+  Clang 16
 
 
   De-deprecating volatile compound operations


Index: clang/www/cxx_status.html
===
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1432,7 +1432,7 @@
 
   The Equality Operator You Are Looking For
   https://wg21.link/P2468R2;>P2468R2
-  No
+  Clang 16
 
 
   De-deprecating volatile compound operations
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D134529: [C++20][Clang] P2468R2 The Equality Operator You Are Looking For

2022-10-10 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 added a comment.

Sent out https://reviews.llvm.org/D135608 to update implementation status.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D134529

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


[PATCH] D135608: Update implementation status of P2468R2

2022-10-10 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 created this revision.
Herald added a project: All.
usaxena95 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D135608

Files:
  clang/www/cxx_status.html


Index: clang/www/cxx_status.html
===
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1432,7 +1432,7 @@
 
   The Equality Operator You Are Looking For
   https://wg21.link/P2468R2;>P2468R2
-  No
+  Clang 16
 
 
   De-deprecating volatile compound operations


Index: clang/www/cxx_status.html
===
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1432,7 +1432,7 @@
 
   The Equality Operator You Are Looking For
   https://wg21.link/P2468R2;>P2468R2
-  No
+  Clang 16
 
 
   De-deprecating volatile compound operations
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D134529: [C++20][Clang] P2468R2 The Equality Operator You Are Looking For

2022-10-06 Thread Utkarsh Saxena via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG38b9d313e694: [C++20][Clang] P2468R2 The Equality Operator 
You Are Looking For (authored by usaxena95).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D134529

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Overload.h
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaOverload.cpp
  clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp

Index: clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
===
--- clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
+++ clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
@@ -125,46 +125,204 @@
   bool b2 = 0 == ADL::type();
 }
 
-// Various C++17 cases that are known to be broken by the C++20 rules.
-namespace problem_cases {
-  // We can have an ambiguity between an operator and its reversed form. This
-  // wasn't intended by the original "consistent comparison" proposal, and we
-  // allow it as extension, picking the non-reversed form.
-  struct A {
-bool operator==(const A&); // expected-note {{ambiguity is between a regular call to this operator and a call with the argument order reversed}}
-  };
-  bool cmp_non_const = A() == A(); // expected-warning {{ambiguous}}
+namespace P2468R2 {
+// Problem cases prior to P2468R2 but now intentionally rejected.
+struct SymmetricNonConst {
+  bool operator==(const SymmetricNonConst&); // expected-note {{ambiguity is between a regular call to this operator and a call with the argument order reversed}}
+  // expected-note@-1 {{mark 'operator==' as const or add a matching 'operator!=' to resolve the ambiguity}}
+};
+bool cmp_non_const = SymmetricNonConst() == SymmetricNonConst(); // expected-warning {{ambiguous}}
 
-  struct B {
-virtual bool operator==(const B&) const;
-  };
-  struct D : B {
-bool operator==(const B&) const override; // expected-note {{operator}}
-  };
-  bool cmp_base_derived = D() == D(); // expected-warning {{ambiguous}}
+struct SymmetricConst {
+  bool operator==(const SymmetricConst&) const;
+};
+bool cmp_const = SymmetricConst() == SymmetricConst();
 
-  template struct CRTPBase {
-bool operator==(const T&) const; // expected-note {{operator}} expected-note {{reversed}}
-bool operator!=(const T&) const; // expected-note {{non-reversed}}
-  };
-  struct CRTP : CRTPBase {};
-  bool cmp_crtp = CRTP() == CRTP(); // expected-warning-re {{ambiguous despite there being a unique best viable function{{$}}
-  bool cmp_crtp2 = CRTP() != CRTP(); // expected-warning {{ambiguous despite there being a unique best viable function with non-reversed arguments}}
-
-  // Given a choice between a rewritten and non-rewritten function with the
-  // same parameter types, where the rewritten function is reversed and each
-  // has a better conversion for one of the two arguments, prefer the
-  // non-rewritten one.
-  using UBool = signed char; // ICU uses this.
-  struct ICUBase {
-virtual UBool operator==(const ICUBase&) const;
-UBool operator!=(const ICUBase ) const { return !operator==(arg); }
-  };
-  struct ICUDerived : ICUBase {
-UBool operator==(const ICUBase&) const override; // expected-note {{declared here}} expected-note {{ambiguity is between}}
-  };
-  bool cmp_icu = ICUDerived() != ICUDerived(); // expected-warning {{ambiguous}} expected-warning {{'bool', not 'UBool'}}
+struct SymmetricNonConstWithoutConstRef {
+  bool operator==(SymmetricNonConstWithoutConstRef);
+};
+bool cmp_non_const_wo_ref = SymmetricNonConstWithoutConstRef() == SymmetricNonConstWithoutConstRef();
+
+struct B {
+  virtual bool operator==(const B&) const;
+};
+struct D : B {
+  bool operator==(const B&) const override; // expected-note {{operator}}
+};
+bool cmp_base_derived = D() == D(); // expected-warning {{ambiguous}}
+
+// Reversed "3" not used because we find "2".
+// Rewrite != from "3" but warn that "chosen rewritten candidate must return cv-bool".
+using UBool = signed char;
+struct ICUBase {
+  virtual UBool operator==(const ICUBase&) const; // 1.
+  UBool operator!=(const ICUBase ) const { return !operator==(arg); } // 2.
+};
+struct ICUDerived : ICUBase {
+  // 3.
+  UBool operator==(const ICUBase&) const override; // expected-note {{declared here}}
+};
+bool cmp_icu = ICUDerived() != ICUDerived(); // expected-warning {{ISO C++20 requires return type of selected 'operator==' function for rewritten '!=' comparison to be 'bool', not 'UBool' (aka 'signed char')}}
+// Accepted by P2468R2.
+// 1
+struct S {
+  bool operator==(const S&) { return true; }
+  bool operator!=(const S&) { return false; }
+};
+bool ts = S{} != S{};
+// 2
+template struct 

[PATCH] D134529: [C++20][Clang] P2468R2 The Equality Operator You Are Looking For

2022-10-06 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 465686.
usaxena95 marked 2 inline comments as done.
usaxena95 added a comment.

Addressed comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D134529

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Overload.h
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaOverload.cpp
  clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp

Index: clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
===
--- clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
+++ clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
@@ -125,46 +125,204 @@
   bool b2 = 0 == ADL::type();
 }
 
-// Various C++17 cases that are known to be broken by the C++20 rules.
-namespace problem_cases {
-  // We can have an ambiguity between an operator and its reversed form. This
-  // wasn't intended by the original "consistent comparison" proposal, and we
-  // allow it as extension, picking the non-reversed form.
-  struct A {
-bool operator==(const A&); // expected-note {{ambiguity is between a regular call to this operator and a call with the argument order reversed}}
-  };
-  bool cmp_non_const = A() == A(); // expected-warning {{ambiguous}}
+namespace P2468R2 {
+// Problem cases prior to P2468R2 but now intentionally rejected.
+struct SymmetricNonConst {
+  bool operator==(const SymmetricNonConst&); // expected-note {{ambiguity is between a regular call to this operator and a call with the argument order reversed}}
+  // expected-note@-1 {{mark 'operator==' as const or add a matching 'operator!=' to resolve the ambiguity}}
+};
+bool cmp_non_const = SymmetricNonConst() == SymmetricNonConst(); // expected-warning {{ambiguous}}
 
-  struct B {
-virtual bool operator==(const B&) const;
-  };
-  struct D : B {
-bool operator==(const B&) const override; // expected-note {{operator}}
-  };
-  bool cmp_base_derived = D() == D(); // expected-warning {{ambiguous}}
+struct SymmetricConst {
+  bool operator==(const SymmetricConst&) const;
+};
+bool cmp_const = SymmetricConst() == SymmetricConst();
 
-  template struct CRTPBase {
-bool operator==(const T&) const; // expected-note {{operator}} expected-note {{reversed}}
-bool operator!=(const T&) const; // expected-note {{non-reversed}}
-  };
-  struct CRTP : CRTPBase {};
-  bool cmp_crtp = CRTP() == CRTP(); // expected-warning-re {{ambiguous despite there being a unique best viable function{{$}}
-  bool cmp_crtp2 = CRTP() != CRTP(); // expected-warning {{ambiguous despite there being a unique best viable function with non-reversed arguments}}
-
-  // Given a choice between a rewritten and non-rewritten function with the
-  // same parameter types, where the rewritten function is reversed and each
-  // has a better conversion for one of the two arguments, prefer the
-  // non-rewritten one.
-  using UBool = signed char; // ICU uses this.
-  struct ICUBase {
-virtual UBool operator==(const ICUBase&) const;
-UBool operator!=(const ICUBase ) const { return !operator==(arg); }
-  };
-  struct ICUDerived : ICUBase {
-UBool operator==(const ICUBase&) const override; // expected-note {{declared here}} expected-note {{ambiguity is between}}
-  };
-  bool cmp_icu = ICUDerived() != ICUDerived(); // expected-warning {{ambiguous}} expected-warning {{'bool', not 'UBool'}}
+struct SymmetricNonConstWithoutConstRef {
+  bool operator==(SymmetricNonConstWithoutConstRef);
+};
+bool cmp_non_const_wo_ref = SymmetricNonConstWithoutConstRef() == SymmetricNonConstWithoutConstRef();
+
+struct B {
+  virtual bool operator==(const B&) const;
+};
+struct D : B {
+  bool operator==(const B&) const override; // expected-note {{operator}}
+};
+bool cmp_base_derived = D() == D(); // expected-warning {{ambiguous}}
+
+// Reversed "3" not used because we find "2".
+// Rewrite != from "3" but warn that "chosen rewritten candidate must return cv-bool".
+using UBool = signed char;
+struct ICUBase {
+  virtual UBool operator==(const ICUBase&) const; // 1.
+  UBool operator!=(const ICUBase ) const { return !operator==(arg); } // 2.
+};
+struct ICUDerived : ICUBase {
+  // 3.
+  UBool operator==(const ICUBase&) const override; // expected-note {{declared here}}
+};
+bool cmp_icu = ICUDerived() != ICUDerived(); // expected-warning {{ISO C++20 requires return type of selected 'operator==' function for rewritten '!=' comparison to be 'bool', not 'UBool' (aka 'signed char')}}
+// Accepted by P2468R2.
+// 1
+struct S {
+  bool operator==(const S&) { return true; }
+  bool operator!=(const S&) { return false; }
+};
+bool ts = S{} != S{};
+// 2
+template struct CRTPBase {
+  bool operator==(const T&) const;
+  bool operator!=(const T&) const;
+};
+struct CRTP : CRTPBase {};

[PATCH] D134529: [C++20][Clang] P2468R2 The Equality Operator You Are Looking For

2022-10-05 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 added inline comments.



Comment at: clang/include/clang/Sema/Overload.h:1024
   /// candidates for operator Op.
-  bool shouldAddReversed(OverloadedOperatorKind Op);
+  bool mayAddReversed(OverloadedOperatorKind Op);
 

ilya-biryukov wrote:
> I am not sure the new name adds clarity.
> It's unclear what the `true` return value means here. `should` clearly 
> indicated returning true means the code has to proceed with adding the 
> reversed operator. `may` means the code can choose to do so or not, I don't 
> think that's quite right. `should` was really a better choice here.
> 
> That said, I don't think the rename itself is a bad idea, maybe there is a 
> better name, but I couldn't come up with one.
Just to be clear, it is possible to not reverse the args even if this returns 
true now since we do not do full check for `==` here.

I renamed it `allowsReversed` on the same line of `AllowRewrittenCandidates`.

Intention is to convey that if this is true then reversing is allowed and you 
can choose not to do so as well.



Comment at: clang/lib/Sema/SemaOverload.cpp:976
 bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed(
-ASTContext , const FunctionDecl *FD) {
-  if (!shouldAddReversed(FD->getDeclName().getCXXOverloadedOperator()))
+Sema , ArrayRef Args, const FunctionDecl *FD) {
+  auto Op = FD->getOverloadedOperator();

ilya-biryukov wrote:
> NIT: same suggestion as before. Just pass `Expr* FirstOperand` as the 
> parameter instead of an array.
I would prefer not to use a `FirstOperand` for `shouldAddReversed` as it serves 
more than just `operator==`. 

It might be confusing/error-prone for the users as to what is the "first 
operand" here (Args[0] or Args[1] ? In reversed args or original args ?). I 
think it would be a better API to just have original args as the parameter let 
this function decide which is the `FirstOperand`.



Comment at: 
clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp:231
+bool c1 = B() == C(); // OK, calls 2; reversed 2 is not a candidate because 
search for operator!= in C finds #3
+bool c2 = C() == B();  // expected-warning {{ISO C++20 considers use of 
overloaded operator '==' (with operand types 'C' and 'B') to be ambiguous 
despite there being a unique best viable function}}
+

ilya-biryukov wrote:
> NIT: could you add a comment explaining why this is ambiguous? This seems 
> non-obvious.
> It's because the search for `operator!=` happens inside `B` and never finds 
> `3`, right?
Yes. That is correct.



Comment at: 
clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp:269
+};
+bool b = B() == B(); // ok. No rewrite due to const.
+

ilya-biryukov wrote:
> Also due to different parameter types (`T` vs `B`)?
> So the description is incomplete or am I missing something?
This verifies that adding `const` would solve the ambiguity without adding a 
matching `!=`. The `!=` here does not match because it is non-template and, 
yes, because of different param types.



Comment at: 
clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp:300
+} // using_decls
+// FIXME: Match requires clause.
+// namespace match_requires_clause {

ilya-biryukov wrote:
> NIT: maybe file a bug for this and mention the GH issue number?
> (could be done in the last iteration right before landing the change)
Sure. I can do this in a followup patch once this issue lands.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D134529

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


[PATCH] D134529: [C++20][Clang] P2468R2 The Equality Operator You Are Looking For

2022-10-05 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 465393.
usaxena95 marked 11 inline comments as done.
usaxena95 added a comment.

Addressed comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D134529

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Overload.h
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaOverload.cpp
  clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp

Index: clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
===
--- clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
+++ clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
@@ -125,46 +125,204 @@
   bool b2 = 0 == ADL::type();
 }
 
-// Various C++17 cases that are known to be broken by the C++20 rules.
-namespace problem_cases {
-  // We can have an ambiguity between an operator and its reversed form. This
-  // wasn't intended by the original "consistent comparison" proposal, and we
-  // allow it as extension, picking the non-reversed form.
-  struct A {
-bool operator==(const A&); // expected-note {{ambiguity is between a regular call to this operator and a call with the argument order reversed}}
-  };
-  bool cmp_non_const = A() == A(); // expected-warning {{ambiguous}}
+namespace P2468R2 {
+// Problem cases prior to P2468R2 but now intentionally rejected.
+struct SymmetricNonConst {
+  bool operator==(const SymmetricNonConst&); // expected-note {{ambiguity is between a regular call to this operator and a call with the argument order reversed}}
+  // expected-note@-1 {{mark 'operator==' as const or add a matching 'operator!=' to resolve the ambiguity}}
+};
+bool cmp_non_const = SymmetricNonConst() == SymmetricNonConst(); // expected-warning {{ambiguous}}
 
-  struct B {
-virtual bool operator==(const B&) const;
-  };
-  struct D : B {
-bool operator==(const B&) const override; // expected-note {{operator}}
-  };
-  bool cmp_base_derived = D() == D(); // expected-warning {{ambiguous}}
+struct SymmetricConst {
+  bool operator==(const SymmetricConst&) const;
+};
+bool cmp_const = SymmetricConst() == SymmetricConst();
 
-  template struct CRTPBase {
-bool operator==(const T&) const; // expected-note {{operator}} expected-note {{reversed}}
-bool operator!=(const T&) const; // expected-note {{non-reversed}}
-  };
-  struct CRTP : CRTPBase {};
-  bool cmp_crtp = CRTP() == CRTP(); // expected-warning-re {{ambiguous despite there being a unique best viable function{{$}}
-  bool cmp_crtp2 = CRTP() != CRTP(); // expected-warning {{ambiguous despite there being a unique best viable function with non-reversed arguments}}
-
-  // Given a choice between a rewritten and non-rewritten function with the
-  // same parameter types, where the rewritten function is reversed and each
-  // has a better conversion for one of the two arguments, prefer the
-  // non-rewritten one.
-  using UBool = signed char; // ICU uses this.
-  struct ICUBase {
-virtual UBool operator==(const ICUBase&) const;
-UBool operator!=(const ICUBase ) const { return !operator==(arg); }
-  };
-  struct ICUDerived : ICUBase {
-UBool operator==(const ICUBase&) const override; // expected-note {{declared here}} expected-note {{ambiguity is between}}
-  };
-  bool cmp_icu = ICUDerived() != ICUDerived(); // expected-warning {{ambiguous}} expected-warning {{'bool', not 'UBool'}}
+struct SymmetricNonConstWithoutConstRef {
+  bool operator==(SymmetricNonConstWithoutConstRef);
+};
+bool cmp_non_const_wo_ref = SymmetricNonConstWithoutConstRef() == SymmetricNonConstWithoutConstRef();
+
+struct B {
+  virtual bool operator==(const B&) const;
+};
+struct D : B {
+  bool operator==(const B&) const override; // expected-note {{operator}}
+};
+bool cmp_base_derived = D() == D(); // expected-warning {{ambiguous}}
+
+// Reversed "3" not used because we find "2".
+// Rewrite != from "3" but warn that "chosen rewritten candidate must return cv-bool".
+using UBool = signed char;
+struct ICUBase {
+  virtual UBool operator==(const ICUBase&) const; // 1.
+  UBool operator!=(const ICUBase ) const { return !operator==(arg); } // 2.
+};
+struct ICUDerived : ICUBase {
+  // 3.
+  UBool operator==(const ICUBase&) const override; // expected-note {{declared here}}
+};
+bool cmp_icu = ICUDerived() != ICUDerived(); // expected-warning {{ISO C++20 requires return type of selected 'operator==' function for rewritten '!=' comparison to be 'bool', not 'UBool' (aka 'signed char')}}
+// Accepted by P2468R2.
+// 1
+struct S {
+  bool operator==(const S&) { return true; }
+  bool operator!=(const S&) { return false; }
+};
+bool ts = S{} != S{};
+// 2
+template struct CRTPBase {
+  bool operator==(const T&) const;
+  bool operator!=(const T&) const;
+};
+struct CRTP : CRTPBase {};

[PATCH] D134529: [C++20][Clang] P2468R2 The Equality Operator You Are Looking For

2022-09-29 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 added inline comments.



Comment at: clang/lib/Sema/SemaOverload.cpp:887
 
-bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed(
-OverloadedOperatorKind Op) {

ilya-biryukov wrote:
> Why do we need to move this from `OperatorRewriteInfo` to 
> `OverloadCandidateSet`?
> 
We are using operator location for search which is part of 
OverloadCandidateSet. 
I propagated it to the RewriteInfo without shuffling these declarations.



Comment at: clang/lib/Sema/SemaOverload.cpp:918
+  for (NamedDecl *Op : Members)
+if (S.Context.hasSameUnqualifiedType(
+MD->getParamDecl(0)->getType(),

ilya-biryukov wrote:
> Could we implement the "corresponds" check from 
> [(basic.scope.scope)p4](https://eel.is/c++draft/basic.scope.scope) directly?
> 
> This should address the existing FIXMEs about `const` members and template 
> functions.
Implemented the corresponds and search through LookupName. 
Needs additional filtering based on matching `DeclContext` to verify they are 
from the same namespace.

I was not able to find any utility which facilitates "search" out of the box. 
Does this look good ?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D134529

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


[PATCH] D134529: [C++20][Clang] P2468R2 The Equality Operator You Are Looking For

2022-09-29 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 464012.
usaxena95 added a comment.

Added test for static operator.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D134529

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Overload.h
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaOverload.cpp
  clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp

Index: clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
===
--- clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
+++ clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
@@ -125,46 +125,198 @@
   bool b2 = 0 == ADL::type();
 }
 
-// Various C++17 cases that are known to be broken by the C++20 rules.
-namespace problem_cases {
-  // We can have an ambiguity between an operator and its reversed form. This
-  // wasn't intended by the original "consistent comparison" proposal, and we
-  // allow it as extension, picking the non-reversed form.
-  struct A {
-bool operator==(const A&); // expected-note {{ambiguity is between a regular call to this operator and a call with the argument order reversed}}
-  };
-  bool cmp_non_const = A() == A(); // expected-warning {{ambiguous}}
+namespace P2468R2 {
+//=Problem cases prior to P2468R2 but now intentionally rejected=
+struct SymmetricNonConst {
+  bool operator==(const SymmetricNonConst&); // expected-note {{ambiguity is between a regular call to this operator and a call with the argument order reversed}}
+  // expected-note@-1 {{mark operator== as const or add a matching operator!= to resolve the ambiguity}}
+};
+bool cmp_non_const = SymmetricNonConst() == SymmetricNonConst(); // expected-warning {{ambiguous}}
 
-  struct B {
-virtual bool operator==(const B&) const;
-  };
-  struct D : B {
-bool operator==(const B&) const override; // expected-note {{operator}}
-  };
-  bool cmp_base_derived = D() == D(); // expected-warning {{ambiguous}}
+struct SymmetricConst {
+  bool operator==(const SymmetricConst&) const;
+};
+bool cmp_const = SymmetricConst() == SymmetricConst();
 
-  template struct CRTPBase {
-bool operator==(const T&) const; // expected-note {{operator}} expected-note {{reversed}}
-bool operator!=(const T&) const; // expected-note {{non-reversed}}
-  };
-  struct CRTP : CRTPBase {};
-  bool cmp_crtp = CRTP() == CRTP(); // expected-warning-re {{ambiguous despite there being a unique best viable function{{$}}
-  bool cmp_crtp2 = CRTP() != CRTP(); // expected-warning {{ambiguous despite there being a unique best viable function with non-reversed arguments}}
-
-  // Given a choice between a rewritten and non-rewritten function with the
-  // same parameter types, where the rewritten function is reversed and each
-  // has a better conversion for one of the two arguments, prefer the
-  // non-rewritten one.
-  using UBool = signed char; // ICU uses this.
-  struct ICUBase {
-virtual UBool operator==(const ICUBase&) const;
-UBool operator!=(const ICUBase ) const { return !operator==(arg); }
-  };
-  struct ICUDerived : ICUBase {
-UBool operator==(const ICUBase&) const override; // expected-note {{declared here}} expected-note {{ambiguity is between}}
-  };
-  bool cmp_icu = ICUDerived() != ICUDerived(); // expected-warning {{ambiguous}} expected-warning {{'bool', not 'UBool'}}
+struct B {
+  virtual bool operator==(const B&) const;
+};
+struct D : B {
+  bool operator==(const B&) const override; // expected-note {{operator}}
+};
+bool cmp_base_derived = D() == D(); // expected-warning {{ambiguous}}
+
+// Reversed "3" not used because we find "2".
+// Rewrite != from "3" but warn that "chosen rewritten candidate must return cv-bool".
+using UBool = signed char;
+struct ICUBase {
+  virtual UBool operator==(const ICUBase&) const; // 1.
+  UBool operator!=(const ICUBase ) const { return !operator==(arg); } // 2.
+};
+struct ICUDerived : ICUBase {
+  // 3.
+  UBool operator==(const ICUBase&) const override; // expected-note {{declared here}}
+};
+bool cmp_icu = ICUDerived() != ICUDerived(); // expected-warning {{ISO C++20 requires return type of selected 'operator==' function for rewritten '!=' comparison to be 'bool', not 'UBool' (aka 'signed char')}}
+// Accepted by P2468R2.
+// 1
+struct S {
+  bool operator==(const S&) { return true; }
+  bool operator!=(const S&) { return false; }
+};
+bool ts = S{} != S{};
+// 2
+template struct CRTPBase {
+  bool operator==(const T&) const;
+  bool operator!=(const T&) const;
+};
+struct CRTP : CRTPBase {};
+bool cmp_crtp = CRTP() == CRTP();
+bool cmp_crtp2 = CRTP() != CRTP();
+// https://github.com/llvm/llvm-project/issues/57711
+namespace issue_57711 {
+template 
+bool compare(T l, T r)
+requires requires { l == r; 

[PATCH] D134529: [C++20][Clang] P2468R2 The Equality Operator You Are Looking For

2022-09-29 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 464010.
usaxena95 marked 7 inline comments as done.
usaxena95 added a comment.

Addressed comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D134529

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Overload.h
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaOverload.cpp
  clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp

Index: clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
===
--- clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
+++ clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
@@ -125,46 +125,188 @@
   bool b2 = 0 == ADL::type();
 }
 
-// Various C++17 cases that are known to be broken by the C++20 rules.
-namespace problem_cases {
-  // We can have an ambiguity between an operator and its reversed form. This
-  // wasn't intended by the original "consistent comparison" proposal, and we
-  // allow it as extension, picking the non-reversed form.
-  struct A {
-bool operator==(const A&); // expected-note {{ambiguity is between a regular call to this operator and a call with the argument order reversed}}
-  };
-  bool cmp_non_const = A() == A(); // expected-warning {{ambiguous}}
+namespace P2468R2 {
+//=Problem cases prior to P2468R2 but now intentionally rejected=
+struct SymmetricNonConst {
+  bool operator==(const SymmetricNonConst&); // expected-note {{ambiguity is between a regular call to this operator and a call with the argument order reversed}}
+  // expected-note@-1 {{mark operator== as const or add a matching operator!= to resolve the ambiguity}}
+};
+bool cmp_non_const = SymmetricNonConst() == SymmetricNonConst(); // expected-warning {{ambiguous}}
 
-  struct B {
-virtual bool operator==(const B&) const;
-  };
-  struct D : B {
-bool operator==(const B&) const override; // expected-note {{operator}}
-  };
-  bool cmp_base_derived = D() == D(); // expected-warning {{ambiguous}}
+struct SymmetricConst {
+  bool operator==(const SymmetricConst&) const;
+};
+bool cmp_const = SymmetricConst() == SymmetricConst();
 
-  template struct CRTPBase {
-bool operator==(const T&) const; // expected-note {{operator}} expected-note {{reversed}}
-bool operator!=(const T&) const; // expected-note {{non-reversed}}
-  };
-  struct CRTP : CRTPBase {};
-  bool cmp_crtp = CRTP() == CRTP(); // expected-warning-re {{ambiguous despite there being a unique best viable function{{$}}
-  bool cmp_crtp2 = CRTP() != CRTP(); // expected-warning {{ambiguous despite there being a unique best viable function with non-reversed arguments}}
-
-  // Given a choice between a rewritten and non-rewritten function with the
-  // same parameter types, where the rewritten function is reversed and each
-  // has a better conversion for one of the two arguments, prefer the
-  // non-rewritten one.
-  using UBool = signed char; // ICU uses this.
-  struct ICUBase {
-virtual UBool operator==(const ICUBase&) const;
-UBool operator!=(const ICUBase ) const { return !operator==(arg); }
-  };
-  struct ICUDerived : ICUBase {
-UBool operator==(const ICUBase&) const override; // expected-note {{declared here}} expected-note {{ambiguity is between}}
-  };
-  bool cmp_icu = ICUDerived() != ICUDerived(); // expected-warning {{ambiguous}} expected-warning {{'bool', not 'UBool'}}
+struct B {
+  virtual bool operator==(const B&) const;
+};
+struct D : B {
+  bool operator==(const B&) const override; // expected-note {{operator}}
+};
+bool cmp_base_derived = D() == D(); // expected-warning {{ambiguous}}
+
+// Reversed "3" not used because we find "2".
+// Rewrite != from "3" but warn that "chosen rewritten candidate must return cv-bool".
+using UBool = signed char;
+struct ICUBase {
+  virtual UBool operator==(const ICUBase&) const; // 1.
+  UBool operator!=(const ICUBase ) const { return !operator==(arg); } // 2.
+};
+struct ICUDerived : ICUBase {
+  // 3.
+  UBool operator==(const ICUBase&) const override; // expected-note {{declared here}}
+};
+bool cmp_icu = ICUDerived() != ICUDerived(); // expected-warning {{ISO C++20 requires return type of selected 'operator==' function for rewritten '!=' comparison to be 'bool', not 'UBool' (aka 'signed char')}}
+// Accepted by P2468R2.
+// 1
+struct S {
+  bool operator==(const S&) { return true; }
+  bool operator!=(const S&) { return false; }
+};
+bool ts = S{} != S{};
+// 2
+template struct CRTPBase {
+  bool operator==(const T&) const;
+  bool operator!=(const T&) const;
+};
+struct CRTP : CRTPBase {};
+bool cmp_crtp = CRTP() == CRTP();
+bool cmp_crtp2 = CRTP() != CRTP();
+// https://github.com/llvm/llvm-project/issues/57711
+namespace issue_57711 {
+template 
+bool compare(T l, T r)
+ 

[PATCH] D134529: [C++20][Clang] P2468R2 The Equality Operator You Are Looking For

2022-09-27 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 463237.
usaxena95 added a comment.

Added better diagnostic for non-const symmetric operator==.
Added release notes.
Updated tests.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D134529

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Overload.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaOverload.cpp
  clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp

Index: clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
===
--- clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
+++ clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
@@ -125,46 +125,124 @@
   bool b2 = 0 == ADL::type();
 }
 
-// Various C++17 cases that are known to be broken by the C++20 rules.
-namespace problem_cases {
-  // We can have an ambiguity between an operator and its reversed form. This
-  // wasn't intended by the original "consistent comparison" proposal, and we
-  // allow it as extension, picking the non-reversed form.
-  struct A {
-bool operator==(const A&); // expected-note {{ambiguity is between a regular call to this operator and a call with the argument order reversed}}
-  };
-  bool cmp_non_const = A() == A(); // expected-warning {{ambiguous}}
+namespace P2468R2 {
+//=Problem cases prior to P2468R2 but now intentionally rejected=
+struct SymmetricNonConst {
+  bool operator==(const SymmetricNonConst&); // expected-note {{ambiguity is between a regular call to this operator and a call with the argument order reversed}}
+  // expected-note@-1 {{mark operator== as const or add a matching operator!= to resolve the ambiguity}}
+};
+bool cmp_non_const = SymmetricNonConst() == SymmetricNonConst(); // expected-warning {{ambiguous}}
 
-  struct B {
-virtual bool operator==(const B&) const;
-  };
-  struct D : B {
-bool operator==(const B&) const override; // expected-note {{operator}}
-  };
-  bool cmp_base_derived = D() == D(); // expected-warning {{ambiguous}}
+struct SymmetricConst {
+  bool operator==(const SymmetricConst&) const;
+};
+bool cmp_const = SymmetricConst() == SymmetricConst();
 
-  template struct CRTPBase {
-bool operator==(const T&) const; // expected-note {{operator}} expected-note {{reversed}}
-bool operator!=(const T&) const; // expected-note {{non-reversed}}
-  };
-  struct CRTP : CRTPBase {};
-  bool cmp_crtp = CRTP() == CRTP(); // expected-warning-re {{ambiguous despite there being a unique best viable function{{$}}
-  bool cmp_crtp2 = CRTP() != CRTP(); // expected-warning {{ambiguous despite there being a unique best viable function with non-reversed arguments}}
-
-  // Given a choice between a rewritten and non-rewritten function with the
-  // same parameter types, where the rewritten function is reversed and each
-  // has a better conversion for one of the two arguments, prefer the
-  // non-rewritten one.
-  using UBool = signed char; // ICU uses this.
-  struct ICUBase {
-virtual UBool operator==(const ICUBase&) const;
-UBool operator!=(const ICUBase ) const { return !operator==(arg); }
-  };
-  struct ICUDerived : ICUBase {
-UBool operator==(const ICUBase&) const override; // expected-note {{declared here}} expected-note {{ambiguity is between}}
-  };
-  bool cmp_icu = ICUDerived() != ICUDerived(); // expected-warning {{ambiguous}} expected-warning {{'bool', not 'UBool'}}
+struct B {
+  virtual bool operator==(const B&) const;
+};
+struct D : B {
+  bool operator==(const B&) const override; // expected-note {{operator}}
+};
+bool cmp_base_derived = D() == D(); // expected-warning {{ambiguous}}
+
+// Reversed "3" not used because we find "2".
+// Rewrite != from "3" but warn that "chosen rewritten candidate must return cv-bool".
+using UBool = signed char;
+struct ICUBase {
+  virtual UBool operator==(const ICUBase&) const; // 1.
+  UBool operator!=(const ICUBase ) const { return !operator==(arg); } // 2.
+};
+struct ICUDerived : ICUBase {
+  // 3.
+  UBool operator==(const ICUBase&) const override; // expected-note {{declared here}}
+};
+bool cmp_icu = ICUDerived() != ICUDerived(); // expected-warning {{ISO C++20 requires return type of selected 'operator==' function for rewritten '!=' comparison to be 'bool', not 'UBool' (aka 'signed char')}}
+//=Accepted by P2468R2=
+// 1
+struct S {
+  bool operator==(const S&) { return true; }
+  bool operator!=(const S&) { return false; }
+};
+bool ts = S{} != S{};
+// 2
+template struct CRTPBase {
+  bool operator==(const T&) const;
+  bool operator!=(const T&) const;
+};
+struct CRTP : CRTPBase {};
+bool cmp_crtp = CRTP() == CRTP();
+bool cmp_crtp2 = CRTP() != CRTP();
+// https://github.com/llvm/llvm-project/issues/57711

[PATCH] D134529: [C++20][Clang] P2468R2 The Equality Operator You Are Looking For

2022-09-23 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 created this revision.
Herald added a project: All.
usaxena95 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Implement
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2468r2.html.

Primarily we now accept

  template struct CRTPBase {
bool operator==(const T&) const;
bool operator!=(const T&) const;
  };
  struct CRTP : CRTPBase {};
  bool cmp_crtp = CRTP() == CRTP();
  bool cmp_crtp2 = CRTP() != CRTP();

Open questions:

1. Symmetric == member without a != defined.

`struct S{ bool operator==(const S&);};`.
In principle we should not add a reversed== in such cases as this would
never yield a better candidate and always an ambiguity with itself.
We already don't add reversed == for non-member operator with symmetric
parameters. The following is already accepted.

  struct S{};
  bool operator==(const S&, const S&);
  S() == S();

My proposal will be to do the same for member==.

2. The following example from the proposal produces error while paper suggests 
that this should be accepted. ``` struct D {};

template bool operator==(D, T); // 4
// expected-note@-1 {{candidate function template not viable: no known 
conversion from 'int' to 'D' for 1st argument}}
inline namespace N {

  template bool operator!=(D, T);   // 5

}
bool d1 = 0 == D();

  I don't follow why this disallows the reverse #4.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D134529

Files:
  clang/include/clang/Sema/Overload.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaOverload.cpp
  clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp

Index: clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
===
--- clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
+++ clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
@@ -135,36 +135,117 @@
   };
   bool cmp_non_const = A() == A(); // expected-warning {{ambiguous}}
 
-  struct B {
-virtual bool operator==(const B&) const;
-  };
-  struct D : B {
-bool operator==(const B&) const override; // expected-note {{operator}}
-  };
-  bool cmp_base_derived = D() == D(); // expected-warning {{ambiguous}}
+} // namespace problem_cases
 
-  template struct CRTPBase {
-bool operator==(const T&) const; // expected-note {{operator}} expected-note {{reversed}}
-bool operator!=(const T&) const; // expected-note {{non-reversed}}
-  };
-  struct CRTP : CRTPBase {};
-  bool cmp_crtp = CRTP() == CRTP(); // expected-warning-re {{ambiguous despite there being a unique best viable function{{$}}
-  bool cmp_crtp2 = CRTP() != CRTP(); // expected-warning {{ambiguous despite there being a unique best viable function with non-reversed arguments}}
-
-  // Given a choice between a rewritten and non-rewritten function with the
-  // same parameter types, where the rewritten function is reversed and each
-  // has a better conversion for one of the two arguments, prefer the
-  // non-rewritten one.
-  using UBool = signed char; // ICU uses this.
-  struct ICUBase {
-virtual UBool operator==(const ICUBase&) const;
-UBool operator!=(const ICUBase ) const { return !operator==(arg); }
-  };
-  struct ICUDerived : ICUBase {
-UBool operator==(const ICUBase&) const override; // expected-note {{declared here}} expected-note {{ambiguity is between}}
-  };
-  bool cmp_icu = ICUDerived() != ICUDerived(); // expected-warning {{ambiguous}} expected-warning {{'bool', not 'UBool'}}
+namespace P2468R2 {
+//=Problem cases prior to P2468R2 but now intentionally rejected=
+namespace no_more_problem_cases {
+struct B {
+  virtual bool operator==(const B&) const;
+};
+struct D : B {
+  bool operator==(const B&) const override; // expected-note {{operator}}
+};
+bool cmp_base_derived = D() == D(); // expected-warning {{ambiguous}}
+
+// Reversed "3" not used because we find "2".
+// Rewrite != from "3" but warn that "chosen rewritten candidate must return cv-bool".
+using UBool = signed char;
+struct ICUBase {
+  virtual UBool operator==(const ICUBase&) const; // 1.
+  UBool operator!=(const ICUBase ) const { return !operator==(arg); } // 2.
+};
+struct ICUDerived : ICUBase {
+  // 3.
+  UBool operator==(const ICUBase&) const override; // expected-note {{declared here}}
+};
+bool cmp_icu = ICUDerived() != ICUDerived(); // expected-warning {{ISO C++20 requires return type of selected 'operator==' function for rewritten '!=' comparison to be 'bool', not 'UBool' (aka 'signed char')}}
+} // namespace no_more_problem_cases
+//=Accepted by P2468R2=
+// 1
+struct S {
+  bool operator==(const S&) { return true; }
+  bool operator!=(const S&) { return false; }
+};
+bool ts = S{} != S{};
+// 2
+template struct CRTPBase {
+  bool operator==(const T&) const;
+  bool operator!=(const T&) const;
+};
+struct CRTP : 

[PATCH] D133299: [clangd] Fix LineFoldingOnly flag is not propagated correctly to ClangdServer.

2022-09-05 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 accepted this revision.
usaxena95 added a comment.
This revision is now accepted and ready to land.

Thanks. Sorry I missed this.




Comment at: clang-tools-extra/clangd/ClangdLSPServer.cpp:487-497
   {
 // Switch caller's context with LSPServer's background context. Since we
 // rather want to propagate information from LSPServer's context into the
 // Server, CDB, etc.
 WithContext MainContext(BackgroundContext.clone());
 llvm::Optional WithOffsetEncoding;
 if (Opts.Encoding)

I think we should do this after the Opts has been fully set to avoid the 
confusion


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D133299

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


[PATCH] D132945: [clang] Skip re-building lambda expressions in parameters to consteval fns.

2022-09-02 Thread Utkarsh Saxena via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGe7eec3824656: [clang] Skip re-building lambda expressions in 
parameters to consteval fns. (authored by usaxena95).

Changed prior to commit:
  https://reviews.llvm.org/D132945?vs=457546=457555#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132945

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/Sema/SemaExpr.cpp
  clang/test/SemaCXX/cxx2a-consteval.cpp

Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -939,3 +939,82 @@
 static_assert(max(1,2)==2);
 static_assert(mid(1,2,3)==2);
 } // namespace GH51182
+
+// https://github.com/llvm/llvm-project/issues/56183
+namespace GH56183 {
+consteval auto Foo(auto c) { return c; }
+consteval auto Bar(auto f) { return f(); }
+void test() {
+  constexpr auto x = Foo(Bar([] { return 'a'; }));
+  static_assert(x == 'a');
+}
+}  // namespace GH56183
+
+// https://github.com/llvm/llvm-project/issues/51695
+namespace GH51695 {
+// Original 
+template 
+struct type_t {};
+
+template 
+struct list_t {};
+
+template 
+consteval auto pop_front(list_t) -> auto {
+  return list_t{};
+}
+
+template 
+consteval auto apply(list_t, F fn) -> auto {
+  return fn(type_t{}...);
+}
+
+void test1() {
+  constexpr auto x = apply(pop_front(list_t{}),
+[](type_t...) { return 42; });
+  static_assert(x == 42);
+}
+// Reduced 1 
+consteval bool zero() { return false; }
+
+template 
+consteval bool foo(bool, F f) {
+  return f();
+}
+
+void test2() {
+  constexpr auto x = foo(zero(), []() { return true; });
+  static_assert(x);
+}
+
+// Reduced 2 
+template 
+consteval auto bar(F f) { return f;}
+
+void test3() {
+  constexpr auto t1 = bar(bar(bar(bar([]() { return true; }();
+  static_assert(t1);
+
+  int a = 1; // expected-note {{declared here}}
+  auto t2 = bar(bar(bar(bar([=]() { return a; }(); // expected-error-re {{call to consteval function 'GH51695::bar<(lambda at {{.*}})>' is not a constant expression}}
+  // expected-note@-1 {{read of non-const variable 'a' is not allowed in a constant expression}}
+
+  constexpr auto t3 = bar(bar([x=bar(42)]() { return x; }))();
+  static_assert(t3==42);
+  constexpr auto t4 = bar(bar([x=bar(42)]() consteval { return x; }))();
+  static_assert(t4==42);
+}
+
+}  // namespace GH51695
+
+// https://github.com/llvm/llvm-project/issues/50455
+namespace GH50455 {
+void f() {
+  []() consteval { int i{}; }();
+  []() consteval { int i{}; ++i; }();
+}
+void g() {
+  (void)[](int i) consteval { return i; }(0);
+  (void)[](int i) consteval { return i; }(0);
+}
+}  // namespace GH50455
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -17598,6 +17598,11 @@
   DRSet.erase(E);
   return E;
 }
+ExprResult TransformLambdaExpr(LambdaExpr *E) {
+  // Do not rebuild lambdas to avoid creating a new type.
+  // Lambdas have already been processed inside their eval context.
+  return E;
+}
 bool AlwaysRebuild() { return false; }
 bool ReplacingOriginal() { return true; }
 bool AllowSkippingCXXConstructExpr() {
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -211,9 +211,16 @@
 - Correctly set expression evaluation context as 'immediate function context' in
   consteval functions.
   This fixes `GH51182 `
+
 - Fixes an assert crash caused by looking up missing vtable information on ``consteval``
   virtual functions. Fixes `GH55065 `_.
 
+- Skip rebuilding lambda expressions in arguments of immediate invocations.
+  This fixes `GH56183 `_,
+  `GH51695 `_,
+  `GH50455 `_,
+  `GH54872 `_,
+  `GH54587 `_.
 
 C++2b Feature Support
 ^
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132945: [clang] Skip re-building lambda expressions in parameters to consteval fns.

2022-09-02 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 457546.
usaxena95 marked 2 inline comments as done.
usaxena95 added a comment.

Addressed comments and added more tests.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132945

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/Sema/SemaExpr.cpp
  clang/test/SemaCXX/cxx2a-consteval.cpp

Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -939,3 +939,82 @@
 static_assert(max(1,2)==2);
 static_assert(mid(1,2,3)==2);
 } // namespace GH51182
+
+// https://github.com/llvm/llvm-project/issues/56183
+namespace GH56183 {
+consteval auto Foo(auto c) { return c; }
+consteval auto Bar(auto f) { return f(); }
+void test() {
+  constexpr auto x = Foo(Bar([] { return 'a'; }));
+  static_assert(x == 'a');
+}
+}  // namespace GH56183
+
+// https://github.com/llvm/llvm-project/issues/51695
+namespace GH51695 {
+// Original 
+template 
+struct type_t {};
+
+template 
+struct list_t {};
+
+template 
+consteval auto pop_front(list_t) -> auto {
+  return list_t{};
+}
+
+template 
+consteval auto apply(list_t, F fn) -> auto {
+  return fn(type_t{}...);
+}
+
+void test1() {
+  constexpr auto x = apply(pop_front(list_t{}),
+[](type_t...) { return 42; });
+  static_assert(x == 42);
+}
+// Reduced 1 
+consteval bool zero() { return false; }
+
+template 
+consteval bool foo(bool, F f) {
+  return f();
+}
+
+void test2() {
+  constexpr auto x = foo(zero(), []() { return true; });
+  static_assert(x);
+}
+
+// Reduced 2 
+template 
+consteval auto bar(F f) { return f;}
+
+void test3() {
+  constexpr auto t1 = bar(bar(bar(bar([]() { return true; }();
+  static_assert(t1);
+
+  int a = 1; // expected-note {{declared here}}
+  auto t2 = bar(bar(bar(bar([=]() { return a; }(); // expected-error-re {{call to consteval function 'GH51695::bar<(lambda at {{.*}})>' is not a constant expression}}
+  // expected-note@-1 {{read of non-const variable 'a' is not allowed in a constant expression}}
+
+  constexpr auto t3 = bar(bar([x=bar(42)]() { return x; }))();
+  static_assert(t3==42);
+  constexpr auto t4 = bar(bar([x=bar(42)]() consteval { return x; }))();
+  static_assert(t4==42);
+}
+
+}  // namespace GH51695
+
+// https://github.com/llvm/llvm-project/issues/50455
+namespace GH50455 {
+void f() {
+  []() consteval { int i{}; }();
+  []() consteval { int i{}; ++i; }();
+}
+void g() {
+  (void)[](int i) consteval { return i; }(0);
+  (void)[](int i) consteval { return i; }(0);
+}
+}  // namespace GH50455
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -17598,6 +17598,11 @@
   DRSet.erase(E);
   return E;
 }
+ExprResult TransformLambdaExpr(LambdaExpr *E) {
+  // Do not rebuild lambdas to avoid creating a new type.
+  // Lambdas have already been processed inside their eval context.
+  return E;
+}
 bool AlwaysRebuild() { return false; }
 bool ReplacingOriginal() { return true; }
 bool AllowSkippingCXXConstructExpr() {
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -191,8 +191,14 @@
 
 - Correctly set expression evaluation context as 'immediate function context' in
   consteval functions.
-  This fixes `GH51182 `
-
+  This fixes `GH51182 `_.
+
+- Skip rebuilding lambda expressions in arguments of immediate invocations.
+  This fixes `GH56183 `_,
+  `GH51695 `_,
+  `GH50455 `_,
+  `GH54872 `_,
+  `GH54587 `_.
 
 C++2b Feature Support
 ^
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132945: [clang] Skip re-building lambda expressions in parameters to consteval fns.

2022-09-01 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 added a comment.

Gentle ping for review.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132945

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


[PATCH] D132945: [clang] Skip re-building lambda expressions in parameters to consteval fns.

2022-08-30 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 456745.
usaxena95 added a comment.

This actually fixes two more issues.
Update release notes and add more documentation.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132945

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/Sema/SemaExpr.cpp
  clang/test/SemaCXX/cxx2a-consteval.cpp

Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -939,3 +939,77 @@
 static_assert(max(1,2)==2);
 static_assert(mid(1,2,3)==2);
 } // namespace GH51182
+
+// https://github.com/llvm/llvm-project/issues/56183
+namespace GH56183 {
+consteval auto Foo(auto c) { return c; }
+consteval auto Bar(auto f) { return f(); }
+void test() {
+  constexpr auto x = Foo(Bar([] { return 'a'; }));
+  static_assert(x == 'a');
+}
+}  // namespace GH56183
+
+// https://github.com/llvm/llvm-project/issues/51695
+namespace GH51695 {
+// Original 
+template 
+struct type_t {};
+
+template 
+struct list_t {};
+
+template 
+consteval auto pop_front(list_t) -> auto {
+  return list_t{};
+}
+
+template 
+consteval auto apply(list_t, F fn) -> auto {
+  return fn(type_t{}...);
+}
+
+void test1() {
+  constexpr auto x = apply(pop_front(list_t{}),
+[](type_t...) { return 42; });
+  static_assert(x == 42);
+}
+// Reduced 1 
+consteval bool zero() { return false; }
+
+template 
+consteval bool foo(bool, F f) {
+  return f();
+}
+
+void test2() {
+  constexpr auto x = foo(zero(), []() { return true; });
+  static_assert(x);
+}
+
+// Reduced 2 
+template 
+consteval auto bar(F f) { return f;}
+
+void test3() {
+  constexpr auto x = bar(bar(bar(bar([]() { return true; }();
+  static_assert(x);
+
+  int a = 1; // expected-note {{declared here}}
+  auto y = bar(bar(bar(bar([=]() { return a; }(); // expected-error-re {{call to consteval function 'GH51695::bar<(lambda at {{.*}})>' is not a constant expression}}
+  // expected-note@-1 {{read of non-const variable 'a' is not allowed in a constant expression}}
+}
+
+}  // namespace GH51695
+
+// https://github.com/llvm/llvm-project/issues/50455
+namespace GH50455 {
+void f() {
+  []() consteval { int i{}; }();
+  []() consteval { int i{}; ++i; }();
+}
+void g() {
+  (void)[](int i) consteval { return i; }(0);
+  (void)[](int i) consteval { return i; }(0);
+}
+}  // namespace GH50455
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -17598,6 +17598,11 @@
   DRSet.erase(E);
   return E;
 }
+ExprResult TransformLambdaExpr(LambdaExpr *E) {
+  // Lambdas must be built already. They must not be re-built as it always
+  // creates new types.
+  return E;
+}
 bool AlwaysRebuild() { return false; }
 bool ReplacingOriginal() { return true; }
 bool AllowSkippingCXXConstructExpr() {
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -191,8 +191,14 @@
 
 - Correctly set expression evaluation context as 'immediate function context' in
   consteval functions.
-  This fixes `GH51182 `
-
+  This fixes `GH51182 `_.
+
+- Skip re-building lambda expressions when they appear as parameters to an immediate invocation.
+  This fixes `GH56183 `_,
+  `GH51695 `_,
+  `GH50455 `_,
+  `GH54872 `_,
+  `GH54587 `_.
 
 C++2b Feature Support
 ^
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132945: [clang] Skip re-building lambda expressions in parameters to consteval fns.

2022-08-30 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 456739.
usaxena95 added a comment.

Add some test with expected errors as well.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132945

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/Sema/SemaExpr.cpp
  clang/test/SemaCXX/cxx2a-consteval.cpp

Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -939,3 +939,77 @@
 static_assert(max(1,2)==2);
 static_assert(mid(1,2,3)==2);
 } // namespace GH51182
+
+// https://github.com/llvm/llvm-project/issues/56183
+namespace GH56183 {
+consteval auto Foo(auto c) { return c; }
+consteval auto Bar(auto f) { return f(); }
+void test() {
+  constexpr auto x = Foo(Bar([] { return 'a'; }));
+  static_assert(x == 'a');
+}
+}  // namespace GH56183
+
+// https://github.com/llvm/llvm-project/issues/51695
+namespace GH51695 {
+// Original 
+template 
+struct type_t {};
+
+template 
+struct list_t {};
+
+template 
+consteval auto pop_front(list_t) -> auto {
+  return list_t{};
+}
+
+template 
+consteval auto apply(list_t, F fn) -> auto {
+  return fn(type_t{}...);
+}
+
+void test1() {
+  constexpr auto x = apply(pop_front(list_t{}),
+[](type_t...) { return 42; });
+  static_assert(x == 42);
+}
+// Reduced 1 
+consteval bool zero() { return false; }
+
+template 
+consteval bool foo(bool, F f) {
+  return f();
+}
+
+void test2() {
+  constexpr auto x = foo(zero(), []() { return true; });
+  static_assert(x);
+}
+
+// Reduced 2 
+template 
+consteval auto bar(F f) { return f;}
+
+void test3() {
+  constexpr auto x = bar(bar(bar(bar([]() { return true; }();
+  static_assert(x);
+
+  int a = 1; // expected-note {{declared here}}
+  auto y = bar(bar(bar(bar([=]() { return a; }(); // expected-error-re {{call to consteval function 'GH51695::bar<(lambda at {{.*}})>' is not a constant expression}}
+  // expected-note@-1 {{read of non-const variable 'a' is not allowed in a constant expression}}
+}
+
+}  // namespace GH51695
+
+// https://github.com/llvm/llvm-project/issues/50455
+namespace GH50455 {
+void f() {
+  []() consteval { int i{}; }();
+  []() consteval { int i{}; ++i; }();
+}
+void g() {
+  (void)[](int i) consteval { return i; }(0);
+  (void)[](int i) consteval { return i; }(0);
+}
+}  // namespace GH50455
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -17598,6 +17598,7 @@
   DRSet.erase(E);
   return E;
 }
+ExprResult TransformLambdaExpr(LambdaExpr *E) { return E; }
 bool AlwaysRebuild() { return false; }
 bool ReplacingOriginal() { return true; }
 bool AllowSkippingCXXConstructExpr() {
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -191,8 +191,12 @@
 
 - Correctly set expression evaluation context as 'immediate function context' in
   consteval functions.
-  This fixes `GH51182 `
+  This fixes `GH51182 `_.
 
+- Skip re-building lambda expressions when they appear as parameters to an immediate invocation.
+  This fixes `GH56183 `_,
+  `GH51695 `_,
+  `GH50455 `_.
 
 C++2b Feature Support
 ^
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132945: [clang] Skip re-building lambda expressions in parameters to consteval fns.

2022-08-30 Thread Utkarsh Saxena via Phabricator via cfe-commits
usaxena95 updated this revision to Diff 456685.
usaxena95 added a comment.

new line.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D132945

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/Sema/SemaExpr.cpp
  clang/test/SemaCXX/cxx2a-consteval.cpp

Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -939,3 +939,68 @@
 static_assert(max(1,2)==2);
 static_assert(mid(1,2,3)==2);
 } // namespace GH51182
+
+// https://github.com/llvm/llvm-project/issues/56183
+namespace GH56183 {
+consteval auto Foo(auto c) { return c; }
+consteval auto Bar(auto f) { return f(); }
+void test() {
+  constexpr auto x = Foo(Bar([] { return 'a'; }));
+  static_assert(x == 'a');
+}
+}  // namespace GH56183
+
+// https://github.com/llvm/llvm-project/issues/51695
+namespace GH51695 {
+// Original 
+template 
+struct type_t {};
+
+template 
+struct list_t {};
+
+template 
+consteval auto pop_front(list_t) -> auto {
+  return list_t{};
+}
+
+template 
+consteval auto apply(list_t, F fn) -> auto {
+  return fn(type_t{}...);
+}
+
+void test1() {
+  constexpr auto x = apply(pop_front(list_t{}),
+[](type_t...) { return 42; });
+  static_assert(x == 42);
+}
+// Reduced 
+consteval bool zero() { return false; }
+
+template 
+consteval bool foo(bool, F f) {
+  return f();
+}
+
+template 
+consteval auto bar(F f) { return f;}
+
+void test2() {
+  constexpr auto x = foo(zero(), []() { return true; });
+  constexpr auto y = bar(bar(bar(bar([]() { return true; }();
+  static_assert(x && y);
+}
+
+}  // namespace GH51695
+
+// https://github.com/llvm/llvm-project/issues/50455
+namespace GH50455 {
+void f() {
+  []() consteval { int i{}; }();
+  []() consteval { int i{}; ++i; }();
+}
+void g() {
+  (void)[](int i) consteval { return i; }(0);
+  (void)[](int i) consteval { return i; }(0);
+}
+}  // namespace GH50455
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -17598,6 +17598,7 @@
   DRSet.erase(E);
   return E;
 }
+ExprResult TransformLambdaExpr(LambdaExpr *E) { return E; }
 bool AlwaysRebuild() { return false; }
 bool ReplacingOriginal() { return true; }
 bool AllowSkippingCXXConstructExpr() {
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -191,8 +191,12 @@
 
 - Correctly set expression evaluation context as 'immediate function context' in
   consteval functions.
-  This fixes `GH51182 `
+  This fixes `GH51182 `_.
 
+- Skip re-building lambda expressions when they appear as parameters to an immediate invocation.
+  This fixes `GH56183 `_,
+  `GH51695 `_,
+  `GH50455 `_.
 
 C++2b Feature Support
 ^
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


  1   2   3   4   5   >