[PATCH] D88900: check before accessing possibly null node

2020-10-06 Thread Ding Fei via Phabricator via cfe-commits
danix800 created this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
danix800 requested review of this revision.

Testcase: (main.cpp)

  int foo(int i);
  
  int main() {
int i = 1;
while (i-- >= 0) {
  return 3 / foo(i);
}
  }

run with

  clang -cc1 -analyze -analyzer-checker=debug.DumpDominators main.cpp

triggers nullptr dereference.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D88900

Files:
  clang/include/clang/Analysis/Analyses/Dominators.h


Index: clang/include/clang/Analysis/Analyses/Dominators.h
===
--- clang/include/clang/Analysis/Analyses/Dominators.h
+++ clang/include/clang/Analysis/Analyses/Dominators.h
@@ -101,7 +101,12 @@
  "LLVM's Dominator tree builder uses nullpointers to signify the "
  "virtual root!");
 
-  DomTreeNode *IDom = DT.getNode(*I)->getIDom();
+  auto *Node = DT.getNode(*I);
+  if (Node == nullptr) {
+continue;
+  }
+
+  DomTreeNode *IDom = Node->getIDom();
   if (IDom && IDom->getBlock())
 llvm::errs() << "(" << (*I)->getBlockID()
  << ","


Index: clang/include/clang/Analysis/Analyses/Dominators.h
===
--- clang/include/clang/Analysis/Analyses/Dominators.h
+++ clang/include/clang/Analysis/Analyses/Dominators.h
@@ -101,7 +101,12 @@
  "LLVM's Dominator tree builder uses nullpointers to signify the "
  "virtual root!");
 
-  DomTreeNode *IDom = DT.getNode(*I)->getIDom();
+  auto *Node = DT.getNode(*I);
+  if (Node == nullptr) {
+continue;
+  }
+
+  DomTreeNode *IDom = Node->getIDom();
   if (IDom && IDom->getBlock())
 llvm::errs() << "(" << (*I)->getBlockID()
  << ","
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D155576: [NFC][clang-extdef-mapping] fix test failure on nonsupported targets

2023-07-18 Thread Ding Fei via Phabricator via cfe-commits
danix800 created this revision.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Specify a working target as POC


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D155576

Files:
  clang/test/Tooling/ms-asm-clang-extdef-mapping.c


Index: clang/test/Tooling/ms-asm-clang-extdef-mapping.c
===
--- clang/test/Tooling/ms-asm-clang-extdef-mapping.c
+++ clang/test/Tooling/ms-asm-clang-extdef-mapping.c
@@ -1,7 +1,9 @@
-// RUN: clang-extdef-mapping "%s" -- -fasm-blocks 2>&1 | FileCheck %s
+// RUN: clang-extdef-mapping "%s" -- -fasm-blocks \
+// RUN:   -target x86_64-apple-darwin10 2>&1 | FileCheck %s
+// REQUIRES: x86-registered-target
 
 void Break() {
   __asm { int 3 }
 }
 
-// CHECK: {{c:@F@Break .*}}
+// CHECK: {{10:c:@F@Break}}


Index: clang/test/Tooling/ms-asm-clang-extdef-mapping.c
===
--- clang/test/Tooling/ms-asm-clang-extdef-mapping.c
+++ clang/test/Tooling/ms-asm-clang-extdef-mapping.c
@@ -1,7 +1,9 @@
-// RUN: clang-extdef-mapping "%s" -- -fasm-blocks 2>&1 | FileCheck %s
+// RUN: clang-extdef-mapping "%s" -- -fasm-blocks \
+// RUN:   -target x86_64-apple-darwin10 2>&1 | FileCheck %s
+// REQUIRES: x86-registered-target
 
 void Break() {
   __asm { int 3 }
 }
 
-// CHECK: {{c:@F@Break .*}}
+// CHECK: {{10:c:@F@Break}}
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D155537: [ASTImporter] Fix import failed when anonymous union defined in class

2023-07-18 Thread Ding Fei via Phabricator via cfe-commits
danix800 added a comment.

Already fixed by https://reviews.llvm.org/D154764 .


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155537

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


[PATCH] D155661: [ASTImporter] Fix recursive friend class template with non-type parm

2023-07-18 Thread Ding Fei via Phabricator via cfe-commits
danix800 created this revision.
Herald added subscribers: martong, kristof.beyls.
Herald added a reviewer: a.sidorin.
Herald added a reviewer: shafik.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

For friend class template within dependent context:

1. Should not do structure matching checking
2. Should not be added into redecls chain

See `Sema::CheckClassTemplate`.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D155661

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -3969,7 +3969,32 @@
 }
 
 
-struct ImportFriendClasses : ASTImporterOptionSpecificTestBase {};
+struct ImportFriendClasses : ASTImporterOptionSpecificTestBase {
+  void testRecursiveFriendClassTemplate(Decl *FromTu) {
+auto *FromD =
+FirstDeclMatcher().match(FromTu,
+classTemplateDecl());
+auto *ToD = Import(FromD, Lang_CXX03);
+
+auto Pattern = classTemplateDecl(
+has(cxxRecordDecl(has(friendDecl(has(classTemplateDecl()));
+ASSERT_TRUE(MatchVerifier{}.match(FromD, Pattern));
+EXPECT_TRUE(MatchVerifier{}.match(ToD, Pattern));
+
+auto *FromFriend =
+FirstDeclMatcher().match(FromD, friendDecl());
+auto *FromClass =
+FirstDeclMatcher().match(FromD, classTemplateDecl());
+EXPECT_NE(FromFriend->getFriendDecl(), FromClass);
+EXPECT_TRUE(FromFriend->getFriendDecl()->getPreviousDecl() == nullptr);
+
+auto *Class =
+FirstDeclMatcher().match(ToD, classTemplateDecl());
+auto *Friend = FirstDeclMatcher().match(ToD, friendDecl());
+EXPECT_NE(Friend->getFriendDecl(), Class);
+EXPECT_TRUE(Friend->getFriendDecl()->getPreviousDecl() == nullptr);
+  }
+};
 
 TEST_P(ImportFriendClasses, ImportOfFriendRecordDoesNotMergeDefinition) {
   Decl *FromTU = getTuDecl(
@@ -4074,20 +4099,19 @@
   )",
   Lang_CXX03, "input.cc");
 
-  auto *FromD =
-  FirstDeclMatcher().match(FromTu, classTemplateDecl());
-  auto *ToD = Import(FromD, Lang_CXX03);
-
-  auto Pattern = classTemplateDecl(
-  has(cxxRecordDecl(has(friendDecl(has(classTemplateDecl()));
-  ASSERT_TRUE(MatchVerifier{}.match(FromD, Pattern));
-  EXPECT_TRUE(MatchVerifier{}.match(ToD, Pattern));
+  testRecursiveFriendClassTemplate(FromTu);
+}
 
-  auto *Class =
-  FirstDeclMatcher().match(ToD, classTemplateDecl());
-  auto *Friend = FirstDeclMatcher().match(ToD, friendDecl());
-  EXPECT_NE(Friend->getFriendDecl(), Class);
-  EXPECT_EQ(Friend->getFriendDecl()->getPreviousDecl(), Class);
+TEST_P(ImportFriendClasses,
+   ImportOfRecursiveFriendClassTemplateWithNonTypeParm) {
+  Decl *FromTu = getTuDecl(
+  R"(
+  template class declToImport {
+template friend class declToImport;
+  };
+  )",
+  Lang_CXX03, "input.cc");
+  testRecursiveFriendClassTemplate(FromTu);
 }
 
 TEST_P(ImportFriendClasses, ProperPrevDeclForClassTemplateDecls) {
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -2857,6 +2857,10 @@
   } else if (Importer.getToContext().getLangOpts().CPlusPlus)
 IDNS |= Decl::IDNS_Ordinary | Decl::IDNS_TagFriend;
 
+  bool IsDependentContext = DC != LexicalDC ?
+  LexicalDC->isDependentContext() : DC->isDependentContext();
+  bool ShouldAddRedecl = !(IsFriendTemplate && IsDependentContext);
+
   // We may already have a record of the same name; try to find and match it.
   RecordDecl *PrevDecl = nullptr;
   if (!DC->isFunctionOrMethod() && !D->isLambda()) {
@@ -2897,7 +2901,7 @@
 if (!hasSameVisibilityContextAndLinkage(FoundRecord, D))
   continue;
 
-if (IsStructuralMatch(D, FoundRecord)) {
+if (!ShouldAddRedecl || IsStructuralMatch(D, FoundRecord)) {
   RecordDecl *FoundDef = FoundRecord->getDefinition();
   if (D->isThisDeclarationADefinition() && FoundDef) {
 // FIXME: Structural equivalence check should check for same
@@ -2955,7 +2959,7 @@
 return CDeclOrErr.takeError();
   Numbering.ContextDecl = *CDeclOrErr;
   D2CXX->setLambdaNumbering(Numbering);
-   } else if (DCXX->isInjectedClassName()) {
+} else if (DCXX->isInjectedClassName()) {
   // We have to be careful to do a similar dance to the one in
   // Sema::ActOnStartCXXMemberDeclarations
   const bool DelayTypeCreation = true;
@@ -2970,7 +2974,9 @@
   if (GetImportedOrCreateDecl(D2CXX, D, Importer.getToContext(),
   D->getTagKind(), DC, *BeginLocOrErr, Loc,
   Name.getAsIdentifierInfo(),
-  cast_or_null(PrevDecl)))
+ 

[PATCH] D155396: [Sema][ObjC] Propagating value-dependent errors into BlockExpr

2023-07-20 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/lib/Sema/SemaExpr.cpp:16749-16753
+  bool ContainsError = llvm::any_of(BSI->Returns, [](const ReturnStmt *Return) 
{
+const auto *RetValExpr = Return->getRetValue();
+return RetValExpr && RetValExpr->containsErrors();
+  });
+  BlockExpr *Result = new (Context) BlockExpr(BD, BlockTy, ContainsError);

hokein wrote:
> aaron.ballman wrote:
> > Hmmm -- is the block *expression* what contains the errors in this case  or 
> > is it the block declaration? I would have expected this to be an issue for 
> > the block declaration created for the block expression. CC @rjmccall 
> I think a reasonable model is to follow how we handle `FunctionDecl`, as 
> `BlockDecl` and `FunctionDecl` are similar function-decl concepts.
> 
> For the crash case like `int (^a)() = ^() { return undefined; }`, we should:
> 
> - invalidate the `BlockDecl` as its returned type can not be deduced because 
> of the error return stmt (similar to `FunctionDecl`, we invalidate it for 
> `auto func() { return undefined; }`)
> - for an invalid `BlockDecl`, we should not build a `BlockExpr` that refers 
> to it (we don't build `DeclRefExpr` for invalid `FunctionDecl`). For error 
> recovery, we should use `RecoveryExpr`.
> 
> So I think the reasonable fix is to invalidate the BlockDecl (calling 
> `Decl->setInvalidDecl()`) if its body has any error stmt, and return 
> `ExprError()` if the BlockDecl is invalid.
> 
Thanks for sharing and pointing out the right direction.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155396

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


[PATCH] D155396: [Sema][ObjC] Propagating value-dependent errors into BlockExpr

2023-07-20 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 542559.
danix800 edited the summary of this revision.
danix800 added a comment.

Invalidate `BlockDecl` with implicit return type, in case any of the return 
value exprs is invalid.
Propagating the error info up by replacing `BlockExpr` with a `RecoveryExpr`.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155396

Files:
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/test/SemaObjC/crash-on-val-dep-block-expr.m


Index: clang/test/SemaObjC/crash-on-val-dep-block-expr.m
===
--- /dev/null
+++ clang/test/SemaObjC/crash-on-val-dep-block-expr.m
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fblocks -fsyntax-only -verify %s
+// no crash
+
+int (^a)() = ^() {
+  return c; // expected-error {{use of undeclared identifier 'c'}}
+};
+
+int (^b)() = (^() {
+  return c; // expected-error {{use of undeclared identifier 'c'}}
+});
Index: clang/lib/Sema/SemaStmt.cpp
===
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -3730,6 +3730,13 @@
   if (FunctionScopes.back()->FirstReturnLoc.isInvalid())
 FunctionScopes.back()->FirstReturnLoc = ReturnLoc;
 
+  BlockScopeInfo *CurBlock = dyn_cast(CurCap);
+  if (CurBlock && CurCap->HasImplicitReturnType) {
+BlockDecl *BD = CurBlock->TheDecl;
+if (!BD->isInvalidDecl() && RetValExp && RetValExp->containsErrors())
+  BD->setInvalidDecl();
+  }
+
   return Result;
 }
 
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -17159,6 +17159,9 @@
   if (getCurFunction())
 getCurFunction()->addBlock(BD);
 
+  if (BD->isInvalidDecl())
+return CreateRecoveryExpr(Result->getBeginLoc(), Result->getEndLoc(),
+{Result}, Result->getType());
   return Result;
 }
 


Index: clang/test/SemaObjC/crash-on-val-dep-block-expr.m
===
--- /dev/null
+++ clang/test/SemaObjC/crash-on-val-dep-block-expr.m
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fblocks -fsyntax-only -verify %s
+// no crash
+
+int (^a)() = ^() {
+  return c; // expected-error {{use of undeclared identifier 'c'}}
+};
+
+int (^b)() = (^() {
+  return c; // expected-error {{use of undeclared identifier 'c'}}
+});
Index: clang/lib/Sema/SemaStmt.cpp
===
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -3730,6 +3730,13 @@
   if (FunctionScopes.back()->FirstReturnLoc.isInvalid())
 FunctionScopes.back()->FirstReturnLoc = ReturnLoc;
 
+  BlockScopeInfo *CurBlock = dyn_cast(CurCap);
+  if (CurBlock && CurCap->HasImplicitReturnType) {
+BlockDecl *BD = CurBlock->TheDecl;
+if (!BD->isInvalidDecl() && RetValExp && RetValExp->containsErrors())
+  BD->setInvalidDecl();
+  }
+
   return Result;
 }
 
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -17159,6 +17159,9 @@
   if (getCurFunction())
 getCurFunction()->addBlock(BD);
 
+  if (BD->isInvalidDecl())
+return CreateRecoveryExpr(Result->getBeginLoc(), Result->getEndLoc(),
+{Result}, Result->getType());
   return Result;
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D155396: [Sema][ObjC] Propagating value-dependent errors into BlockExpr

2023-07-20 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 542735.
danix800 edited the summary of this revision.
danix800 added a comment.
Herald added a reviewer: gkistanova.

Update clang/docs/ReleaseNotes.rst to reflect this fix.


Repository:
  rZORG LLVM Github Zorg

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

https://reviews.llvm.org/D155396

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/test/SemaObjC/crash-on-val-dep-block-expr.m


Index: clang/test/SemaObjC/crash-on-val-dep-block-expr.m
===
--- /dev/null
+++ clang/test/SemaObjC/crash-on-val-dep-block-expr.m
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fblocks -fsyntax-only -verify %s
+// no crash
+
+int (^a)() = ^() {
+  return c; // expected-error {{use of undeclared identifier 'c'}}
+};
+
+int (^b)() = (^() {
+  return c; // expected-error {{use of undeclared identifier 'c'}}
+});
Index: clang/lib/Sema/SemaStmt.cpp
===
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -3730,6 +3730,13 @@
   if (FunctionScopes.back()->FirstReturnLoc.isInvalid())
 FunctionScopes.back()->FirstReturnLoc = ReturnLoc;
 
+  if (auto *CurBlock = dyn_cast(CurCap);
+  CurBlock && CurCap->HasImplicitReturnType) {
+BlockDecl *BD = CurBlock->TheDecl;
+if (!BD->isInvalidDecl() && RetValExp && RetValExp->containsErrors())
+  BD->setInvalidDecl();
+  }
+
   return Result;
 }
 
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -17159,6 +17159,9 @@
   if (getCurFunction())
 getCurFunction()->addBlock(BD);
 
+  if (BD->isInvalidDecl())
+return CreateRecoveryExpr(Result->getBeginLoc(), Result->getEndLoc(),
+  {Result}, Result->getType());
   return Result;
 }
 
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -657,6 +657,10 @@
   (`#63169 _`)
 - Fix crash when casting an object to an array type.
   (`#63758 _`)
+- Invalidate BlockDecl with implicit return type, in case any of the return
+  value exprs is invalid. Propagating the error info up by replacing BlockExpr
+  with a RecoveryExpr. This fixes:
+  (`#63863 _`)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/SemaObjC/crash-on-val-dep-block-expr.m
===
--- /dev/null
+++ clang/test/SemaObjC/crash-on-val-dep-block-expr.m
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fblocks -fsyntax-only -verify %s
+// no crash
+
+int (^a)() = ^() {
+  return c; // expected-error {{use of undeclared identifier 'c'}}
+};
+
+int (^b)() = (^() {
+  return c; // expected-error {{use of undeclared identifier 'c'}}
+});
Index: clang/lib/Sema/SemaStmt.cpp
===
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -3730,6 +3730,13 @@
   if (FunctionScopes.back()->FirstReturnLoc.isInvalid())
 FunctionScopes.back()->FirstReturnLoc = ReturnLoc;
 
+  if (auto *CurBlock = dyn_cast(CurCap);
+  CurBlock && CurCap->HasImplicitReturnType) {
+BlockDecl *BD = CurBlock->TheDecl;
+if (!BD->isInvalidDecl() && RetValExp && RetValExp->containsErrors())
+  BD->setInvalidDecl();
+  }
+
   return Result;
 }
 
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -17159,6 +17159,9 @@
   if (getCurFunction())
 getCurFunction()->addBlock(BD);
 
+  if (BD->isInvalidDecl())
+return CreateRecoveryExpr(Result->getBeginLoc(), Result->getEndLoc(),
+  {Result}, Result->getType());
   return Result;
 }
 
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -657,6 +657,10 @@
   (`#63169 _`)
 - Fix crash when casting an object to an array type.
   (`#63758 _`)
+- Invalidate BlockDecl with implicit return type, in case any of the return
+  value exprs is invalid. Propagating the error info up by replacing BlockExpr
+  with a RecoveryExpr. This fixes:
+  (`#63863 _`)
 
 Bug Fixes to Compiler Builtins
 ^^
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org

[PATCH] D155661: [ASTImporter] Fix friend class template import within dependent context

2023-07-21 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 542778.
danix800 added a comment.

Apply git-clang-format.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155661

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -3968,8 +3968,31 @@
   EXPECT_EQ(ToDef->getPreviousDecl(), ToProto);
 }
 
-
-struct ImportFriendClasses : ASTImporterOptionSpecificTestBase {};
+struct ImportFriendClasses : ASTImporterOptionSpecificTestBase {
+  void testRecursiveFriendClassTemplate(Decl *FromTu) {
+auto *FromD = FirstDeclMatcher().match(
+FromTu, classTemplateDecl());
+auto *ToD = Import(FromD, Lang_CXX03);
+
+auto Pattern = classTemplateDecl(
+has(cxxRecordDecl(has(friendDecl(has(classTemplateDecl()));
+ASSERT_TRUE(MatchVerifier{}.match(FromD, Pattern));
+EXPECT_TRUE(MatchVerifier{}.match(ToD, Pattern));
+
+auto *FromFriend =
+FirstDeclMatcher().match(FromD, friendDecl());
+auto *FromClass =
+FirstDeclMatcher().match(FromD, classTemplateDecl());
+EXPECT_NE(FromFriend->getFriendDecl(), FromClass);
+EXPECT_TRUE(FromFriend->getFriendDecl()->getPreviousDecl() == nullptr);
+
+auto *Class =
+FirstDeclMatcher().match(ToD, classTemplateDecl());
+auto *Friend = FirstDeclMatcher().match(ToD, friendDecl());
+EXPECT_NE(Friend->getFriendDecl(), Class);
+EXPECT_TRUE(Friend->getFriendDecl()->getPreviousDecl() == nullptr);
+  }
+};
 
 TEST_P(ImportFriendClasses, ImportOfFriendRecordDoesNotMergeDefinition) {
   Decl *FromTU = getTuDecl(
@@ -4074,20 +4097,19 @@
   )",
   Lang_CXX03, "input.cc");
 
-  auto *FromD =
-  FirstDeclMatcher().match(FromTu, classTemplateDecl());
-  auto *ToD = Import(FromD, Lang_CXX03);
-
-  auto Pattern = classTemplateDecl(
-  has(cxxRecordDecl(has(friendDecl(has(classTemplateDecl()));
-  ASSERT_TRUE(MatchVerifier{}.match(FromD, Pattern));
-  EXPECT_TRUE(MatchVerifier{}.match(ToD, Pattern));
+  testRecursiveFriendClassTemplate(FromTu);
+}
 
-  auto *Class =
-  FirstDeclMatcher().match(ToD, classTemplateDecl());
-  auto *Friend = FirstDeclMatcher().match(ToD, friendDecl());
-  EXPECT_NE(Friend->getFriendDecl(), Class);
-  EXPECT_EQ(Friend->getFriendDecl()->getPreviousDecl(), Class);
+TEST_P(ImportFriendClasses,
+   ImportOfRecursiveFriendClassTemplateWithNonTypeParm) {
+  Decl *FromTu = getTuDecl(
+  R"(
+  template class declToImport {
+template friend class declToImport;
+  };
+  )",
+  Lang_CXX03, "input.cc");
+  testRecursiveFriendClassTemplate(FromTu);
 }
 
 TEST_P(ImportFriendClasses, ProperPrevDeclForClassTemplateDecls) {
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -2857,6 +2857,10 @@
   } else if (Importer.getToContext().getLangOpts().CPlusPlus)
 IDNS |= Decl::IDNS_Ordinary | Decl::IDNS_TagFriend;
 
+  bool IsDependentContext = DC != LexicalDC ? LexicalDC->isDependentContext()
+: DC->isDependentContext();
+  bool ShouldAddRedecl = !(IsFriendTemplate && IsDependentContext);
+
   // We may already have a record of the same name; try to find and match it.
   RecordDecl *PrevDecl = nullptr;
   if (!DC->isFunctionOrMethod() && !D->isLambda()) {
@@ -2897,7 +2901,7 @@
 if (!hasSameVisibilityContextAndLinkage(FoundRecord, D))
   continue;
 
-if (IsStructuralMatch(D, FoundRecord)) {
+if (!ShouldAddRedecl || IsStructuralMatch(D, FoundRecord)) {
   RecordDecl *FoundDef = FoundRecord->getDefinition();
   if (D->isThisDeclarationADefinition() && FoundDef) {
 // FIXME: Structural equivalence check should check for same
@@ -2955,7 +2959,7 @@
 return CDeclOrErr.takeError();
   Numbering.ContextDecl = *CDeclOrErr;
   D2CXX->setLambdaNumbering(Numbering);
-   } else if (DCXX->isInjectedClassName()) {
+} else if (DCXX->isInjectedClassName()) {
   // We have to be careful to do a similar dance to the one in
   // Sema::ActOnStartCXXMemberDeclarations
   const bool DelayTypeCreation = true;
@@ -2967,10 +2971,11 @@
   Importer.getToContext().getTypeDeclType(
   D2CXX, dyn_cast(DC));
 } else {
-  if (GetImportedOrCreateDecl(D2CXX, D, Importer.getToContext(),
-  D->getTagKind(), DC, *BeginLocOrErr, Loc,
-  Name.getAsIdentifierInfo(),
-  cast_or_null(PrevDecl)))
+  if (GetImportedOrCreateDecl(
+  D2CXX, D, Importer.getToContext(), D->getTagKind(), DC,
+  *BeginLocOrErr, 

[PATCH] D155321: [clang][Analysis] ExprMutationAnalyzer: break infinite recursion on recursive function call

2023-07-21 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 542824.
danix800 added a comment.

Apply git-clang-format


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155321

Files:
  
clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof-nocrash.cpp
  clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
  clang/lib/Analysis/ExprMutationAnalyzer.cpp
  clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp

Index: clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
===
--- clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
+++ clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
@@ -1309,6 +1309,30 @@
   EXPECT_FALSE(isMutated(Results, AST.get()));
 }
 
+TEST(ExprMutationAnalyzerTest, RangeForNonArrayByConstRefNoCrash) {
+  const auto AST = buildASTFromCode(R"(
+struct V {
+  V* begin() const;
+  V* end() const;
+};
+void f(V &elem) {
+  auto rec = [](const auto& e, auto&& self) -> bool {
+for (auto& child : e) {
+  if (!self(child, self)) {
+return false;
+  }
+}
+return true;
+  };
+
+  rec(elem, rec);
+}
+  )");
+  const auto Results =
+  match(withEnclosingCompound(declRefTo("elem")), AST->getASTContext());
+  EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
 // section: unevaluated expressions
 
 TEST(ExprMutationAnalyzerTest, UnevaluatedExpressions) {
Index: clang/lib/Analysis/ExprMutationAnalyzer.cpp
===
--- clang/lib/Analysis/ExprMutationAnalyzer.cpp
+++ clang/lib/Analysis/ExprMutationAnalyzer.cpp
@@ -568,6 +568,11 @@
 if (!Func->getBody() || !Func->getPrimaryTemplate())
   return Exp;
 
+if (DeclAnalyzed->contains(Func)) {
+  return nullptr;
+}
+DeclAnalyzed->insert(Func);
+
 const auto *Parm = Nodes.getNodeAs("parm");
 const ArrayRef AllParams =
 Func->getPrimaryTemplate()->getTemplatedDecl()->parameters();
@@ -586,7 +591,8 @@
 std::unique_ptr &Analyzer =
 FuncParmAnalyzer[Func];
 if (!Analyzer)
-  Analyzer.reset(new FunctionParmMutationAnalyzer(*Func, Context));
+  Analyzer.reset(
+  new FunctionParmMutationAnalyzer(*Func, Context, DeclAnalyzed));
 if (Analyzer->findMutation(Parm))
   return Exp;
 continue;
@@ -599,8 +605,8 @@
 }
 
 FunctionParmMutationAnalyzer::FunctionParmMutationAnalyzer(
-const FunctionDecl &Func, ASTContext &Context)
-: BodyAnalyzer(*Func.getBody(), Context) {
+const FunctionDecl &Func, ASTContext &Context, DeclSet *DeclAnalyzed)
+: BodyAnalyzer(*Func.getBody(), Context, DeclAnalyzed) {
   if (const auto *Ctor = dyn_cast(&Func)) {
 // CXXCtorInitializer might also mutate Param but they're not part of
 // function body, check them eagerly here since they're typically trivial.
Index: clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
===
--- clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
+++ clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
@@ -18,12 +18,20 @@
 
 class FunctionParmMutationAnalyzer;
 
+using DeclSet = llvm::DenseSet;
+
 /// Analyzes whether any mutative operations are applied to an expression within
 /// a given statement.
 class ExprMutationAnalyzer {
 public:
-  ExprMutationAnalyzer(const Stmt &Stm, ASTContext &Context)
-  : Stm(Stm), Context(Context) {}
+  ExprMutationAnalyzer(const Stmt &Stm, ASTContext &Context,
+   DeclSet *DeclAnalyzed = nullptr)
+  : Stm(Stm), Context(Context), DeclAnalyzed(DeclAnalyzed) {
+if (nullptr == DeclAnalyzed) {
+  OwningDeclAnalyzed = std::make_unique();
+  this->DeclAnalyzed = OwningDeclAnalyzed.get();
+}
+  }
 
   bool isMutated(const Expr *Exp) { return findMutation(Exp) != nullptr; }
   bool isMutated(const Decl *Dec) { return findMutation(Dec) != nullptr; }
@@ -74,13 +82,16 @@
   FuncParmAnalyzer;
   ResultMap Results;
   ResultMap PointeeResults;
+  DeclSet *DeclAnalyzed;
+  std::unique_ptr OwningDeclAnalyzed;
 };
 
 // A convenient wrapper around ExprMutationAnalyzer for analyzing function
 // params.
 class FunctionParmMutationAnalyzer {
 public:
-  FunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context);
+  FunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context,
+   DeclSet *DeclAnalyzed = nullptr);
 
   bool isMutated(const ParmVarDecl *Parm) {
 return findMutation(Parm) != nullptr;
Index: clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof-nocrash.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof-nocrash.cpp
@@ -0,0 +1,20 @@
+

[PATCH] D155396: [Sema][ObjC] Propagating value-dependent errors into BlockExpr

2023-07-21 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/lib/Sema/SemaStmt.cpp:3736
+BlockDecl *BD = CurBlock->TheDecl;
+if (!BD->isInvalidDecl() && RetValExp && RetValExp->containsErrors())
+  BD->setInvalidDecl();

hokein wrote:
> nit: the `isInvalidDecl` check is not need, we can inline the `RetValExpr` to 
> the above if as well.
> 
> ```
> if (auto *CurBlock = dyn_cast(CurCap); CurBlock && 
> CurCap->HasImplicitReturnType && RetValExp && RetValExp->containsErrors()) 
>   CurBlock->TheDecl->setInvalidDecl();
> ```
Nice, look more cleaner!



Comment at: clang/test/SemaObjC/crash-on-val-dep-block-expr.m:1
+// RUN: %clang_cc1 -fblocks -fsyntax-only -verify %s
+// no crash

hokein wrote:
> can you move these tests to `llvm-project/clang/test/AST/ast-dump-recovery.c`?
No problem. But I noticed `llvm-project/clang/test/AST/ast-dump-recovery.m` 
also exists,
should I put them into this `.m` file instead?


Repository:
  rZORG LLVM Github Zorg

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

https://reviews.llvm.org/D155396

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


[PATCH] D155396: [Sema][ObjC] Propagating value-dependent errors into BlockExpr

2023-07-21 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/test/SemaObjC/crash-on-val-dep-block-expr.m:1
+// RUN: %clang_cc1 -fblocks -fsyntax-only -verify %s
+// no crash

danix800 wrote:
> hokein wrote:
> > can you move these tests to 
> > `llvm-project/clang/test/AST/ast-dump-recovery.c`?
> No problem. But I noticed `llvm-project/clang/test/AST/ast-dump-recovery.m` 
> also exists,
> should I put them into this `.m` file instead?
I'd prefer `ast-dump-recovery.m` since this file is much shorter. Either file 
needs appending `-fblocks`.


Repository:
  rZORG LLVM Github Zorg

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

https://reviews.llvm.org/D155396

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


[PATCH] D155396: [Sema][ObjC] Propagating value-dependent errors into BlockExpr

2023-07-21 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 542950.
danix800 added a comment.

1. Remove unnecessary condition & cleanup code
2. Move testcase into correct place.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155396

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/test/AST/ast-dump-recovery.m


Index: clang/test/AST/ast-dump-recovery.m
===
--- clang/test/AST/ast-dump-recovery.m
+++ clang/test/AST/ast-dump-recovery.m
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -triple x86_64-unknown-unknown -frecovery-ast 
-frecovery-ast-type -ast-dump %s | FileCheck -strict-whitespace %s
+// RUN: not %clang_cc1 -triple x86_64-unknown-unknown -frecovery-ast 
-frecovery-ast-type -fblocks -ast-dump %s | FileCheck -strict-whitespace %s
 
 @interface Foo
 - (void)method:(int)n;
@@ -16,3 +16,11 @@
   // CHECK-NEXT:   `-DeclRefExpr {{.*}} 'foo'
   foo.undef;
 }
+
+// CHECK: |-VarDecl {{.*}} 'int (^)()' cinit
+// CHECK: | `-RecoveryExpr {{.*}} ' (^)(void)' contains-errors 
lvalue
+// CHECK: |   `-BlockExpr {{.*}} ' (^)(void)'
+// CHECK: | `-BlockDecl {{.*}} invalid
+int (^a)() = ^() {
+  return c;
+};
Index: clang/lib/Sema/SemaStmt.cpp
===
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -3730,6 +3730,11 @@
   if (FunctionScopes.back()->FirstReturnLoc.isInvalid())
 FunctionScopes.back()->FirstReturnLoc = ReturnLoc;
 
+  if (auto *CurBlock = dyn_cast(CurCap);
+  CurBlock && CurCap->HasImplicitReturnType && RetValExp &&
+  RetValExp->containsErrors())
+CurBlock->TheDecl->setInvalidDecl();
+
   return Result;
 }
 
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -17159,6 +17159,9 @@
   if (getCurFunction())
 getCurFunction()->addBlock(BD);
 
+  if (BD->isInvalidDecl())
+return CreateRecoveryExpr(Result->getBeginLoc(), Result->getEndLoc(),
+  {Result}, Result->getType());
   return Result;
 }
 
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -663,6 +663,10 @@
 - Correcly diagnose jumps into statement expressions.
   This ensures the behavior of Clang is consistent with GCC.
   (`#63682 `_)
+- Invalidate BlockDecl with implicit return type, in case any of the return
+  value exprs is invalid. Propagating the error info up by replacing BlockExpr
+  with a RecoveryExpr. This fixes:
+  (`#63863 _`)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/AST/ast-dump-recovery.m
===
--- clang/test/AST/ast-dump-recovery.m
+++ clang/test/AST/ast-dump-recovery.m
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -triple x86_64-unknown-unknown -frecovery-ast -frecovery-ast-type -ast-dump %s | FileCheck -strict-whitespace %s
+// RUN: not %clang_cc1 -triple x86_64-unknown-unknown -frecovery-ast -frecovery-ast-type -fblocks -ast-dump %s | FileCheck -strict-whitespace %s
 
 @interface Foo
 - (void)method:(int)n;
@@ -16,3 +16,11 @@
   // CHECK-NEXT:   `-DeclRefExpr {{.*}} 'foo'
   foo.undef;
 }
+
+// CHECK: |-VarDecl {{.*}} 'int (^)()' cinit
+// CHECK: | `-RecoveryExpr {{.*}} ' (^)(void)' contains-errors lvalue
+// CHECK: |   `-BlockExpr {{.*}} ' (^)(void)'
+// CHECK: | `-BlockDecl {{.*}} invalid
+int (^a)() = ^() {
+  return c;
+};
Index: clang/lib/Sema/SemaStmt.cpp
===
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -3730,6 +3730,11 @@
   if (FunctionScopes.back()->FirstReturnLoc.isInvalid())
 FunctionScopes.back()->FirstReturnLoc = ReturnLoc;
 
+  if (auto *CurBlock = dyn_cast(CurCap);
+  CurBlock && CurCap->HasImplicitReturnType && RetValExp &&
+  RetValExp->containsErrors())
+CurBlock->TheDecl->setInvalidDecl();
+
   return Result;
 }
 
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -17159,6 +17159,9 @@
   if (getCurFunction())
 getCurFunction()->addBlock(BD);
 
+  if (BD->isInvalidDecl())
+return CreateRecoveryExpr(Result->getBeginLoc(), Result->getEndLoc(),
+  {Result}, Result->getType());
   return Result;
 }
 
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -663,6 +663,10 @@
 - Correcly diagnose jumps into statem

[PATCH] D155984: [Sema][ObjC] Invalidate BlockDecl with invalid ParmVarDecl

2023-07-21 Thread Ding Fei via Phabricator via cfe-commits
danix800 created this revision.
danix800 added reviewers: hokein, aaron.ballman.
danix800 added a project: clang.
Herald added a subscriber: kristof.beyls.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a subscriber: cfe-commits.

`BlockDecl` should be invalidated because of its invalid `ParmVarDecl`.

Fixes #1 of https://github.com/llvm/llvm-project/issues/64005


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D155984

Files:
  clang/lib/Sema/SemaExpr.cpp
  clang/test/AST/ast-dump-recovery.m


Index: clang/test/AST/ast-dump-recovery.m
===
--- clang/test/AST/ast-dump-recovery.m
+++ clang/test/AST/ast-dump-recovery.m
@@ -16,3 +16,9 @@
   // CHECK-NEXT:   `-DeclRefExpr {{.*}} 'foo'
   foo.undef;
 }
+
+// CHECK:  `-BlockExpr {{.*}} 'int (^)(int, int)'
+// CHECK-NEXT:   `-BlockDecl {{.*}} invalid
+int (^a)(int, int) = ^(int, undefine b) {
+   return 1;
+};
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -16959,6 +16959,9 @@
 
   PushOnScopeChains(AI, CurBlock->TheScope);
 }
+
+if (AI->isInvalidDecl())
+  CurBlock->TheDecl->setInvalidDecl();
   }
 }
 


Index: clang/test/AST/ast-dump-recovery.m
===
--- clang/test/AST/ast-dump-recovery.m
+++ clang/test/AST/ast-dump-recovery.m
@@ -16,3 +16,9 @@
   // CHECK-NEXT:   `-DeclRefExpr {{.*}} 'foo'
   foo.undef;
 }
+
+// CHECK:  `-BlockExpr {{.*}} 'int (^)(int, int)'
+// CHECK-NEXT:   `-BlockDecl {{.*}} invalid
+int (^a)(int, int) = ^(int, undefine b) {
+   return 1;
+};
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -16959,6 +16959,9 @@
 
   PushOnScopeChains(AI, CurBlock->TheScope);
 }
+
+if (AI->isInvalidDecl())
+  CurBlock->TheDecl->setInvalidDecl();
   }
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D155985: [clang][ASTDumper] Remove redundant dump of ParmVarDecl

2023-07-21 Thread Ding Fei via Phabricator via cfe-commits
danix800 created this revision.
danix800 added reviewers: hokein, aaron.ballman.
danix800 added a project: clang.
Herald added a subscriber: kristof.beyls.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a subscriber: cfe-commits.

`ParmVarDecl` of `BlockDecl` is unnecessary dumped twice.
Remove this duplication as other `FunctionDecl`s.

Fixes #2 of https://github.com/llvm/llvm-project/issues/64005


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D155985

Files:
  clang/include/clang/AST/ASTNodeTraverser.h
  clang/test/AST/ast-dump-decl-json.m
  clang/test/AST/ast-dump-decl.m


Index: clang/test/AST/ast-dump-decl.m
===
--- clang/test/AST/ast-dump-decl.m
+++ clang/test/AST/ast-dump-decl.m
@@ -142,12 +142,17 @@
 
 void TestBlockDecl(int x) {
   ^(int y, ...){ x; };
+  int z;
 }
 // CHECK:  FunctionDecl{{.*}}TestBlockDecl
 // CHECK:  BlockDecl {{.+}}  col:3 variadic
 // CHECK-NEXT:   ParmVarDecl{{.*}} y 'int'
 // CHECK-NEXT:   capture ParmVar{{.*}} 'x' 'int'
 // CHECK-NEXT:   CompoundStmt
+// CHECK-NEXT: ImplicitCastExpr
+// CHECK-NEXT:   DeclRefExpr{{.*}} 'x'
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT:   VarDecl{{.*}} z
 
 @interface B
 + (int) foo;
Index: clang/test/AST/ast-dump-decl-json.m
===
--- clang/test/AST/ast-dump-decl-json.m
+++ clang/test/AST/ast-dump-decl-json.m
@@ -1924,31 +1924,6 @@
 // CHECK-NEXT:  ]
 // CHECK-NEXT: }
 // CHECK-NEXT:]
-// CHECK-NEXT:   },
-// CHECK-NEXT:   {
-// CHECK-NEXT:"id": "0x{{.*}}",
-// CHECK-NEXT:"kind": "ParmVarDecl",
-// CHECK-NEXT:"loc": {
-// CHECK-NEXT: "offset": {{[0-9]+}},
-// CHECK-NEXT: "col": 9,
-// CHECK-NEXT: "tokLen": 1
-// CHECK-NEXT:},
-// CHECK-NEXT:"range": {
-// CHECK-NEXT: "begin": {
-// CHECK-NEXT:  "offset": {{[0-9]+}},
-// CHECK-NEXT:  "col": 5,
-// CHECK-NEXT:  "tokLen": 3
-// CHECK-NEXT: },
-// CHECK-NEXT: "end": {
-// CHECK-NEXT:  "offset": {{[0-9]+}},
-// CHECK-NEXT:  "col": 9,
-// CHECK-NEXT:  "tokLen": 1
-// CHECK-NEXT: }
-// CHECK-NEXT:},
-// CHECK-NEXT:"name": "y",
-// CHECK-NEXT:"type": {
-// CHECK-NEXT: "qualType": "int"
-// CHECK-NEXT:}
 // CHECK-NEXT:   }
 // CHECK-NEXT:  ]
 // CHECK-NEXT: }
Index: clang/include/clang/AST/ASTNodeTraverser.h
===
--- clang/include/clang/AST/ASTNodeTraverser.h
+++ clang/include/clang/AST/ASTNodeTraverser.h
@@ -104,7 +104,8 @@
 Visit(Comment, Comment);
 
   // Decls within functions are visited by the body.
-  if (!isa(*D) && !isa(*D)) {
+  if (!isa(*D) && !isa(*D) &&
+  !isa(*D)) {
 if (Traversal != TK_AsIs) {
   if (const auto *CTSD = dyn_cast(D)) 
{
 auto SK = CTSD->getSpecializationKind();


Index: clang/test/AST/ast-dump-decl.m
===
--- clang/test/AST/ast-dump-decl.m
+++ clang/test/AST/ast-dump-decl.m
@@ -142,12 +142,17 @@
 
 void TestBlockDecl(int x) {
   ^(int y, ...){ x; };
+  int z;
 }
 // CHECK:  FunctionDecl{{.*}}TestBlockDecl
 // CHECK:  BlockDecl {{.+}}  col:3 variadic
 // CHECK-NEXT:   ParmVarDecl{{.*}} y 'int'
 // CHECK-NEXT:   capture ParmVar{{.*}} 'x' 'int'
 // CHECK-NEXT:   CompoundStmt
+// CHECK-NEXT: ImplicitCastExpr
+// CHECK-NEXT:   DeclRefExpr{{.*}} 'x'
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT:   VarDecl{{.*}} z
 
 @interface B
 + (int) foo;
Index: clang/test/AST/ast-dump-decl-json.m
===
--- clang/test/AST/ast-dump-decl-json.m
+++ clang/test/AST/ast-dump-decl-json.m
@@ -1924,31 +1924,6 @@
 // CHECK-NEXT:  ]
 // CHECK-NEXT: }
 // CHECK-NEXT:]
-// CHECK-NEXT:   },
-// CHECK-NEXT:   {
-// CHECK-NEXT:"id": "0x{{.*}}",
-// CHECK-NEXT:"kind": "ParmVarDecl",
-// CHECK-NEXT:"loc": {
-// CHECK-NEXT: "offset": {{[0-9]+}},
-// CHECK-NEXT: "col": 9,
-// CHECK-NEXT: "tokLen": 1
-// CHECK-NEXT:},
-// CHECK-NEXT:"range": {
-// CHECK-NEXT: "begin": {
-// CHECK-NEXT:  "offset": {{[0-9]+}},
-// CHECK-NEXT:  "col": 5,
-// CHECK-NEXT:  "tokLen": 3
-// CHECK-NEXT: },
-// CHECK-NEXT: "end": {
-// CHECK-NEXT:  "offset": {{[0-9]+}},
-// CHECK-NEXT:  "col": 9,
-// CHECK-NEXT:  "tokLen": 1
-// CHECK-NEXT: }
-// CHECK-NEXT:},
-// CHECK-NEX

[PATCH] D155985: [clang][ASTDumper] Remove redundant dump of BlockDecl's ParmVarDecl

2023-07-21 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 543003.
danix800 retitled this revision from "[clang][ASTDumper] Remove redundant dump 
of ParmVarDecl" to "[clang][ASTDumper] Remove redundant dump of BlockDecl's 
ParmVarDecl".
danix800 edited the summary of this revision.
danix800 added a comment.

Update ReleaseNotes.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155985

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/ASTNodeTraverser.h
  clang/test/AST/ast-dump-decl-json.m
  clang/test/AST/ast-dump-decl.m


Index: clang/test/AST/ast-dump-decl.m
===
--- clang/test/AST/ast-dump-decl.m
+++ clang/test/AST/ast-dump-decl.m
@@ -142,12 +142,17 @@
 
 void TestBlockDecl(int x) {
   ^(int y, ...){ x; };
+  int z;
 }
 // CHECK:  FunctionDecl{{.*}}TestBlockDecl
 // CHECK:  BlockDecl {{.+}}  col:3 variadic
 // CHECK-NEXT:   ParmVarDecl{{.*}} y 'int'
 // CHECK-NEXT:   capture ParmVar{{.*}} 'x' 'int'
 // CHECK-NEXT:   CompoundStmt
+// CHECK-NEXT: ImplicitCastExpr
+// CHECK-NEXT:   DeclRefExpr{{.*}} 'x'
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT:   VarDecl{{.*}} z
 
 @interface B
 + (int) foo;
Index: clang/test/AST/ast-dump-decl-json.m
===
--- clang/test/AST/ast-dump-decl-json.m
+++ clang/test/AST/ast-dump-decl-json.m
@@ -1924,31 +1924,6 @@
 // CHECK-NEXT:  ]
 // CHECK-NEXT: }
 // CHECK-NEXT:]
-// CHECK-NEXT:   },
-// CHECK-NEXT:   {
-// CHECK-NEXT:"id": "0x{{.*}}",
-// CHECK-NEXT:"kind": "ParmVarDecl",
-// CHECK-NEXT:"loc": {
-// CHECK-NEXT: "offset": {{[0-9]+}},
-// CHECK-NEXT: "col": 9,
-// CHECK-NEXT: "tokLen": 1
-// CHECK-NEXT:},
-// CHECK-NEXT:"range": {
-// CHECK-NEXT: "begin": {
-// CHECK-NEXT:  "offset": {{[0-9]+}},
-// CHECK-NEXT:  "col": 5,
-// CHECK-NEXT:  "tokLen": 3
-// CHECK-NEXT: },
-// CHECK-NEXT: "end": {
-// CHECK-NEXT:  "offset": {{[0-9]+}},
-// CHECK-NEXT:  "col": 9,
-// CHECK-NEXT:  "tokLen": 1
-// CHECK-NEXT: }
-// CHECK-NEXT:},
-// CHECK-NEXT:"name": "y",
-// CHECK-NEXT:"type": {
-// CHECK-NEXT: "qualType": "int"
-// CHECK-NEXT:}
 // CHECK-NEXT:   }
 // CHECK-NEXT:  ]
 // CHECK-NEXT: }
Index: clang/include/clang/AST/ASTNodeTraverser.h
===
--- clang/include/clang/AST/ASTNodeTraverser.h
+++ clang/include/clang/AST/ASTNodeTraverser.h
@@ -104,7 +104,8 @@
 Visit(Comment, Comment);
 
   // Decls within functions are visited by the body.
-  if (!isa(*D) && !isa(*D)) {
+  if (!isa(*D) && !isa(*D) &&
+  !isa(*D)) {
 if (Traversal != TK_AsIs) {
   if (const auto *CTSD = dyn_cast(D)) 
{
 auto SK = CTSD->getSpecializationKind();
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -663,6 +663,8 @@
 - Correcly diagnose jumps into statement expressions.
   This ensures the behavior of Clang is consistent with GCC.
   (`#63682 `_)
+- Remove redundant dump of BlockDecl's ParmVarDecl
+  (`#64005 _`)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/AST/ast-dump-decl.m
===
--- clang/test/AST/ast-dump-decl.m
+++ clang/test/AST/ast-dump-decl.m
@@ -142,12 +142,17 @@
 
 void TestBlockDecl(int x) {
   ^(int y, ...){ x; };
+  int z;
 }
 // CHECK:  FunctionDecl{{.*}}TestBlockDecl
 // CHECK:  BlockDecl {{.+}}  col:3 variadic
 // CHECK-NEXT:   ParmVarDecl{{.*}} y 'int'
 // CHECK-NEXT:   capture ParmVar{{.*}} 'x' 'int'
 // CHECK-NEXT:   CompoundStmt
+// CHECK-NEXT: ImplicitCastExpr
+// CHECK-NEXT:   DeclRefExpr{{.*}} 'x'
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT:   VarDecl{{.*}} z
 
 @interface B
 + (int) foo;
Index: clang/test/AST/ast-dump-decl-json.m
===
--- clang/test/AST/ast-dump-decl-json.m
+++ clang/test/AST/ast-dump-decl-json.m
@@ -1924,31 +1924,6 @@
 // CHECK-NEXT:  ]
 // CHECK-NEXT: }
 // CHECK-NEXT:]
-// CHECK-NEXT:   },
-// CHECK-NEXT:   {
-// CHECK-NEXT:"id": "0x{{.*}}",
-// CHECK-NEXT:"kind": "ParmVarDecl",
-// CHECK-NEXT:"loc": {
-// CHECK-NEXT: "offset": {{[0-9]+}},
-// CHECK-NEXT: "col": 9,
-// CHECK-NEXT:   

[PATCH] D155984: [Sema][ObjC] Invalidate BlockDecl with invalid ParmVarDecl

2023-07-21 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 543005.
danix800 added a comment.

Update ReleaseNotes


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155984

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/Sema/SemaExpr.cpp
  clang/test/AST/ast-dump-recovery.m


Index: clang/test/AST/ast-dump-recovery.m
===
--- clang/test/AST/ast-dump-recovery.m
+++ clang/test/AST/ast-dump-recovery.m
@@ -16,3 +16,9 @@
   // CHECK-NEXT:   `-DeclRefExpr {{.*}} 'foo'
   foo.undef;
 }
+
+// CHECK:  `-BlockExpr {{.*}} 'int (^)(int, int)'
+// CHECK-NEXT:   `-BlockDecl {{.*}} invalid
+int (^a)(int, int) = ^(int, undefine b) {
+   return 1;
+};
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -16959,6 +16959,9 @@
 
   PushOnScopeChains(AI, CurBlock->TheScope);
 }
+
+if (AI->isInvalidDecl())
+  CurBlock->TheDecl->setInvalidDecl();
   }
 }
 
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -663,6 +663,8 @@
 - Correcly diagnose jumps into statement expressions.
   This ensures the behavior of Clang is consistent with GCC.
   (`#63682 `_)
+- Invalidate BlockDecl with invalid ParmVarDecl
+  (`#64005 _`)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/AST/ast-dump-recovery.m
===
--- clang/test/AST/ast-dump-recovery.m
+++ clang/test/AST/ast-dump-recovery.m
@@ -16,3 +16,9 @@
   // CHECK-NEXT:   `-DeclRefExpr {{.*}} 'foo'
   foo.undef;
 }
+
+// CHECK:  `-BlockExpr {{.*}} 'int (^)(int, int)'
+// CHECK-NEXT:   `-BlockDecl {{.*}} invalid
+int (^a)(int, int) = ^(int, undefine b) {
+   return 1;
+};
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -16959,6 +16959,9 @@
 
   PushOnScopeChains(AI, CurBlock->TheScope);
 }
+
+if (AI->isInvalidDecl())
+  CurBlock->TheDecl->setInvalidDecl();
   }
 }
 
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -663,6 +663,8 @@
 - Correcly diagnose jumps into statement expressions.
   This ensures the behavior of Clang is consistent with GCC.
   (`#63682 `_)
+- Invalidate BlockDecl with invalid ParmVarDecl
+  (`#64005 _`)
 
 Bug Fixes to Compiler Builtins
 ^^
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D155396: [Sema][ObjC] Invalidate BlockDecl with invalid return expr & its parent BlockExpr

2023-07-21 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 543010.
danix800 retitled this revision from "[Sema][ObjC] Propagating value-dependent 
errors into BlockExpr" to "[Sema][ObjC] Invalidate BlockDecl with invalid 
return expr & its parent BlockExpr".
danix800 added a comment.

Fix testcase tag with `CHECK-NEXT`.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155396

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/test/AST/ast-dump-recovery.m


Index: clang/test/AST/ast-dump-recovery.m
===
--- clang/test/AST/ast-dump-recovery.m
+++ clang/test/AST/ast-dump-recovery.m
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -triple x86_64-unknown-unknown -frecovery-ast 
-frecovery-ast-type -ast-dump %s | FileCheck -strict-whitespace %s
+// RUN: not %clang_cc1 -triple x86_64-unknown-unknown -frecovery-ast 
-frecovery-ast-type -fblocks -ast-dump %s | FileCheck -strict-whitespace %s
 
 @interface Foo
 - (void)method:(int)n;
@@ -16,3 +16,11 @@
   // CHECK-NEXT:   `-DeclRefExpr {{.*}} 'foo'
   foo.undef;
 }
+
+// CHECK:  |-VarDecl {{.*}} 'int (^)()' cinit
+// CHECK-NEXT: | `-RecoveryExpr {{.*}} ' (^)(void)' 
contains-errors lvalue
+// CHECK-NEXT: |   `-BlockExpr {{.*}} ' (^)(void)'
+// CHECK-NEXT: | `-BlockDecl {{.*}} invalid
+int (^a)() = ^() {
+  return c;
+};
Index: clang/lib/Sema/SemaStmt.cpp
===
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -3730,6 +3730,11 @@
   if (FunctionScopes.back()->FirstReturnLoc.isInvalid())
 FunctionScopes.back()->FirstReturnLoc = ReturnLoc;
 
+  if (auto *CurBlock = dyn_cast(CurCap);
+  CurBlock && CurCap->HasImplicitReturnType && RetValExp &&
+  RetValExp->containsErrors())
+CurBlock->TheDecl->setInvalidDecl();
+
   return Result;
 }
 
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -17159,6 +17159,9 @@
   if (getCurFunction())
 getCurFunction()->addBlock(BD);
 
+  if (BD->isInvalidDecl())
+return CreateRecoveryExpr(Result->getBeginLoc(), Result->getEndLoc(),
+  {Result}, Result->getType());
   return Result;
 }
 
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -663,6 +663,10 @@
 - Correcly diagnose jumps into statement expressions.
   This ensures the behavior of Clang is consistent with GCC.
   (`#63682 `_)
+- Invalidate BlockDecl with implicit return type, in case any of the return
+  value exprs is invalid. Propagating the error info up by replacing BlockExpr
+  with a RecoveryExpr. This fixes:
+  (`#63863 _`)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/AST/ast-dump-recovery.m
===
--- clang/test/AST/ast-dump-recovery.m
+++ clang/test/AST/ast-dump-recovery.m
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -triple x86_64-unknown-unknown -frecovery-ast -frecovery-ast-type -ast-dump %s | FileCheck -strict-whitespace %s
+// RUN: not %clang_cc1 -triple x86_64-unknown-unknown -frecovery-ast -frecovery-ast-type -fblocks -ast-dump %s | FileCheck -strict-whitespace %s
 
 @interface Foo
 - (void)method:(int)n;
@@ -16,3 +16,11 @@
   // CHECK-NEXT:   `-DeclRefExpr {{.*}} 'foo'
   foo.undef;
 }
+
+// CHECK:  |-VarDecl {{.*}} 'int (^)()' cinit
+// CHECK-NEXT: | `-RecoveryExpr {{.*}} ' (^)(void)' contains-errors lvalue
+// CHECK-NEXT: |   `-BlockExpr {{.*}} ' (^)(void)'
+// CHECK-NEXT: | `-BlockDecl {{.*}} invalid
+int (^a)() = ^() {
+  return c;
+};
Index: clang/lib/Sema/SemaStmt.cpp
===
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -3730,6 +3730,11 @@
   if (FunctionScopes.back()->FirstReturnLoc.isInvalid())
 FunctionScopes.back()->FirstReturnLoc = ReturnLoc;
 
+  if (auto *CurBlock = dyn_cast(CurCap);
+  CurBlock && CurCap->HasImplicitReturnType && RetValExp &&
+  RetValExp->containsErrors())
+CurBlock->TheDecl->setInvalidDecl();
+
   return Result;
 }
 
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -17159,6 +17159,9 @@
   if (getCurFunction())
 getCurFunction()->addBlock(BD);
 
+  if (BD->isInvalidDecl())
+return CreateRecoveryExpr(Result->getBeginLoc(), Result->getEndLoc(),
+  {Result}, Result->getType());
   return Result;
 }
 
Index: clang/docs/ReleaseNotes.rst
===

[PATCH] D155661: [ASTImporter] Fix friend class template import within dependent context

2023-07-23 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 543387.

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155661

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -3968,8 +3968,31 @@
   EXPECT_EQ(ToDef->getPreviousDecl(), ToProto);
 }
 
-
-struct ImportFriendClasses : ASTImporterOptionSpecificTestBase {};
+struct ImportFriendClasses : ASTImporterOptionSpecificTestBase {
+  void testRecursiveFriendClassTemplate(Decl *FromTu) {
+auto *FromD = FirstDeclMatcher().match(
+FromTu, classTemplateDecl());
+auto *ToD = Import(FromD, Lang_CXX03);
+
+auto Pattern = classTemplateDecl(
+has(cxxRecordDecl(has(friendDecl(has(classTemplateDecl()));
+ASSERT_TRUE(MatchVerifier{}.match(FromD, Pattern));
+EXPECT_TRUE(MatchVerifier{}.match(ToD, Pattern));
+
+auto *FromFriend =
+FirstDeclMatcher().match(FromD, friendDecl());
+auto *FromClass =
+FirstDeclMatcher().match(FromD, classTemplateDecl());
+EXPECT_NE(FromFriend->getFriendDecl(), FromClass);
+EXPECT_TRUE(FromFriend->getFriendDecl()->getPreviousDecl() == nullptr);
+
+auto *Class =
+FirstDeclMatcher().match(ToD, classTemplateDecl());
+auto *Friend = FirstDeclMatcher().match(ToD, friendDecl());
+EXPECT_NE(Friend->getFriendDecl(), Class);
+EXPECT_TRUE(Friend->getFriendDecl()->getPreviousDecl() == nullptr);
+  }
+};
 
 TEST_P(ImportFriendClasses, ImportOfFriendRecordDoesNotMergeDefinition) {
   Decl *FromTU = getTuDecl(
@@ -4074,20 +4097,19 @@
   )",
   Lang_CXX03, "input.cc");
 
-  auto *FromD =
-  FirstDeclMatcher().match(FromTu, classTemplateDecl());
-  auto *ToD = Import(FromD, Lang_CXX03);
-
-  auto Pattern = classTemplateDecl(
-  has(cxxRecordDecl(has(friendDecl(has(classTemplateDecl()));
-  ASSERT_TRUE(MatchVerifier{}.match(FromD, Pattern));
-  EXPECT_TRUE(MatchVerifier{}.match(ToD, Pattern));
+  testRecursiveFriendClassTemplate(FromTu);
+}
 
-  auto *Class =
-  FirstDeclMatcher().match(ToD, classTemplateDecl());
-  auto *Friend = FirstDeclMatcher().match(ToD, friendDecl());
-  EXPECT_NE(Friend->getFriendDecl(), Class);
-  EXPECT_EQ(Friend->getFriendDecl()->getPreviousDecl(), Class);
+TEST_P(ImportFriendClasses,
+   ImportOfRecursiveFriendClassTemplateWithNonTypeParm) {
+  Decl *FromTu = getTuDecl(
+  R"(
+  template class declToImport {
+template friend class declToImport;
+  };
+  )",
+  Lang_CXX03, "input.cc");
+  testRecursiveFriendClassTemplate(FromTu);
 }
 
 TEST_P(ImportFriendClasses, ProperPrevDeclForClassTemplateDecls) {
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -2857,6 +2857,10 @@
   } else if (Importer.getToContext().getLangOpts().CPlusPlus)
 IDNS |= Decl::IDNS_Ordinary | Decl::IDNS_TagFriend;
 
+  bool IsDependentContext = DC != LexicalDC ? LexicalDC->isDependentContext()
+: DC->isDependentContext();
+  bool ShouldAddRedecl = !(IsFriendTemplate && IsDependentContext);
+
   // We may already have a record of the same name; try to find and match it.
   RecordDecl *PrevDecl = nullptr;
   if (!DC->isFunctionOrMethod() && !D->isLambda()) {
@@ -2897,7 +2901,7 @@
 if (!hasSameVisibilityContextAndLinkage(FoundRecord, D))
   continue;
 
-if (IsStructuralMatch(D, FoundRecord)) {
+if (IsFriendTemplate || IsStructuralMatch(D, FoundRecord)) {
   RecordDecl *FoundDef = FoundRecord->getDefinition();
   if (D->isThisDeclarationADefinition() && FoundDef) {
 // FIXME: Structural equivalence check should check for same
@@ -2955,7 +2959,7 @@
 return CDeclOrErr.takeError();
   Numbering.ContextDecl = *CDeclOrErr;
   D2CXX->setLambdaNumbering(Numbering);
-   } else if (DCXX->isInjectedClassName()) {
+} else if (DCXX->isInjectedClassName()) {
   // We have to be careful to do a similar dance to the one in
   // Sema::ActOnStartCXXMemberDeclarations
   const bool DelayTypeCreation = true;
@@ -2967,10 +2971,11 @@
   Importer.getToContext().getTypeDeclType(
   D2CXX, dyn_cast(DC));
 } else {
-  if (GetImportedOrCreateDecl(D2CXX, D, Importer.getToContext(),
-  D->getTagKind(), DC, *BeginLocOrErr, Loc,
-  Name.getAsIdentifierInfo(),
-  cast_or_null(PrevDecl)))
+  if (GetImportedOrCreateDecl(
+  D2CXX, D, Importer.getToContext(), D->getTagKind(), DC,
+  *BeginLocOrErr, Loc, Name.getAsIdentifierInfo(),
+  Shou

[PATCH] D155396: [Sema][ObjC] Invalidate BlockDecl with invalid return expr & its parent BlockExpr

2023-07-24 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/test/AST/ast-dump-recovery.m:24
+// CHECK-NEXT: | `-BlockDecl {{.*}} invalid
+int (^a)() = ^() {
+  return c;

hokein wrote:
> nit: it'd be nice to encode the github issue number to the testcase here, for 
> example (renaming the `a` to `gh63863` etc).
Will be fixed in the final commit!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155396

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


[PATCH] D155984: [Sema][ObjC] Invalidate BlockDecl with invalid ParmVarDecl

2023-07-24 Thread Ding Fei via Phabricator via cfe-commits
danix800 marked an inline comment as done.
danix800 added inline comments.



Comment at: clang/test/AST/ast-dump-recovery.m:22
+// CHECK-NEXT:   `-BlockDecl {{.*}} invalid
+int (^a)(int, int) = ^(int, undefine b) {
+   return 1;

hokein wrote:
> nit: a => `gh64005`
Will be fixed in the final commit!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155984

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


[PATCH] D156093: [ASTImporter] Add extra sorting round for keeping lexical order of all imported decls within record

2023-07-24 Thread Ding Fei via Phabricator via cfe-commits
danix800 created this revision.
danix800 added a project: clang.
Herald added a subscriber: martong.
Herald added a reviewer: a.sidorin.
Herald added a reviewer: shafik.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a subscriber: cfe-commits.

Revision https://reviews.llvm.org/D154764 is still not complete. An extra 
sorting is needed
for keeping lexical order of all imported decls within a record. The final 
algorithm could be
summarized as the following:

1. Import all fields that'll be part of the layout;
2. Sort these fields to ensure correct layout;
3. Import everything else;
4. Final sort for correct lexical order.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D156093

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -1462,10 +1462,10 @@
   MatchVerifier{}.match(To->getTranslationUnitDecl(), Pattern));
 }
 
-AST_MATCHER_P(RecordDecl, hasFieldOrder, std::vector, Order) {
+AST_MATCHER_P(RecordDecl, hasLexicalOrder, std::vector, Order) {
   size_t Index = 0;
   for (Decl *D : Node.decls()) {
-if (isa(D) || isa(D)) {
+if (isa(D) || isa(D) || !D->isImplicit()) {
   auto *ND = cast(D);
   if (Index == Order.size())
 return false;
@@ -1513,8 +1513,8 @@
   Lang_CXX11, "", Lang_CXX11);
 
   MatchVerifier Verifier;
-  ASSERT_TRUE(Verifier.match(From, cxxRecordDecl(hasFieldOrder({"a", "b"};
-  EXPECT_TRUE(Verifier.match(To, cxxRecordDecl(hasFieldOrder({"a", "b"};
+  ASSERT_TRUE(Verifier.match(From, cxxRecordDecl(hasLexicalOrder({"a", "b"};
+  EXPECT_TRUE(Verifier.match(To, cxxRecordDecl(hasLexicalOrder({"a", "b"};
 }
 
 TEST_P(ASTImporterOptionSpecificTestBase,
@@ -1532,11 +1532,30 @@
   )s",
   Lang_CXX11, "", Lang_CXX11);
 
+  auto Pattern = cxxRecordDecl(hasLexicalOrder({"a", "b", "c"}));
   MatchVerifier Verifier;
-  ASSERT_TRUE(
-  Verifier.match(From, cxxRecordDecl(hasFieldOrder({"a", "b", "c"};
-  EXPECT_TRUE(
-  Verifier.match(To, cxxRecordDecl(hasFieldOrder({"a", "b", "c"};
+  ASSERT_TRUE(Verifier.match(From, Pattern));
+  EXPECT_TRUE(Verifier.match(To, Pattern));
+}
+
+TEST_P(ASTImporterOptionSpecificTestBase, CXXRecordDeclCorrectLexicalOrder) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"s(
+  struct declToImport {
+  int a = c;
+  void g() { h(); }
+  int b = 1;
+  void h();
+  int c = 2;
+  };
+  )s",
+  Lang_CXX11, "", Lang_CXX11);
+
+  auto Pattern = cxxRecordDecl(hasLexicalOrder({"a", "g", "b", "h", "c"}));
+  MatchVerifier Verifier;
+  ASSERT_TRUE(Verifier.match(From, Pattern));
+  EXPECT_TRUE(Verifier.match(To, Pattern));
 }
 
 TEST_P(ASTImporterOptionSpecificTestBase,
@@ -1557,11 +1576,17 @@
   )s",
   Lang_CXX11, "", Lang_CXX11);
 
+  auto Pattern = cxxRecordDecl(hasLexicalOrder({
+"a",
+"" /*anony union*/,
+"" /* implicit field */,
+"b" /* indirect */,
+"c" /* indirect */,
+"d"
+  }));
   MatchVerifier Verifier;
-  ASSERT_TRUE(Verifier.match(
-  From, cxxRecordDecl(hasFieldOrder({"a", "", "b", "c", "d"};
-  EXPECT_TRUE(Verifier.match(
-  To, cxxRecordDecl(hasFieldOrder({"a", "", "b", "c", "d"};
+  ASSERT_TRUE(Verifier.match(From, Pattern));
+  EXPECT_TRUE(Verifier.match(To, Pattern));
 }
 
 TEST_P(ASTImporterOptionSpecificTestBase, ShouldImportImplicitCXXRecordDecl) {
@@ -3007,7 +3032,7 @@
  "  int a = 5;"
  "};",
  Lang_CXX11, "", Lang_CXX11, Verifier,
- recordDecl(hasFieldOrder({"b", "a"})));
+ recordDecl(hasLexicalOrder({"b", "a"})));
 }
 
 const internal::VariadicDynCastAllOfMatcher
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -1942,6 +1942,16 @@
 ImportedOrErr.takeError());
   }
 
+  // Final round to re-order everything
+  for (auto *D : FromDC->decls()) {
+assert(D && "DC contains a null decl");
+if (Decl *ToD = Importer.GetAlreadyImportedOrNull(D); ToD &&
+ToDC == ToD->getLexicalDeclContext() && ToDC->containsDecl(ToD)) {
+  ToDC->removeDecl(ToD);
+  ToDC->addDeclInternal(ToD);
+}
+  }
+
   return ChildErrors;
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156093: [ASTImporter] Re-odering by lexical order for all imported decls within record

2023-07-24 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 543535.
danix800 retitled this revision from "[ASTImporter] Add extra sorting round for 
keeping lexical order of all imported decls within record" to "[ASTImporter] 
Re-odering by lexical order for all imported decls within record".
danix800 edited the summary of this revision.
danix800 added a reviewer: balazske.

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156093

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -1462,11 +1462,18 @@
   MatchVerifier{}.match(To->getTranslationUnitDecl(), Pattern));
 }
 
-AST_MATCHER_P(RecordDecl, hasFieldOrder, std::vector, Order) {
+AST_MATCHER_P(RecordDecl, hasLexicalOrder, std::vector, Order) {
   size_t Index = 0;
   for (Decl *D : Node.decls()) {
-if (isa(D) || isa(D)) {
-  auto *ND = cast(D);
+if (isa(D) || isa(D) || !D->isImplicit()) {
+  NamedDecl *ND = nullptr;
+  if (isa(D))
+ND = cast(D);
+  else if (auto *Friend = dyn_cast(D);
+   Friend && !(ND = Friend->getFriendDecl()))
+ND = Friend->getFriendType()->getType()->getAsRecordDecl();
+  if (!ND)
+return false;
   if (Index == Order.size())
 return false;
   if (ND->getName() != Order[Index])
@@ -1513,8 +1520,8 @@
   Lang_CXX11, "", Lang_CXX11);
 
   MatchVerifier Verifier;
-  ASSERT_TRUE(Verifier.match(From, cxxRecordDecl(hasFieldOrder({"a", "b"};
-  EXPECT_TRUE(Verifier.match(To, cxxRecordDecl(hasFieldOrder({"a", "b"};
+  ASSERT_TRUE(Verifier.match(From, cxxRecordDecl(hasLexicalOrder({"a", "b"};
+  EXPECT_TRUE(Verifier.match(To, cxxRecordDecl(hasLexicalOrder({"a", "b"};
 }
 
 TEST_P(ASTImporterOptionSpecificTestBase,
@@ -1532,19 +1539,46 @@
   )s",
   Lang_CXX11, "", Lang_CXX11);
 
+  auto Pattern = cxxRecordDecl(hasLexicalOrder({"a", "b", "c"}));
   MatchVerifier Verifier;
-  ASSERT_TRUE(
-  Verifier.match(From, cxxRecordDecl(hasFieldOrder({"a", "b", "c"};
-  EXPECT_TRUE(
-  Verifier.match(To, cxxRecordDecl(hasFieldOrder({"a", "b", "c"};
+  ASSERT_TRUE(Verifier.match(From, Pattern));
+  EXPECT_TRUE(Verifier.match(To, Pattern));
+}
+
+TEST_P(ASTImporterOptionSpecificTestBase, CXXRecordDeclCorrectLexicalOrder) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"s(
+  struct declToImport {
+int a = c;
+void b() { d(); }
+int c = 1;
+void d();
+friend class e;
+int f = 2;
+enum {
+  g, h
+};
+class I {};
+enum J {
+  k, l
+};
+template class M;
+  };
+  )s",
+  Lang_CXX11, "", Lang_CXX11);
+
+  auto Pattern = cxxRecordDecl(
+  hasLexicalOrder({"a", "b", "c", "d", "e", "f", "", "I", "J", "M"}));
+  MatchVerifier Verifier;
+  ASSERT_TRUE(Verifier.match(From, Pattern));
+  EXPECT_TRUE(Verifier.match(To, Pattern));
 }
 
 TEST_P(ASTImporterOptionSpecificTestBase,
CXXRecordDeclFieldAndIndirectFieldOrder) {
   Decl *From, *To;
   std::tie(From, To) = getImportedDecl(
-  // First field is "a", then the field for unnamed union, then "b" and "c"
-  // from it (indirect fields), then "d".
   R"s(
   struct declToImport {
 int a = d;
@@ -1557,11 +1591,14 @@
   )s",
   Lang_CXX11, "", Lang_CXX11);
 
+  auto Pattern = cxxRecordDecl(hasLexicalOrder({"a", "", /* anonymous union */
+"",  /* implicit field */
+"b", /* indirect field */
+"c", /* indirect field */
+"d"}));
   MatchVerifier Verifier;
-  ASSERT_TRUE(Verifier.match(
-  From, cxxRecordDecl(hasFieldOrder({"a", "", "b", "c", "d"};
-  EXPECT_TRUE(Verifier.match(
-  To, cxxRecordDecl(hasFieldOrder({"a", "", "b", "c", "d"};
+  ASSERT_TRUE(Verifier.match(From, Pattern));
+  EXPECT_TRUE(Verifier.match(To, Pattern));
 }
 
 TEST_P(ASTImporterOptionSpecificTestBase, ShouldImportImplicitCXXRecordDecl) {
@@ -3007,7 +3044,7 @@
  "  int a = 5;"
  "};",
  Lang_CXX11, "", Lang_CXX11, Verifier,
- recordDecl(hasFieldOrder({"b", "a"})));
+ recordDecl(hasLexicalOrder({"b", "a"})));
 }
 
 const internal::VariadicDynCastAllOfMatcher
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -1942,6 +1942,17 @@
 ImportedOrErr.takeError());
   }
 
+  // Finally re-ord

[PATCH] D156201: [ASTImporter] Fix two cases on fields circular refs

2023-07-24 Thread Ding Fei via Phabricator via cfe-commits
danix800 created this revision.
danix800 added a project: clang.
Herald added a subscriber: martong.
Herald added a reviewer: a.sidorin.
Herald added a reviewer: shafik.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a subscriber: cfe-commits.

Fixes two cases on fields circular refs:

1. Field in-class initializer is deferred until all fields are imported. No 
reordering for fields is needed. For final lexical order, see 
https://reviews.llvm.org/D156093
2. UnaryOperator(&)'s creation might need layout of some records whose fields 
importation are still on fly, the layout is incorrectly computed and cached. 
Clients relying on this will not work properly or crash direclty (e.g 
StaticAnalyzer's MemRegion.cpp (calculateOffset)). Use 
UnaryOperator::CreateEmpty() instead of UnaryOperator::Create() to avoid this 
computation.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D156201

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -10,6 +10,7 @@
 //
 //===--===//
 
+#include "clang/AST/RecordLayout.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/Support/SmallVectorMemoryBuffer.h"
@@ -1539,6 +1540,83 @@
   Verifier.match(To, cxxRecordDecl(hasFieldOrder({"a", "b", "c"};
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase, FieldCircularRef) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"s(
+struct declToImport {
+  int a{a};
+  int b = c;
+  int c = b + c + a;
+};
+  )s",
+  Lang_CXX11, "", Lang_CXX11);
+
+  auto FieldBWithInit = has(fieldDecl(
+  hasName("b"),
+  hasInClassInitializer(ignoringImpCasts(memberExpr(
+  hasObjectExpression(cxxThisExpr()), member(hasName("c")));
+  auto FieldCWithInit = has(fieldDecl(
+  hasName("c"),
+  hasInClassInitializer(binaryOperator(hasLHS(binaryOperator());
+  auto Pattern = cxxRecordDecl(FieldBWithInit, FieldCWithInit,
+   hasFieldOrder({"a", "b", "c"}));
+  MatchVerifier Verifier;
+  ASSERT_TRUE(Verifier.match(From, Pattern));
+  EXPECT_TRUE(Verifier.match(To, Pattern));
+}
+
+TEST_P(ASTImporterOptionSpecificTestBase,
+   ImportFieldDirectlyWithInitializerContainingCircularRef) {
+  auto Code = R"s(
+struct declToImport {
+  int a{a};
+  int b = c;
+  int c = b + c + a;
+};
+  )s";
+
+  auto *FromField = FirstDeclMatcher().match(
+  getTuDecl(Code, Lang_CXX11), fieldDecl(hasName("b")));
+  auto *ToField = Import(FromField, Lang_CXX11);
+
+  auto Pattern = fieldDecl(
+  hasName("b"),
+  hasInClassInitializer(ignoringImpCasts(memberExpr(
+  hasObjectExpression(cxxThisExpr()), member(hasName("c"));
+
+  MatchVerifier Verifier;
+  ASSERT_TRUE(Verifier.match(FromField, Pattern));
+  EXPECT_TRUE(Verifier.match(ToField, Pattern));
+}
+
+TEST_P(ASTImporterOptionSpecificTestBase, FieldCircularIndirectRef) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"s(
+static int ref_A();
+static int ref_B();
+struct A {
+  int a = ref_B();
+};
+struct B {
+  int b = ref_A();
+};
+int ref_B() { B b; return b.b; }
+int ref_A() { A a; return a.a; }
+  )s",
+  Lang_CXX11, "", Lang_CXX11, "A");
+
+  auto InitByRefB =
+  hasInClassInitializer(callExpr(callee(functionDecl(hasName("ref_B");
+  auto FieldAWithInit = has(fieldDecl(hasName("a"), InitByRefB));
+  auto Pattern =
+  cxxRecordDecl(hasName("A"), FieldAWithInit, hasFieldOrder({"a"}));
+  MatchVerifier Verifier;
+  ASSERT_TRUE(Verifier.match(From, Pattern));
+  EXPECT_TRUE(Verifier.match(To, Pattern));
+}
+
 TEST_P(ASTImporterOptionSpecificTestBase,
CXXRecordDeclFieldAndIndirectFieldOrder) {
   Decl *From, *To;
@@ -8028,6 +8106,45 @@
   Import(FromF, Lang_CXX11);
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase,
+   ImportCirularRefFieldsWithoutCorruptedRecordLayoutCacheTest) {
+  // Import sequence: A => A.b => B => B.f() => ... => UnaryOperator(&) => ...
+  //
+  // UnaryOperator(&) force computing RecordLayout of 'A' while it's still not
+  // completely imported.
+  auto Code =
+  R"(
+  class B;
+  class A {
+B* b;
+int c;
+  };
+  class B {
+A *f() { return &((B *)0)->a; }
+A a;
+  };
+  )";
+
+  auto *FromR = FirstDeclMatcher().match(
+  getTuDecl(Code, Lang_CXX11), cxxRecordDecl(hasName("A")));
+  FromR = FromR->getDefinition();
+  auto &FromAST = FromR->getASTContext();
+  auto *ToR = Import(FromR, Lang_CXX11);
+  auto &ToAST = ToR-

[PATCH] D156201: [ASTImporter] Fix two cases on fields circular refs

2023-07-24 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 543834.
danix800 added a comment.

Restore in-class initializer importing  when minimal importing.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156201

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -10,6 +10,7 @@
 //
 //===--===//
 
+#include "clang/AST/RecordLayout.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/Support/SmallVectorMemoryBuffer.h"
@@ -1539,6 +1540,83 @@
   Verifier.match(To, cxxRecordDecl(hasFieldOrder({"a", "b", "c"};
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase, FieldCircularRef) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"s(
+struct declToImport {
+  int a{a};
+  int b = c;
+  int c = b + c + a;
+};
+  )s",
+  Lang_CXX11, "", Lang_CXX11);
+
+  auto FieldBWithInit = has(fieldDecl(
+  hasName("b"),
+  hasInClassInitializer(ignoringImpCasts(memberExpr(
+  hasObjectExpression(cxxThisExpr()), member(hasName("c")));
+  auto FieldCWithInit = has(fieldDecl(
+  hasName("c"),
+  hasInClassInitializer(binaryOperator(hasLHS(binaryOperator());
+  auto Pattern = cxxRecordDecl(FieldBWithInit, FieldCWithInit,
+   hasFieldOrder({"a", "b", "c"}));
+  MatchVerifier Verifier;
+  ASSERT_TRUE(Verifier.match(From, Pattern));
+  EXPECT_TRUE(Verifier.match(To, Pattern));
+}
+
+TEST_P(ASTImporterOptionSpecificTestBase,
+   ImportFieldDirectlyWithInitializerContainingCircularRef) {
+  auto Code = R"s(
+struct declToImport {
+  int a{a};
+  int b = c;
+  int c = b + c + a;
+};
+  )s";
+
+  auto *FromField = FirstDeclMatcher().match(
+  getTuDecl(Code, Lang_CXX11), fieldDecl(hasName("b")));
+  auto *ToField = Import(FromField, Lang_CXX11);
+
+  auto Pattern = fieldDecl(
+  hasName("b"),
+  hasInClassInitializer(ignoringImpCasts(memberExpr(
+  hasObjectExpression(cxxThisExpr()), member(hasName("c"));
+
+  MatchVerifier Verifier;
+  ASSERT_TRUE(Verifier.match(FromField, Pattern));
+  EXPECT_TRUE(Verifier.match(ToField, Pattern));
+}
+
+TEST_P(ASTImporterOptionSpecificTestBase, FieldCircularIndirectRef) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"s(
+static int ref_A();
+static int ref_B();
+struct A {
+  int a = ref_B();
+};
+struct B {
+  int b = ref_A();
+};
+int ref_B() { B b; return b.b; }
+int ref_A() { A a; return a.a; }
+  )s",
+  Lang_CXX11, "", Lang_CXX11, "A");
+
+  auto InitByRefB =
+  hasInClassInitializer(callExpr(callee(functionDecl(hasName("ref_B");
+  auto FieldAWithInit = has(fieldDecl(hasName("a"), InitByRefB));
+  auto Pattern =
+  cxxRecordDecl(hasName("A"), FieldAWithInit, hasFieldOrder({"a"}));
+  MatchVerifier Verifier;
+  ASSERT_TRUE(Verifier.match(From, Pattern));
+  EXPECT_TRUE(Verifier.match(To, Pattern));
+}
+
 TEST_P(ASTImporterOptionSpecificTestBase,
CXXRecordDeclFieldAndIndirectFieldOrder) {
   Decl *From, *To;
@@ -8028,6 +8106,45 @@
   Import(FromF, Lang_CXX11);
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase,
+   ImportCirularRefFieldsWithoutCorruptedRecordLayoutCacheTest) {
+  // Import sequence: A => A.b => B => B.f() => ... => UnaryOperator(&) => ...
+  //
+  // UnaryOperator(&) force computing RecordLayout of 'A' while it's still not
+  // completely imported.
+  auto Code =
+  R"(
+  class B;
+  class A {
+B* b;
+int c;
+  };
+  class B {
+A *f() { return &((B *)0)->a; }
+A a;
+  };
+  )";
+
+  auto *FromR = FirstDeclMatcher().match(
+  getTuDecl(Code, Lang_CXX11), cxxRecordDecl(hasName("A")));
+  FromR = FromR->getDefinition();
+  auto &FromAST = FromR->getASTContext();
+  auto *ToR = Import(FromR, Lang_CXX11);
+  auto &ToAST = ToR->getASTContext();
+
+  uint64_t SecondFieldOffset = FromAST.getTypeSize(FromAST.VoidPtrTy);
+
+  EXPECT_TRUE(FromR->isCompleteDefinition());
+  const auto &FromLayout = FromAST.getASTRecordLayout(FromR);
+  EXPECT_TRUE(FromLayout.getFieldOffset(0) == 0);
+  EXPECT_TRUE(FromLayout.getFieldOffset(1) == SecondFieldOffset);
+
+  EXPECT_TRUE(ToR->isCompleteDefinition());
+  const auto &ToLayout = ToAST.getASTRecordLayout(ToR);
+  EXPECT_TRUE(ToLayout.getFieldOffset(0) == 0);
+  EXPECT_TRUE(ToLayout.getFieldOffset(1) == SecondFieldOffset);
+}
+
 TEST_P(ASTImporterOptionSpecificTestBase,
ImportRecordWithLayoutRequestingExpr) {
   TranslationUnitDecl *FromTU = g

[PATCH] D155574: [clang][ASTImporter] Fix import of recursive field initializer.

2023-07-25 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/lib/AST/ASTImporter.cpp:3936-3937
+return std::move(Err);
+  if (ToInitializer)
+ToField->setInClassInitializer(ToInitializer);
   return ToField;

Initializer could indirectly depends on this field and set the initializer 
while importing.
`setInClassInitializer()` asserts that initializer should not be set more than 
once:

```
static int ref_A();
static int ref_B();
struct A {
  int a = ref_B();
};
struct B {
  int b = ref_A();
};
int ref_B() { B b; return b.b; }
int ref_A() { A a; return a.a; }
```


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155574

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


[PATCH] D156277: [Parser][ObjC] Stop parsing on eof

2023-07-25 Thread Ding Fei via Phabricator via cfe-commits
danix800 created this revision.
danix800 added a project: clang.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a subscriber: cfe-commits.

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


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D156277

Files:
  clang/lib/Parse/ParseObjc.cpp
  clang/test/Parser/gh64065-nocrash.m


Index: clang/test/Parser/gh64065-nocrash.m
===
--- /dev/null
+++ clang/test/Parser/gh64065-nocrash.m
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// expected-error@+4 {{missing '@end'}}
+// expected-note@+3 {{class started here}}
+// expected-error@+2 {{missing '@end'}}
+// expected-note@+1 {{class started here}}
+@interface Roo@interface
Index: clang/lib/Parse/ParseObjc.cpp
===
--- clang/lib/Parse/ParseObjc.cpp
+++ clang/lib/Parse/ParseObjc.cpp
@@ -745,7 +745,8 @@
   << FixItHint::CreateInsertion(AtLoc, "@end\n");
   Diag(CDecl->getBeginLoc(), diag::note_objc_container_start)
   << (int)Actions.getObjCContainerKind();
-  ConsumeToken();
+  if (!Tok.is(tok::eof))
+ConsumeToken();
   break;
 
 case tok::objc_required:


Index: clang/test/Parser/gh64065-nocrash.m
===
--- /dev/null
+++ clang/test/Parser/gh64065-nocrash.m
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// expected-error@+4 {{missing '@end'}}
+// expected-note@+3 {{class started here}}
+// expected-error@+2 {{missing '@end'}}
+// expected-note@+1 {{class started here}}
+@interface Roo@interface
Index: clang/lib/Parse/ParseObjc.cpp
===
--- clang/lib/Parse/ParseObjc.cpp
+++ clang/lib/Parse/ParseObjc.cpp
@@ -745,7 +745,8 @@
   << FixItHint::CreateInsertion(AtLoc, "@end\n");
   Diag(CDecl->getBeginLoc(), diag::note_objc_container_start)
   << (int)Actions.getObjCContainerKind();
-  ConsumeToken();
+  if (!Tok.is(tok::eof))
+ConsumeToken();
   break;
 
 case tok::objc_required:
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156201: [ASTImporter] Fix corrupted RecordLayout introduced by circular referenced fields

2023-07-25 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 544168.
danix800 added a comment.

Remove case #1 (fixed by https://reviews.llvm.org/D155574 from @balazske which 
is better).


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156201

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp


Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -10,6 +10,7 @@
 //
 
//===--===//
 
+#include "clang/AST/RecordLayout.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/Support/SmallVectorMemoryBuffer.h"
@@ -8028,6 +8029,45 @@
   Import(FromF, Lang_CXX11);
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase,
+   ImportCirularRefFieldsWithoutCorruptedRecordLayoutCacheTest) {
+  // Import sequence: A => A.b => B => B.f() => ... => UnaryOperator(&) => ...
+  //
+  // UnaryOperator(&) should not introduce invalid RecordLayout since 'A' is
+  // still not completely imported.
+  auto Code =
+  R"(
+  class B;
+  class A {
+B* b;
+int c;
+  };
+  class B {
+A *f() { return &((B *)0)->a; }
+A a;
+  };
+  )";
+
+  auto *FromR = FirstDeclMatcher().match(
+  getTuDecl(Code, Lang_CXX11), cxxRecordDecl(hasName("A")));
+  FromR = FromR->getDefinition();
+  auto &FromAST = FromR->getASTContext();
+  auto *ToR = Import(FromR, Lang_CXX11);
+  auto &ToAST = ToR->getASTContext();
+
+  uint64_t SecondFieldOffset = FromAST.getTypeSize(FromAST.VoidPtrTy);
+
+  EXPECT_TRUE(FromR->isCompleteDefinition());
+  const auto &FromLayout = FromAST.getASTRecordLayout(FromR);
+  EXPECT_TRUE(FromLayout.getFieldOffset(0) == 0);
+  EXPECT_TRUE(FromLayout.getFieldOffset(1) == SecondFieldOffset);
+
+  EXPECT_TRUE(ToR->isCompleteDefinition());
+  const auto &ToLayout = ToAST.getASTRecordLayout(ToR);
+  EXPECT_TRUE(ToLayout.getFieldOffset(0) == 0);
+  EXPECT_TRUE(ToLayout.getFieldOffset(1) == SecondFieldOffset);
+}
+
 TEST_P(ASTImporterOptionSpecificTestBase,
ImportRecordWithLayoutRequestingExpr) {
   TranslationUnitDecl *FromTU = getTuDecl(
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -7394,10 +7394,15 @@
   if (Err)
 return std::move(Err);
 
-  return UnaryOperator::Create(
-  Importer.getToContext(), ToSubExpr, E->getOpcode(), ToType,
-  E->getValueKind(), E->getObjectKind(), ToOperatorLoc, E->canOverflow(),
-  E->getFPOptionsOverride());
+  auto *UO = UnaryOperator::CreateEmpty(Importer.getToContext(),
+E->hasStoredFPFeatures());
+  UO->setType(ToType);
+  UO->setSubExpr(ToSubExpr);
+  UO->setOpcode(E->getOpcode());
+  UO->setOperatorLoc(ToOperatorLoc);
+  UO->setCanOverflow(E->canOverflow());
+
+  return UO;
 }
 
 ExpectedStmt


Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -10,6 +10,7 @@
 //
 //===--===//
 
+#include "clang/AST/RecordLayout.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/Support/SmallVectorMemoryBuffer.h"
@@ -8028,6 +8029,45 @@
   Import(FromF, Lang_CXX11);
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase,
+   ImportCirularRefFieldsWithoutCorruptedRecordLayoutCacheTest) {
+  // Import sequence: A => A.b => B => B.f() => ... => UnaryOperator(&) => ...
+  //
+  // UnaryOperator(&) should not introduce invalid RecordLayout since 'A' is
+  // still not completely imported.
+  auto Code =
+  R"(
+  class B;
+  class A {
+B* b;
+int c;
+  };
+  class B {
+A *f() { return &((B *)0)->a; }
+A a;
+  };
+  )";
+
+  auto *FromR = FirstDeclMatcher().match(
+  getTuDecl(Code, Lang_CXX11), cxxRecordDecl(hasName("A")));
+  FromR = FromR->getDefinition();
+  auto &FromAST = FromR->getASTContext();
+  auto *ToR = Import(FromR, Lang_CXX11);
+  auto &ToAST = ToR->getASTContext();
+
+  uint64_t SecondFieldOffset = FromAST.getTypeSize(FromAST.VoidPtrTy);
+
+  EXPECT_TRUE(FromR->isCompleteDefinition());
+  const auto &FromLayout = FromAST.getASTRecordLayout(FromR);
+  EXPECT_TRUE(FromLayout.getFieldOffset(0) == 0);
+  EXPECT_TRUE(FromLayout.getFieldOffset(1) == SecondFieldOffset);
+
+  EXPECT_TRUE(ToR->isCompleteDefinition());
+  const auto &ToLayout = ToAST.getASTRecordLayout(ToR);
+  EXPECT_TRUE(ToLayout.getFieldOffset(0) == 0);
+  EXPECT_TRUE(ToLayout.getFieldOffset(1) == SecondFieldOffset);
+}
+
 TEST_P

[PATCH] D156277: [Parser][ObjC] Stop parsing on eof

2023-07-26 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/lib/Parse/ParseObjc.cpp:749
+  if (!Tok.is(tok::eof))
+ConsumeToken();
   break;

tbaeder wrote:
> Why is there a `ConsumeToken()` call at all here? The token is already being 
> consumed in line 729.
Didn't notice this, thanks for reminding!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156277

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


[PATCH] D155574: [clang][ASTImporter] Fix import of recursive field initializer.

2023-07-26 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/lib/AST/ASTImporter.cpp:3936-3937
+return std::move(Err);
+  if (ToInitializer)
+ToField->setInClassInitializer(ToInitializer);
   return ToField;

balazske wrote:
> danix800 wrote:
> > Initializer could indirectly depends on this field and set the initializer 
> > while importing.
> > `setInClassInitializer()` asserts that initializer should not be set more 
> > than once:
> > 
> > ```
> > static int ref_A();
> > static int ref_B();
> > struct A {
> >   int a = ref_B();
> > };
> > struct B {
> >   int b = ref_A();
> > };
> > int ref_B() { B b; return b.b; }
> > int ref_A() { A a; return a.a; }
> > ```
> This example code really causes problems. But import of `Expr` is not checked 
> for recursion, the assertion in the new code fails for this test.
> 
> Why do you want to use such code? It looks to cause infinite loop when 
> executed. Even code like `class A { int b{b}; };` is probably not correct.
Like `int a{a};` this testcase is minimized to just show what might cause the 
problem.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155574

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


[PATCH] D156277: [Parser][ObjC] Stop parsing on eof

2023-07-27 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/lib/Parse/ParseObjc.cpp:749
+  if (!Tok.is(tok::eof))
+ConsumeToken();
   break;

rjmccall wrote:
> aaron.ballman wrote:
> > rjmccall wrote:
> > > aaron.ballman wrote:
> > > > aaron.ballman wrote:
> > > > > danix800 wrote:
> > > > > > tbaeder wrote:
> > > > > > > Why is there a `ConsumeToken()` call at all here? The token is 
> > > > > > > already being consumed in line 729.
> > > > > > Didn't notice this, thanks for reminding!
> > > > > I have the same question as @tbaeder -- what token is this intending 
> > > > > to consume? CC @rjmccall for Obj-C expertise
> > > > OH! This is consuming the identifier for the implementation/interface 
> > > > name itself. e.g.,
> > > > ```
> > > > @interface Frobble
> > > > ```
> > > > The consume on line 709 gets the `@`, the consume on line 729 gets the 
> > > > `interface`, and the consume on line 749 is getting the `Frobble`. That 
> > > > makes sense to me now.
> > > > 
> > > I don't think any language expertise is required here — just seems like a 
> > > straightforward bug on an error path that's probably not exercised all 
> > > that often.  Maybe somebody moved the `ConsumeToken` and forgot to fix 
> > > this case or something.
> > What concerns me about this fix is that we don't typically check whether 
> > the token is EOF or not before consuming; that's usually an anti-pattern, 
> > isn't it? Wouldn't it make sense for this to use 
> > `SkipUntil(tok::identifier)` instead?
> Okay, so now I can bring a little language expertise to bear. :)
> 
> We're in the middle of parsing an ObjC block (e.g. `@interface`), and we see 
> `@interface` or `@implementation`, which starts a new block.  You can never 
> nest these ObjC blocks, so the parser is reasonably assuming that the second 
> `@keyword` is an attempt to start a new block and the user just forgot to 
> terminate the last block with `@end`.  Unfortunately, the actual recovery 
> done by the parser doesn't seem to match the diagnostic and the fixit — it's 
> trying to swallow `@interface Foo` (or whatever) and then continue the loop 
> as if it were part of the current block, which is definitely not the right 
> thing to do.
> 
> The right way to recover here is to act like we actually saw `@end` and break 
> out of the loop, leaving `Tok` on the `@` so that the parser will pick up 
> parsing `@interface` normally after we return.  To do that, we just need to 
> get the ObjC keyword by peeking at the next token instead of consuming.
> 
> Also, we should take this recovery path on every `@` keyword that's only 
> allowed at the top level (so `@class`, `@compatibility_alias`, `@interface`, 
> `@implementation`, and `@protocol`).
It's really great to learn things here! I don't know two much about ObjC. I 
seached google trying to find some standard or specs for ObjC but only docs 
like tutorials teaching how to use it can be found, so I might not be able to 
give a good enough fix for this issue. I'll give it a try though.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156277

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


[PATCH] D156461: [clang][ASTImporter] Merge implicit ctors with definition

2023-07-27 Thread Ding Fei via Phabricator via cfe-commits
danix800 created this revision.
danix800 added a project: clang.
Herald added a subscriber: martong.
Herald added a reviewer: a.sidorin.
Herald added a reviewer: shafik.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a subscriber: cfe-commits.

Implicit ctors generated with definition should be merged into `To` context.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D156461

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp


Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -3175,6 +3175,38 @@
   testNoImportOf(cxxMethodDecl(hasName("f")), Code);
 }
 
+TEST_P(ImportImplicitMethods, MergeImplicitMethodWithDefinition) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"s(
+struct A {
+  A() : m() {}
+  int m;
+};
+
+A foo() { A a; return a; }
+A bar() { return {}; }
+  )s",
+  Lang_CXX17,
+  R"s(
+struct A {
+  A() : m() {}
+  int m;
+};
+  )s",
+  Lang_CXX17, "A");
+
+  MatchVerifier Verifier;
+  auto HasCopyCtor = has(cxxConstructorDecl(isCopyConstructor(), 
isImplicit()));
+  auto HasCtorInit =
+  hasAnyConstructorInitializer(cxxCtorInitializer(isMemberInitializer()));
+  auto HasMoveCtor =
+  has(cxxConstructorDecl(isMoveConstructor(), isImplicit(), HasCtorInit));
+  auto Pattern = cxxRecordDecl(HasCopyCtor, HasMoveCtor);
+  ASSERT_TRUE(Verifier.match(From, Pattern));
+  EXPECT_TRUE(Verifier.match(To, Pattern));
+}
+
 TEST_P(ASTImporterOptionSpecificTestBase, ImportOfEquivalentRecord) {
   Decl *ToR1;
   {
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -3734,9 +3734,14 @@
 
   // Connect the redecl chain.
   if (FoundByLookup) {
-auto *Recent = const_cast(
-  FoundByLookup->getMostRecentDecl());
-ToFunction->setPreviousDecl(Recent);
+//if (auto *Ctor = dyn_cast(D);
+//Ctor && Ctor->isImplicit())
+//  DC->removeDecl(FoundByLookup);
+//else {
+  auto *Recent =
+  const_cast(FoundByLookup->getMostRecentDecl());
+  ToFunction->setPreviousDecl(Recent);
+//}
 // FIXME Probably we should merge exception specifications.  E.g. In the
 // "To" context the existing function may have exception specification with
 // noexcept-unevaluated, while the newly imported function may have an


Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -3175,6 +3175,38 @@
   testNoImportOf(cxxMethodDecl(hasName("f")), Code);
 }
 
+TEST_P(ImportImplicitMethods, MergeImplicitMethodWithDefinition) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"s(
+struct A {
+  A() : m() {}
+  int m;
+};
+
+A foo() { A a; return a; }
+A bar() { return {}; }
+  )s",
+  Lang_CXX17,
+  R"s(
+struct A {
+  A() : m() {}
+  int m;
+};
+  )s",
+  Lang_CXX17, "A");
+
+  MatchVerifier Verifier;
+  auto HasCopyCtor = has(cxxConstructorDecl(isCopyConstructor(), isImplicit()));
+  auto HasCtorInit =
+  hasAnyConstructorInitializer(cxxCtorInitializer(isMemberInitializer()));
+  auto HasMoveCtor =
+  has(cxxConstructorDecl(isMoveConstructor(), isImplicit(), HasCtorInit));
+  auto Pattern = cxxRecordDecl(HasCopyCtor, HasMoveCtor);
+  ASSERT_TRUE(Verifier.match(From, Pattern));
+  EXPECT_TRUE(Verifier.match(To, Pattern));
+}
+
 TEST_P(ASTImporterOptionSpecificTestBase, ImportOfEquivalentRecord) {
   Decl *ToR1;
   {
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -3734,9 +3734,14 @@
 
   // Connect the redecl chain.
   if (FoundByLookup) {
-auto *Recent = const_cast(
-  FoundByLookup->getMostRecentDecl());
-ToFunction->setPreviousDecl(Recent);
+//if (auto *Ctor = dyn_cast(D);
+//Ctor && Ctor->isImplicit())
+//  DC->removeDecl(FoundByLookup);
+//else {
+  auto *Recent =
+  const_cast(FoundByLookup->getMostRecentDecl());
+  ToFunction->setPreviousDecl(Recent);
+//}
 // FIXME Probably we should merge exception specifications.  E.g. In the
 // "To" context the existing function may have exception specification with
 // noexcept-unevaluated, while the newly imported function may have an
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-com

[PATCH] D156461: [clang][ASTImporter] Merge implicit ctors with definition

2023-07-27 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 544854.
danix800 edited the summary of this revision.
Herald added a subscriber: pengfei.

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156461

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp


Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -3175,6 +3175,39 @@
   testNoImportOf(cxxMethodDecl(hasName("f")), Code);
 }
 
+TEST_P(ImportImplicitMethods, MergeImplicitMethodWithDefinition) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"s(
+struct A {
+  A() : m() {}
+  int m;
+};
+
+A foo() { A a; return a; }
+A bar() { return {}; }
+  )s",
+  Lang_CXX17,
+  R"s(
+struct A {
+  A() : m() {}
+  int m;
+};
+A baz() { return {}; }
+  )s",
+  Lang_CXX17, "A");
+
+  MatchVerifier Verifier;
+  auto HasCopyCtor = has(cxxConstructorDecl(isCopyConstructor(), 
isImplicit()));
+  auto HasCtorInit =
+  hasAnyConstructorInitializer(cxxCtorInitializer(isMemberInitializer()));
+  auto HasMoveCtor =
+  has(cxxConstructorDecl(isMoveConstructor(), isImplicit(), HasCtorInit));
+  auto Pattern = cxxRecordDecl(HasCopyCtor, HasMoveCtor);
+  ASSERT_TRUE(Verifier.match(From, Pattern));
+  EXPECT_TRUE(Verifier.match(To, Pattern));
+}
+
 TEST_P(ASTImporterOptionSpecificTestBase, ImportOfEquivalentRecord) {
   Decl *ToR1;
   {
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -3734,9 +3734,14 @@
 
   // Connect the redecl chain.
   if (FoundByLookup) {
-auto *Recent = const_cast(
-  FoundByLookup->getMostRecentDecl());
-ToFunction->setPreviousDecl(Recent);
+if (auto *Ctor = dyn_cast(D);
+Ctor && Ctor->isImplicit())
+  DC->removeDecl(FoundByLookup);
+else {
+  auto *Recent =
+  const_cast(FoundByLookup->getMostRecentDecl());
+  ToFunction->setPreviousDecl(Recent);
+}
 // FIXME Probably we should merge exception specifications.  E.g. In the
 // "To" context the existing function may have exception specification with
 // noexcept-unevaluated, while the newly imported function may have an


Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -3175,6 +3175,39 @@
   testNoImportOf(cxxMethodDecl(hasName("f")), Code);
 }
 
+TEST_P(ImportImplicitMethods, MergeImplicitMethodWithDefinition) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"s(
+struct A {
+  A() : m() {}
+  int m;
+};
+
+A foo() { A a; return a; }
+A bar() { return {}; }
+  )s",
+  Lang_CXX17,
+  R"s(
+struct A {
+  A() : m() {}
+  int m;
+};
+A baz() { return {}; }
+  )s",
+  Lang_CXX17, "A");
+
+  MatchVerifier Verifier;
+  auto HasCopyCtor = has(cxxConstructorDecl(isCopyConstructor(), isImplicit()));
+  auto HasCtorInit =
+  hasAnyConstructorInitializer(cxxCtorInitializer(isMemberInitializer()));
+  auto HasMoveCtor =
+  has(cxxConstructorDecl(isMoveConstructor(), isImplicit(), HasCtorInit));
+  auto Pattern = cxxRecordDecl(HasCopyCtor, HasMoveCtor);
+  ASSERT_TRUE(Verifier.match(From, Pattern));
+  EXPECT_TRUE(Verifier.match(To, Pattern));
+}
+
 TEST_P(ASTImporterOptionSpecificTestBase, ImportOfEquivalentRecord) {
   Decl *ToR1;
   {
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -3734,9 +3734,14 @@
 
   // Connect the redecl chain.
   if (FoundByLookup) {
-auto *Recent = const_cast(
-  FoundByLookup->getMostRecentDecl());
-ToFunction->setPreviousDecl(Recent);
+if (auto *Ctor = dyn_cast(D);
+Ctor && Ctor->isImplicit())
+  DC->removeDecl(FoundByLookup);
+else {
+  auto *Recent =
+  const_cast(FoundByLookup->getMostRecentDecl());
+  ToFunction->setPreviousDecl(Recent);
+}
 // FIXME Probably we should merge exception specifications.  E.g. In the
 // "To" context the existing function may have exception specification with
 // noexcept-unevaluated, while the newly imported function may have an
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D155661: [clang][ASTImporter] Fix friend class template import within dependent context

2023-07-27 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 544993.
danix800 retitled this revision from "[ASTImporter] Fix friend class template 
import within dependent context" to "[clang][ASTImporter] Fix friend class 
template import within dependent context".
danix800 added a comment.

Update ReleaseNotes


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155661

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -3968,8 +3968,31 @@
   EXPECT_EQ(ToDef->getPreviousDecl(), ToProto);
 }
 
-
-struct ImportFriendClasses : ASTImporterOptionSpecificTestBase {};
+struct ImportFriendClasses : ASTImporterOptionSpecificTestBase {
+  void testRecursiveFriendClassTemplate(Decl *FromTu) {
+auto *FromD = FirstDeclMatcher().match(
+FromTu, classTemplateDecl());
+auto *ToD = Import(FromD, Lang_CXX03);
+
+auto Pattern = classTemplateDecl(
+has(cxxRecordDecl(has(friendDecl(has(classTemplateDecl()));
+ASSERT_TRUE(MatchVerifier{}.match(FromD, Pattern));
+EXPECT_TRUE(MatchVerifier{}.match(ToD, Pattern));
+
+auto *FromFriend =
+FirstDeclMatcher().match(FromD, friendDecl());
+auto *FromClass =
+FirstDeclMatcher().match(FromD, classTemplateDecl());
+EXPECT_NE(FromFriend->getFriendDecl(), FromClass);
+EXPECT_TRUE(FromFriend->getFriendDecl()->getPreviousDecl() == nullptr);
+
+auto *Class =
+FirstDeclMatcher().match(ToD, classTemplateDecl());
+auto *Friend = FirstDeclMatcher().match(ToD, friendDecl());
+EXPECT_NE(Friend->getFriendDecl(), Class);
+EXPECT_TRUE(Friend->getFriendDecl()->getPreviousDecl() == nullptr);
+  }
+};
 
 TEST_P(ImportFriendClasses, ImportOfFriendRecordDoesNotMergeDefinition) {
   Decl *FromTU = getTuDecl(
@@ -4074,20 +4097,19 @@
   )",
   Lang_CXX03, "input.cc");
 
-  auto *FromD =
-  FirstDeclMatcher().match(FromTu, classTemplateDecl());
-  auto *ToD = Import(FromD, Lang_CXX03);
-
-  auto Pattern = classTemplateDecl(
-  has(cxxRecordDecl(has(friendDecl(has(classTemplateDecl()));
-  ASSERT_TRUE(MatchVerifier{}.match(FromD, Pattern));
-  EXPECT_TRUE(MatchVerifier{}.match(ToD, Pattern));
+  testRecursiveFriendClassTemplate(FromTu);
+}
 
-  auto *Class =
-  FirstDeclMatcher().match(ToD, classTemplateDecl());
-  auto *Friend = FirstDeclMatcher().match(ToD, friendDecl());
-  EXPECT_NE(Friend->getFriendDecl(), Class);
-  EXPECT_EQ(Friend->getFriendDecl()->getPreviousDecl(), Class);
+TEST_P(ImportFriendClasses,
+   ImportOfRecursiveFriendClassTemplateWithNonTypeParm) {
+  Decl *FromTu = getTuDecl(
+  R"(
+  template class declToImport {
+template friend class declToImport;
+  };
+  )",
+  Lang_CXX03, "input.cc");
+  testRecursiveFriendClassTemplate(FromTu);
 }
 
 TEST_P(ImportFriendClasses, ProperPrevDeclForClassTemplateDecls) {
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -2857,6 +2857,10 @@
   } else if (Importer.getToContext().getLangOpts().CPlusPlus)
 IDNS |= Decl::IDNS_Ordinary | Decl::IDNS_TagFriend;
 
+  bool IsDependentContext = DC != LexicalDC ? LexicalDC->isDependentContext()
+: DC->isDependentContext();
+  bool ShouldAddRedecl = !(IsFriendTemplate && IsDependentContext);
+
   // We may already have a record of the same name; try to find and match it.
   RecordDecl *PrevDecl = nullptr;
   if (!DC->isFunctionOrMethod() && !D->isLambda()) {
@@ -2897,7 +2901,7 @@
 if (!hasSameVisibilityContextAndLinkage(FoundRecord, D))
   continue;
 
-if (IsStructuralMatch(D, FoundRecord)) {
+if (IsFriendTemplate || IsStructuralMatch(D, FoundRecord)) {
   RecordDecl *FoundDef = FoundRecord->getDefinition();
   if (D->isThisDeclarationADefinition() && FoundDef) {
 // FIXME: Structural equivalence check should check for same
@@ -2955,7 +2959,7 @@
 return CDeclOrErr.takeError();
   Numbering.ContextDecl = *CDeclOrErr;
   D2CXX->setLambdaNumbering(Numbering);
-   } else if (DCXX->isInjectedClassName()) {
+} else if (DCXX->isInjectedClassName()) {
   // We have to be careful to do a similar dance to the one in
   // Sema::ActOnStartCXXMemberDeclarations
   const bool DelayTypeCreation = true;
@@ -2967,10 +2971,11 @@
   Importer.getToContext().getTypeDeclType(
   D2CXX, dyn_cast(DC));
 } else {
-  if (GetImportedOrCreateDecl(D2CXX, D, Importer.getToContext(),
-  D->getTagKind(), DC, *BeginLocOrErr, Loc,
-  Na

[PATCH] D156093: [ASTImporter] Re-odering by lexical order for all imported decls within record

2023-07-27 Thread Ding Fei via Phabricator via cfe-commits
danix800 added a comment.

After thought a little bit more I'm doubting whether this lexical ordering is 
of any practical usage or any meanfullness at all,
especially when imported into existing (non-empty) context, reordering by 
`From` context can not be correct after merging
occured.

I need more comment on this before I close this.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156093

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


[PATCH] D154764: [ASTImporter] Fields are imported first and reordered for correct layout.

2023-07-27 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/unittests/AST/ASTImporterTest.cpp:8018
+int m() {
+  return &((A *)0)->f1 - &((A *)0)->f2;
+}

shafik wrote:
> So is it the case that this caused `f2` to be imported first and then `f1`? 
> Which is the opposite of the example in the comments:
> 
> ```
>  struct declToImport {
>   int a = c + b;
>   int b = 1;
>   int c = 2;
>   };
> ```
> 
> which causes the order to be c, b and then a.
The issue caused by this case
```
int m() {
   return &((A *)0)->f1 - &((A *)0)->f2;
}
int f1;
int f2;
```
is that before fixing, method `m` is imported first, which triggers expr 
(UnaryOperator) dependency computation, further relies on the correct 
RecordLayout of `declToImport`, but `f1` & `f2` is not imported at this moment.

This is not the opposite to the case like `int a = c + b;`, but both are caused 
by circular refs.

Similar record layout issue will also be triggered like:
```
class B;
class A {
  B* b;
  int c;
};
class B {
   A *f() { return &((B *)0)->a; }
   A a;
};
```
https://reviews.llvm.org/D156201 removes the unnecessary record layout as 
another fix to this kind of circular refs
(which cannot be fixed simply by re-adjusting import ordering).




Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D154764

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


[PATCH] D156201: [ASTImporter] Fix corrupted RecordLayout introduced by circular referenced fields

2023-07-27 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/lib/AST/ASTImporter.cpp:7403
+  UO->setOperatorLoc(ToOperatorLoc);
+  UO->setCanOverflow(E->canOverflow());
+

shafik wrote:
> I don't see the following values from the old code used: `E->getValueKind()`, 
> `E->getObjectKind()` and `E->getFPOptionsOverride()`
These three values are set for all Exprs in `Import(Stmt *FromS)`:

```
Expected ASTImporter::Import(Stmt *FromS) {
  // ...
  if (auto *ToE = dyn_cast(*ToSOrErr)) {
auto *FromE = cast(FromS);
// Copy ExprBitfields, which may not be handled in Expr subclasses
// constructors.
ToE->setValueKind(FromE->getValueKind());
ToE->setObjectKind(FromE->getObjectKind());
ToE->setDependence(FromE->getDependence());
  }
  // ...
}
```


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156201

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


[PATCH] D154764: [ASTImporter] Fields are imported first and reordered for correct layout.

2023-07-27 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/unittests/AST/ASTImporterTest.cpp:8018
+int m() {
+  return &((A *)0)->f1 - &((A *)0)->f2;
+}

danix800 wrote:
> shafik wrote:
> > So is it the case that this caused `f2` to be imported first and then `f1`? 
> > Which is the opposite of the example in the comments:
> > 
> > ```
> >  struct declToImport {
> >   int a = c + b;
> >   int b = 1;
> >   int c = 2;
> >   };
> > ```
> > 
> > which causes the order to be c, b and then a.
> The issue caused by this case
> ```
> int m() {
>return &((A *)0)->f1 - &((A *)0)->f2;
> }
> int f1;
> int f2;
> ```
> is that before fixing, method `m` is imported first, which triggers expr 
> (UnaryOperator) dependency computation, further relies on the correct 
> RecordLayout of `declToImport`, but `f1` & `f2` is not imported at this 
> moment.
> 
> This is not the opposite to the case like `int a = c + b;`, but both are 
> caused by circular refs.
> 
> Similar record layout issue will also be triggered like:
> ```
> class B;
> class A {
>   B* b;
>   int c;
> };
> class B {
>A *f() { return &((B *)0)->a; }
>A a;
> };
> ```
> https://reviews.llvm.org/D156201 removes the unnecessary record layout as 
> another fix to this kind of circular refs
> (which cannot be fixed simply by re-adjusting import ordering).
> 
> 
Sorry for typos, they are both import ordering issues (not circular ref issues).


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D154764

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


[PATCH] D156201: [ASTImporter] Fix corrupted RecordLayout introduced by circular referenced fields

2023-07-27 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/lib/AST/ASTImporter.cpp:7403
+  UO->setOperatorLoc(ToOperatorLoc);
+  UO->setCanOverflow(E->canOverflow());
+

danix800 wrote:
> shafik wrote:
> > I don't see the following values from the old code used: 
> > `E->getValueKind()`, `E->getObjectKind()` and `E->getFPOptionsOverride()`
> These three values are set for all Exprs in `Import(Stmt *FromS)`:
> 
> ```
> Expected ASTImporter::Import(Stmt *FromS) {
>   // ...
>   if (auto *ToE = dyn_cast(*ToSOrErr)) {
> auto *FromE = cast(FromS);
> // Copy ExprBitfields, which may not be handled in Expr subclasses
> // constructors.
> ToE->setValueKind(FromE->getValueKind());
> ToE->setObjectKind(FromE->getObjectKind());
> ToE->setDependence(FromE->getDependence());
>   }
>   // ...
> }
> ```
Oh only the first two are set, `FPOptionsOverride` is missing! I'll fix that.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156201

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


[PATCH] D156201: [ASTImporter] Fix corrupted RecordLayout introduced by circular referenced fields

2023-07-27 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 545016.
danix800 added a comment.

Add missing field value setting (`FPOptionsOverride`).


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156201

Files:
  clang/include/clang/AST/Expr.h
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp


Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -10,6 +10,7 @@
 //
 
//===--===//
 
+#include "clang/AST/RecordLayout.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/Support/SmallVectorMemoryBuffer.h"
@@ -8028,6 +8029,45 @@
   Import(FromF, Lang_CXX11);
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase,
+   ImportCirularRefFieldsWithoutCorruptedRecordLayoutCacheTest) {
+  // Import sequence: A => A.b => B => B.f() => ... => UnaryOperator(&) => ...
+  //
+  // UnaryOperator(&) should not introduce invalid RecordLayout since 'A' is
+  // still not completely imported.
+  auto Code =
+  R"(
+  class B;
+  class A {
+B* b;
+int c;
+  };
+  class B {
+A *f() { return &((B *)0)->a; }
+A a;
+  };
+  )";
+
+  auto *FromR = FirstDeclMatcher().match(
+  getTuDecl(Code, Lang_CXX11), cxxRecordDecl(hasName("A")));
+  FromR = FromR->getDefinition();
+  auto &FromAST = FromR->getASTContext();
+  auto *ToR = Import(FromR, Lang_CXX11);
+  auto &ToAST = ToR->getASTContext();
+
+  uint64_t SecondFieldOffset = FromAST.getTypeSize(FromAST.VoidPtrTy);
+
+  EXPECT_TRUE(FromR->isCompleteDefinition());
+  const auto &FromLayout = FromAST.getASTRecordLayout(FromR);
+  EXPECT_TRUE(FromLayout.getFieldOffset(0) == 0);
+  EXPECT_TRUE(FromLayout.getFieldOffset(1) == SecondFieldOffset);
+
+  EXPECT_TRUE(ToR->isCompleteDefinition());
+  const auto &ToLayout = ToAST.getASTRecordLayout(ToR);
+  EXPECT_TRUE(ToLayout.getFieldOffset(0) == 0);
+  EXPECT_TRUE(ToLayout.getFieldOffset(1) == SecondFieldOffset);
+}
+
 TEST_P(ASTImporterOptionSpecificTestBase,
ImportRecordWithLayoutRequestingExpr) {
   TranslationUnitDecl *FromTU = getTuDecl(
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -7405,10 +7405,17 @@
   if (Err)
 return std::move(Err);
 
-  return UnaryOperator::Create(
-  Importer.getToContext(), ToSubExpr, E->getOpcode(), ToType,
-  E->getValueKind(), E->getObjectKind(), ToOperatorLoc, E->canOverflow(),
-  E->getFPOptionsOverride());
+  auto *UO = UnaryOperator::CreateEmpty(Importer.getToContext(),
+E->hasStoredFPFeatures());
+  UO->setType(ToType);
+  UO->setSubExpr(ToSubExpr);
+  UO->setOpcode(E->getOpcode());
+  UO->setOperatorLoc(ToOperatorLoc);
+  UO->setCanOverflow(E->canOverflow());
+  if (E->hasStoredFPFeatures())
+UO->setStoredFPFeatures(E->getStoredFPFeatures());
+
+  return UO;
 }
 
 ExpectedStmt
Index: clang/include/clang/AST/Expr.h
===
--- clang/include/clang/AST/Expr.h
+++ clang/include/clang/AST/Expr.h
@@ -2340,8 +2340,7 @@
 return getTrailingFPFeatures();
   }
 
-protected:
-  /// Set FPFeatures in trailing storage, used only by Serialization
+  /// Set FPFeatures in trailing storage, used by Serialization & ASTImporter
   void setStoredFPFeatures(FPOptionsOverride F) { getTrailingFPFeatures() = F; 
}
 
 public:


Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -10,6 +10,7 @@
 //
 //===--===//
 
+#include "clang/AST/RecordLayout.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/Support/SmallVectorMemoryBuffer.h"
@@ -8028,6 +8029,45 @@
   Import(FromF, Lang_CXX11);
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase,
+   ImportCirularRefFieldsWithoutCorruptedRecordLayoutCacheTest) {
+  // Import sequence: A => A.b => B => B.f() => ... => UnaryOperator(&) => ...
+  //
+  // UnaryOperator(&) should not introduce invalid RecordLayout since 'A' is
+  // still not completely imported.
+  auto Code =
+  R"(
+  class B;
+  class A {
+B* b;
+int c;
+  };
+  class B {
+A *f() { return &((B *)0)->a; }
+A a;
+  };
+  )";
+
+  auto *FromR = FirstDeclMatcher().match(
+  getTuDecl(Code, Lang_CXX11), cxxRecordDecl(hasName("A")));
+  FromR = FromR->getDefinition();
+  auto &FromAST = FromR->getASTContext();
+  auto *ToR = Import(FromR, Lang

[PATCH] D157114: [clang][ASTImporter] Improve StructuralEquivalence algorithm on repeated friends

2023-08-10 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 549059.
danix800 added a comment.

`CXXRecordDecl::friend_iterator` is actually a reversed iterator. Deduplication 
with
different iterator direction produces different result. ASTImporter uses 
forward iterator
so structural equivalence checking should be in consistent with that.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157114

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/lib/AST/ASTStructuralEquivalence.cpp
  clang/unittests/AST/ASTImporterTest.cpp
  clang/unittests/AST/StructuralEquivalenceTest.cpp

Index: clang/unittests/AST/StructuralEquivalenceTest.cpp
===
--- clang/unittests/AST/StructuralEquivalenceTest.cpp
+++ clang/unittests/AST/StructuralEquivalenceTest.cpp
@@ -833,7 +833,18 @@
   auto t = makeNamedDecls("struct foo { friend class X; };",
   "struct foo { friend class X; friend class X; };",
   Lang_CXX11);
-  EXPECT_FALSE(testStructuralMatch(t));
+  EXPECT_TRUE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceRecordTest,
+   SameFriendMultipleTimesForwardIteratorDirection) {
+  // Deduplication with forward iterator produces the same 'foo', but reverse
+  // iterator doesn't.
+  auto t = makeNamedDecls(
+  "struct foo { friend class X; friend class Y;};",
+  "struct foo { friend class X; friend class Y; friend class X; };",
+  Lang_CXX11);
+  EXPECT_TRUE(testStructuralMatch(t));
 }
 
 TEST_F(StructuralEquivalenceRecordTest, SameFriendsDifferentOrder) {
Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -10,6 +10,7 @@
 //
 //===--===//
 
+#include "clang/AST/ASTStructuralEquivalence.h"
 #include "clang/AST/RecordLayout.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "llvm/ADT/StringMap.h"
@@ -4385,6 +4386,44 @@
   EXPECT_EQ(ToFriend2, ToImportedFriend2);
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase, ImportRepeatedFriendDeclIntoEmptyDC) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(R"(
+  template 
+  class A {
+  public:
+template  friend A &f();
+template  friend A &f();
+  };
+  )",
+   Lang_CXX17, "", Lang_CXX17, "A");
+
+  auto *FromFriend1 = FirstDeclMatcher().match(From, friendDecl());
+  auto *FromFriend2 = LastDeclMatcher().match(From, friendDecl());
+  auto *ToFriend1 = FirstDeclMatcher().match(To, friendDecl());
+  auto *ToFriend2 = LastDeclMatcher().match(To, friendDecl());
+
+  // Two different FriendDecls in From context.
+  EXPECT_TRUE(FromFriend1 != FromFriend2);
+  // Only one is imported into empty DC.
+  EXPECT_TRUE(ToFriend1 == ToFriend2);
+
+  // 'A' is imported into empty DC, keeping structure equivalence.
+  llvm::DenseSet> NonEquivalentDecls01;
+  llvm::DenseSet> NonEquivalentDecls10;
+  StructuralEquivalenceContext Ctx01(
+  From->getASTContext(), To->getASTContext(), NonEquivalentDecls01,
+  StructuralEquivalenceKind::Default, false, false);
+  StructuralEquivalenceContext Ctx10(
+  To->getASTContext(), From->getASTContext(), NonEquivalentDecls10,
+  StructuralEquivalenceKind::Default, false, false);
+
+  bool Eq01 = Ctx01.IsEquivalent(From, To);
+  bool Eq10 = Ctx10.IsEquivalent(To, From);
+  EXPECT_EQ(Eq01, Eq10);
+  EXPECT_TRUE(Eq01);
+}
+
 TEST_P(ASTImporterOptionSpecificTestBase, FriendFunInClassTemplate) {
   auto *Code = R"(
   template 
Index: clang/lib/AST/ASTStructuralEquivalence.cpp
===
--- clang/lib/AST/ASTStructuralEquivalence.cpp
+++ clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -1464,6 +1464,165 @@
   return IsStructurallyEquivalent(GetName(D1), GetName(D2));
 }
 
+static bool
+IsCXXRecordBaseStructurallyEquivalent(StructuralEquivalenceContext &Context,
+  RecordDecl *D1, RecordDecl *D2) {
+  auto *D1CXX = cast(D1);
+  auto *D2CXX = cast(D2);
+
+  if (D1CXX->getNumBases() != D2CXX->getNumBases()) {
+if (Context.Complain) {
+  Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
+   diag::err_odr_tag_type_inconsistent))
+  << Context.ToCtx.getTypeDeclType(D2);
+  Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)
+  << D2CXX->getNumBases();
+  Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases)
+  << D1CXX->getNumBases();
+}
+return false;
+  }
+
+  for (CXXRecordDecl::base_class_iterator Base1 = D1CXX->bases_begin(),
+  BaseEnd1 = D1CXX->bases_end(),
+  Base2 

[PATCH] D157637: [ASTImporter][NFC] Fix typo in testcase

2023-08-10 Thread Ding Fei via Phabricator via cfe-commits
danix800 created this revision.
danix800 added a reviewer: balazske.
Herald added a subscriber: martong.
Herald added a reviewer: a.sidorin.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Fix typo in testcase.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D157637

Files:
  clang/unittests/AST/StructuralEquivalenceTest.cpp


Index: clang/unittests/AST/StructuralEquivalenceTest.cpp
===
--- clang/unittests/AST/StructuralEquivalenceTest.cpp
+++ clang/unittests/AST/StructuralEquivalenceTest.cpp
@@ -992,8 +992,8 @@
 
 TEST_F(StructuralEquivalenceRecordContextTest, NamespaceInlineTopLevel) {
   auto Decls =
-  makeNamedDecls("inline namespace A { class X; } }",
- "inline namespace B { class X; } }", Lang_CXX17, "X");
+  makeNamedDecls("inline namespace A { class X; }",
+ "inline namespace B { class X; }", Lang_CXX17, "X");
   EXPECT_TRUE(testStructuralMatch(Decls));
 }
 


Index: clang/unittests/AST/StructuralEquivalenceTest.cpp
===
--- clang/unittests/AST/StructuralEquivalenceTest.cpp
+++ clang/unittests/AST/StructuralEquivalenceTest.cpp
@@ -992,8 +992,8 @@
 
 TEST_F(StructuralEquivalenceRecordContextTest, NamespaceInlineTopLevel) {
   auto Decls =
-  makeNamedDecls("inline namespace A { class X; } }",
- "inline namespace B { class X; } }", Lang_CXX17, "X");
+  makeNamedDecls("inline namespace A { class X; }",
+ "inline namespace B { class X; }", Lang_CXX17, "X");
   EXPECT_TRUE(testStructuralMatch(Decls));
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D157684: [clang][ASTImporter] Repeated friend templates are partially imported

2023-08-11 Thread Ding Fei via Phabricator via cfe-commits
danix800 created this revision.
danix800 added reviewers: balazske, aaron.ballman.
danix800 added a project: clang.
Herald added subscribers: pengfei, martong, kristof.beyls.
Herald added a reviewer: a.sidorin.
Herald added a reviewer: shafik.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a subscriber: cfe-commits.

1. Repeated friends of template class/function in template class are partially 
imported:

  template 
  class Container {
template  friend void m();
template  friend void m();
  };

Only one `m` can be imported,

`FromTu`:

  ClassTemplateDecl 0x5590cff47ae0  line:3:15 Container
  |-TemplateTypeParmDecl 0x5590cff47990  col:25 class depth 
0 index 0 T
  `-CXXRecordDecl 0x5590cff47a50  line:3:15 class Container 
definition
|-DefinitionData empty aggregate standard_layout trivially_copyable pod 
trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
| |-DefaultConstructor exists trivial constexpr needs_implicit 
defaulted_is_constexpr
| |-CopyConstructor simple trivial has_const_param needs_implicit 
implicit_has_const_param
| |-MoveConstructor exists simple trivial needs_implicit
| |-CopyAssignment simple trivial has_const_param needs_implicit 
implicit_has_const_param
| |-MoveAssignment exists simple trivial needs_implicit
| `-Destructor simple irrelevant trivial needs_implicit
|-CXXRecordDecl 0x5590cff47d30  col:15 implicit class 
Container
|-FriendDecl 0x5590cff48048  col:42
| `-FunctionTemplateDecl 0x5590cff47f80 parent 0x5590cfefeda8  col:42 m
|   |-TemplateTypeParmDecl 0x5590cff47dc0  col:27 class 
depth 1 index 0 U
|   `-FunctionDecl 0x5590cff47ec8 parent 0x5590cfefeda8  
col:42 m 'void ()'
`-FriendDecl 0x5590cff48260  col:42
  `-FunctionTemplateDecl 0x5590cff481f8 parent 0x5590cfefeda8  col:42 m
|-TemplateTypeParmDecl 0x5590cff48088  col:27 class 
depth 1 index 0 U
`-FunctionDecl 0x5590cff48140 parent 0x5590cfefeda8  
col:42 m 'void ()'

`ToTu`:

  ClassTemplateDecl 0x5590cffe3ad8  line:3:15 Container
  |-TemplateTypeParmDecl 0x5590cffe3950  col:25 class depth 
0 index 0 T
  `-CXXRecordDecl 0x5590cffe3a10  line:3:15 class Container 
definition
|-DefinitionData empty aggregate standard_layout trivially_copyable pod 
trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
| |-DefaultConstructor exists trivial constexpr needs_implicit 
defaulted_is_constexpr
| |-CopyConstructor simple trivial has_const_param needs_implicit 
implicit_has_const_param
| |-MoveConstructor exists simple trivial needs_implicit
| |-CopyAssignment simple trivial has_const_param needs_implicit 
implicit_has_const_param
| |-MoveAssignment exists simple trivial needs_implicit
| `-Destructor simple irrelevant trivial needs_implicit
|-FunctionTemplateDecl 0x5590cffe3ef8 parent 0x5590cff9b128  col:42 m // extranous node
| |-TemplateTypeParmDecl 0x5590cffe3d20  col:27 class depth 
1 index 0 U
| `-FunctionDecl 0x5590cffe3e28 parent 0x5590cff9b128  
col:42 m 'void ()'
|-FriendDecl 0x5590cffe3f60  col:42
| `-FunctionTemplateDecl 0x5590cffe3ef8 parent 0x5590cff9b128  col:42 m
|   |-TemplateTypeParmDecl 0x5590cffe3d20  col:27 class 
depth 1 index 0 U
|   `-FunctionDecl 0x5590cffe3e28 parent 0x5590cff9b128  
col:42 m 'void ()'
`-CXXRecordDecl 0x5590cffe3fa0  col:15 implicit class 
Container

Also note that an extranous `FunctionTemplateDecl 0x5590cffe3ef8` is added into 
this `ClassTemplateDecl 0x5590cffe3ad8` lexical context, which
renders it NOT identical to the original DeclContext, even after the second 
friend is successfully imported, this extra node would crash 
`clang-import-test`.
Plan to fix it in another revision.

2. Import single friend node `m` into existing context would crash with an 
assertion failure:

  ./build/tools/clang/unittests/AST/ASTTests 
--gtest_filter="*ImportFriendClasses.ImportOfRepeatedFriendFunctionTemplateDecl*"
 |& sed 's/danis/x/'
  Note: Google Test filter = 
*ImportFriendClasses.ImportOfRepeatedFriendFunctionTemplateDecl*
  [==] Running 4 tests from 1 test suite.
  [--] Global test environment set-up.
  [--] 4 tests from ParameterizedTests/ImportFriendClasses
  [ RUN  ] 
ParameterizedTests/ImportFriendClasses.ImportOfRepeatedFriendFunctionTemplateDecl/0
  ASTTests: 
/home/x/Sources/llvm-project-main/clang/lib/AST/ASTImporter.cpp:4139: 
clang::ExpectedDecl clang::ASTNodeImporter::VisitFriendDecl(clang::FriendDecl 
*): Assertion `ImportedEquivalentFriends.size() <= CountAndPosition.TotalCount 
&& "Class with non-matching friends is imported, ODR check wrong?"' failed.
   #0 0x7f1f53bf812a llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) 
/home/x/Sources/llvm-project-main/llvm/lib/Support/Unix/Signals.inc:602:11
   #1 0x7f1f53bf82db PrintStackTraceSignalHandler(void*) 
/home/x/Sources/llvm-project-main/llvm/lib/Support/Uni

[PATCH] D157684: [clang][ASTImporter] Repeated friend templates are partially imported

2023-08-11 Thread Ding Fei via Phabricator via cfe-commits
danix800 added a comment.

By `FromContext` dump it's easy to observe that there're two different 
`FunctionTemplateDecl` (`0x5590cff48048` and `0x5590cff481f8`):

  |-FriendDecl 0x5590cff48048  col:42
  | `-FunctionTemplateDecl 0x5590cff47f80 parent 0x5590cfefeda8  col:42 m
  |   |-...
  `-FriendDecl 0x5590cff48260  col:42
`-FunctionTemplateDecl 0x5590cff481f8 parent 0x5590cfefeda8  col:42 m
  |-...


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157684

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


[PATCH] D157691: [ASTImporter] Remove extranous FunctionTemplateDecl introduced by templated friend

2023-08-11 Thread Ding Fei via Phabricator via cfe-commits
danix800 created this revision.
danix800 added reviewers: balazske, aaron.ballman.
danix800 added a project: clang.
Herald added subscribers: pengfei, martong, kristof.beyls.
Herald added a reviewer: a.sidorin.
Herald added a reviewer: shafik.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a subscriber: cfe-commits.

An extranous `FunctionTemplateDecl` is introduced in the following testcase:

  template  struct A {
template  friend void f();
  };

`From`:

  ClassTemplateDecl 0x55dae7001500  col:30 A
  |-TemplateTypeParmDecl 0x55dae70013b0  col:20 typename depth 
0 index 0 T
  `-CXXRecordDecl 0x55dae7001470  col:30 struct A definition
|-DefinitionData empty aggregate standard_layout trivially_copyable pod 
trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
| |-DefaultConstructor exists trivial constexpr needs_implicit 
defaulted_is_constexpr
| |-CopyConstructor simple trivial has_const_param needs_implicit 
implicit_has_const_param
| |-MoveConstructor exists simple trivial needs_implicit
| |-CopyAssignment simple trivial has_const_param needs_implicit 
implicit_has_const_param
| |-MoveAssignment exists simple trivial needs_implicit
| `-Destructor simple irrelevant trivial needs_implicit
|-CXXRecordDecl 0x55dae7001750  col:30 implicit struct A
`-FriendDecl 0x55dae7001a68  col:69
  `-FunctionTemplateDecl 0x55dae70019a0 parent 0x55dae6f97e28  col:69 f
|-TemplateTypeParmDecl 0x55dae70017e0  col:54 typename 
depth 1 index 0 U
`-FunctionDecl 0x55dae70018e8 parent 0x55dae6f97e28  
col:69 f 'void ()'

`To`:

  ClassTemplateDecl 0x55dae7116618  col:30 A
  |-TemplateTypeParmDecl 0x55dae7116490  col:20 typename depth 
0 index 0 T
  `-CXXRecordDecl 0x55dae7116550  col:30 struct A definition
|-DefinitionData empty aggregate standard_layout trivially_copyable pod 
trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
| |-DefaultConstructor exists trivial constexpr needs_implicit 
defaulted_is_constexpr
| |-CopyConstructor simple trivial has_const_param needs_implicit 
implicit_has_const_param
| |-MoveConstructor exists simple trivial needs_implicit
| |-CopyAssignment simple trivial has_const_param needs_implicit 
implicit_has_const_param
| |-MoveAssignment exists simple trivial needs_implicit
| `-Destructor simple irrelevant trivial needs_implicit
|-FunctionTemplateDecl 0x55dae7116a38 parent 0x55dae6fa2b68  col:69 f// extranous node
| |-TemplateTypeParmDecl 0x55dae7116860  col:54 typename 
depth 1 index 0 U
| `-FunctionDecl 0x55dae7116968 parent 0x55dae6fa2b68  
col:69 f 'void ()'
|-FriendDecl 0x55dae7116aa0  col:69
| `-FunctionTemplateDecl 0x55dae7116a38 parent 0x55dae6fa2b68  col:69 f
|   |-TemplateTypeParmDecl 0x55dae7116860  col:54 typename 
depth 1 index 0 U
|   `-FunctionDecl 0x55dae7116968 parent 0x55dae6fa2b68  
col:69 f 'void ()'
`-CXXRecordDecl 0x55dae7116ae0  col:30 implicit struct A

`clang-import-test` would crash on this case:

  clang-import-test: 
/home/x/Sources/llvm-project-main/clang/lib/AST/ExternalASTMerger.cpp:533: 
auto clang::ExternalASTMerger::FindExternalLexicalDecls(const 
clang::DeclContext *, llvm::function_ref, 
SmallVectorImpl &)::(anonymous 
class)::operator()(clang::ASTImporter &, clang::ASTImporter &, Source) const: Assertion `!(*ImportedDeclOrErr) || 
IsSameDC((*ImportedDeclOrErr)->getDeclContext(), DC)' failed.
  f #0 0x7fec39df812a llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) 
/home/x/Sources/llvm-project-main/llvm/lib/Support/Unix/Signals.inc:602:11
   #1 0x7fec39df82db PrintStackTraceSignalHandler(void*) 
/home/x/Sources/llvm-project-main/llvm/lib/Support/Unix/Signals.inc:675:1
   #2 0x7fec39df6846 llvm::sys::RunSignalHandlers() 
/home/x/Sources/llvm-project-main/llvm/lib/Support/Signals.cpp:104:5
   #3 0x7fec39df8af5 SignalHandler(int) 
/home/x/Sources/llvm-project-main/llvm/lib/Support/Unix/Signals.inc:413:1
   #4 0x7fec3985afd0 (/lib/x86_64-linux-gnu/libc.so.6+0x3bfd0)
   #5 0x7fec398a9d3c __pthread_kill_implementation 
./nptl/pthread_kill.c:44:76
   #6 0x7fec3985af32 raise ./signal/../sysdeps/posix/raise.c:27:6
   #7 0x7fec39845472 abort ./stdlib/abort.c:81:7
   #8 0x7fec39845395 _nl_load_domain ./intl/loadmsgcat.c:1177:9
   #9 0x7fec39853e32 (/lib/x86_64-linux-gnu/libc.so.6+0x34e32)
  #10 0x7fec3c90c203 
clang::ExternalASTMerger::FindExternalLexicalDecls(clang::DeclContext const*, 
llvm::function_ref, 
llvm::SmallVectorImpl&)::$_5::operator()(clang::ASTImporter&, 
clang::ASTImporter&, (anonymous namespace)::Source) 
const 
/home/x/Sources/llvm-project-main/clang/lib/AST/ExternalASTMerger.cpp:532:11
  #11 0x7fec3c9094a7 void 
clang::ExternalASTMerger::ForEachMatchingDC, 
llvm::SmallVectorImpl&)::$_5>(clang::DeclContext const*, 
clang::ExternalASTMerger::FindExternalLexicalDecls

[PATCH] D157684: [clang][ASTImporter] Repeated friend templates are partially imported

2023-08-11 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 549376.
danix800 added a comment.

Apply git-clang-format.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157684

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -4054,6 +4054,25 @@
  ->lookup(ToRecordOfFriend->getDeclName())
  .empty());
   }
+
+  void testRepeatedFriendImport(const char *Code) {
+Decl *ToTu = getToTuDecl(Code, Lang_CXX03);
+Decl *FromTu = getTuDecl(Code, Lang_CXX03, "from.cc");
+
+auto *ToFriend1 = FirstDeclMatcher().match(ToTu, friendDecl());
+auto *ToFriend2 = LastDeclMatcher().match(ToTu, friendDecl());
+auto *FromFriend1 =
+FirstDeclMatcher().match(FromTu, friendDecl());
+auto *FromFriend2 =
+LastDeclMatcher().match(FromTu, friendDecl());
+
+FriendDecl *ToImportedFriend1 = Import(FromFriend1, Lang_CXX03);
+FriendDecl *ToImportedFriend2 = Import(FromFriend2, Lang_CXX03);
+
+EXPECT_NE(ToImportedFriend1, ToImportedFriend2);
+EXPECT_EQ(ToFriend1, ToImportedFriend1);
+EXPECT_EQ(ToFriend2, ToImportedFriend2);
+  }
 };
 
 TEST_P(ImportFriendClasses, ImportOfFriendRecordDoesNotMergeDefinition) {
@@ -4343,21 +4362,7 @@
 friend class X;
   };
   )";
-  Decl *ToTu = getToTuDecl(Code, Lang_CXX03);
-  Decl *FromTu = getTuDecl(Code, Lang_CXX03, "from.cc");
-
-  auto *ToFriend1 = FirstDeclMatcher().match(ToTu, friendDecl());
-  auto *ToFriend2 = LastDeclMatcher().match(ToTu, friendDecl());
-  auto *FromFriend1 =
-  FirstDeclMatcher().match(FromTu, friendDecl());
-  auto *FromFriend2 = LastDeclMatcher().match(FromTu, friendDecl());
-
-  FriendDecl *ToImportedFriend1 = Import(FromFriend1, Lang_CXX03);
-  FriendDecl *ToImportedFriend2 = Import(FromFriend2, Lang_CXX03);
-
-  EXPECT_NE(ToImportedFriend1, ToImportedFriend2);
-  EXPECT_EQ(ToFriend1, ToImportedFriend1);
-  EXPECT_EQ(ToFriend2, ToImportedFriend2);
+  testRepeatedFriendImport(Code);
 }
 
 TEST_P(ImportFriendClasses, ImportOfRepeatedFriendDecl) {
@@ -4368,21 +4373,31 @@
 friend void f();
   };
   )";
-  Decl *ToTu = getToTuDecl(Code, Lang_CXX03);
-  Decl *FromTu = getTuDecl(Code, Lang_CXX03, "from.cc");
-
-  auto *ToFriend1 = FirstDeclMatcher().match(ToTu, friendDecl());
-  auto *ToFriend2 = LastDeclMatcher().match(ToTu, friendDecl());
-  auto *FromFriend1 =
-  FirstDeclMatcher().match(FromTu, friendDecl());
-  auto *FromFriend2 = LastDeclMatcher().match(FromTu, friendDecl());
+  testRepeatedFriendImport(Code);
+}
 
-  FriendDecl *ToImportedFriend1 = Import(FromFriend1, Lang_CXX03);
-  FriendDecl *ToImportedFriend2 = Import(FromFriend2, Lang_CXX03);
+TEST_P(ImportFriendClasses, ImportOfRepeatedFriendFunctionTemplateDecl) {
+  const char *Code =
+  R"(
+template 
+class Container {
+  template  friend void m();
+  template  friend void m();
+};
+  )";
+  testRepeatedFriendImport(Code);
+}
 
-  EXPECT_NE(ToImportedFriend1, ToImportedFriend2);
-  EXPECT_EQ(ToFriend1, ToImportedFriend1);
-  EXPECT_EQ(ToFriend2, ToImportedFriend2);
+TEST_P(ImportFriendClasses, ImportOfRepeatedFriendClassTemplateDecl) {
+  const char *Code =
+  R"(
+template 
+class Container {
+  template  friend class X;
+  template  friend class X;
+};
+  )";
+  testRepeatedFriendImport(Code);
 }
 
 TEST_P(ASTImporterOptionSpecificTestBase, FriendFunInClassTemplate) {
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -4064,22 +4064,32 @@
   unsigned int IndexOfDecl;
 };
 
-template 
-static FriendCountAndPosition getFriendCountAndPosition(
-const FriendDecl *FD,
-llvm::function_ref GetCanTypeOrDecl) {
+static bool IsEquivalentFriend(ASTImporter &Importer, FriendDecl *FD1,
+   FriendDecl *FD2) {
+  if ((!FD1->getFriendType()) != (!FD2->getFriendType()))
+return false;
+
+  if (auto *TSI = FD1->getFriendType())
+return Importer.IsStructurallyEquivalent(
+TSI->getType(), FD2->getFriendType()->getType(), /*Complain=*/false);
+
+  StructuralEquivalenceContext Ctx(
+  Importer.getFromContext(), Importer.getToContext(),
+  Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer));
+  return Ctx.IsEquivalent(FD1, FD2);
+}
+
+static FriendCountAndPosition getFriendCountAndPosition(ASTImporter &Importer,
+FriendDecl *FD) {
   unsigned int FriendCount = 0;
   std::optional FriendPosition;
   const auto *RD = cast(FD->getLexicalDeclContext());
 
-

[PATCH] D157684: [clang][ASTImporter] Repeated friend templates are partially imported

2023-08-11 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 549436.
danix800 added a comment.

Turn off `Complain` mode on `IsEquivalentFriend` checking.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157684

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -4054,6 +4054,25 @@
  ->lookup(ToRecordOfFriend->getDeclName())
  .empty());
   }
+
+  void testRepeatedFriendImport(const char *Code) {
+Decl *ToTu = getToTuDecl(Code, Lang_CXX03);
+Decl *FromTu = getTuDecl(Code, Lang_CXX03, "from.cc");
+
+auto *ToFriend1 = FirstDeclMatcher().match(ToTu, friendDecl());
+auto *ToFriend2 = LastDeclMatcher().match(ToTu, friendDecl());
+auto *FromFriend1 =
+FirstDeclMatcher().match(FromTu, friendDecl());
+auto *FromFriend2 =
+LastDeclMatcher().match(FromTu, friendDecl());
+
+FriendDecl *ToImportedFriend1 = Import(FromFriend1, Lang_CXX03);
+FriendDecl *ToImportedFriend2 = Import(FromFriend2, Lang_CXX03);
+
+EXPECT_NE(ToImportedFriend1, ToImportedFriend2);
+EXPECT_EQ(ToFriend1, ToImportedFriend1);
+EXPECT_EQ(ToFriend2, ToImportedFriend2);
+  }
 };
 
 TEST_P(ImportFriendClasses, ImportOfFriendRecordDoesNotMergeDefinition) {
@@ -4343,21 +4362,7 @@
 friend class X;
   };
   )";
-  Decl *ToTu = getToTuDecl(Code, Lang_CXX03);
-  Decl *FromTu = getTuDecl(Code, Lang_CXX03, "from.cc");
-
-  auto *ToFriend1 = FirstDeclMatcher().match(ToTu, friendDecl());
-  auto *ToFriend2 = LastDeclMatcher().match(ToTu, friendDecl());
-  auto *FromFriend1 =
-  FirstDeclMatcher().match(FromTu, friendDecl());
-  auto *FromFriend2 = LastDeclMatcher().match(FromTu, friendDecl());
-
-  FriendDecl *ToImportedFriend1 = Import(FromFriend1, Lang_CXX03);
-  FriendDecl *ToImportedFriend2 = Import(FromFriend2, Lang_CXX03);
-
-  EXPECT_NE(ToImportedFriend1, ToImportedFriend2);
-  EXPECT_EQ(ToFriend1, ToImportedFriend1);
-  EXPECT_EQ(ToFriend2, ToImportedFriend2);
+  testRepeatedFriendImport(Code);
 }
 
 TEST_P(ImportFriendClasses, ImportOfRepeatedFriendDecl) {
@@ -4368,21 +4373,31 @@
 friend void f();
   };
   )";
-  Decl *ToTu = getToTuDecl(Code, Lang_CXX03);
-  Decl *FromTu = getTuDecl(Code, Lang_CXX03, "from.cc");
-
-  auto *ToFriend1 = FirstDeclMatcher().match(ToTu, friendDecl());
-  auto *ToFriend2 = LastDeclMatcher().match(ToTu, friendDecl());
-  auto *FromFriend1 =
-  FirstDeclMatcher().match(FromTu, friendDecl());
-  auto *FromFriend2 = LastDeclMatcher().match(FromTu, friendDecl());
+  testRepeatedFriendImport(Code);
+}
 
-  FriendDecl *ToImportedFriend1 = Import(FromFriend1, Lang_CXX03);
-  FriendDecl *ToImportedFriend2 = Import(FromFriend2, Lang_CXX03);
+TEST_P(ImportFriendClasses, ImportOfRepeatedFriendFunctionTemplateDecl) {
+  const char *Code =
+  R"(
+template 
+class Container {
+  template  friend void m();
+  template  friend void m();
+};
+  )";
+  testRepeatedFriendImport(Code);
+}
 
-  EXPECT_NE(ToImportedFriend1, ToImportedFriend2);
-  EXPECT_EQ(ToFriend1, ToImportedFriend1);
-  EXPECT_EQ(ToFriend2, ToImportedFriend2);
+TEST_P(ImportFriendClasses, ImportOfRepeatedFriendClassTemplateDecl) {
+  const char *Code =
+  R"(
+template 
+class Container {
+  template  friend class X;
+  template  friend class X;
+};
+  )";
+  testRepeatedFriendImport(Code);
 }
 
 TEST_P(ASTImporterOptionSpecificTestBase, FriendFunInClassTemplate) {
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -4064,22 +4064,33 @@
   unsigned int IndexOfDecl;
 };
 
-template 
-static FriendCountAndPosition getFriendCountAndPosition(
-const FriendDecl *FD,
-llvm::function_ref GetCanTypeOrDecl) {
+static bool IsEquivalentFriend(ASTImporter &Importer, FriendDecl *FD1,
+   FriendDecl *FD2) {
+  if ((!FD1->getFriendType()) != (!FD2->getFriendType()))
+return false;
+
+  if (auto *TSI = FD1->getFriendType())
+return Importer.IsStructurallyEquivalent(
+TSI->getType(), FD2->getFriendType()->getType(), /*Complain=*/false);
+
+  StructuralEquivalenceContext Ctx(
+  FD1->getASTContext(), FD2->getASTContext(),
+  Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer),
+  /* StrictTypeSpelling = */ false, /* Complain = */ false);
+  return Ctx.IsEquivalent(FD1, FD2);
+}
+
+static FriendCountAndPosition getFriendCountAndPosition(ASTImporter &Importer,
+FriendDecl *FD) {
   unsigned int FriendCount = 0;

[PATCH] D157777: [ASTMatcher] Add matcher for 'MacroQualifiedType'

2023-08-12 Thread Ding Fei via Phabricator via cfe-commits
danix800 created this revision.
danix800 added a project: clang.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a subscriber: cfe-commits.

Add matcher for 'MacroQualifiedType'


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D15

Files:
  clang/docs/LibASTMatchersReference.html
  clang/docs/ReleaseNotes.rst
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/lib/ASTMatchers/ASTMatchersInternal.cpp
  clang/lib/ASTMatchers/Dynamic/Registry.cpp
  clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp


Index: clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -1838,6 +1838,15 @@
 namesType(typedefType()));
 }
 
+TEST_P(ASTMatchersTest, MacroQualifiedType) {
+  EXPECT_TRUE(matches(R"(
+#define CDECL __attribute__((cdecl))
+typedef void (CDECL *X)();
+  )",
+  typedefDecl(hasName("X"), hasType(pointerType(pointee(
+macroQualifiedType()));
+}
+
 TEST_P(ASTMatchersTest, TemplateSpecializationType) {
   if (!GetParam().isCXX()) {
 return;
Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===
--- clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -485,6 +485,7 @@
   REGISTER_MATCHER(lambdaCapture);
   REGISTER_MATCHER(lambdaExpr);
   REGISTER_MATCHER(linkageSpecDecl);
+  REGISTER_MATCHER(macroQualifiedType);
   REGISTER_MATCHER(materializeTemporaryExpr);
   REGISTER_MATCHER(member);
   REGISTER_MATCHER(memberExpr);
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -1058,6 +1058,7 @@
 const AstTypeMatcher functionProtoType;
 const AstTypeMatcher parenType;
 const AstTypeMatcher blockPointerType;
+const AstTypeMatcher macroQualifiedType;
 const AstTypeMatcher memberPointerType;
 const AstTypeMatcher pointerType;
 const AstTypeMatcher objcObjectPointerType;
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -7258,6 +7258,17 @@
 ///   matches "typedef int X"
 extern const AstTypeMatcher typedefType;
 
+/// Matches macro qualified types.
+///
+/// Given
+/// \code
+///   #define CDECL __attribute__((cdecl))
+///   typedef void (CDECL *X)();
+/// \endcode
+/// macroQualifiedType()
+///   matches the type of the typedef declaration of \c X.
+extern const AstTypeMatcher macroQualifiedType;
+
 /// Matches enum types.
 ///
 /// Given
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -244,6 +244,7 @@
 
 - Add ``convertVectorExpr``.
 - Add ``dependentSizedExtVectorType``.
+- Add ``macroQualifiedType``.
 
 clang-format
 
Index: clang/docs/LibASTMatchersReference.html
===
--- clang/docs/LibASTMatchersReference.html
+++ clang/docs/LibASTMatchersReference.html
@@ -2648,6 +2648,17 @@
 
 
 
+MatcherType>macroQualifiedTypeMatcherMacroQualifiedType>...
+Matches macro 
qualified types.
+
+Given
+  #define CDECL __attribute__((cdecl))
+  typedef void (CDECL *X)();
+macroQualifiedType()
+  matches the type of the typedef declaration of X.
+
+
+
 MatcherType>memberPointerTypeMatcherMemberPointerType>...
 Matches member 
pointer types.
 Given


Index: clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -1838,6 +1838,15 @@
 namesType(typedefType()));
 }
 
+TEST_P(ASTMatchersTest, MacroQualifiedType) {
+  EXPECT_TRUE(matches(R"(
+#define CDECL __attribute__((cdecl))
+typedef void (CDECL *X)();
+  )",
+  typedefDecl(hasName("X"), hasType(pointerType(pointee(
+macroQualifiedType()));
+}
+
 TEST_P(ASTMatchersTest, TemplateSpecializationType) {
   if (!GetParam().isCXX()) {
 return;
Index: clang/lib/ASTMatchers/Dynamic/Regis

[PATCH] D157777: [ASTMatcher] Add matcher for 'MacroQualifiedType'

2023-08-12 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 549605.
danix800 added a comment.
Herald added a subscriber: martong.
Herald added a reviewer: shafik.

Add import of MacroQualifiedType.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D15

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp


Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -8638,6 +8638,24 @@
   EXPECT_TRUE(ToCtx.hasSameType(ToInjTypedef, ToInjParmVar));
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase, ImportMacroQualifiedType) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"(
+#define CDECL __attribute__((cdecl))
+typedef void (CDECL *X)();
+  )",
+  Lang_CXX03, "", Lang_CXX03, "X");
+
+  auto *FromTy =
+  FirstDeclMatcher().match(From, macroQualifiedType());
+  auto *ToTy =
+  FirstDeclMatcher().match(To, macroQualifiedType());
+
+  EXPECT_TRUE(isa(FromTy->getUnderlyingType()));
+  EXPECT_TRUE(isa(ToTy->getUnderlyingType()));
+}
+
 TEST_P(ASTImporterOptionSpecificTestBase, ImportCorrectTemplateName) {
   constexpr auto TestCode = R"(
   template 
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -419,6 +419,7 @@
 ExpectedType VisitObjCInterfaceType(const ObjCInterfaceType *T);
 ExpectedType VisitObjCObjectType(const ObjCObjectType *T);
 ExpectedType VisitObjCObjectPointerType(const ObjCObjectPointerType *T);
+ExpectedType VisitMacroQualifiedType(const MacroQualifiedType *T);
 
 // Importing declarations
 Error ImportDeclParts(NamedDecl *D, DeclarationName &Name, NamedDecl *&ToD,
@@ -1701,6 +1702,17 @@
   return Importer.getToContext().getObjCObjectPointerType(*ToPointeeTypeOrErr);
 }
 
+ExpectedType
+ASTNodeImporter::VisitMacroQualifiedType(const MacroQualifiedType *T) {
+  ExpectedType ToUnderlyingTypeOrErr = import(T->getUnderlyingType());
+  if (!ToUnderlyingTypeOrErr)
+return ToUnderlyingTypeOrErr.takeError();
+
+  IdentifierInfo *ToIdentifier = Importer.Import(T->getMacroIdentifier());
+  return Importer.getToContext().getMacroQualifiedType(*ToUnderlyingTypeOrErr,
+   ToIdentifier);
+}
+
 //
 // Import Declarations
 //


Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -8638,6 +8638,24 @@
   EXPECT_TRUE(ToCtx.hasSameType(ToInjTypedef, ToInjParmVar));
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase, ImportMacroQualifiedType) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"(
+#define CDECL __attribute__((cdecl))
+typedef void (CDECL *X)();
+  )",
+  Lang_CXX03, "", Lang_CXX03, "X");
+
+  auto *FromTy =
+  FirstDeclMatcher().match(From, macroQualifiedType());
+  auto *ToTy =
+  FirstDeclMatcher().match(To, macroQualifiedType());
+
+  EXPECT_TRUE(isa(FromTy->getUnderlyingType()));
+  EXPECT_TRUE(isa(ToTy->getUnderlyingType()));
+}
+
 TEST_P(ASTImporterOptionSpecificTestBase, ImportCorrectTemplateName) {
   constexpr auto TestCode = R"(
   template 
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -419,6 +419,7 @@
 ExpectedType VisitObjCInterfaceType(const ObjCInterfaceType *T);
 ExpectedType VisitObjCObjectType(const ObjCObjectType *T);
 ExpectedType VisitObjCObjectPointerType(const ObjCObjectPointerType *T);
+ExpectedType VisitMacroQualifiedType(const MacroQualifiedType *T);
 
 // Importing declarations
 Error ImportDeclParts(NamedDecl *D, DeclarationName &Name, NamedDecl *&ToD,
@@ -1701,6 +1702,17 @@
   return Importer.getToContext().getObjCObjectPointerType(*ToPointeeTypeOrErr);
 }
 
+ExpectedType
+ASTNodeImporter::VisitMacroQualifiedType(const MacroQualifiedType *T) {
+  ExpectedType ToUnderlyingTypeOrErr = import(T->getUnderlyingType());
+  if (!ToUnderlyingTypeOrErr)
+return ToUnderlyingTypeOrErr.takeError();
+
+  IdentifierInfo *ToIdentifier = Importer.Import(T->getMacroIdentifier());
+  return Importer.getToContext().getMacroQualifiedType(*ToUnderlyingTypeOrErr,
+   ToIdentifier);
+}
+
 //
 // Import Declarations
 //
_

[PATCH] D157777: [ASTMatcher] Add matcher for 'MacroQualifiedType'

2023-08-12 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 549607.

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D15

Files:
  clang/docs/LibASTMatchersReference.html
  clang/docs/ReleaseNotes.rst
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/lib/ASTMatchers/ASTMatchersInternal.cpp
  clang/lib/ASTMatchers/Dynamic/Registry.cpp
  clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp


Index: clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -1838,6 +1838,15 @@
 namesType(typedefType()));
 }
 
+TEST_P(ASTMatchersTest, MacroQualifiedType) {
+  EXPECT_TRUE(matches(R"(
+#define CDECL __attribute__((cdecl))
+typedef void (CDECL *X)();
+  )",
+  typedefDecl(hasName("X"), hasType(pointerType(pointee(
+macroQualifiedType()));
+}
+
 TEST_P(ASTMatchersTest, TemplateSpecializationType) {
   if (!GetParam().isCXX()) {
 return;
Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===
--- clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -485,6 +485,7 @@
   REGISTER_MATCHER(lambdaCapture);
   REGISTER_MATCHER(lambdaExpr);
   REGISTER_MATCHER(linkageSpecDecl);
+  REGISTER_MATCHER(macroQualifiedType);
   REGISTER_MATCHER(materializeTemporaryExpr);
   REGISTER_MATCHER(member);
   REGISTER_MATCHER(memberExpr);
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -1058,6 +1058,7 @@
 const AstTypeMatcher functionProtoType;
 const AstTypeMatcher parenType;
 const AstTypeMatcher blockPointerType;
+const AstTypeMatcher macroQualifiedType;
 const AstTypeMatcher memberPointerType;
 const AstTypeMatcher pointerType;
 const AstTypeMatcher objcObjectPointerType;
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -7258,6 +7258,17 @@
 ///   matches "typedef int X"
 extern const AstTypeMatcher typedefType;
 
+/// Matches macro qualified types.
+///
+/// Given
+/// \code
+///   #define CDECL __attribute__((cdecl))
+///   typedef void (CDECL *X)();
+/// \endcode
+/// macroQualifiedType()
+///   matches the type of the typedef declaration of \c X.
+extern const AstTypeMatcher macroQualifiedType;
+
 /// Matches enum types.
 ///
 /// Given
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -244,6 +244,7 @@
 
 - Add ``convertVectorExpr``.
 - Add ``dependentSizedExtVectorType``.
+- Add ``macroQualifiedType``.
 
 clang-format
 
Index: clang/docs/LibASTMatchersReference.html
===
--- clang/docs/LibASTMatchersReference.html
+++ clang/docs/LibASTMatchersReference.html
@@ -2648,6 +2648,17 @@
 
 
 
+MatcherType>macroQualifiedTypeMatcherMacroQualifiedType>...
+Matches macro 
qualified types.
+
+Given
+  #define CDECL __attribute__((cdecl))
+  typedef void (CDECL *X)();
+macroQualifiedType()
+  matches the type of the typedef declaration of X.
+
+
+
 MatcherType>memberPointerTypeMatcherMemberPointerType>...
 Matches member 
pointer types.
 Given


Index: clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -1838,6 +1838,15 @@
 namesType(typedefType()));
 }
 
+TEST_P(ASTMatchersTest, MacroQualifiedType) {
+  EXPECT_TRUE(matches(R"(
+#define CDECL __attribute__((cdecl))
+typedef void (CDECL *X)();
+  )",
+  typedefDecl(hasName("X"), hasType(pointerType(pointee(
+macroQualifiedType()));
+}
+
 TEST_P(ASTMatchersTest, TemplateSpecializationType) {
   if (!GetParam().isCXX()) {
 return;
Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===
--- clang/lib/ASTMatchers/D

[PATCH] D157780: [ASTImporter] Add import of MacroQualifiedType

2023-08-12 Thread Ding Fei via Phabricator via cfe-commits
danix800 created this revision.
danix800 added a project: clang.
Herald added a subscriber: martong.
Herald added a reviewer: a.sidorin.
Herald added a reviewer: shafik.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a subscriber: cfe-commits.

Add import of MacroQualifiedType.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D157780

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp


Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -8638,6 +8638,24 @@
   EXPECT_TRUE(ToCtx.hasSameType(ToInjTypedef, ToInjParmVar));
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase, ImportMacroQualifiedType) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"(
+#define CDECL __attribute__((cdecl))
+typedef void (CDECL *X)();
+  )",
+  Lang_CXX03, "", Lang_CXX03, "X");
+
+  auto *FromTy =
+  FirstDeclMatcher().match(From, macroQualifiedType());
+  auto *ToTy =
+  FirstDeclMatcher().match(To, macroQualifiedType());
+
+  EXPECT_TRUE(isa(FromTy->getUnderlyingType()));
+  EXPECT_TRUE(isa(ToTy->getUnderlyingType()));
+}
+
 TEST_P(ASTImporterOptionSpecificTestBase, ImportCorrectTemplateName) {
   constexpr auto TestCode = R"(
   template 
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -419,6 +419,7 @@
 ExpectedType VisitObjCInterfaceType(const ObjCInterfaceType *T);
 ExpectedType VisitObjCObjectType(const ObjCObjectType *T);
 ExpectedType VisitObjCObjectPointerType(const ObjCObjectPointerType *T);
+ExpectedType VisitMacroQualifiedType(const MacroQualifiedType *T);
 
 // Importing declarations
 Error ImportDeclParts(NamedDecl *D, DeclarationName &Name, NamedDecl *&ToD,
@@ -1701,6 +1702,17 @@
   return Importer.getToContext().getObjCObjectPointerType(*ToPointeeTypeOrErr);
 }
 
+ExpectedType
+ASTNodeImporter::VisitMacroQualifiedType(const MacroQualifiedType *T) {
+  ExpectedType ToUnderlyingTypeOrErr = import(T->getUnderlyingType());
+  if (!ToUnderlyingTypeOrErr)
+return ToUnderlyingTypeOrErr.takeError();
+
+  IdentifierInfo *ToIdentifier = Importer.Import(T->getMacroIdentifier());
+  return Importer.getToContext().getMacroQualifiedType(*ToUnderlyingTypeOrErr,
+   ToIdentifier);
+}
+
 //
 // Import Declarations
 //


Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -8638,6 +8638,24 @@
   EXPECT_TRUE(ToCtx.hasSameType(ToInjTypedef, ToInjParmVar));
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase, ImportMacroQualifiedType) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"(
+#define CDECL __attribute__((cdecl))
+typedef void (CDECL *X)();
+  )",
+  Lang_CXX03, "", Lang_CXX03, "X");
+
+  auto *FromTy =
+  FirstDeclMatcher().match(From, macroQualifiedType());
+  auto *ToTy =
+  FirstDeclMatcher().match(To, macroQualifiedType());
+
+  EXPECT_TRUE(isa(FromTy->getUnderlyingType()));
+  EXPECT_TRUE(isa(ToTy->getUnderlyingType()));
+}
+
 TEST_P(ASTImporterOptionSpecificTestBase, ImportCorrectTemplateName) {
   constexpr auto TestCode = R"(
   template 
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -419,6 +419,7 @@
 ExpectedType VisitObjCInterfaceType(const ObjCInterfaceType *T);
 ExpectedType VisitObjCObjectType(const ObjCObjectType *T);
 ExpectedType VisitObjCObjectPointerType(const ObjCObjectPointerType *T);
+ExpectedType VisitMacroQualifiedType(const MacroQualifiedType *T);
 
 // Importing declarations
 Error ImportDeclParts(NamedDecl *D, DeclarationName &Name, NamedDecl *&ToD,
@@ -1701,6 +1702,17 @@
   return Importer.getToContext().getObjCObjectPointerType(*ToPointeeTypeOrErr);
 }
 
+ExpectedType
+ASTNodeImporter::VisitMacroQualifiedType(const MacroQualifiedType *T) {
+  ExpectedType ToUnderlyingTypeOrErr = import(T->getUnderlyingType());
+  if (!ToUnderlyingTypeOrErr)
+return ToUnderlyingTypeOrErr.takeError();
+
+  IdentifierInfo *ToIdentifier = Importer.Import(T->getMacroIdentifier());
+  return Importer.getToContext().getMacroQualifiedType(*ToUnderlyingTypeOrErr,
+   ToIdentifier);
+}
+
 //
 // Import Declarations
 //

[PATCH] D157780: [ASTImporter] Add import of MacroQualifiedType

2023-08-12 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 549609.

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157780

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp


Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -8638,6 +8638,24 @@
   EXPECT_TRUE(ToCtx.hasSameType(ToInjTypedef, ToInjParmVar));
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase, ImportMacroQualifiedType) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"(
+#define CDECL __attribute__((cdecl))
+typedef void (CDECL *X)();
+  )",
+  Lang_CXX03, "", Lang_CXX03, "X");
+
+  auto *FromTy =
+  FirstDeclMatcher().match(From, macroQualifiedType());
+  auto *ToTy =
+  FirstDeclMatcher().match(To, macroQualifiedType());
+
+  EXPECT_TRUE(isa(FromTy->getUnderlyingType()));
+  EXPECT_TRUE(isa(ToTy->getUnderlyingType()));
+}
+
 TEST_P(ASTImporterOptionSpecificTestBase, ImportCorrectTemplateName) {
   constexpr auto TestCode = R"(
   template 
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -419,6 +419,7 @@
 ExpectedType VisitObjCInterfaceType(const ObjCInterfaceType *T);
 ExpectedType VisitObjCObjectType(const ObjCObjectType *T);
 ExpectedType VisitObjCObjectPointerType(const ObjCObjectPointerType *T);
+ExpectedType VisitMacroQualifiedType(const MacroQualifiedType *T);
 
 // Importing declarations
 Error ImportDeclParts(NamedDecl *D, DeclarationName &Name, NamedDecl *&ToD,
@@ -1701,6 +1702,17 @@
   return Importer.getToContext().getObjCObjectPointerType(*ToPointeeTypeOrErr);
 }
 
+ExpectedType
+ASTNodeImporter::VisitMacroQualifiedType(const MacroQualifiedType *T) {
+  ExpectedType ToUnderlyingTypeOrErr = import(T->getUnderlyingType());
+  if (!ToUnderlyingTypeOrErr)
+return ToUnderlyingTypeOrErr.takeError();
+
+  IdentifierInfo *ToIdentifier = Importer.Import(T->getMacroIdentifier());
+  return Importer.getToContext().getMacroQualifiedType(*ToUnderlyingTypeOrErr,
+   ToIdentifier);
+}
+
 //
 // Import Declarations
 //


Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -8638,6 +8638,24 @@
   EXPECT_TRUE(ToCtx.hasSameType(ToInjTypedef, ToInjParmVar));
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase, ImportMacroQualifiedType) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"(
+#define CDECL __attribute__((cdecl))
+typedef void (CDECL *X)();
+  )",
+  Lang_CXX03, "", Lang_CXX03, "X");
+
+  auto *FromTy =
+  FirstDeclMatcher().match(From, macroQualifiedType());
+  auto *ToTy =
+  FirstDeclMatcher().match(To, macroQualifiedType());
+
+  EXPECT_TRUE(isa(FromTy->getUnderlyingType()));
+  EXPECT_TRUE(isa(ToTy->getUnderlyingType()));
+}
+
 TEST_P(ASTImporterOptionSpecificTestBase, ImportCorrectTemplateName) {
   constexpr auto TestCode = R"(
   template 
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -419,6 +419,7 @@
 ExpectedType VisitObjCInterfaceType(const ObjCInterfaceType *T);
 ExpectedType VisitObjCObjectType(const ObjCObjectType *T);
 ExpectedType VisitObjCObjectPointerType(const ObjCObjectPointerType *T);
+ExpectedType VisitMacroQualifiedType(const MacroQualifiedType *T);
 
 // Importing declarations
 Error ImportDeclParts(NamedDecl *D, DeclarationName &Name, NamedDecl *&ToD,
@@ -1701,6 +1702,17 @@
   return Importer.getToContext().getObjCObjectPointerType(*ToPointeeTypeOrErr);
 }
 
+ExpectedType
+ASTNodeImporter::VisitMacroQualifiedType(const MacroQualifiedType *T) {
+  ExpectedType ToUnderlyingTypeOrErr = import(T->getUnderlyingType());
+  if (!ToUnderlyingTypeOrErr)
+return ToUnderlyingTypeOrErr.takeError();
+
+  IdentifierInfo *ToIdentifier = Importer.Import(T->getMacroIdentifier());
+  return Importer.getToContext().getMacroQualifiedType(*ToUnderlyingTypeOrErr,
+   ToIdentifier);
+}
+
 //
 // Import Declarations
 //
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://

[PATCH] D157691: [ASTImporter] Remove extranous FunctionTemplateDecl introduced by templated friend

2023-08-14 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 550160.
danix800 added a comment.

1. Add unit testcase
2. Use better API


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157691

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/test/Import/templated-friend/Inputs/T.cpp
  clang/test/Import/templated-friend/test.cpp
  clang/unittests/AST/ASTImporterTest.cpp


Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -5634,6 +5634,42 @@
   EXPECT_EQ(Imported->getPreviousDecl(), Friend);
 }
 
+TEST_P(ImportFriendFunctionTemplates, ImportFriendFunctionInsideClassTemplate) 
{
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(R"(
+  template  struct X {
+template  friend void f();
+  };
+)",
+   Lang_CXX03, "", Lang_CXX03, "X");
+
+  auto *FromFriend = FirstDeclMatcher().match(From, friendDecl());
+  auto *ToFriend = FirstDeclMatcher().match(To, friendDecl());
+
+  EXPECT_TRUE(FromFriend ==
+  LastDeclMatcher().match(From, friendDecl()));
+  EXPECT_TRUE(ToFriend ==
+  LastDeclMatcher().match(To, friendDecl()));
+
+  auto *FromDecl = FromFriend->getFriendDecl();
+  auto *FromDC = FromFriend->getDeclContext();
+  auto *FromLexicalDC = FromFriend->getLexicalDeclContext();
+
+  EXPECT_TRUE(FromDC->containsDecl(FromFriend));
+  EXPECT_FALSE(FromDC->containsDecl(FromDecl));
+  EXPECT_TRUE(FromLexicalDC->containsDecl(FromFriend));
+  EXPECT_FALSE(FromLexicalDC->containsDecl(FromDecl));
+
+  auto *ToDecl = ToFriend->getFriendDecl();
+  auto *ToDC = ToFriend->getDeclContext();
+  auto *ToLexicalDC = ToFriend->getLexicalDeclContext();
+
+  EXPECT_TRUE(ToDC->containsDecl(ToFriend));
+  EXPECT_FALSE(ToDC->containsDecl(ToDecl));
+  EXPECT_TRUE(ToLexicalDC->containsDecl(ToFriend));
+  EXPECT_FALSE(ToLexicalDC->containsDecl(ToDecl));
+}
+
 struct ASTImporterWithFakeErrors : ASTImporter {
   using ASTImporter::ASTImporter;
   bool returnWithErrorInTest() override { return true; }
Index: clang/test/Import/templated-friend/test.cpp
===
--- /dev/null
+++ clang/test/Import/templated-friend/test.cpp
@@ -0,0 +1,5 @@
+// RUN: clang-import-test -import %S/Inputs/T.cpp -expression %s
+
+void expr() {
+  A a;
+}
Index: clang/test/Import/templated-friend/Inputs/T.cpp
===
--- /dev/null
+++ clang/test/Import/templated-friend/Inputs/T.cpp
@@ -0,0 +1,3 @@
+template  struct A {
+  template  friend void f();
+};
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -6447,7 +6447,7 @@
 
   ToFunc->setAccess(D->getAccess());
   ToFunc->setLexicalDeclContext(LexicalDC);
-  LexicalDC->addDeclInternal(ToFunc);
+  addDeclToContexts(D, ToFunc);
 
   ASTImporterLookupTable *LT = Importer.SharedState->getLookupTable();
   if (LT && !OldParamDC.empty()) {


Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -5634,6 +5634,42 @@
   EXPECT_EQ(Imported->getPreviousDecl(), Friend);
 }
 
+TEST_P(ImportFriendFunctionTemplates, ImportFriendFunctionInsideClassTemplate) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(R"(
+  template  struct X {
+template  friend void f();
+  };
+)",
+   Lang_CXX03, "", Lang_CXX03, "X");
+
+  auto *FromFriend = FirstDeclMatcher().match(From, friendDecl());
+  auto *ToFriend = FirstDeclMatcher().match(To, friendDecl());
+
+  EXPECT_TRUE(FromFriend ==
+  LastDeclMatcher().match(From, friendDecl()));
+  EXPECT_TRUE(ToFriend ==
+  LastDeclMatcher().match(To, friendDecl()));
+
+  auto *FromDecl = FromFriend->getFriendDecl();
+  auto *FromDC = FromFriend->getDeclContext();
+  auto *FromLexicalDC = FromFriend->getLexicalDeclContext();
+
+  EXPECT_TRUE(FromDC->containsDecl(FromFriend));
+  EXPECT_FALSE(FromDC->containsDecl(FromDecl));
+  EXPECT_TRUE(FromLexicalDC->containsDecl(FromFriend));
+  EXPECT_FALSE(FromLexicalDC->containsDecl(FromDecl));
+
+  auto *ToDecl = ToFriend->getFriendDecl();
+  auto *ToDC = ToFriend->getDeclContext();
+  auto *ToLexicalDC = ToFriend->getLexicalDeclContext();
+
+  EXPECT_TRUE(ToDC->containsDecl(ToFriend));
+  EXPECT_FALSE(ToDC->containsDecl(ToDecl));
+  EXPECT_TRUE(ToLexicalDC->containsDecl(ToFriend));
+  EXPECT_FALSE(ToLexicalDC->containsDecl(ToDecl));
+}
+
 struct ASTImporterWithFakeErrors : ASTImporter {
   using ASTImporter::ASTImporter;
   bool returnWithErrorInTest() override { return true; }
Index: clang/t

[PATCH] D157777: [ASTMatcher] Add matcher for 'MacroQualifiedType'

2023-08-14 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/include/clang/ASTMatchers/ASTMatchers.h:7261
 
+/// Matches macro qualified types.
+///

aaron.ballman wrote:
> How about: Matches qualified types when the qualifier is applied via a macro.
> 
> and then a second example like:
> ```
> int * const qual_ptr;
> 
> #define nonnull _Nonnull
> int * const nonnull macro_qual_ptr;
> ```
> where we match `macro_qual_ptr` but not `qual_ptr`.
> How about: Matches qualified types when the qualifier is applied via a macro.

Forgive my broken English!  :-)

> and then a second example like:
> ```
> int * const qual_ptr;
> 
> #define nonnull _Nonnull
> int * const nonnull macro_qual_ptr;
> ```
> where we match `macro_qual_ptr` but not `qual_ptr`.

Thanks for reminding me of the counter-example, it's critical for better test 
coverage.

I'll pertain to the original one but with counter-example appended, because the 
macro
`nonnull` in this case will not generate a `MacroQualifiedType` for 
`macro_qual_ptr`.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D15

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


[PATCH] D157777: [ASTMatcher] Add matcher for 'MacroQualifiedType'

2023-08-14 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 550178.
danix800 added a comment.

1. Improve matcher description
2. Add a counter-example for test


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D15

Files:
  clang/docs/LibASTMatchersReference.html
  clang/docs/ReleaseNotes.rst
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/lib/ASTMatchers/ASTMatchersInternal.cpp
  clang/lib/ASTMatchers/Dynamic/Registry.cpp
  clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -1838,6 +1838,20 @@
 namesType(typedefType()));
 }
 
+TEST_P(ASTMatchersTest, MacroQualifiedType) {
+  EXPECT_TRUE(matches(
+  R"(
+#define CDECL __attribute__((cdecl))
+typedef void (CDECL *X)();
+  )",
+  typedefDecl(hasType(pointerType(pointee(macroQualifiedType()));
+  EXPECT_TRUE(notMatches(
+  R"(
+typedef void (__attribute__((cdecl)) *Y)();
+  )",
+  typedefDecl(hasType(pointerType(pointee(macroQualifiedType()));
+}
+
 TEST_P(ASTMatchersTest, TemplateSpecializationType) {
   if (!GetParam().isCXX()) {
 return;
Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===
--- clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -485,6 +485,7 @@
   REGISTER_MATCHER(lambdaCapture);
   REGISTER_MATCHER(lambdaExpr);
   REGISTER_MATCHER(linkageSpecDecl);
+  REGISTER_MATCHER(macroQualifiedType);
   REGISTER_MATCHER(materializeTemporaryExpr);
   REGISTER_MATCHER(member);
   REGISTER_MATCHER(memberExpr);
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -1058,6 +1058,7 @@
 const AstTypeMatcher functionProtoType;
 const AstTypeMatcher parenType;
 const AstTypeMatcher blockPointerType;
+const AstTypeMatcher macroQualifiedType;
 const AstTypeMatcher memberPointerType;
 const AstTypeMatcher pointerType;
 const AstTypeMatcher objcObjectPointerType;
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -7258,6 +7258,18 @@
 ///   matches "typedef int X"
 extern const AstTypeMatcher typedefType;
 
+/// Matches qualified types when the qualifier is applied via a macro.
+///
+/// Given
+/// \code
+///   #define CDECL __attribute__((cdecl))
+///   typedef void (CDECL *X)();
+///   typedef void (__attribute__((cdecl)) *Y)();
+/// \endcode
+/// macroQualifiedType()
+///   matches the type of the typedef declaration of \c X but not \c Y.
+extern const AstTypeMatcher macroQualifiedType;
+
 /// Matches enum types.
 ///
 /// Given
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -249,6 +249,7 @@
 
 - Add ``convertVectorExpr``.
 - Add ``dependentSizedExtVectorType``.
+- Add ``macroQualifiedType``.
 
 clang-format
 
Index: clang/docs/LibASTMatchersReference.html
===
--- clang/docs/LibASTMatchersReference.html
+++ clang/docs/LibASTMatchersReference.html
@@ -2648,6 +2648,18 @@
 
 
 
+MatcherType>macroQualifiedTypeMatcherMacroQualifiedType>...
+Matches qualified types when the qualifier is applied via a macro.
+
+Given
+  #define CDECL __attribute__((cdecl))
+  typedef void (CDECL *X)();
+  typedef void (__attribute__((cdecl)) *Y)();
+macroQualifiedType()
+  matches the type of the typedef declaration of X but not Y.
+
+
+
 MatcherType>memberPointerTypeMatcherMemberPointerType>...
 Matches member pointer types.
 Given
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D157691: [ASTImporter] Remove extranous FunctionTemplateDecl introduced by templated friend

2023-08-15 Thread Ding Fei via Phabricator via cfe-commits
danix800 added a comment.

In D157691#4587490 , @balazske wrote:

> When committing this patch, the commit message should not contain the whole 
> AST and crash dump (phabricator takes the "summary" text), this looks too 
> much in a commit message. One AST dump from the wrong To AST is enough.

👍


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157691

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


[PATCH] D157691: [ASTImporter] Remove extranous FunctionTemplateDecl introduced by templated friend

2023-08-15 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 550210.
danix800 added a comment.

1. Remove unnecessary testcase.
2. Format unittest code.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157691

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp


Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -5634,6 +5634,43 @@
   EXPECT_EQ(Imported->getPreviousDecl(), Friend);
 }
 
+TEST_P(ImportFriendFunctionTemplates, ImportFriendFunctionInsideClassTemplate) 
{
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"(
+  template  struct X {
+template  friend void f();
+  };
+  )",
+  Lang_CXX03, "", Lang_CXX03, "X");
+
+  auto *FromFriend = FirstDeclMatcher().match(From, friendDecl());
+  auto *ToFriend = FirstDeclMatcher().match(To, friendDecl());
+
+  EXPECT_TRUE(FromFriend ==
+  LastDeclMatcher().match(From, friendDecl()));
+  EXPECT_TRUE(ToFriend ==
+  LastDeclMatcher().match(To, friendDecl()));
+
+  auto *FromDecl = FromFriend->getFriendDecl();
+  auto *FromDC = FromFriend->getDeclContext();
+  auto *FromLexicalDC = FromFriend->getLexicalDeclContext();
+
+  EXPECT_TRUE(FromDC->containsDecl(FromFriend));
+  EXPECT_FALSE(FromDC->containsDecl(FromDecl));
+  EXPECT_TRUE(FromLexicalDC->containsDecl(FromFriend));
+  EXPECT_FALSE(FromLexicalDC->containsDecl(FromDecl));
+
+  auto *ToDecl = ToFriend->getFriendDecl();
+  auto *ToDC = ToFriend->getDeclContext();
+  auto *ToLexicalDC = ToFriend->getLexicalDeclContext();
+
+  EXPECT_TRUE(ToDC->containsDecl(ToFriend));
+  EXPECT_FALSE(ToDC->containsDecl(ToDecl));
+  EXPECT_TRUE(ToLexicalDC->containsDecl(ToFriend));
+  EXPECT_FALSE(ToLexicalDC->containsDecl(ToDecl));
+}
+
 struct ASTImporterWithFakeErrors : ASTImporter {
   using ASTImporter::ASTImporter;
   bool returnWithErrorInTest() override { return true; }
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -6447,7 +6447,7 @@
 
   ToFunc->setAccess(D->getAccess());
   ToFunc->setLexicalDeclContext(LexicalDC);
-  LexicalDC->addDeclInternal(ToFunc);
+  addDeclToContexts(D, ToFunc);
 
   ASTImporterLookupTable *LT = Importer.SharedState->getLookupTable();
   if (LT && !OldParamDC.empty()) {


Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -5634,6 +5634,43 @@
   EXPECT_EQ(Imported->getPreviousDecl(), Friend);
 }
 
+TEST_P(ImportFriendFunctionTemplates, ImportFriendFunctionInsideClassTemplate) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"(
+  template  struct X {
+template  friend void f();
+  };
+  )",
+  Lang_CXX03, "", Lang_CXX03, "X");
+
+  auto *FromFriend = FirstDeclMatcher().match(From, friendDecl());
+  auto *ToFriend = FirstDeclMatcher().match(To, friendDecl());
+
+  EXPECT_TRUE(FromFriend ==
+  LastDeclMatcher().match(From, friendDecl()));
+  EXPECT_TRUE(ToFriend ==
+  LastDeclMatcher().match(To, friendDecl()));
+
+  auto *FromDecl = FromFriend->getFriendDecl();
+  auto *FromDC = FromFriend->getDeclContext();
+  auto *FromLexicalDC = FromFriend->getLexicalDeclContext();
+
+  EXPECT_TRUE(FromDC->containsDecl(FromFriend));
+  EXPECT_FALSE(FromDC->containsDecl(FromDecl));
+  EXPECT_TRUE(FromLexicalDC->containsDecl(FromFriend));
+  EXPECT_FALSE(FromLexicalDC->containsDecl(FromDecl));
+
+  auto *ToDecl = ToFriend->getFriendDecl();
+  auto *ToDC = ToFriend->getDeclContext();
+  auto *ToLexicalDC = ToFriend->getLexicalDeclContext();
+
+  EXPECT_TRUE(ToDC->containsDecl(ToFriend));
+  EXPECT_FALSE(ToDC->containsDecl(ToDecl));
+  EXPECT_TRUE(ToLexicalDC->containsDecl(ToFriend));
+  EXPECT_FALSE(ToLexicalDC->containsDecl(ToDecl));
+}
+
 struct ASTImporterWithFakeErrors : ASTImporter {
   using ASTImporter::ASTImporter;
   bool returnWithErrorInTest() override { return true; }
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -6447,7 +6447,7 @@
 
   ToFunc->setAccess(D->getAccess());
   ToFunc->setLexicalDeclContext(LexicalDC);
-  LexicalDC->addDeclInternal(ToFunc);
+  addDeclToContexts(D, ToFunc);
 
   ASTImporterLookupTable *LT = Importer.SharedState->getLookupTable();
   if (LT && !OldParamDC.empty()) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158145: [clang] Update NumFunctionDeclBits for FunctionDeclBitfields

2023-08-16 Thread Ding Fei via Phabricator via cfe-commits
danix800 created this revision.
danix800 added reviewers: aaron.ballman, cor3ntin, ychen, balazske.
danix800 added a project: clang.
Herald added a reviewer: shafik.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a subscriber: cfe-commits.

`FunctionDeclBitfields.NumFunctionDeclBits` is not updated when 
`DeductionCandidateKind` is incremented.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D158145

Files:
  clang/include/clang/AST/DeclBase.h
  clang/lib/Serialization/ASTWriterDecl.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -7832,6 +7832,47 @@
   CheckAST(ToTU, ToC);
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase,
+ImportFunctionDeclBitShouldNotStampingOnCtorDeclBits) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"s(
+struct A {
+  A() : m() {}
+  int m;
+};
+
+A foo() { A a; return a; }
+A bar() { return {}; }
+  )s",
+  Lang_CXX17,
+  R"s(
+struct A {
+  A() : m() {}
+  int m;
+};
+A baz() { return {}; }
+  )s",
+  Lang_CXX17, "A");
+
+  auto HasCtorInit =
+  hasAnyConstructorInitializer(cxxCtorInitializer(isMemberInitializer()));
+  auto ImpMoveCtor =
+  cxxConstructorDecl(isMoveConstructor(), isImplicit(), HasCtorInit);
+
+  auto *FromImpMoveCtor = FirstDeclMatcher().match(
+  From, ImpMoveCtor);
+  auto *ToImpMoveCtor = FirstDeclMatcher().match(
+  To, ImpMoveCtor);
+
+  EXPECT_TRUE(FromImpMoveCtor->getNumCtorInitializers() == 1);
+  EXPECT_FALSE(FromImpMoveCtor->FriendConstraintRefersToEnclosingTemplate());
+
+  EXPECT_TRUE(ToImpMoveCtor->getNumCtorInitializers() == 1);
+  EXPECT_FALSE(ToImpMoveCtor->FriendConstraintRefersToEnclosingTemplate());
+  EXPECT_TRUE(*ToImpMoveCtor->init_begin());
+}
+
 AST_MATCHER_P(UsingShadowDecl, hasIntroducerDecl, internal::Matcher,
   InnerMatcher) {
   return InnerMatcher.matches(*Node.getIntroducer(), Finder, Builder);
Index: clang/lib/Serialization/ASTWriterDecl.cpp
===
--- clang/lib/Serialization/ASTWriterDecl.cpp
+++ clang/lib/Serialization/ASTWriterDecl.cpp
@@ -580,7 +580,7 @@
 }
 
 void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
-  static_assert(DeclContext::NumFunctionDeclBits == 30,
+  static_assert(DeclContext::NumFunctionDeclBits == 31,
 "You need to update the serializer after you change the "
 "FunctionDeclBits");
 
@@ -1495,7 +1495,7 @@
 }
 
 void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
-  static_assert(DeclContext::NumCXXConstructorDeclBits == 21,
+  static_assert(DeclContext::NumCXXConstructorDeclBits == 20,
 "You need to update the serializer after you change the "
 "CXXConstructorDeclBits");
 
Index: clang/include/clang/AST/DeclBase.h
===
--- clang/include/clang/AST/DeclBase.h
+++ clang/include/clang/AST/DeclBase.h
@@ -1702,7 +1702,7 @@
   };
 
   /// Number of non-inherited bits in FunctionDeclBitfields.
-  enum { NumFunctionDeclBits = 30 };
+  enum { NumFunctionDeclBits = 31 };
 
   /// Stores the bits used by CXXConstructorDecl. If modified
   /// NumCXXConstructorDeclBits and the accessor
@@ -1714,12 +1714,12 @@
 /// For the bits in FunctionDeclBitfields.
 uint64_t : NumFunctionDeclBits;
 
-/// 21 bits to fit in the remaining available space.
+/// 20 bits to fit in the remaining available space.
 /// Note that this makes CXXConstructorDeclBitfields take
 /// exactly 64 bits and thus the width of NumCtorInitializers
 /// will need to be shrunk if some bit is added to NumDeclContextBitfields,
 /// NumFunctionDeclBitfields or CXXConstructorDeclBitfields.
-uint64_t NumCtorInitializers : 18;
+uint64_t NumCtorInitializers : 17;
 uint64_t IsInheritingConstructor : 1;
 
 /// Whether this constructor has a trail-allocated explicit specifier.
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156461: [clang][ASTImporter] Merge implicit ctors with definition

2023-08-16 Thread Ding Fei via Phabricator via cfe-commits
danix800 added a comment.

In D156461#4583806 , @balazske wrote:

> It looks not good to remove an invalid node from the DeclContext that 
> otherwise remains in the AST. I checked the problem and found that the 
> existing move constructor (originally in the To AST which had no definition) 
> gets a `getNumCtorInitializers` value of 1 but the `init_begin` returns 0. 
> This causes crash even when dumping it. I did not find the cause of this 
> situation (the first time at line 3822 it is already changed, and 
> `ASTImporter` has this single position to change the value). Normally what 
> should happen is that a new move constructor is imported (with a definition) 
> and linked after the existing one (and the existing is not modified). We get 
> an AST that does not occur after a normal compile, I do not know if this 
> causes problems or if this is the real reason for this patch. What should be 
> done is find the existing constructor and update it with the definition and 
> return it from the import. This can be done with any type of constructor.

The root cause might be that `FunctionDeclBitfields.NumFunctionDeclBits` is not 
in syncing with updated `FunctionDeclBitfields.DeductionCandidateKind`. See 
D158145 .


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156461

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


[PATCH] D158145: [clang] Update NumFunctionDeclBits for FunctionDeclBitfields

2023-08-16 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 551016.
danix800 added a comment.

Add alternative testcase.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158145

Files:
  clang/include/clang/AST/DeclBase.h
  clang/lib/Serialization/ASTWriterDecl.cpp
  clang/unittests/AST/ASTImporterTest.cpp
  clang/unittests/AST/DeclTest.cpp

Index: clang/unittests/AST/DeclTest.cpp
===
--- clang/unittests/AST/DeclTest.cpp
+++ clang/unittests/AST/DeclTest.cpp
@@ -353,6 +353,33 @@
   EXPECT_TRUE(getFooValue->isInlined());
 }
 
+TEST(Decl, FunctionDeclBitsShouldNotOverlappningWithCXXConstructorDeclBits) {
+  llvm::Annotations Code(R"(
+struct A {
+  A() : m() {}
+  int m;
+};
+
+A f() { return A(); }
+)");
+
+  auto AST = tooling::buildASTFromCodeWithArgs(Code.code(), {"-std=c++14"});
+  ASTContext &Ctx = AST->getASTContext();
+  Ctx.getTranslationUnitDecl()->dump();
+
+  auto HasCtorInit =
+  hasAnyConstructorInitializer(cxxCtorInitializer(isMemberInitializer()));
+  auto ImpMoveCtor =
+  cxxConstructorDecl(isMoveConstructor(), isImplicit(), HasCtorInit)
+  .bind("MoveCtor");
+
+  auto *ToImpMoveCtor =
+  selectFirst("MoveCtor", match(ImpMoveCtor, Ctx));
+
+  EXPECT_TRUE(ToImpMoveCtor->getNumCtorInitializers() == 1);
+  EXPECT_FALSE(ToImpMoveCtor->FriendConstraintRefersToEnclosingTemplate());
+}
+
 TEST(Decl, NoProtoFunctionDeclAttributes) {
   llvm::Annotations Code(R"(
 void f();
Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -7832,6 +7832,47 @@
   CheckAST(ToTU, ToC);
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase,
+ImportFunctionDeclBitShouldNotStampingOnCtorDeclBits) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"s(
+struct A {
+  A() : m() {}
+  int m;
+};
+
+A foo() { A a; return a; }
+A bar() { return {}; }
+  )s",
+  Lang_CXX17,
+  R"s(
+struct A {
+  A() : m() {}
+  int m;
+};
+A baz() { return {}; }
+  )s",
+  Lang_CXX17, "A");
+
+  auto HasCtorInit =
+  hasAnyConstructorInitializer(cxxCtorInitializer(isMemberInitializer()));
+  auto ImpMoveCtor =
+  cxxConstructorDecl(isMoveConstructor(), isImplicit(), HasCtorInit);
+
+  auto *FromImpMoveCtor = FirstDeclMatcher().match(
+  From, ImpMoveCtor);
+  auto *ToImpMoveCtor = FirstDeclMatcher().match(
+  To, ImpMoveCtor);
+
+  EXPECT_TRUE(FromImpMoveCtor->getNumCtorInitializers() == 1);
+  EXPECT_FALSE(FromImpMoveCtor->FriendConstraintRefersToEnclosingTemplate());
+
+  EXPECT_TRUE(ToImpMoveCtor->getNumCtorInitializers() == 1);
+  EXPECT_FALSE(ToImpMoveCtor->FriendConstraintRefersToEnclosingTemplate());
+  EXPECT_TRUE(*ToImpMoveCtor->init_begin());
+}
+
 AST_MATCHER_P(UsingShadowDecl, hasIntroducerDecl, internal::Matcher,
   InnerMatcher) {
   return InnerMatcher.matches(*Node.getIntroducer(), Finder, Builder);
Index: clang/lib/Serialization/ASTWriterDecl.cpp
===
--- clang/lib/Serialization/ASTWriterDecl.cpp
+++ clang/lib/Serialization/ASTWriterDecl.cpp
@@ -580,7 +580,7 @@
 }
 
 void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
-  static_assert(DeclContext::NumFunctionDeclBits == 30,
+  static_assert(DeclContext::NumFunctionDeclBits == 31,
 "You need to update the serializer after you change the "
 "FunctionDeclBits");
 
@@ -1495,7 +1495,7 @@
 }
 
 void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
-  static_assert(DeclContext::NumCXXConstructorDeclBits == 21,
+  static_assert(DeclContext::NumCXXConstructorDeclBits == 20,
 "You need to update the serializer after you change the "
 "CXXConstructorDeclBits");
 
Index: clang/include/clang/AST/DeclBase.h
===
--- clang/include/clang/AST/DeclBase.h
+++ clang/include/clang/AST/DeclBase.h
@@ -1702,7 +1702,7 @@
   };
 
   /// Number of non-inherited bits in FunctionDeclBitfields.
-  enum { NumFunctionDeclBits = 30 };
+  enum { NumFunctionDeclBits = 31 };
 
   /// Stores the bits used by CXXConstructorDecl. If modified
   /// NumCXXConstructorDeclBits and the accessor
@@ -1714,12 +1714,12 @@
 /// For the bits in FunctionDeclBitfields.
 uint64_t : NumFunctionDeclBits;
 
-/// 21 bits to fit in the remaining available space.
+/// 20 bits to fit in the remaining available space.
 /// Note that this makes CXXConstructorDeclBitfields take
 /// exactly 64 bits and thus the width of NumCtorInitializers
 /// will need to be shrunk if some bit is added to NumDeclContextBitfields,
 /// NumFunc

[PATCH] D156461: [clang][ASTImporter] Merge implicit ctors with definition

2023-08-17 Thread Ding Fei via Phabricator via cfe-commits
danix800 added a comment.

In D156461#4583806 , @balazske wrote:

> Normally what should happen is that a new move constructor is imported (with 
> a definition) and linked after the existing one (and the existing is not 
> modified).

Does this violate the constraint that ctor shouldn't be re-declared?

> We get an AST that does not occur after a normal compile, I do not know if 
> this causes problems or if this is the real reason for this patch.

Agreed. The original AST should not be touched.

> What should be done is find the existing constructor and update it with the 
> definition and return it from the import. This can be done with any type of 
> constructor.

So does this mean that importer might be improved on this part?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156461

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


[PATCH] D158145: [clang] Update NumFunctionDeclBits for FunctionDeclBitfields

2023-08-17 Thread Ding Fei via Phabricator via cfe-commits
danix800 added a comment.

> Can you an an entry in `clang/docs/ReleaseNotes.rst` (mentioning the github 
> issue)

No problem!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158145

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


[PATCH] D158145: [clang] Update NumFunctionDeclBits for FunctionDeclBitfields

2023-08-17 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/unittests/AST/ASTImporterTest.cpp:7836
+TEST_P(ASTImporterOptionSpecificTestBase,
+ImportFunctionDeclBitShouldNotStampingOnCtorDeclBits) {
+  Decl *From, *To;

cor3ntin wrote:
> `ImportFunctionDeclBitShouldNotOverwriteCtorDeclBits`
I added the case into `DeclTest.cpp` because i think it can cover the root 
cause for both testcases.

How about remove the somewhat repeated one in `ASTImporterTest.cpp`?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158145

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


[PATCH] D158145: [clang] Update NumFunctionDeclBits for FunctionDeclBitfields

2023-08-17 Thread Ding Fei via Phabricator via cfe-commits
danix800 added a comment.

I also investigated whether we could count those bits at compile time and 
statically assert on them,
because a small typo or missed update could spend us a lot of time to dig for 
the cause.

My first step is trying to count number of bits for a single bitfield, this is 
promising based on this 
 but
with a restriction, it only works on `struct` (default public fields), not 
`class` (default to private fields).

If we can implement this `bitsizeof` then we could have:

  enum { NumFunctionDeclBits = offsetof(FunctionDeclBitfields, SClass)
 + offsetof(FunctionDeclBitfields, IsInline)
 + ... };

This can automatically update total number of bits if any of the existing one 
is updated.

The second step is trying to enumerate all bit fields at compile time so that 
we can totally fix this kind
of issue, but it seems not possible.

Any suggestions or advices? Is it even worth it to do it like this?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158145

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


[PATCH] D158145: [clang] Update NumFunctionDeclBits for FunctionDeclBitfields

2023-08-17 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/unittests/AST/ASTImporterTest.cpp:7836
+TEST_P(ASTImporterOptionSpecificTestBase,
+ImportFunctionDeclBitShouldNotStampingOnCtorDeclBits) {
+  Decl *From, *To;

cor3ntin wrote:
> danix800 wrote:
> > cor3ntin wrote:
> > > `ImportFunctionDeclBitShouldNotOverwriteCtorDeclBits`
> > I added the case into `DeclTest.cpp` because i think it can cover the root 
> > cause for both testcases.
> > 
> > How about remove the somewhat repeated one in `ASTImporterTest.cpp`?
> Now that you have written it, we can leave both tests i think.
> Afaik one test serialization so they complement each other
OK! :-)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158145

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


[PATCH] D158145: [clang] Update NumFunctionDeclBits for FunctionDeclBitfields

2023-08-17 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 551037.
danix800 added a comment.

1. Update ReleaseNotes.rst
2. Fix typos pointed out by @cor3ntin (thanks!)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158145

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/DeclBase.h
  clang/lib/Serialization/ASTWriterDecl.cpp
  clang/unittests/AST/ASTImporterTest.cpp
  clang/unittests/AST/DeclTest.cpp

Index: clang/unittests/AST/DeclTest.cpp
===
--- clang/unittests/AST/DeclTest.cpp
+++ clang/unittests/AST/DeclTest.cpp
@@ -353,6 +353,33 @@
   EXPECT_TRUE(getFooValue->isInlined());
 }
 
+TEST(Decl, FunctionDeclBitsShouldNotOverlapWithCXXConstructorDeclBits) {
+  llvm::Annotations Code(R"(
+struct A {
+  A() : m() {}
+  int m;
+};
+
+A f() { return A(); }
+)");
+
+  auto AST = tooling::buildASTFromCodeWithArgs(Code.code(), {"-std=c++14"});
+  ASTContext &Ctx = AST->getASTContext();
+  Ctx.getTranslationUnitDecl()->dump();
+
+  auto HasCtorInit =
+  hasAnyConstructorInitializer(cxxCtorInitializer(isMemberInitializer()));
+  auto ImpMoveCtor =
+  cxxConstructorDecl(isMoveConstructor(), isImplicit(), HasCtorInit)
+  .bind("MoveCtor");
+
+  auto *ToImpMoveCtor =
+  selectFirst("MoveCtor", match(ImpMoveCtor, Ctx));
+
+  EXPECT_TRUE(ToImpMoveCtor->getNumCtorInitializers() == 1);
+  EXPECT_FALSE(ToImpMoveCtor->FriendConstraintRefersToEnclosingTemplate());
+}
+
 TEST(Decl, NoProtoFunctionDeclAttributes) {
   llvm::Annotations Code(R"(
 void f();
Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -7832,6 +7832,47 @@
   CheckAST(ToTU, ToC);
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase,
+   ImportFunctionDeclBitShouldNotOverwriteCtorDeclBits) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"s(
+struct A {
+  A() : m() {}
+  int m;
+};
+
+A foo() { A a; return a; }
+A bar() { return {}; }
+  )s",
+  Lang_CXX17,
+  R"s(
+struct A {
+  A() : m() {}
+  int m;
+};
+A baz() { return {}; }
+  )s",
+  Lang_CXX17, "A");
+
+  auto HasCtorInit =
+  hasAnyConstructorInitializer(cxxCtorInitializer(isMemberInitializer()));
+  auto ImpMoveCtor =
+  cxxConstructorDecl(isMoveConstructor(), isImplicit(), HasCtorInit);
+
+  auto *FromImpMoveCtor = FirstDeclMatcher().match(
+  From, ImpMoveCtor);
+  auto *ToImpMoveCtor = FirstDeclMatcher().match(
+  To, ImpMoveCtor);
+
+  EXPECT_TRUE(FromImpMoveCtor->getNumCtorInitializers() == 1);
+  EXPECT_FALSE(FromImpMoveCtor->FriendConstraintRefersToEnclosingTemplate());
+
+  EXPECT_TRUE(ToImpMoveCtor->getNumCtorInitializers() == 1);
+  EXPECT_FALSE(ToImpMoveCtor->FriendConstraintRefersToEnclosingTemplate());
+  EXPECT_TRUE(*ToImpMoveCtor->init_begin());
+}
+
 AST_MATCHER_P(UsingShadowDecl, hasIntroducerDecl, internal::Matcher,
   InnerMatcher) {
   return InnerMatcher.matches(*Node.getIntroducer(), Finder, Builder);
Index: clang/lib/Serialization/ASTWriterDecl.cpp
===
--- clang/lib/Serialization/ASTWriterDecl.cpp
+++ clang/lib/Serialization/ASTWriterDecl.cpp
@@ -580,7 +580,7 @@
 }
 
 void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
-  static_assert(DeclContext::NumFunctionDeclBits == 30,
+  static_assert(DeclContext::NumFunctionDeclBits == 31,
 "You need to update the serializer after you change the "
 "FunctionDeclBits");
 
@@ -1495,7 +1495,7 @@
 }
 
 void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
-  static_assert(DeclContext::NumCXXConstructorDeclBits == 21,
+  static_assert(DeclContext::NumCXXConstructorDeclBits == 20,
 "You need to update the serializer after you change the "
 "CXXConstructorDeclBits");
 
Index: clang/include/clang/AST/DeclBase.h
===
--- clang/include/clang/AST/DeclBase.h
+++ clang/include/clang/AST/DeclBase.h
@@ -1702,7 +1702,7 @@
   };
 
   /// Number of non-inherited bits in FunctionDeclBitfields.
-  enum { NumFunctionDeclBits = 30 };
+  enum { NumFunctionDeclBits = 31 };
 
   /// Stores the bits used by CXXConstructorDecl. If modified
   /// NumCXXConstructorDeclBits and the accessor
@@ -1714,12 +1714,12 @@
 /// For the bits in FunctionDeclBitfields.
 uint64_t : NumFunctionDeclBits;
 
-/// 21 bits to fit in the remaining available space.
+/// 20 bits to fit in the remaining available space.
 /// Note that this makes CXXConstructorDeclBitfields take
 /// exactly 64 bits and thus the width of NumCtorInitializers
 /// will need to

[PATCH] D158145: [clang] Update NumFunctionDeclBits for FunctionDeclBitfields

2023-08-17 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/unittests/AST/DeclTest.cpp:368
+  ASTContext &Ctx = AST->getASTContext();
+  Ctx.getTranslationUnitDecl()->dump();
+

balazske wrote:
> This dump is not needed?
Yeah it's for debug only, I'll remove it.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158145

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


[PATCH] D158145: [clang] Update NumFunctionDeclBits for FunctionDeclBitfields

2023-08-17 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 551078.
danix800 added a comment.

Remove debug code.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158145

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/DeclBase.h
  clang/lib/Serialization/ASTWriterDecl.cpp
  clang/unittests/AST/ASTImporterTest.cpp
  clang/unittests/AST/DeclTest.cpp

Index: clang/unittests/AST/DeclTest.cpp
===
--- clang/unittests/AST/DeclTest.cpp
+++ clang/unittests/AST/DeclTest.cpp
@@ -353,6 +353,32 @@
   EXPECT_TRUE(getFooValue->isInlined());
 }
 
+TEST(Decl, FunctionDeclBitsShouldNotOverlapWithCXXConstructorDeclBits) {
+  llvm::Annotations Code(R"(
+struct A {
+  A() : m() {}
+  int m;
+};
+
+A f() { return A(); }
+)");
+
+  auto AST = tooling::buildASTFromCodeWithArgs(Code.code(), {"-std=c++14"});
+  ASTContext &Ctx = AST->getASTContext();
+
+  auto HasCtorInit =
+  hasAnyConstructorInitializer(cxxCtorInitializer(isMemberInitializer()));
+  auto ImpMoveCtor =
+  cxxConstructorDecl(isMoveConstructor(), isImplicit(), HasCtorInit)
+  .bind("MoveCtor");
+
+  auto *ToImpMoveCtor =
+  selectFirst("MoveCtor", match(ImpMoveCtor, Ctx));
+
+  EXPECT_TRUE(ToImpMoveCtor->getNumCtorInitializers() == 1);
+  EXPECT_FALSE(ToImpMoveCtor->FriendConstraintRefersToEnclosingTemplate());
+}
+
 TEST(Decl, NoProtoFunctionDeclAttributes) {
   llvm::Annotations Code(R"(
 void f();
Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -7832,6 +7832,47 @@
   CheckAST(ToTU, ToC);
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase,
+   ImportFunctionDeclBitShouldNotOverwriteCtorDeclBits) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+  R"s(
+struct A {
+  A() : m() {}
+  int m;
+};
+
+A foo() { A a; return a; }
+A bar() { return {}; }
+  )s",
+  Lang_CXX17,
+  R"s(
+struct A {
+  A() : m() {}
+  int m;
+};
+A baz() { return {}; }
+  )s",
+  Lang_CXX17, "A");
+
+  auto HasCtorInit =
+  hasAnyConstructorInitializer(cxxCtorInitializer(isMemberInitializer()));
+  auto ImpMoveCtor =
+  cxxConstructorDecl(isMoveConstructor(), isImplicit(), HasCtorInit);
+
+  auto *FromImpMoveCtor = FirstDeclMatcher().match(
+  From, ImpMoveCtor);
+  auto *ToImpMoveCtor = FirstDeclMatcher().match(
+  To, ImpMoveCtor);
+
+  EXPECT_TRUE(FromImpMoveCtor->getNumCtorInitializers() == 1);
+  EXPECT_FALSE(FromImpMoveCtor->FriendConstraintRefersToEnclosingTemplate());
+
+  EXPECT_TRUE(ToImpMoveCtor->getNumCtorInitializers() == 1);
+  EXPECT_FALSE(ToImpMoveCtor->FriendConstraintRefersToEnclosingTemplate());
+  EXPECT_TRUE(*ToImpMoveCtor->init_begin());
+}
+
 AST_MATCHER_P(UsingShadowDecl, hasIntroducerDecl, internal::Matcher,
   InnerMatcher) {
   return InnerMatcher.matches(*Node.getIntroducer(), Finder, Builder);
Index: clang/lib/Serialization/ASTWriterDecl.cpp
===
--- clang/lib/Serialization/ASTWriterDecl.cpp
+++ clang/lib/Serialization/ASTWriterDecl.cpp
@@ -580,7 +580,7 @@
 }
 
 void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
-  static_assert(DeclContext::NumFunctionDeclBits == 30,
+  static_assert(DeclContext::NumFunctionDeclBits == 31,
 "You need to update the serializer after you change the "
 "FunctionDeclBits");
 
@@ -1495,7 +1495,7 @@
 }
 
 void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
-  static_assert(DeclContext::NumCXXConstructorDeclBits == 21,
+  static_assert(DeclContext::NumCXXConstructorDeclBits == 20,
 "You need to update the serializer after you change the "
 "CXXConstructorDeclBits");
 
Index: clang/include/clang/AST/DeclBase.h
===
--- clang/include/clang/AST/DeclBase.h
+++ clang/include/clang/AST/DeclBase.h
@@ -1702,7 +1702,7 @@
   };
 
   /// Number of non-inherited bits in FunctionDeclBitfields.
-  enum { NumFunctionDeclBits = 30 };
+  enum { NumFunctionDeclBits = 31 };
 
   /// Stores the bits used by CXXConstructorDecl. If modified
   /// NumCXXConstructorDeclBits and the accessor
@@ -1714,12 +1714,12 @@
 /// For the bits in FunctionDeclBitfields.
 uint64_t : NumFunctionDeclBits;
 
-/// 21 bits to fit in the remaining available space.
+/// 20 bits to fit in the remaining available space.
 /// Note that this makes CXXConstructorDeclBitfields take
 /// exactly 64 bits and thus the width of NumCtorInitializers
 /// will need to be shrunk if some bit is added to NumDeclContextBitfields,
 /// NumFunctionDeclBitfields or 

[PATCH] D158302: [clang] Add simple utils to ensure static assert on bit count of DeclContext

2023-08-18 Thread Ding Fei via Phabricator via cfe-commits
danix800 created this revision.
danix800 added a reviewer: aaron.ballman.
danix800 added a project: clang.
Herald added a subscriber: kristof.beyls.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a subscriber: cfe-commits.

Manually counting bits for DeclContext is error-prone. These two are still 
out-dated:

1. `NumObjCMethodDeclBits` (25, not 24)
2. `NumBlockDeclBits` (6, not 5)

Although no harm at this moment but it's still misleading and might cause 
problem
for the future.

Two simple reflection-like utilities `countBits` & `countFields` are added for 
auto-
updating these bits at compile time and static assert on syncing with any 
changes.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D158302

Files:
  clang/include/clang/AST/DeclBase.h
  clang/include/clang/Support/BitFieldReflection.h
  clang/lib/Serialization/ASTWriterDecl.cpp

Index: clang/lib/Serialization/ASTWriterDecl.cpp
===
--- clang/lib/Serialization/ASTWriterDecl.cpp
+++ clang/lib/Serialization/ASTWriterDecl.cpp
@@ -433,10 +433,6 @@
 }
 
 void ASTDeclWriter::VisitTagDecl(TagDecl *D) {
-  static_assert(DeclContext::NumTagDeclBits == 10,
-"You need to update the serializer after you change the "
-"TagDeclBits");
-
   VisitRedeclarable(D);
   VisitTypeDecl(D);
   Record.push_back(D->getIdentifierNamespace());
@@ -461,10 +457,6 @@
 }
 
 void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
-  static_assert(DeclContext::NumEnumDeclBits == 20,
-"You need to update the serializer after you change the "
-"EnumDeclBits");
-
   VisitTagDecl(D);
   Record.AddTypeSourceInfo(D->getIntegerTypeSourceInfo());
   if (!D->getIntegerTypeSourceInfo())
@@ -508,10 +500,6 @@
 }
 
 void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
-  static_assert(DeclContext::NumRecordDeclBits == 41,
-"You need to update the serializer after you change the "
-"RecordDeclBits");
-
   VisitTagDecl(D);
   Record.push_back(D->hasFlexibleArrayMember());
   Record.push_back(D->isAnonymousStructOrUnion());
@@ -580,10 +568,6 @@
 }
 
 void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
-  static_assert(DeclContext::NumFunctionDeclBits == 31,
-"You need to update the serializer after you change the "
-"FunctionDeclBits");
-
   VisitRedeclarable(D);
 
   Record.push_back(D->getTemplatedKind());
@@ -735,10 +719,6 @@
 }
 
 void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
-  static_assert(DeclContext::NumObjCMethodDeclBits == 24,
-"You need to update the serializer after you change the "
-"ObjCMethodDeclBits");
-
   VisitNamedDecl(D);
   // FIXME: convert to LazyStmtPtr?
   // Unlike C/C++, method bodies will never be in header files.
@@ -797,10 +777,6 @@
 }
 
 void ASTDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) {
-  static_assert(DeclContext::NumObjCContainerDeclBits == 51,
-"You need to update the serializer after you change the "
-"ObjCContainerDeclBits");
-
   VisitNamedDecl(D);
   Record.AddSourceLocation(D->getAtStartLoc());
   Record.AddSourceRange(D->getAtEndRange());
@@ -1284,10 +1260,6 @@
 }
 
 void ASTDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
-  static_assert(DeclContext::NumLinkageSpecDeclBits == 4,
-"You need to update the serializer after you change the"
-"LinkageSpecDeclBits");
-
   VisitDecl(D);
   Record.push_back(D->getLanguage());
   Record.AddSourceLocation(D->getExternLoc());
@@ -1495,10 +1467,6 @@
 }
 
 void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
-  static_assert(DeclContext::NumCXXConstructorDeclBits == 20,
-"You need to update the serializer after you change the "
-"CXXConstructorDeclBits");
-
   Record.push_back(D->getTrailingAllocKind());
   addExplicitSpecifier(D->getExplicitSpecifier(), Record);
   if (auto Inherited = D->getInheritedConstructor()) {
@@ -1875,10 +1843,6 @@
 
 /// Emit the DeclContext part of a declaration context decl.
 void ASTDeclWriter::VisitDeclContext(DeclContext *DC) {
-  static_assert(DeclContext::NumDeclContextBits == 13,
-"You need to update the serializer after you change the "
-"DeclContextBits");
-
   Record.AddOffset(Writer.WriteDeclContextLexicalBlock(Context, DC));
   Record.AddOffset(Writer.WriteDeclContextVisibleBlock(Context, DC));
 }
@@ -1989,10 +1953,6 @@
 }
 
 void ASTDeclWriter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
-  static_assert(DeclContext::NumOMPDeclareReductionDeclBits == 2,
-"You need to update the serializer after you change the "
-"NumOMPDeclareReductionDeclBits");
-
   VisitValueDecl(D);
   Record.AddSourceLocation(D->getBeginLoc());
   Record.AddStmt(D->getCombinerIn());
Index: clang/include/c

[PATCH] D158302: [clang] Add simple utils to ensure static assert on bit count of DeclContext

2023-08-19 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 551737.
danix800 added a comment.

Remove ununsed code.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158302

Files:
  clang/include/clang/AST/DeclBase.h
  clang/include/clang/Support/BitFieldReflection.h
  clang/lib/Serialization/ASTWriterDecl.cpp

Index: clang/lib/Serialization/ASTWriterDecl.cpp
===
--- clang/lib/Serialization/ASTWriterDecl.cpp
+++ clang/lib/Serialization/ASTWriterDecl.cpp
@@ -433,10 +433,6 @@
 }
 
 void ASTDeclWriter::VisitTagDecl(TagDecl *D) {
-  static_assert(DeclContext::NumTagDeclBits == 10,
-"You need to update the serializer after you change the "
-"TagDeclBits");
-
   VisitRedeclarable(D);
   VisitTypeDecl(D);
   Record.push_back(D->getIdentifierNamespace());
@@ -461,10 +457,6 @@
 }
 
 void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
-  static_assert(DeclContext::NumEnumDeclBits == 20,
-"You need to update the serializer after you change the "
-"EnumDeclBits");
-
   VisitTagDecl(D);
   Record.AddTypeSourceInfo(D->getIntegerTypeSourceInfo());
   if (!D->getIntegerTypeSourceInfo())
@@ -508,10 +500,6 @@
 }
 
 void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
-  static_assert(DeclContext::NumRecordDeclBits == 41,
-"You need to update the serializer after you change the "
-"RecordDeclBits");
-
   VisitTagDecl(D);
   Record.push_back(D->hasFlexibleArrayMember());
   Record.push_back(D->isAnonymousStructOrUnion());
@@ -580,10 +568,6 @@
 }
 
 void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
-  static_assert(DeclContext::NumFunctionDeclBits == 31,
-"You need to update the serializer after you change the "
-"FunctionDeclBits");
-
   VisitRedeclarable(D);
 
   Record.push_back(D->getTemplatedKind());
@@ -735,10 +719,6 @@
 }
 
 void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
-  static_assert(DeclContext::NumObjCMethodDeclBits == 24,
-"You need to update the serializer after you change the "
-"ObjCMethodDeclBits");
-
   VisitNamedDecl(D);
   // FIXME: convert to LazyStmtPtr?
   // Unlike C/C++, method bodies will never be in header files.
@@ -797,10 +777,6 @@
 }
 
 void ASTDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) {
-  static_assert(DeclContext::NumObjCContainerDeclBits == 51,
-"You need to update the serializer after you change the "
-"ObjCContainerDeclBits");
-
   VisitNamedDecl(D);
   Record.AddSourceLocation(D->getAtStartLoc());
   Record.AddSourceRange(D->getAtEndRange());
@@ -1284,10 +1260,6 @@
 }
 
 void ASTDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
-  static_assert(DeclContext::NumLinkageSpecDeclBits == 4,
-"You need to update the serializer after you change the"
-"LinkageSpecDeclBits");
-
   VisitDecl(D);
   Record.push_back(D->getLanguage());
   Record.AddSourceLocation(D->getExternLoc());
@@ -1495,10 +1467,6 @@
 }
 
 void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
-  static_assert(DeclContext::NumCXXConstructorDeclBits == 20,
-"You need to update the serializer after you change the "
-"CXXConstructorDeclBits");
-
   Record.push_back(D->getTrailingAllocKind());
   addExplicitSpecifier(D->getExplicitSpecifier(), Record);
   if (auto Inherited = D->getInheritedConstructor()) {
@@ -1875,10 +1843,6 @@
 
 /// Emit the DeclContext part of a declaration context decl.
 void ASTDeclWriter::VisitDeclContext(DeclContext *DC) {
-  static_assert(DeclContext::NumDeclContextBits == 13,
-"You need to update the serializer after you change the "
-"DeclContextBits");
-
   Record.AddOffset(Writer.WriteDeclContextLexicalBlock(Context, DC));
   Record.AddOffset(Writer.WriteDeclContextVisibleBlock(Context, DC));
 }
@@ -1989,10 +1953,6 @@
 }
 
 void ASTDeclWriter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
-  static_assert(DeclContext::NumOMPDeclareReductionDeclBits == 2,
-"You need to update the serializer after you change the "
-"NumOMPDeclareReductionDeclBits");
-
   VisitValueDecl(D);
   Record.AddSourceLocation(D->getBeginLoc());
   Record.AddStmt(D->getCombinerIn());
Index: clang/include/clang/Support/BitFieldReflection.h
===
--- /dev/null
+++ clang/include/clang/Support/BitFieldReflection.h
@@ -0,0 +1,104 @@
+//===--- BitFieldReflection.h - BitField Reflection Utils ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--

[PATCH] D158302: [clang] Add simple utils to ensure static assert on bit count of DeclContext

2023-08-19 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 551738.
danix800 added a comment.

Apply git-clang-format


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158302

Files:
  clang/include/clang/AST/DeclBase.h
  clang/include/clang/Support/BitFieldReflection.h
  clang/lib/Serialization/ASTWriterDecl.cpp

Index: clang/lib/Serialization/ASTWriterDecl.cpp
===
--- clang/lib/Serialization/ASTWriterDecl.cpp
+++ clang/lib/Serialization/ASTWriterDecl.cpp
@@ -433,10 +433,6 @@
 }
 
 void ASTDeclWriter::VisitTagDecl(TagDecl *D) {
-  static_assert(DeclContext::NumTagDeclBits == 10,
-"You need to update the serializer after you change the "
-"TagDeclBits");
-
   VisitRedeclarable(D);
   VisitTypeDecl(D);
   Record.push_back(D->getIdentifierNamespace());
@@ -461,10 +457,6 @@
 }
 
 void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
-  static_assert(DeclContext::NumEnumDeclBits == 20,
-"You need to update the serializer after you change the "
-"EnumDeclBits");
-
   VisitTagDecl(D);
   Record.AddTypeSourceInfo(D->getIntegerTypeSourceInfo());
   if (!D->getIntegerTypeSourceInfo())
@@ -508,10 +500,6 @@
 }
 
 void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
-  static_assert(DeclContext::NumRecordDeclBits == 41,
-"You need to update the serializer after you change the "
-"RecordDeclBits");
-
   VisitTagDecl(D);
   Record.push_back(D->hasFlexibleArrayMember());
   Record.push_back(D->isAnonymousStructOrUnion());
@@ -580,10 +568,6 @@
 }
 
 void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
-  static_assert(DeclContext::NumFunctionDeclBits == 31,
-"You need to update the serializer after you change the "
-"FunctionDeclBits");
-
   VisitRedeclarable(D);
 
   Record.push_back(D->getTemplatedKind());
@@ -735,10 +719,6 @@
 }
 
 void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
-  static_assert(DeclContext::NumObjCMethodDeclBits == 24,
-"You need to update the serializer after you change the "
-"ObjCMethodDeclBits");
-
   VisitNamedDecl(D);
   // FIXME: convert to LazyStmtPtr?
   // Unlike C/C++, method bodies will never be in header files.
@@ -797,10 +777,6 @@
 }
 
 void ASTDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) {
-  static_assert(DeclContext::NumObjCContainerDeclBits == 51,
-"You need to update the serializer after you change the "
-"ObjCContainerDeclBits");
-
   VisitNamedDecl(D);
   Record.AddSourceLocation(D->getAtStartLoc());
   Record.AddSourceRange(D->getAtEndRange());
@@ -1284,10 +1260,6 @@
 }
 
 void ASTDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
-  static_assert(DeclContext::NumLinkageSpecDeclBits == 4,
-"You need to update the serializer after you change the"
-"LinkageSpecDeclBits");
-
   VisitDecl(D);
   Record.push_back(D->getLanguage());
   Record.AddSourceLocation(D->getExternLoc());
@@ -1495,10 +1467,6 @@
 }
 
 void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
-  static_assert(DeclContext::NumCXXConstructorDeclBits == 20,
-"You need to update the serializer after you change the "
-"CXXConstructorDeclBits");
-
   Record.push_back(D->getTrailingAllocKind());
   addExplicitSpecifier(D->getExplicitSpecifier(), Record);
   if (auto Inherited = D->getInheritedConstructor()) {
@@ -1875,10 +1843,6 @@
 
 /// Emit the DeclContext part of a declaration context decl.
 void ASTDeclWriter::VisitDeclContext(DeclContext *DC) {
-  static_assert(DeclContext::NumDeclContextBits == 13,
-"You need to update the serializer after you change the "
-"DeclContextBits");
-
   Record.AddOffset(Writer.WriteDeclContextLexicalBlock(Context, DC));
   Record.AddOffset(Writer.WriteDeclContextVisibleBlock(Context, DC));
 }
@@ -1989,10 +1953,6 @@
 }
 
 void ASTDeclWriter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
-  static_assert(DeclContext::NumOMPDeclareReductionDeclBits == 2,
-"You need to update the serializer after you change the "
-"NumOMPDeclareReductionDeclBits");
-
   VisitValueDecl(D);
   Record.AddSourceLocation(D->getBeginLoc());
   Record.AddStmt(D->getCombinerIn());
Index: clang/include/clang/Support/BitFieldReflection.h
===
--- /dev/null
+++ clang/include/clang/Support/BitFieldReflection.h
@@ -0,0 +1,104 @@
+//===--- BitFieldReflection.h - BitField Reflection Utils ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===

[PATCH] D157684: [clang][ASTImporter] Repeated friend templates are partially imported

2023-08-22 Thread Ding Fei via Phabricator via cfe-commits
danix800 added a comment.

ping~ @balazske @aaron.ballman


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157684

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


[PATCH] D158499: [analyzer] Compute FAM dynamic size

2023-08-22 Thread Ding Fei via Phabricator via cfe-commits
danix800 created this revision.
danix800 added a project: clang.
Herald added subscribers: steakhal, manas, ASDenysPetrov, martong, dkrupp, 
donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, 
xazax.hun.
Herald added a reviewer: NoQ.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a subscriber: cfe-commits.

This commit computes size of FAM which is normally allocated dynamically.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D158499

Files:
  clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp
  clang/test/Analysis/flexible-array-members.c

Index: clang/test/Analysis/flexible-array-members.c
===
--- clang/test/Analysis/flexible-array-members.c
+++ clang/test/Analysis/flexible-array-members.c
@@ -44,20 +44,52 @@
   clang_analyzer_dump(clang_analyzer_getExtent(&fam));
   clang_analyzer_dump(clang_analyzer_getExtent(fam.data));
   // expected-warning@-2 {{4 S64b}}
-  // expected-warning@-2 {{Unknown}}
+  // expected-warning@-2 {{0 U64b}}
 
   FAM *p = (FAM *)alloca(sizeof(FAM));
   clang_analyzer_dump(clang_analyzer_getExtent(p));
   clang_analyzer_dump(clang_analyzer_getExtent(p->data));
   // expected-warning@-2 {{4 U64b}}
-  // expected-warning@-2 {{Unknown}}
+  // expected-warning@-2 {{0 U64b}}
 
   FAM *q = (FAM *)malloc(sizeof(FAM));
   clang_analyzer_dump(clang_analyzer_getExtent(q));
   clang_analyzer_dump(clang_analyzer_getExtent(q->data));
   // expected-warning@-2 {{4 U64b}}
-  // expected-warning@-2 {{Unknown}}
+  // expected-warning@-2 {{0 U64b}}
   free(q);
+
+  q = (FAM *)malloc(sizeof(FAM) + sizeof(int) * 2);
+  clang_analyzer_dump(clang_analyzer_getExtent(q));
+  clang_analyzer_dump(clang_analyzer_getExtent(q->data));
+  // expected-warning@-2 {{12 U64b}}
+  // expected-warning@-2 {{8 U64b}}
+  free(q);
+
+  typedef struct __attribute__((packed)) {
+char c;
+int data[];
+  } PackedFAM;
+
+  PackedFAM *t = (PackedFAM *)malloc(sizeof(PackedFAM) + sizeof(int) * 2);
+  clang_analyzer_dump(clang_analyzer_getExtent(t));
+  clang_analyzer_dump(clang_analyzer_getExtent(t->data));
+  // expected-warning@-2 {{9 U64b}}
+  // expected-warning@-2 {{8 U64b}}
+  free(t);
+}
+
+void test_too_small_base(void) {
+  typedef struct FAM {
+long c;
+int data[0];
+  } FAM;
+  short s = 0;
+  FAM *p = (FAM *) &s;
+  clang_analyzer_dump(clang_analyzer_getExtent(p));
+  clang_analyzer_dump(clang_analyzer_getExtent(p->data));
+  // expected-warning@-2 {{2 S64b}}
+  // expected-warning@-2 {{Unknown}}
 }
 
 void test_zero_length_array_fam(void) {
Index: clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp
===
--- clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp
+++ clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp
@@ -25,6 +25,51 @@
 namespace clang {
 namespace ento {
 
+DefinedOrUnknownSVal getDynamicExtent(ProgramStateRef State,
+  const MemRegion *MR, SValBuilder &SVB);
+
+static bool isFlexibleArrayMember(const FieldDecl *FD) {
+  const auto *RD = FD->getParent();
+  if (!RD->hasFlexibleArrayMember())
+return false;
+
+  const FieldDecl *LastFD = nullptr;
+  for (const FieldDecl *It : RD->fields())
+LastFD = It;
+
+  return FD == LastFD;
+}
+
+static std::optional
+getFlexibleArrayExtent(ProgramStateRef State, const MemRegion *MR,
+   SValBuilder &SVB) {
+  const auto *FieldMR = dyn_cast(MR);
+  if (nullptr == FieldMR)
+return std::nullopt;
+
+  const FieldDecl *FD = FieldMR->getDecl();
+  if (!isFlexibleArrayMember(FD))
+return std::nullopt;
+
+  const RecordDecl *RD = FD->getParent();
+  const MemRegion *BaseMR = FieldMR->getBaseRegion();
+  auto BaseSize = getDynamicExtent(State, BaseMR, SVB);
+
+  auto &C = SVB.getContext();
+  uint64_t RecordSize = C.getTypeSizeInChars(C.getRecordType(RD)).getQuantity();
+  SVal RecordSizeVal = SVB.makeIntVal(RecordSize, C.getSizeType());
+
+  SVal BaseTooSmall =
+  SVB.evalBinOp(State, BO_LT, BaseSize, RecordSizeVal, C.BoolTy);
+  if (!BaseTooSmall.isUndef() &&
+  State->assume(*BaseTooSmall.getAs(), true))
+return std::nullopt;
+
+  SVal FlexibleArrayExtent =
+  SVB.evalBinOp(State, BO_Sub, BaseSize, RecordSizeVal, C.getSizeType());
+  return FlexibleArrayExtent.getAs();
+}
+
 DefinedOrUnknownSVal getDynamicExtent(ProgramStateRef State,
   const MemRegion *MR, SValBuilder &SVB) {
   MR = MR->StripCasts();
@@ -32,6 +77,9 @@
   if (const DefinedOrUnknownSVal *Size = State->get(MR))
 return *Size;
 
+  if (auto FlexibleArrayExtent = getFlexibleArrayExtent(State, MR, SVB))
+return *FlexibleArrayExtent;
+
   return MR->getMemRegionManager().getStaticSize(MR, SVB);
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158499: [analyzer] Compute FAM dynamic size

2023-08-22 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 552288.
danix800 added a comment.

Update testcase


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158499

Files:
  clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp
  clang/test/Analysis/flexible-array-members.c

Index: clang/test/Analysis/flexible-array-members.c
===
--- clang/test/Analysis/flexible-array-members.c
+++ clang/test/Analysis/flexible-array-members.c
@@ -44,20 +44,52 @@
   clang_analyzer_dump(clang_analyzer_getExtent(&fam));
   clang_analyzer_dump(clang_analyzer_getExtent(fam.data));
   // expected-warning@-2 {{4 S64b}}
-  // expected-warning@-2 {{Unknown}}
+  // expected-warning@-2 {{0 U64b}}
 
   FAM *p = (FAM *)alloca(sizeof(FAM));
   clang_analyzer_dump(clang_analyzer_getExtent(p));
   clang_analyzer_dump(clang_analyzer_getExtent(p->data));
   // expected-warning@-2 {{4 U64b}}
-  // expected-warning@-2 {{Unknown}}
+  // expected-warning@-2 {{0 U64b}}
 
   FAM *q = (FAM *)malloc(sizeof(FAM));
   clang_analyzer_dump(clang_analyzer_getExtent(q));
   clang_analyzer_dump(clang_analyzer_getExtent(q->data));
   // expected-warning@-2 {{4 U64b}}
-  // expected-warning@-2 {{Unknown}}
+  // expected-warning@-2 {{0 U64b}}
   free(q);
+
+  q = (FAM *)malloc(sizeof(FAM) + sizeof(int) * 2);
+  clang_analyzer_dump(clang_analyzer_getExtent(q));
+  clang_analyzer_dump(clang_analyzer_getExtent(q->data));
+  // expected-warning@-2 {{12 U64b}}
+  // expected-warning@-2 {{8 U64b}}
+  free(q);
+
+  typedef struct __attribute__((packed)) {
+char c;
+int data[];
+  } PackedFAM;
+
+  PackedFAM *t = (PackedFAM *)malloc(sizeof(PackedFAM) + sizeof(int) * 2);
+  clang_analyzer_dump(clang_analyzer_getExtent(t));
+  clang_analyzer_dump(clang_analyzer_getExtent(t->data));
+  // expected-warning@-2 {{9 U64b}}
+  // expected-warning@-2 {{8 U64b}}
+  free(t);
+}
+
+void test_too_small_base(void) {
+  typedef struct FAM {
+long c;
+int data[];
+  } FAM;
+  short s = 0;
+  FAM *p = (FAM *) &s;
+  clang_analyzer_dump(clang_analyzer_getExtent(p));
+  clang_analyzer_dump(clang_analyzer_getExtent(p->data));
+  // expected-warning@-2 {{2 S64b}}
+  // expected-warning@-2 {{Unknown}}
 }
 
 void test_zero_length_array_fam(void) {
Index: clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp
===
--- clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp
+++ clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp
@@ -25,6 +25,51 @@
 namespace clang {
 namespace ento {
 
+DefinedOrUnknownSVal getDynamicExtent(ProgramStateRef State,
+  const MemRegion *MR, SValBuilder &SVB);
+
+static bool isFlexibleArrayMember(const FieldDecl *FD) {
+  const auto *RD = FD->getParent();
+  if (!RD->hasFlexibleArrayMember())
+return false;
+
+  const FieldDecl *LastFD = nullptr;
+  for (const FieldDecl *It : RD->fields())
+LastFD = It;
+
+  return FD == LastFD;
+}
+
+static std::optional
+getFlexibleArrayExtent(ProgramStateRef State, const MemRegion *MR,
+   SValBuilder &SVB) {
+  const auto *FieldMR = dyn_cast(MR);
+  if (nullptr == FieldMR)
+return std::nullopt;
+
+  const FieldDecl *FD = FieldMR->getDecl();
+  if (!isFlexibleArrayMember(FD))
+return std::nullopt;
+
+  const RecordDecl *RD = FD->getParent();
+  const MemRegion *BaseMR = FieldMR->getBaseRegion();
+  auto BaseSize = getDynamicExtent(State, BaseMR, SVB);
+
+  auto &C = SVB.getContext();
+  uint64_t RecordSize = C.getTypeSizeInChars(C.getRecordType(RD)).getQuantity();
+  SVal RecordSizeVal = SVB.makeIntVal(RecordSize, C.getSizeType());
+
+  SVal BaseTooSmall =
+  SVB.evalBinOp(State, BO_LT, BaseSize, RecordSizeVal, C.BoolTy);
+  if (!BaseTooSmall.isUndef() &&
+  State->assume(*BaseTooSmall.getAs(), true))
+return std::nullopt;
+
+  SVal FlexibleArrayExtent =
+  SVB.evalBinOp(State, BO_Sub, BaseSize, RecordSizeVal, C.getSizeType());
+  return FlexibleArrayExtent.getAs();
+}
+
 DefinedOrUnknownSVal getDynamicExtent(ProgramStateRef State,
   const MemRegion *MR, SValBuilder &SVB) {
   MR = MR->StripCasts();
@@ -32,6 +77,9 @@
   if (const DefinedOrUnknownSVal *Size = State->get(MR))
 return *Size;
 
+  if (auto FlexibleArrayExtent = getFlexibleArrayExtent(State, MR, SVB))
+return *FlexibleArrayExtent;
+
   return MR->getMemRegionManager().getStaticSize(MR, SVB);
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158499: [analyzer] Compute FAM dynamic size

2023-08-22 Thread Ding Fei via Phabricator via cfe-commits
danix800 added a comment.

In D158499#4606291 , @steakhal wrote:

> Thanks for submitting this.
> A funny thing is that in my free time I was also working on this last week. 
> I'll have a look at this more in depth during the week.
> For the mean time here is my version, committed pretty much a couple days ago 
> to my fork.
> https://github.com/steakhal/llvm-project/commit/986059a146e036ec84db64868a079d3c4a0e5e16
>
> EDIT: fix the link to point to my fork.
>
> Your proposed change looks pretty similar to mine.

Are you going to submit your changes? Which one do you think is more suitable?

Please let me know whether I should continue on this one or wait for yours. 
Thanks!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158499

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


[PATCH] D157684: [clang][ASTImporter] Repeated friend templates are partially imported

2023-08-22 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/lib/AST/ASTImporter.cpp:4114
   SmallVector ImportedEquivalentFriends;
-
-  while (ImportedFriend) {
-bool Match = false;
-if (D->getFriendDecl() && ImportedFriend->getFriendDecl()) {
-  Match =
-  IsStructuralMatch(D->getFriendDecl(), 
ImportedFriend->getFriendDecl(),
-/*Complain=*/false);
-} else if (D->getFriendType() && ImportedFriend->getFriendType()) {
-  Match = Importer.IsStructurallyEquivalent(
-  D->getFriendType()->getType(),
-  ImportedFriend->getFriendType()->getType(), /*Complain=*/false);
-}
-if (Match)
+  for (auto *ImportedFriend : RD->friends())
+if (IsEquivalentFriend(Importer, D, ImportedFriend))

balazske wrote:
> `auto` should not be used here, this loop could be replaced by some generic 
> "algorithm" function call (`llvm::copy_if`).
There's no trivial predicate so the result code might be:
```
  llvm::copy_if(RD->friends(), std::back_inserter(ImportedEquivalentFriends),
[&](FriendDecl *ImportedFriend) {
  return IsEquivalentFriend(Importer, D, ImportedFriend);
});
```
which is not that 'intuitive' as the for-range version.

I'll pertain to the original one with `auto` replaced with explicit type. 
Thanks!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157684

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


[PATCH] D157684: [clang][ASTImporter] Repeated friend templates are partially imported

2023-08-22 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 552372.
danix800 added a comment.

1. Rebase;
2. Replace `auto` with explicit type;
3. Use local var without interrupting `Importer` state.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157684

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -4054,6 +4054,25 @@
  ->lookup(ToRecordOfFriend->getDeclName())
  .empty());
   }
+
+  void testRepeatedFriendImport(const char *Code) {
+Decl *ToTu = getToTuDecl(Code, Lang_CXX03);
+Decl *FromTu = getTuDecl(Code, Lang_CXX03, "from.cc");
+
+auto *ToFriend1 = FirstDeclMatcher().match(ToTu, friendDecl());
+auto *ToFriend2 = LastDeclMatcher().match(ToTu, friendDecl());
+auto *FromFriend1 =
+FirstDeclMatcher().match(FromTu, friendDecl());
+auto *FromFriend2 =
+LastDeclMatcher().match(FromTu, friendDecl());
+
+FriendDecl *ToImportedFriend1 = Import(FromFriend1, Lang_CXX03);
+FriendDecl *ToImportedFriend2 = Import(FromFriend2, Lang_CXX03);
+
+EXPECT_NE(ToImportedFriend1, ToImportedFriend2);
+EXPECT_EQ(ToFriend1, ToImportedFriend1);
+EXPECT_EQ(ToFriend2, ToImportedFriend2);
+  }
 };
 
 TEST_P(ImportFriendClasses, ImportOfFriendRecordDoesNotMergeDefinition) {
@@ -4395,21 +4414,7 @@
 friend class X;
   };
   )";
-  Decl *ToTu = getToTuDecl(Code, Lang_CXX03);
-  Decl *FromTu = getTuDecl(Code, Lang_CXX03, "from.cc");
-
-  auto *ToFriend1 = FirstDeclMatcher().match(ToTu, friendDecl());
-  auto *ToFriend2 = LastDeclMatcher().match(ToTu, friendDecl());
-  auto *FromFriend1 =
-  FirstDeclMatcher().match(FromTu, friendDecl());
-  auto *FromFriend2 = LastDeclMatcher().match(FromTu, friendDecl());
-
-  FriendDecl *ToImportedFriend1 = Import(FromFriend1, Lang_CXX03);
-  FriendDecl *ToImportedFriend2 = Import(FromFriend2, Lang_CXX03);
-
-  EXPECT_NE(ToImportedFriend1, ToImportedFriend2);
-  EXPECT_EQ(ToFriend1, ToImportedFriend1);
-  EXPECT_EQ(ToFriend2, ToImportedFriend2);
+  testRepeatedFriendImport(Code);
 }
 
 TEST_P(ImportFriendClasses, ImportOfRepeatedFriendDecl) {
@@ -4420,21 +4425,31 @@
 friend void f();
   };
   )";
-  Decl *ToTu = getToTuDecl(Code, Lang_CXX03);
-  Decl *FromTu = getTuDecl(Code, Lang_CXX03, "from.cc");
-
-  auto *ToFriend1 = FirstDeclMatcher().match(ToTu, friendDecl());
-  auto *ToFriend2 = LastDeclMatcher().match(ToTu, friendDecl());
-  auto *FromFriend1 =
-  FirstDeclMatcher().match(FromTu, friendDecl());
-  auto *FromFriend2 = LastDeclMatcher().match(FromTu, friendDecl());
+  testRepeatedFriendImport(Code);
+}
 
-  FriendDecl *ToImportedFriend1 = Import(FromFriend1, Lang_CXX03);
-  FriendDecl *ToImportedFriend2 = Import(FromFriend2, Lang_CXX03);
+TEST_P(ImportFriendClasses, ImportOfRepeatedFriendFunctionTemplateDecl) {
+  const char *Code =
+  R"(
+template 
+class Container {
+  template  friend void m();
+  template  friend void m();
+};
+  )";
+  testRepeatedFriendImport(Code);
+}
 
-  EXPECT_NE(ToImportedFriend1, ToImportedFriend2);
-  EXPECT_EQ(ToFriend1, ToImportedFriend1);
-  EXPECT_EQ(ToFriend2, ToImportedFriend2);
+TEST_P(ImportFriendClasses, ImportOfRepeatedFriendClassTemplateDecl) {
+  const char *Code =
+  R"(
+template 
+class Container {
+  template  friend class X;
+  template  friend class X;
+};
+  )";
+  testRepeatedFriendImport(Code);
 }
 
 TEST_P(ASTImporterOptionSpecificTestBase, FriendFunInClassTemplate) {
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -4079,22 +4079,34 @@
   unsigned int IndexOfDecl;
 };
 
-template 
-static FriendCountAndPosition getFriendCountAndPosition(
-const FriendDecl *FD,
-llvm::function_ref GetCanTypeOrDecl) {
+static bool IsEquivalentFriend(ASTImporter &Importer, FriendDecl *FD1,
+   FriendDecl *FD2) {
+  if ((!FD1->getFriendType()) != (!FD2->getFriendType()))
+return false;
+
+  if (TypeSourceInfo *TSI = FD1->getFriendType())
+return Importer.IsStructurallyEquivalent(
+TSI->getType(), FD2->getFriendType()->getType(), /*Complain=*/false);
+
+  ASTImporter::NonEquivalentDeclSet NonEquivalentDecls;
+  StructuralEquivalenceContext Ctx(
+  FD1->getASTContext(), FD2->getASTContext(), NonEquivalentDecls,
+  StructuralEquivalenceKind::Default,
+  /* StrictTypeSpelling = */ false, /* Complain = */ false);
+  return Ctx.IsEquivalent(FD1, FD2);
+}
+
+static FriendCountAndPosition getFriendCountAndPosition(ASTImporter &Importer,
+   

[PATCH] D158499: [analyzer] Compute FAM dynamic size

2023-08-22 Thread Ding Fei via Phabricator via cfe-commits
danix800 added a comment.

We have `getDynamicExtentWithOffset` to use, which can handle more general
dynamic memory based cases than this fix.

I'll abandon this one.

There are issues worth clarifying and fixing:

1). Debugging APIs like `clang_analyzer_dumpExtent` in `ExprInspection` might 
be expanded
to use `getDynamicExtentWithOffset` if it's intended to be used on not only 
dynamic allocated
regions but more general ones, and more testcases are needed to demonstrate the 
usage.

2). Fix type-inconsistency of several size-related `SVal`s, e.g.

  FAM fam;
  clang_analyzer_dump(clang_analyzer_getExtent(&fam));
  clang_analyzer_dump(clang_analyzer_getExtent(fam.data));
  // expected-warning@-2 {{4 S64b}}  // U64b is more reasonable when used as an 
extent
  // expected-warning@-2 {{0 U64b}}

`ArrayIndexType` might be misused here.

Simple searching results listed here (might not be complete):

1. `getDynamicExtentWithOffset` return value
2. `getElementExtent` return value
3. `ExprEngineCallAndReturn.cpp` when calling `setDynamicExtent` the `Size` arg


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158499

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


[PATCH] D158499: [analyzer] Compute FAM dynamic size

2023-08-22 Thread Ding Fei via Phabricator via cfe-commits
danix800 added a comment.

One of the observable issue with inconsistent size type is

  void clang_analyzer_eval(int);
  
  typedef unsigned long long size_t;
  void *malloc(unsigned long size);
  void free(void *);
  
  void symbolic_longlong_and_int0(long long len) {
char *a = malloc(5);
(void)a[len + 1]; // no-warning
// len: [-1,3]
clang_analyzer_eval(-1 <= len && len <= 3); // expected-warning {{TRUE}}
clang_analyzer_eval(0 <= len);  // expected-warning {{UNKNOWN}}
clang_analyzer_eval(len <= 2);  // expected-warning {{UNKNOWN}}
free(a);
  }

which is extracted from `clang/test/Analysis/array-bound-v2-constraint-check.c`,
with `DynamicMemoryModeling` turned on,
the second warning does not hold anymore: `clang_analyzer_eval(0 <= len);`
will be reported as `TRUE` which is not expected.

`DynamicMemoryModeling` will record the extent of allocated memory as `5ULL`,
`ArrayBoundV2` will do `len + 1 < 5ULL` assumption, simplified to `len < 4ULL`,
which casts `len` to unsigned, dropping `-1`, similar to

  void clang_analyzer_eval(int);
  
  void test(int len) {
if (len >= -1 && len <= 4U) { // len is promoted into unsigned, thus can 
never be negative
clang_analyzer_eval(0 <= len);  // TRUE
}
  }


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158499

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


[PATCH] D158499: [analyzer] Compute FAM dynamic size

2023-08-22 Thread Ding Fei via Phabricator via cfe-commits
danix800 added a comment.

> I suspected that the wrong cast modeling and how we infer what value ranges 
> are calculated is susceptible to such APSInt signedness issues, but I haven't 
> seen a case in the wild for extents. Thus, I didn't think of fixing it 
> either. But yes, we should.

I think cast is not the problem, size-type inconsistent is. For `ArrayBound`, 
the assumption should be done with correct types to avoid `-Wsign-compare` 
issue.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158499

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


[PATCH] D157684: [clang][ASTImporter] Repeated friend templates are partially imported

2023-08-23 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 552678.
danix800 added a comment.

Add `const` qualifier & replace `auto` with explicit type.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157684

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -4054,6 +4054,25 @@
  ->lookup(ToRecordOfFriend->getDeclName())
  .empty());
   }
+
+  void testRepeatedFriendImport(const char *Code) {
+Decl *ToTu = getToTuDecl(Code, Lang_CXX03);
+Decl *FromTu = getTuDecl(Code, Lang_CXX03, "from.cc");
+
+auto *ToFriend1 = FirstDeclMatcher().match(ToTu, friendDecl());
+auto *ToFriend2 = LastDeclMatcher().match(ToTu, friendDecl());
+auto *FromFriend1 =
+FirstDeclMatcher().match(FromTu, friendDecl());
+auto *FromFriend2 =
+LastDeclMatcher().match(FromTu, friendDecl());
+
+FriendDecl *ToImportedFriend1 = Import(FromFriend1, Lang_CXX03);
+FriendDecl *ToImportedFriend2 = Import(FromFriend2, Lang_CXX03);
+
+EXPECT_NE(ToImportedFriend1, ToImportedFriend2);
+EXPECT_EQ(ToFriend1, ToImportedFriend1);
+EXPECT_EQ(ToFriend2, ToImportedFriend2);
+  }
 };
 
 TEST_P(ImportFriendClasses, ImportOfFriendRecordDoesNotMergeDefinition) {
@@ -4395,21 +4414,7 @@
 friend class X;
   };
   )";
-  Decl *ToTu = getToTuDecl(Code, Lang_CXX03);
-  Decl *FromTu = getTuDecl(Code, Lang_CXX03, "from.cc");
-
-  auto *ToFriend1 = FirstDeclMatcher().match(ToTu, friendDecl());
-  auto *ToFriend2 = LastDeclMatcher().match(ToTu, friendDecl());
-  auto *FromFriend1 =
-  FirstDeclMatcher().match(FromTu, friendDecl());
-  auto *FromFriend2 = LastDeclMatcher().match(FromTu, friendDecl());
-
-  FriendDecl *ToImportedFriend1 = Import(FromFriend1, Lang_CXX03);
-  FriendDecl *ToImportedFriend2 = Import(FromFriend2, Lang_CXX03);
-
-  EXPECT_NE(ToImportedFriend1, ToImportedFriend2);
-  EXPECT_EQ(ToFriend1, ToImportedFriend1);
-  EXPECT_EQ(ToFriend2, ToImportedFriend2);
+  testRepeatedFriendImport(Code);
 }
 
 TEST_P(ImportFriendClasses, ImportOfRepeatedFriendDecl) {
@@ -4420,21 +4425,31 @@
 friend void f();
   };
   )";
-  Decl *ToTu = getToTuDecl(Code, Lang_CXX03);
-  Decl *FromTu = getTuDecl(Code, Lang_CXX03, "from.cc");
-
-  auto *ToFriend1 = FirstDeclMatcher().match(ToTu, friendDecl());
-  auto *ToFriend2 = LastDeclMatcher().match(ToTu, friendDecl());
-  auto *FromFriend1 =
-  FirstDeclMatcher().match(FromTu, friendDecl());
-  auto *FromFriend2 = LastDeclMatcher().match(FromTu, friendDecl());
+  testRepeatedFriendImport(Code);
+}
 
-  FriendDecl *ToImportedFriend1 = Import(FromFriend1, Lang_CXX03);
-  FriendDecl *ToImportedFriend2 = Import(FromFriend2, Lang_CXX03);
+TEST_P(ImportFriendClasses, ImportOfRepeatedFriendFunctionTemplateDecl) {
+  const char *Code =
+  R"(
+template 
+class Container {
+  template  friend void m();
+  template  friend void m();
+};
+  )";
+  testRepeatedFriendImport(Code);
+}
 
-  EXPECT_NE(ToImportedFriend1, ToImportedFriend2);
-  EXPECT_EQ(ToFriend1, ToImportedFriend1);
-  EXPECT_EQ(ToFriend2, ToImportedFriend2);
+TEST_P(ImportFriendClasses, ImportOfRepeatedFriendClassTemplateDecl) {
+  const char *Code =
+  R"(
+template 
+class Container {
+  template  friend class X;
+  template  friend class X;
+};
+  )";
+  testRepeatedFriendImport(Code);
 }
 
 TEST_P(ASTImporterOptionSpecificTestBase, FriendFunInClassTemplate) {
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -4079,22 +4079,34 @@
   unsigned int IndexOfDecl;
 };
 
-template 
-static FriendCountAndPosition getFriendCountAndPosition(
-const FriendDecl *FD,
-llvm::function_ref GetCanTypeOrDecl) {
+static bool IsEquivalentFriend(ASTImporter &Importer, FriendDecl *FD1,
+   FriendDecl *FD2) {
+  if ((!FD1->getFriendType()) != (!FD2->getFriendType()))
+return false;
+
+  if (const TypeSourceInfo *TSI = FD1->getFriendType())
+return Importer.IsStructurallyEquivalent(
+TSI->getType(), FD2->getFriendType()->getType(), /*Complain=*/false);
+
+  ASTImporter::NonEquivalentDeclSet NonEquivalentDecls;
+  StructuralEquivalenceContext Ctx(
+  FD1->getASTContext(), FD2->getASTContext(), NonEquivalentDecls,
+  StructuralEquivalenceKind::Default,
+  /* StrictTypeSpelling = */ false, /* Complain = */ false);
+  return Ctx.IsEquivalent(FD1, FD2);
+}
+
+static FriendCountAndPosition getFriendCountAndPosition(ASTImporter &Importer,
+   

[PATCH] D157684: [clang][ASTImporter] Repeated friend templates are partially imported

2023-08-23 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/lib/AST/ASTImporter.cpp:4105
 
-  T TypeOrDecl = GetCanTypeOrDecl(FD);
-
-  for (const FriendDecl *FoundFriend : RD->friends()) {
+  for (FriendDecl *FoundFriend : RD->friends()) {
 if (FoundFriend == FD) {

balazske wrote:
> It is better if this is `const`.
As API requires this decl cannot be const.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157684

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


[PATCH] D156277: [Parser][ObjC] Fix parser crash on nested top-level block with better recovery path

2023-07-28 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 545056.
danix800 retitled this revision from "[Parser][ObjC] Stop parsing on eof" to 
"[Parser][ObjC] Fix parser crash on nested top-level block with better recovery 
path".
danix800 edited the summary of this revision.
danix800 added a comment.

Delay consuming tokens and bail out early if nested top-level block are met
for better diag & recovery.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156277

Files:
  clang/lib/Parse/ParseObjc.cpp
  clang/test/Parser/missing-end-1-gh64065-nocrash.m
  clang/test/Parser/missing-end-2.m
  clang/test/Parser/missing-end-3.m
  clang/test/Parser/missing-end-4.m

Index: clang/test/Parser/missing-end-4.m
===
--- clang/test/Parser/missing-end-4.m
+++ clang/test/Parser/missing-end-4.m
@@ -37,10 +37,10 @@
 - (C*) MyMeth {}
 @end
 
-@interface I2 {}
-@protocol P2; // expected-error {{illegal interface qualifier}}
-@class C2; // expected-error {{illegal interface qualifier}}
-@end
+@interface I2 {} // expected-note {{class started here}}
+@protocol P2; // expected-error {{missing '@end'}}
+@class C2;
+@end // expected-error {{'@end' must appear in an Objective-C context}}
 
 @interface I3
 @end
Index: clang/test/Parser/missing-end-3.m
===
--- clang/test/Parser/missing-end-3.m
+++ clang/test/Parser/missing-end-3.m
@@ -1,10 +1,12 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 // rdar://8283484
+// expected-note@+1 {{previous definition is here}}
 @interface blah { // expected-note {{class started here}}
 @private
 }
 // since I forgot the @end here it should say something
 
+// expected-error@+1 {{duplicate interface definition for class 'blah'}}
 @interface blah  // expected-error {{missing '@end'}}
-@end // and Unknown type name 'end' here
+@end
 
Index: clang/test/Parser/missing-end-2.m
===
--- clang/test/Parser/missing-end-2.m
+++ clang/test/Parser/missing-end-2.m
@@ -1,9 +1,10 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-objc-root-class -verify %s
 // rdar: //7824372
 
 @interface A // expected-note {{class started here}}
--(void) im0;
+-(void) im0; // expected-note {{method 'im0' declared here}}
 
+// expected-warning@+1 {{method definition for 'im0' not found}}
 @implementation A // expected-error {{missing '@end'}}
 @end
 
@@ -13,7 +14,8 @@
 @implementation B // expected-error {{missing '@end'}}
 @end
 
-@interface C // expected-note 2 {{class started here}}
+@interface C // expected-note 1 {{class started here}}
 @property int P;
 
+// expected-note@+1 {{implementation started here}}
 @implementation C // expected-error 2 {{missing '@end'}}
Index: clang/test/Parser/missing-end-1-gh64065-nocrash.m
===
--- /dev/null
+++ clang/test/Parser/missing-end-1-gh64065-nocrash.m
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+@interface Roo // expected-note {{class started here}}
+// expected-error@+1 {{missing '@end'}}
+@interface // expected-error {{expected identifier}}
Index: clang/lib/Parse/ParseObjc.cpp
===
--- clang/lib/Parse/ParseObjc.cpp
+++ clang/lib/Parse/ParseObjc.cpp
@@ -705,15 +705,30 @@
   continue;
 }
 
-// Otherwise, we have an @ directive, eat the @.
-SourceLocation AtLoc = ConsumeToken(); // the "@"
-if (Tok.is(tok::code_completion)) {
+// Otherwise, we have an @ directive, peak at the next token
+SourceLocation AtLoc = Tok.getLocation();
+const auto &NextTok = NextToken();
+if (NextTok.is(tok::code_completion)) {
   cutOffParsing();
   Actions.CodeCompleteObjCAtDirective(getCurScope());
   return;
 }
 
-tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
+tok::ObjCKeywordKind DirectiveKind = NextTok.getObjCKeywordID();
+// Bail out as if we saw an '@end'
+switch (DirectiveKind) {
+case tok::objc_class:
+case tok::objc_compatibility_alias:
+case tok::objc_interface:
+case tok::objc_implementation:
+case tok::objc_protocol:
+  goto MISSING_END;
+default:
+  break;
+}
+
+// Otherwise parse it as part of the current declaration. Eat the "@".
+ConsumeToken();
 
 if (DirectiveKind == tok::objc_end) { // @end -> terminate list
   AtEnd.setBegin(AtLoc);
@@ -739,15 +754,6 @@
   SkipUntil(tok::r_brace, tok::at, StopAtSemi);
   break;
 
-case tok::objc_implementation:
-case tok::objc_interface:
-  Diag(AtLoc, diag::err_objc_missing_end)
-  << FixItHint::CreateInsertion(AtLoc, "@end\n");
-  Diag(CDecl->getBeginLoc(), diag::note_objc_container_start)
-  << (int)Actions.getObjCContainerKind();
-  ConsumeTo

[PATCH] D156277: [Parser][ObjC] Fix parser crash on nested top-level block with better recovery path

2023-07-28 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 545069.
danix800 added a comment.

Update `clang/docs/ReleaseNotes.rst`.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156277

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/Parse/ParseObjc.cpp
  clang/test/Parser/missing-end-1-gh64065-nocrash.m
  clang/test/Parser/missing-end-2.m
  clang/test/Parser/missing-end-3.m
  clang/test/Parser/missing-end-4.m

Index: clang/test/Parser/missing-end-4.m
===
--- clang/test/Parser/missing-end-4.m
+++ clang/test/Parser/missing-end-4.m
@@ -37,10 +37,10 @@
 - (C*) MyMeth {}
 @end
 
-@interface I2 {}
-@protocol P2; // expected-error {{illegal interface qualifier}}
-@class C2; // expected-error {{illegal interface qualifier}}
-@end
+@interface I2 {} // expected-note {{class started here}}
+@protocol P2; // expected-error {{missing '@end'}}
+@class C2;
+@end // expected-error {{'@end' must appear in an Objective-C context}}
 
 @interface I3
 @end
Index: clang/test/Parser/missing-end-3.m
===
--- clang/test/Parser/missing-end-3.m
+++ clang/test/Parser/missing-end-3.m
@@ -1,10 +1,12 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 // rdar://8283484
+// expected-note@+1 {{previous definition is here}}
 @interface blah { // expected-note {{class started here}}
 @private
 }
 // since I forgot the @end here it should say something
 
+// expected-error@+1 {{duplicate interface definition for class 'blah'}}
 @interface blah  // expected-error {{missing '@end'}}
-@end // and Unknown type name 'end' here
+@end
 
Index: clang/test/Parser/missing-end-2.m
===
--- clang/test/Parser/missing-end-2.m
+++ clang/test/Parser/missing-end-2.m
@@ -1,9 +1,10 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-objc-root-class -verify %s
 // rdar: //7824372
 
 @interface A // expected-note {{class started here}}
--(void) im0;
+-(void) im0; // expected-note {{method 'im0' declared here}}
 
+// expected-warning@+1 {{method definition for 'im0' not found}}
 @implementation A // expected-error {{missing '@end'}}
 @end
 
@@ -13,7 +14,8 @@
 @implementation B // expected-error {{missing '@end'}}
 @end
 
-@interface C // expected-note 2 {{class started here}}
+@interface C // expected-note 1 {{class started here}}
 @property int P;
 
+// expected-note@+1 {{implementation started here}}
 @implementation C // expected-error 2 {{missing '@end'}}
Index: clang/test/Parser/missing-end-1-gh64065-nocrash.m
===
--- /dev/null
+++ clang/test/Parser/missing-end-1-gh64065-nocrash.m
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+@interface Roo // expected-note {{class started here}}
+// expected-error@+1 {{missing '@end'}}
+@interface // expected-error {{expected identifier}}
Index: clang/lib/Parse/ParseObjc.cpp
===
--- clang/lib/Parse/ParseObjc.cpp
+++ clang/lib/Parse/ParseObjc.cpp
@@ -705,15 +705,30 @@
   continue;
 }
 
-// Otherwise, we have an @ directive, eat the @.
-SourceLocation AtLoc = ConsumeToken(); // the "@"
-if (Tok.is(tok::code_completion)) {
+// Otherwise, we have an @ directive, peak at the next token
+SourceLocation AtLoc = Tok.getLocation();
+const auto &NextTok = NextToken();
+if (NextTok.is(tok::code_completion)) {
   cutOffParsing();
   Actions.CodeCompleteObjCAtDirective(getCurScope());
   return;
 }
 
-tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
+tok::ObjCKeywordKind DirectiveKind = NextTok.getObjCKeywordID();
+// Bail out as if we saw an '@end'
+switch (DirectiveKind) {
+case tok::objc_class:
+case tok::objc_compatibility_alias:
+case tok::objc_interface:
+case tok::objc_implementation:
+case tok::objc_protocol:
+  goto MISSING_END;
+default:
+  break;
+}
+
+// Otherwise parse it as part of the current declaration. Eat the "@".
+ConsumeToken();
 
 if (DirectiveKind == tok::objc_end) { // @end -> terminate list
   AtEnd.setBegin(AtLoc);
@@ -739,15 +754,6 @@
   SkipUntil(tok::r_brace, tok::at, StopAtSemi);
   break;
 
-case tok::objc_implementation:
-case tok::objc_interface:
-  Diag(AtLoc, diag::err_objc_missing_end)
-  << FixItHint::CreateInsertion(AtLoc, "@end\n");
-  Diag(CDecl->getBeginLoc(), diag::note_objc_container_start)
-  << (int)Actions.getObjCContainerKind();
-  ConsumeToken();
-  break;
-
 case tok::objc_required:
 case tok::objc_optional:
   // This is only valid on protocols.
@@ -825,6 +831,7 @@
   } else if (Tok.isObjCAtKeyword(tok::objc_end)) {
 ConsumeToken(); // the "end" identifier
   } 

[PATCH] D156277: [Parser][ObjC] Fix parser crash on nested top-level block with better recovery path

2023-07-28 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/lib/Parse/ParseObjc.cpp:749
+  if (!Tok.is(tok::eof))
+ConsumeToken();
   break;

rjmccall wrote:
> danix800 wrote:
> > rjmccall wrote:
> > > aaron.ballman wrote:
> > > > rjmccall wrote:
> > > > > aaron.ballman wrote:
> > > > > > aaron.ballman wrote:
> > > > > > > danix800 wrote:
> > > > > > > > tbaeder wrote:
> > > > > > > > > Why is there a `ConsumeToken()` call at all here? The token 
> > > > > > > > > is already being consumed in line 729.
> > > > > > > > Didn't notice this, thanks for reminding!
> > > > > > > I have the same question as @tbaeder -- what token is this 
> > > > > > > intending to consume? CC @rjmccall for Obj-C expertise
> > > > > > OH! This is consuming the identifier for the 
> > > > > > implementation/interface name itself. e.g.,
> > > > > > ```
> > > > > > @interface Frobble
> > > > > > ```
> > > > > > The consume on line 709 gets the `@`, the consume on line 729 gets 
> > > > > > the `interface`, and the consume on line 749 is getting the 
> > > > > > `Frobble`. That makes sense to me now.
> > > > > > 
> > > > > I don't think any language expertise is required here — just seems 
> > > > > like a straightforward bug on an error path that's probably not 
> > > > > exercised all that often.  Maybe somebody moved the `ConsumeToken` 
> > > > > and forgot to fix this case or something.
> > > > What concerns me about this fix is that we don't typically check 
> > > > whether the token is EOF or not before consuming; that's usually an 
> > > > anti-pattern, isn't it? Wouldn't it make sense for this to use 
> > > > `SkipUntil(tok::identifier)` instead?
> > > Okay, so now I can bring a little language expertise to bear. :)
> > > 
> > > We're in the middle of parsing an ObjC block (e.g. `@interface`), and we 
> > > see `@interface` or `@implementation`, which starts a new block.  You can 
> > > never nest these ObjC blocks, so the parser is reasonably assuming that 
> > > the second `@keyword` is an attempt to start a new block and the user 
> > > just forgot to terminate the last block with `@end`.  Unfortunately, the 
> > > actual recovery done by the parser doesn't seem to match the diagnostic 
> > > and the fixit — it's trying to swallow `@interface Foo` (or whatever) and 
> > > then continue the loop as if it were part of the current block, which is 
> > > definitely not the right thing to do.
> > > 
> > > The right way to recover here is to act like we actually saw `@end` and 
> > > break out of the loop, leaving `Tok` on the `@` so that the parser will 
> > > pick up parsing `@interface` normally after we return.  To do that, we 
> > > just need to get the ObjC keyword by peeking at the next token instead of 
> > > consuming.
> > > 
> > > Also, we should take this recovery path on every `@` keyword that's only 
> > > allowed at the top level (so `@class`, `@compatibility_alias`, 
> > > `@interface`, `@implementation`, and `@protocol`).
> > It's really great to learn things here! I don't know two much about ObjC. I 
> > seached google trying to find some standard or specs for ObjC but only docs 
> > like tutorials teaching how to use it can be found, so I might not be able 
> > to give a good enough fix for this issue. I'll give it a try though.
> You should be able to follow the guidance here without needing to know much 
> more about ObjC, just understanding how the parser works.  The key is that 
> you need to delay consuming tokens until you're certain you're going to 
> commit to parsing this `@`-directive as part of the current declaration.
> 
> Start with the line `SourceLocation AtLoc = ConsumeToken();`  Instead of 
> consuming the `@` and then looking at `Tok` to see what the keyword is, you 
> can get the location of `Tok` without consuming it, then use `NextToken()` to 
> peek ahead to the next token to see the keyword.
> 
> Be sure to sink the right number of `ConsumeToken` calls down onto all of the 
> paths that *aren't* bailing out.
Actually `clang/lib/Parse/ParseObjc.cpp` has ObjC part of the syntax well 
documented, plus well written code, it's really helpful.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156277

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


[PATCH] D156201: [ASTImporter] Fix corrupted RecordLayout introduced by circular referenced fields

2023-07-28 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/lib/AST/ASTImporter.cpp:7418
+
+  return UO;
 }

balazske wrote:
> Why is it better to use `CreateEmpty` instead of the old code? Does `Create` 
> do something that does not work at this situation (probably getting the 
> layout)? If yes the same should be done later at some point, can you explain 
> how this works?
`CreateEmpty` is used to avoid unnecessarily (re-)`computeDependence()` of the 
imported `UnaryOperator`. See `UnaryOperator`'s ctors for details.

While importing fields there could be deps on current record's layout. In the 
following testcase, importing `A::b`
will take this path: `A::b` => `B` => ... => `B::f` => ... => 
`UnaryOperator(&)`.
```
  class B;
  class A {
B* b;
int c;
  };
  class B {
A *f() { return &((B *)0)->a; }
A a;
  };
```

The (non-empty) `UnaryOperator (&)` ctor needs the whole RecordLayout 
(including `A`) to be evaluated for
`computeDependence()`, but none of fields of`A` is imported at this moment. The 
RecordLayout is incorrectly
computed and what's worse more is, the RecordLayout is cached for later use. 
Any clients relying on this RecordLayout
would be broken. For example `EXPECT_TRUE(ToLayout.getFieldOffset(0) == 0);` 
would simply crash with
```
ASTTests: 
/home/x/Sources/llvm-project-main/clang/include/clang/AST/ASTVector.h:116: 
clang::ASTVector::const_reference clang::ASTVector::operator[](unsigned int) const [T = unsigned long]: Assertion `Begin + 
idx < End' failed.
...
#10 0x558b01b39942 clang::ASTVector::operator[](unsigned 
int) const 
/home/x/Sources/llvm-project-main/clang/include/clang/AST/ASTVector.h:0:5
#11 0x558b01aaeb0f clang::ASTRecordLayout::getFieldOffset(unsigned int) 
const 
/home/x/Sources/llvm-project-main/clang/include/clang/AST/RecordLayout.h:201:12
#12 0x558b01a6d115 
clang::ast_matchers::ASTImporterOptionSpecificTestBase_ImportCirularRefFieldsWithoutCorruptedRecordLayoutCacheTest_Test::TestBody()
 
/home/x/Sources/llvm-project-main/clang/unittests/AST/ASTImporterTest.cpp:8067:3
...
```

`UnaryOperator` is just one example that could introduce this kind of problem. 
If I understand it correctly, `ASTImporter` is much like `ASTReader` which 
could use `CreateEmpty` directly to avoid recomputing some of the
data, most of which could be copied from `From` context, as `ASTReader` reads 
node data when deserialization.

Maybe `ASTImporter` could be ideally refactored into this behaviour on node 
creation.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156201

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


[PATCH] D156277: [Parser][ObjC] Fix parser crash on nested top-level block with better recovery path

2023-07-29 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 545343.
danix800 added a comment.

Cleanup spaghetti-ish code.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156277

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/Parse/ParseObjc.cpp
  clang/test/Parser/missing-end-1-gh64065-nocrash.m
  clang/test/Parser/missing-end-2.m
  clang/test/Parser/missing-end-3.m
  clang/test/Parser/missing-end-4.m

Index: clang/test/Parser/missing-end-4.m
===
--- clang/test/Parser/missing-end-4.m
+++ clang/test/Parser/missing-end-4.m
@@ -37,10 +37,10 @@
 - (C*) MyMeth {}
 @end
 
-@interface I2 {}
-@protocol P2; // expected-error {{illegal interface qualifier}}
-@class C2; // expected-error {{illegal interface qualifier}}
-@end
+@interface I2 {} // expected-note {{class started here}}
+@protocol P2; // expected-error {{missing '@end'}}
+@class C2;
+@end // expected-error {{'@end' must appear in an Objective-C context}}
 
 @interface I3
 @end
Index: clang/test/Parser/missing-end-3.m
===
--- clang/test/Parser/missing-end-3.m
+++ clang/test/Parser/missing-end-3.m
@@ -1,10 +1,12 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 // rdar://8283484
+// expected-note@+1 {{previous definition is here}}
 @interface blah { // expected-note {{class started here}}
 @private
 }
 // since I forgot the @end here it should say something
 
+// expected-error@+1 {{duplicate interface definition for class 'blah'}}
 @interface blah  // expected-error {{missing '@end'}}
-@end // and Unknown type name 'end' here
+@end
 
Index: clang/test/Parser/missing-end-2.m
===
--- clang/test/Parser/missing-end-2.m
+++ clang/test/Parser/missing-end-2.m
@@ -1,9 +1,10 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-objc-root-class -verify %s
 // rdar: //7824372
 
 @interface A // expected-note {{class started here}}
--(void) im0;
+-(void) im0; // expected-note {{method 'im0' declared here}}
 
+// expected-warning@+1 {{method definition for 'im0' not found}}
 @implementation A // expected-error {{missing '@end'}}
 @end
 
@@ -13,7 +14,8 @@
 @implementation B // expected-error {{missing '@end'}}
 @end
 
-@interface C // expected-note 2 {{class started here}}
+@interface C // expected-note 1 {{class started here}}
 @property int P;
 
+// expected-note@+1 {{implementation started here}}
 @implementation C // expected-error 2 {{missing '@end'}}
Index: clang/test/Parser/missing-end-1-gh64065-nocrash.m
===
--- /dev/null
+++ clang/test/Parser/missing-end-1-gh64065-nocrash.m
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+@interface Roo // expected-note {{class started here}}
+// expected-error@+1 {{missing '@end'}}
+@interface // expected-error {{expected identifier}}
Index: clang/lib/Parse/ParseObjc.cpp
===
--- clang/lib/Parse/ParseObjc.cpp
+++ clang/lib/Parse/ParseObjc.cpp
@@ -613,6 +613,19 @@
   /*mayBeProtocolList=*/false);
 }
 
+static bool isTopLevelObjCKeyword(tok::ObjCKeywordKind DirectiveKind) {
+  switch (DirectiveKind) {
+  case tok::objc_class:
+  case tok::objc_compatibility_alias:
+  case tok::objc_interface:
+  case tok::objc_implementation:
+  case tok::objc_protocol:
+return true;
+  default:
+return false;
+  }
+}
+
 ///   objc-interface-decl-list:
 /// empty
 /// objc-interface-decl-list objc-property-decl [OBJC2]
@@ -705,27 +718,33 @@
   continue;
 }
 
-// Otherwise, we have an @ directive, eat the @.
-SourceLocation AtLoc = ConsumeToken(); // the "@"
-if (Tok.is(tok::code_completion)) {
+// Otherwise, we have an @ directive, peak at the next token
+SourceLocation AtLoc = Tok.getLocation();
+const auto &NextTok = NextToken();
+if (NextTok.is(tok::code_completion)) {
   cutOffParsing();
   Actions.CodeCompleteObjCAtDirective(getCurScope());
   return;
 }
 
-tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
-
+tok::ObjCKeywordKind DirectiveKind = NextTok.getObjCKeywordID();
 if (DirectiveKind == tok::objc_end) { // @end -> terminate list
+  ConsumeToken(); // the "@"
   AtEnd.setBegin(AtLoc);
   AtEnd.setEnd(Tok.getLocation());
   break;
 } else if (DirectiveKind == tok::objc_not_keyword) {
-  Diag(Tok, diag::err_objc_unknown_at);
+  Diag(NextTok, diag::err_objc_unknown_at);
   SkipUntil(tok::semi);
   continue;
 }
 
-// Eat the identifier.
+// Bail out as if we saw an '@end'
+if (isTopLevelObjCKeyword(DirectiveKind))
+  break;
+
+// Otherwise parse it as part of the current declaration. Eat "@identif

[PATCH] D155661: [clang][ASTImporter] Fix friend class template import within dependent context

2023-07-31 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 545912.
danix800 added a comment.

Cleanup as @balazske suggested.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155661

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -3968,8 +3968,31 @@
   EXPECT_EQ(ToDef->getPreviousDecl(), ToProto);
 }
 
-
-struct ImportFriendClasses : ASTImporterOptionSpecificTestBase {};
+struct ImportFriendClasses : ASTImporterOptionSpecificTestBase {
+  void testRecursiveFriendClassTemplate(Decl *FromTu) {
+auto *FromD = FirstDeclMatcher().match(
+FromTu, classTemplateDecl());
+auto *ToD = Import(FromD, Lang_CXX03);
+
+auto Pattern = classTemplateDecl(
+has(cxxRecordDecl(has(friendDecl(has(classTemplateDecl()));
+ASSERT_TRUE(MatchVerifier{}.match(FromD, Pattern));
+EXPECT_TRUE(MatchVerifier{}.match(ToD, Pattern));
+
+auto *FromFriend =
+FirstDeclMatcher().match(FromD, friendDecl());
+auto *FromClass =
+FirstDeclMatcher().match(FromD, classTemplateDecl());
+EXPECT_NE(FromFriend->getFriendDecl(), FromClass);
+EXPECT_TRUE(FromFriend->getFriendDecl()->getPreviousDecl() == nullptr);
+
+auto *Class =
+FirstDeclMatcher().match(ToD, classTemplateDecl());
+auto *Friend = FirstDeclMatcher().match(ToD, friendDecl());
+EXPECT_NE(Friend->getFriendDecl(), Class);
+EXPECT_TRUE(Friend->getFriendDecl()->getPreviousDecl() == nullptr);
+  }
+};
 
 TEST_P(ImportFriendClasses, ImportOfFriendRecordDoesNotMergeDefinition) {
   Decl *FromTU = getTuDecl(
@@ -4074,20 +4097,19 @@
   )",
   Lang_CXX03, "input.cc");
 
-  auto *FromD =
-  FirstDeclMatcher().match(FromTu, classTemplateDecl());
-  auto *ToD = Import(FromD, Lang_CXX03);
-
-  auto Pattern = classTemplateDecl(
-  has(cxxRecordDecl(has(friendDecl(has(classTemplateDecl()));
-  ASSERT_TRUE(MatchVerifier{}.match(FromD, Pattern));
-  EXPECT_TRUE(MatchVerifier{}.match(ToD, Pattern));
+  testRecursiveFriendClassTemplate(FromTu);
+}
 
-  auto *Class =
-  FirstDeclMatcher().match(ToD, classTemplateDecl());
-  auto *Friend = FirstDeclMatcher().match(ToD, friendDecl());
-  EXPECT_NE(Friend->getFriendDecl(), Class);
-  EXPECT_EQ(Friend->getFriendDecl()->getPreviousDecl(), Class);
+TEST_P(ImportFriendClasses,
+   ImportOfRecursiveFriendClassTemplateWithNonTypeParm) {
+  Decl *FromTu = getTuDecl(
+  R"(
+  template class declToImport {
+template friend class declToImport;
+  };
+  )",
+  Lang_CXX03, "input.cc");
+  testRecursiveFriendClassTemplate(FromTu);
 }
 
 TEST_P(ImportFriendClasses, ProperPrevDeclForClassTemplateDecls) {
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -2857,9 +2857,13 @@
   } else if (Importer.getToContext().getLangOpts().CPlusPlus)
 IDNS |= Decl::IDNS_Ordinary | Decl::IDNS_TagFriend;
 
+  bool IsDependentContext = DC != LexicalDC ? LexicalDC->isDependentContext()
+: DC->isDependentContext();
+  bool DependentFriend = IsFriendTemplate && IsDependentContext;
+
   // We may already have a record of the same name; try to find and match it.
   RecordDecl *PrevDecl = nullptr;
-  if (!DC->isFunctionOrMethod() && !D->isLambda()) {
+  if (!DependentFriend && !DC->isFunctionOrMethod() && !D->isLambda()) {
 SmallVector ConflictingDecls;
 auto FoundDecls =
 Importer.findDeclsInToCtx(DC, SearchName);
@@ -5796,10 +5800,15 @@
   if (ToD)
 return ToD;
 
+  bool IsFriendTemplate = D->getFriendObjectKind() != Decl::FOK_None;
+  bool IsDependentContext = DC != LexicalDC ? LexicalDC->isDependentContext()
+: DC->isDependentContext();
+  bool DependentFriend = IsFriendTemplate && IsDependentContext;
+
   ClassTemplateDecl *FoundByLookup = nullptr;
 
   // We may already have a template of the same name; try to find and match it.
-  if (!DC->isFunctionOrMethod()) {
+  if (!DependentFriend && !DC->isFunctionOrMethod()) {
 SmallVector ConflictingDecls;
 auto FoundDecls = Importer.findDeclsInToCtx(DC, Name);
 for (auto *FoundDecl : FoundDecls) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D155661: [clang][ASTImporter] Fix friend class template import within dependent context

2023-07-31 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/lib/AST/ASTImporter.cpp:2862-2866
+  bool ShouldAddRedecl = !(IsFriendTemplate && IsDependentContext);
+
   // We may already have a record of the same name; try to find and match it.
   RecordDecl *PrevDecl = nullptr;
   if (!DC->isFunctionOrMethod() && !D->isLambda()) {

balazske wrote:
> The code seems to work but I was confused by the different conditions used 
> (is it possible that `IsFriendTemplate` and `ShouldAddRedecl` is true at the 
> same time?). I had the observation that if `ShouldAddRedecl` is false we do 
> not need the whole search for previous decl. At a friend template we shall 
> not find a definition, the loop would just find the last declaration (this 
> value is not used). So I have the idea of this code (could not find the 
> "suggest edit" command):
> 
> ```
>   bool DependentFriend = IsFriendTemplate && IsDependentContext;
> 
>   // We may already have a record of the same name; try to find and match it.
>   RecordDecl *PrevDecl = nullptr;
>   if (!DependentFriend && !DC->isFunctionOrMethod() && !D->isLambda()) {
> 
> ```
This is more clear. Thanks.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155661

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


[PATCH] D155661: [clang][ASTImporter] Fix friend class template import within dependent context

2023-07-31 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 545913.
danix800 added a comment.

Update ReleaseNotes.rst


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155661

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -3968,8 +3968,31 @@
   EXPECT_EQ(ToDef->getPreviousDecl(), ToProto);
 }
 
-
-struct ImportFriendClasses : ASTImporterOptionSpecificTestBase {};
+struct ImportFriendClasses : ASTImporterOptionSpecificTestBase {
+  void testRecursiveFriendClassTemplate(Decl *FromTu) {
+auto *FromD = FirstDeclMatcher().match(
+FromTu, classTemplateDecl());
+auto *ToD = Import(FromD, Lang_CXX03);
+
+auto Pattern = classTemplateDecl(
+has(cxxRecordDecl(has(friendDecl(has(classTemplateDecl()));
+ASSERT_TRUE(MatchVerifier{}.match(FromD, Pattern));
+EXPECT_TRUE(MatchVerifier{}.match(ToD, Pattern));
+
+auto *FromFriend =
+FirstDeclMatcher().match(FromD, friendDecl());
+auto *FromClass =
+FirstDeclMatcher().match(FromD, classTemplateDecl());
+EXPECT_NE(FromFriend->getFriendDecl(), FromClass);
+EXPECT_TRUE(FromFriend->getFriendDecl()->getPreviousDecl() == nullptr);
+
+auto *Class =
+FirstDeclMatcher().match(ToD, classTemplateDecl());
+auto *Friend = FirstDeclMatcher().match(ToD, friendDecl());
+EXPECT_NE(Friend->getFriendDecl(), Class);
+EXPECT_TRUE(Friend->getFriendDecl()->getPreviousDecl() == nullptr);
+  }
+};
 
 TEST_P(ImportFriendClasses, ImportOfFriendRecordDoesNotMergeDefinition) {
   Decl *FromTU = getTuDecl(
@@ -4074,20 +4097,19 @@
   )",
   Lang_CXX03, "input.cc");
 
-  auto *FromD =
-  FirstDeclMatcher().match(FromTu, classTemplateDecl());
-  auto *ToD = Import(FromD, Lang_CXX03);
-
-  auto Pattern = classTemplateDecl(
-  has(cxxRecordDecl(has(friendDecl(has(classTemplateDecl()));
-  ASSERT_TRUE(MatchVerifier{}.match(FromD, Pattern));
-  EXPECT_TRUE(MatchVerifier{}.match(ToD, Pattern));
+  testRecursiveFriendClassTemplate(FromTu);
+}
 
-  auto *Class =
-  FirstDeclMatcher().match(ToD, classTemplateDecl());
-  auto *Friend = FirstDeclMatcher().match(ToD, friendDecl());
-  EXPECT_NE(Friend->getFriendDecl(), Class);
-  EXPECT_EQ(Friend->getFriendDecl()->getPreviousDecl(), Class);
+TEST_P(ImportFriendClasses,
+   ImportOfRecursiveFriendClassTemplateWithNonTypeParm) {
+  Decl *FromTu = getTuDecl(
+  R"(
+  template class declToImport {
+template friend class declToImport;
+  };
+  )",
+  Lang_CXX03, "input.cc");
+  testRecursiveFriendClassTemplate(FromTu);
 }
 
 TEST_P(ImportFriendClasses, ProperPrevDeclForClassTemplateDecls) {
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -2857,9 +2857,13 @@
   } else if (Importer.getToContext().getLangOpts().CPlusPlus)
 IDNS |= Decl::IDNS_Ordinary | Decl::IDNS_TagFriend;
 
+  bool IsDependentContext = DC != LexicalDC ? LexicalDC->isDependentContext()
+: DC->isDependentContext();
+  bool DependentFriend = IsFriendTemplate && IsDependentContext;
+
   // We may already have a record of the same name; try to find and match it.
   RecordDecl *PrevDecl = nullptr;
-  if (!DC->isFunctionOrMethod() && !D->isLambda()) {
+  if (!DependentFriend && !DC->isFunctionOrMethod() && !D->isLambda()) {
 SmallVector ConflictingDecls;
 auto FoundDecls =
 Importer.findDeclsInToCtx(DC, SearchName);
@@ -5796,10 +5800,15 @@
   if (ToD)
 return ToD;
 
+  bool IsFriendTemplate = D->getFriendObjectKind() != Decl::FOK_None;
+  bool IsDependentContext = DC != LexicalDC ? LexicalDC->isDependentContext()
+: DC->isDependentContext();
+  bool DependentFriend = IsFriendTemplate && IsDependentContext;
+
   ClassTemplateDecl *FoundByLookup = nullptr;
 
   // We may already have a template of the same name; try to find and match it.
-  if (!DC->isFunctionOrMethod()) {
+  if (!DependentFriend && !DC->isFunctionOrMethod()) {
 SmallVector ConflictingDecls;
 auto FoundDecls = Importer.findDeclsInToCtx(DC, Name);
 for (auto *FoundDecl : FoundDecls) {
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -131,6 +131,8 @@
 
 Bug Fixes to AST Handling
 ^
+- Fixed an import failure of recursive friend class template.
+  `Issue 64169 `_
 
 Miscellaneous Bug Fixes
 ^^^

[PATCH] D156201: [ASTImporter] Fix corrupted RecordLayout introduced by circular referenced fields

2023-08-01 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/unittests/AST/ASTImporterTest.cpp:8033
+TEST_P(ASTImporterOptionSpecificTestBase,
+   ImportCirularRefFieldsWithoutCorruptedRecordLayoutCacheTest) {
+  // Import sequence: A => A.b => B => B.f() => ... => UnaryOperator(&) => ...

balazske wrote:
> A small thing, `ImportCirularRefFieldsWithoutCorruptedRecordLayoutCache` (no 
> `Test` ending) is the usual naming for these tests.
Thanks for reminding, I'll fix all testcases ending with `Test`.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156201

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


[PATCH] D156201: [ASTImporter] Fix corrupted RecordLayout introduced by circular referenced fields

2023-08-01 Thread Ding Fei via Phabricator via cfe-commits
danix800 added inline comments.



Comment at: clang/include/clang/AST/Expr.h:2343-2344
 
-protected:
-  /// Set FPFeatures in trailing storage, used only by Serialization
+  /// Set FPFeatures in trailing storage, used by Serialization & ASTImporter
   void setStoredFPFeatures(FPOptionsOverride F) { getTrailingFPFeatures() = F; 
}
 

aaron.ballman wrote:
> Rather than make this a public API, would it instead make sense to add 
> `friend class ASTNodeImporter;` at the end of the class?
Tested & confirmed, it's unnecessary to expose this method, `friend` is much 
better. Thanks!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156201

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


[PATCH] D156201: [ASTImporter] Fix corrupted RecordLayout introduced by circular referenced fields

2023-08-01 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 546127.
danix800 added a comment.

1. Update `ReleaseNotes.rst`;
2. Fix testcase names (remove `Test` suffix);
3. Use `friend` instead of exposing API.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156201

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/Expr.h
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -10,6 +10,7 @@
 //
 //===--===//
 
+#include "clang/AST/RecordLayout.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/Support/SmallVectorMemoryBuffer.h"
@@ -2333,7 +2334,7 @@
 }
 
 TEST_P(ASTImporterOptionSpecificTestBase,
-   ImportVirtualOverriddenMethodOnALoopTest) {
+   ImportVirtualOverriddenMethodOnALoop) {
   // B::f() calls => f1() ==> C ==> C::f()
   // \
   //  \ A::f()
@@ -8008,7 +8009,7 @@
 }
 
 TEST_P(ASTImporterOptionSpecificTestBase,
-   ImportFieldsFirstForCorrectRecordLayoutTest) {
+   ImportFieldsFirstForCorrectRecordLayout) {
   // UnaryOperator(&) triggers RecordLayout computation, which relies on
   // correctly imported fields.
   auto Code =
@@ -8028,6 +8029,45 @@
   Import(FromF, Lang_CXX11);
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase,
+   ImportCirularRefFieldsWithoutCorruptedRecordLayoutCache) {
+  // Import sequence: A => A.b => B => B.f() => ... => UnaryOperator(&) => ...
+  //
+  // UnaryOperator(&) should not introduce invalid RecordLayout since 'A' is
+  // still not completely imported.
+  auto Code =
+  R"(
+  class B;
+  class A {
+B* b;
+int c;
+  };
+  class B {
+A *f() { return &((B *)0)->a; }
+A a;
+  };
+  )";
+
+  auto *FromR = FirstDeclMatcher().match(
+  getTuDecl(Code, Lang_CXX11), cxxRecordDecl(hasName("A")));
+  FromR = FromR->getDefinition();
+  auto &FromAST = FromR->getASTContext();
+  auto *ToR = Import(FromR, Lang_CXX11);
+  auto &ToAST = ToR->getASTContext();
+
+  uint64_t SecondFieldOffset = FromAST.getTypeSize(FromAST.VoidPtrTy);
+
+  EXPECT_TRUE(FromR->isCompleteDefinition());
+  const auto &FromLayout = FromAST.getASTRecordLayout(FromR);
+  EXPECT_TRUE(FromLayout.getFieldOffset(0) == 0);
+  EXPECT_TRUE(FromLayout.getFieldOffset(1) == SecondFieldOffset);
+
+  EXPECT_TRUE(ToR->isCompleteDefinition());
+  const auto &ToLayout = ToAST.getASTRecordLayout(ToR);
+  EXPECT_TRUE(ToLayout.getFieldOffset(0) == 0);
+  EXPECT_TRUE(ToLayout.getFieldOffset(1) == SecondFieldOffset);
+}
+
 TEST_P(ASTImporterOptionSpecificTestBase,
ImportRecordWithLayoutRequestingExpr) {
   TranslationUnitDecl *FromTU = getTuDecl(
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -7405,10 +7405,17 @@
   if (Err)
 return std::move(Err);
 
-  return UnaryOperator::Create(
-  Importer.getToContext(), ToSubExpr, E->getOpcode(), ToType,
-  E->getValueKind(), E->getObjectKind(), ToOperatorLoc, E->canOverflow(),
-  E->getFPOptionsOverride());
+  auto *UO = UnaryOperator::CreateEmpty(Importer.getToContext(),
+E->hasStoredFPFeatures());
+  UO->setType(ToType);
+  UO->setSubExpr(ToSubExpr);
+  UO->setOpcode(E->getOpcode());
+  UO->setOperatorLoc(ToOperatorLoc);
+  UO->setCanOverflow(E->canOverflow());
+  if (E->hasStoredFPFeatures())
+UO->setStoredFPFeatures(E->getStoredFPFeatures());
+
+  return UO;
 }
 
 ExpectedStmt
Index: clang/include/clang/AST/Expr.h
===
--- clang/include/clang/AST/Expr.h
+++ clang/include/clang/AST/Expr.h
@@ -2341,7 +2341,7 @@
   }
 
 protected:
-  /// Set FPFeatures in trailing storage, used only by Serialization
+  /// Set FPFeatures in trailing storage, used by Serialization & ASTImporter.
   void setStoredFPFeatures(FPOptionsOverride F) { getTrailingFPFeatures() = F; }
 
 public:
@@ -2362,6 +2362,7 @@
   friend class ASTReader;
   friend class ASTStmtReader;
   friend class ASTStmtWriter;
+  friend class ASTNodeImporter;
 };
 
 /// Helper class for OffsetOfExpr.
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -134,6 +134,10 @@
 
 Miscellaneous Bug Fixes
 ^^^
+- Remove unnecessary RecordLayout computation when importing UnaryOperator. The
+  computed RecordLayout is incorrect if fields are not completely imported and
+  should not be cached.
+  `Issue 64170 

[PATCH] D156201: [ASTImporter] Fix corrupted RecordLayout introduced by circular referenced fields

2023-08-01 Thread Ding Fei via Phabricator via cfe-commits
danix800 added a comment.

In D156201#4551270 , @steakhal wrote:

> Have you considered back porting this to clang-17?

How to backport? I'm not familiar with this. Is it plain `cherry-pick` to 
specific branch?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156201

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


[PATCH] D155661: [clang][ASTImporter] Fix friend class template import within dependent context

2023-08-01 Thread Ding Fei via Phabricator via cfe-commits
danix800 added a comment.

In D155661#4550340 , @balazske wrote:

> The fix looks OK, but the test could be improved and cleaned up (for example 
> `FromClass` is the same as `FromD` in the test, and DeclContext is not 
> checked, can be done like in the test 
> `UndeclaredFriendClassShouldNotBeVisible` but the AST is different).

Testcase will be cleaned up in the final commit.

> Probably there are other similar cases, and there is a related problem shown 
> in D156693  (the fix in that patch is not 
> correct, the solution here is not good for that case, it is possible that the 
> same code as here needs to be changed again or a better fix is found). I am 
> accepting this code but probably will create a new patch to improve and add 
> tests for similar cases (if not done before by somebody else).

Confirmed, but I'll not touch this issue in this commit.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D155661

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


[PATCH] D156201: [ASTImporter] Fix corrupted RecordLayout introduced by circular referenced fields

2023-08-01 Thread Ding Fei via Phabricator via cfe-commits
danix800 added a comment.

In D156201#4551464 , @aaron.ballman 
wrote:

> LGTM!
>
> In D156201#4551332 , @danix800 
> wrote:
>
>> In D156201#4551270 , @steakhal 
>> wrote:
>>
>>> Have you considered back porting this to clang-17?
>>
>> How to backport? I'm not familiar with this. Is it plain `cherry-pick` to 
>> specific branch?
>
> We have some documented instructions here: 
> https://llvm.org/docs/GitHub.html#backporting-fixes-to-the-release-branches 
> -- I don't oppose adding this to the release branch (it seems simple and 
> straightforward enough), but if it's not fixing a regression or other 
> critical issue, it might make sense to leave it out of 17.x so there's less 
> moving parts during the release.

I'll leave it out of 17.x.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D156201

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


[PATCH] D157114: [clang][ASTImporter] Improve StructuralEquivalence algorithm on repeated friends

2023-08-04 Thread Ding Fei via Phabricator via cfe-commits
danix800 created this revision.
danix800 added reviewers: balazske, steakhal, aaron.ballman, shafik, martong.
Herald added a reviewer: a.sidorin.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repeated friends are deduplicated when imported, but StructuralEquivalence 
checks friends by exact matching.
If `ToContext` is empty (not containing the class to be imported), the imported 
friends are deduplicated, any
further importing of the class would be rejected at the structure equivalence 
checking, i.e:

  struct foo { friend class X; friend class X; }; // FromContext

only one friend is imported, similar to the following:

  struct foo { friend class X; }; // ToContext

but when imported again, `struct foo` in FromContext is reported as not 
equivalent to `struct foo` in `ToContext`,
thus rejected.

The structural equivalence checking algorithm is improved by applying similar 
deduplication as Importer does.
Thus from StructuralEquivalence's point of view, the above two `RecordDecl`s 
are equivalent.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D157114

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/lib/AST/ASTStructuralEquivalence.cpp
  clang/unittests/AST/ASTImporterTest.cpp
  clang/unittests/AST/StructuralEquivalenceTest.cpp

Index: clang/unittests/AST/StructuralEquivalenceTest.cpp
===
--- clang/unittests/AST/StructuralEquivalenceTest.cpp
+++ clang/unittests/AST/StructuralEquivalenceTest.cpp
@@ -833,7 +833,7 @@
   auto t = makeNamedDecls("struct foo { friend class X; };",
   "struct foo { friend class X; friend class X; };",
   Lang_CXX11);
-  EXPECT_FALSE(testStructuralMatch(t));
+  EXPECT_TRUE(testStructuralMatch(t));
 }
 
 TEST_F(StructuralEquivalenceRecordTest, SameFriendsDifferentOrder) {
Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -10,6 +10,7 @@
 //
 //===--===//
 
+#include "clang/AST/ASTStructuralEquivalence.h"
 #include "clang/AST/RecordLayout.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "llvm/ADT/StringMap.h"
@@ -4351,6 +4352,44 @@
   EXPECT_EQ(ToFriend2, ToImportedFriend2);
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase, ImportRepeatedFriendDeclIntoEmptyDC) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(R"(
+  template 
+  class A {
+  public:
+template  friend A &f();
+template  friend A &f();
+  };
+  )",
+   Lang_CXX17, "", Lang_CXX17, "A");
+
+  auto *FromFriend1 = FirstDeclMatcher().match(From, friendDecl());
+  auto *FromFriend2 = LastDeclMatcher().match(From, friendDecl());
+  auto *ToFriend1 = FirstDeclMatcher().match(To, friendDecl());
+  auto *ToFriend2 = LastDeclMatcher().match(To, friendDecl());
+
+  // Two different FriendDecls in From context.
+  EXPECT_TRUE(FromFriend1 != FromFriend2);
+  // Only one is imported into empty DC.
+  EXPECT_TRUE(ToFriend1 == ToFriend2);
+
+  // 'A' is imported into empty DC, keeping structure equivalence.
+  llvm::DenseSet> NonEquivalentDecls01;
+  llvm::DenseSet> NonEquivalentDecls10;
+  StructuralEquivalenceContext Ctx01(
+  From->getASTContext(), To->getASTContext(), NonEquivalentDecls01,
+  StructuralEquivalenceKind::Default, false, false);
+  StructuralEquivalenceContext Ctx10(
+  To->getASTContext(), From->getASTContext(), NonEquivalentDecls10,
+  StructuralEquivalenceKind::Default, false, false);
+
+  bool Eq01 = Ctx01.IsEquivalent(From, To);
+  bool Eq10 = Ctx10.IsEquivalent(To, From);
+  EXPECT_EQ(Eq01, Eq10);
+  EXPECT_TRUE(Eq01);
+}
+
 TEST_P(ASTImporterOptionSpecificTestBase, FriendFunInClassTemplate) {
   auto *Code = R"(
   template 
Index: clang/lib/AST/ASTStructuralEquivalence.cpp
===
--- clang/lib/AST/ASTStructuralEquivalence.cpp
+++ clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -1464,6 +1464,160 @@
   return IsStructurallyEquivalent(GetName(D1), GetName(D2));
 }
 
+static bool
+IsCXXRecordBaseStructurallyEquivalent(StructuralEquivalenceContext &Context,
+  RecordDecl *D1, RecordDecl *D2) {
+  auto *D1CXX = cast(D1);
+  auto *D2CXX = cast(D2);
+
+  if (D1CXX->getNumBases() != D2CXX->getNumBases()) {
+if (Context.Complain) {
+  Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
+   diag::err_odr_tag_type_inconsistent))
+  << Context.ToCtx.getTypeDeclType(D2);
+  Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)
+  << D2CXX->getNumBases();
+  Context.Diag1(D1->getLocation(),

[PATCH] D157237: [clang][ASTMatcher] Add Matcher 'dependentSizedExtVectorType'

2023-08-06 Thread Ding Fei via Phabricator via cfe-commits
danix800 created this revision.
danix800 added a project: clang.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a subscriber: cfe-commits.

Add Matcher `dependentSizedExtVectorType` for type 
`DependentSizedExtVectorType`.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D157237

Files:
  clang/docs/LibASTMatchersReference.html
  clang/docs/ReleaseNotes.rst
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/lib/ASTMatchers/ASTMatchersInternal.cpp
  clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp


Index: clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -1560,6 +1560,19 @@
  dependentSizedArrayType()));
 }
 
+TEST_P(ASTMatchersTest, DependentSizedExtVectorType) {
+  if (!GetParam().isCXX()) {
+return;
+  }
+  EXPECT_TRUE(matches("template"
+  "class vector {"
+  "  typedef T __attribute__((ext_vector_type(Size))) 
type;"
+  "};", dependentSizedExtVectorType()));
+  EXPECT_TRUE(
+  notMatches("int a[42]; int b[] = { 2, 3 }; void f() { int c[b[0]]; }",
+ dependentSizedExtVectorType()));
+}
+
 TEST_P(ASTMatchersTest, IncompleteArrayType) {
   EXPECT_TRUE(matches("int a[] = { 2, 3 };", incompleteArrayType()));
   EXPECT_TRUE(matches("void f(int a[]) {}", incompleteArrayType()));
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -1046,6 +1046,7 @@
 const AstTypeMatcher
 deducedTemplateSpecializationType;
 const AstTypeMatcher dependentSizedArrayType;
+const AstTypeMatcher dependentSizedExtVectorType;
 const AstTypeMatcher incompleteArrayType;
 const AstTypeMatcher variableArrayType;
 const AstTypeMatcher atomicType;
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -6938,6 +6938,21 @@
 ///   matches "T data[Size]"
 extern const AstTypeMatcher dependentSizedArrayType;
 
+/// Matches C++ extended vector type where either the type or size is
+/// dependent.
+///
+/// Given
+/// \code
+///   template
+///   class vector {
+/// typedef T __attribute__((ext_vector_type(Size))) type;
+///   };
+/// \endcode
+/// dependentSizedExtVectorType
+///   matches "T __attribute__((ext_vector_type(Size)))"
+extern const AstTypeMatcher
+dependentSizedExtVectorType;
+
 /// Matches C arrays with unspecified size.
 ///
 /// Given
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -228,6 +228,7 @@
 
 AST Matchers
 
+- Add ``dependentSizedExtVectorType``.
 
 clang-format
 
Index: clang/docs/LibASTMatchersReference.html
===
--- clang/docs/LibASTMatchersReference.html
+++ clang/docs/LibASTMatchersReference.html
@@ -2531,6 +2531,19 @@
 
 
 
+MatcherType>dependentSizedExtVectorTypeMatcherDependentSizedExtVectorType>...
+Matches 
C++ extended vector type where either the type or size is dependent.
+
+Given
+  template
+  class vector {
+typedef T __attribute__((ext_vector_type(Size))) type;
+  };
+dependentSizedExtVectorType
+  matches "T __attribute__((ext_vector_type(Size)))"
+
+
+
 MatcherType>elaboratedTypeMatcherElaboratedType>...
 Matches types 
specified with an elaborated type keyword or with a
 qualified name.


Index: clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -1560,6 +1560,19 @@
  dependentSizedArrayType()));
 }
 
+TEST_P(ASTMatchersTest, DependentSizedExtVectorType) {
+  if (!GetParam().isCXX()) {
+return;
+  }
+  EXPECT_TRUE(matches("template"
+  "class vector {"
+  "  typedef T __attribute__((ext_vector_type(Size))) type;"
+  "};", dependentSizedExtVectorType()));
+  EXPECT_TRUE(
+  notMatches("int a[42]; int b[] = { 2, 3 }; void f() { int c[b[0]]; }",
+ dependentSizedExtVectorType()));
+}
+
 TEST_P(ASTMatchersTest, IncompleteArrayType) {
   EXPECT_TRUE(

[PATCH] D157238: [clang][ASTImporter] Add import of 'DependentSizedExtVectorType'

2023-08-06 Thread Ding Fei via Phabricator via cfe-commits
danix800 created this revision.
danix800 added reviewers: Aar454on, balazske.
danix800 added a project: clang.
Herald added a subscriber: martong.
Herald added a reviewer: a.sidorin.
Herald added a reviewer: shafik.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a subscriber: cfe-commits.

Add import of 'DependentSizedExtVectorType'.

Depends on https://reviews.llvm.org/D157237


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D157238

Files:
  clang/docs/LibASTMatchersReference.html
  clang/docs/ReleaseNotes.rst
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/lib/AST/ASTImporter.cpp
  clang/lib/ASTMatchers/ASTMatchersInternal.cpp
  clang/unittests/AST/ASTImporterFixtures.h
  clang/unittests/AST/ASTImporterTest.cpp
  clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -1560,6 +1560,19 @@
  dependentSizedArrayType()));
 }
 
+TEST_P(ASTMatchersTest, DependentSizedExtVectorType) {
+  if (!GetParam().isCXX()) {
+return;
+  }
+  EXPECT_TRUE(matches("template"
+  "class vector {"
+  "  typedef T __attribute__((ext_vector_type(Size))) type;"
+  "};", dependentSizedExtVectorType()));
+  EXPECT_TRUE(
+  notMatches("int a[42]; int b[] = { 2, 3 }; void f() { int c[b[0]]; }",
+ dependentSizedExtVectorType()));
+}
+
 TEST_P(ASTMatchersTest, IncompleteArrayType) {
   EXPECT_TRUE(matches("int a[] = { 2, 3 };", incompleteArrayType()));
   EXPECT_TRUE(matches("void f(int a[]) {}", incompleteArrayType()));
Index: clang/unittests/AST/ASTImporterTest.cpp
===
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -1044,6 +1044,17 @@
  has(fieldDecl(hasType(dependentSizedArrayType(;
 }
 
+TEST_P(ImportExpr, DependentSizedExtVectorType) {
+  MatchVerifier Verifier;
+  testImport("template"
+ "class declToImport {"
+ "  typedef T __attribute__((ext_vector_type(Size))) type;"
+ "};",
+ Lang_CXX03, "", Lang_CXX03, Verifier,
+ classTemplateDecl(has(cxxRecordDecl(
+ has(typedefDecl(hasType(dependentSizedExtVectorType(;
+}
+
 TEST_P(ASTImporterOptionSpecificTestBase, ImportUsingPackDecl) {
   Decl *FromTU = getTuDecl(
   "struct A { int operator()() { return 1; } };"
Index: clang/unittests/AST/ASTImporterFixtures.h
===
--- clang/unittests/AST/ASTImporterFixtures.h
+++ clang/unittests/AST/ASTImporterFixtures.h
@@ -260,6 +260,8 @@
  FromAST->getFileManager(), false);
 
 auto FoundNodes = match(SearchMatcher, FromCtx);
+if (FoundNodes.empty())
+  return testing::AssertionFailure() << "No node was found!";
 if (FoundNodes.size() != 1)
   return testing::AssertionFailure()
  << "Multiple potential nodes were found!";
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -1046,6 +1046,7 @@
 const AstTypeMatcher
 deducedTemplateSpecializationType;
 const AstTypeMatcher dependentSizedArrayType;
+const AstTypeMatcher dependentSizedExtVectorType;
 const AstTypeMatcher incompleteArrayType;
 const AstTypeMatcher variableArrayType;
 const AstTypeMatcher atomicType;
Index: clang/lib/AST/ASTImporter.cpp
===
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -381,7 +381,8 @@
 ExpectedType VisitIncompleteArrayType(const IncompleteArrayType *T);
 ExpectedType VisitVariableArrayType(const VariableArrayType *T);
 ExpectedType VisitDependentSizedArrayType(const DependentSizedArrayType *T);
-// FIXME: DependentSizedExtVectorType
+ExpectedType
+VisitDependentSizedExtVectorType(const DependentSizedExtVectorType *T);
 ExpectedType VisitVectorType(const VectorType *T);
 ExpectedType VisitExtVectorType(const ExtVectorType *T);
 ExpectedType VisitFunctionNoProtoType(const FunctionNoProtoType *T);
@@ -1264,6 +1265,18 @@
   T->getIndexTypeCVRQualifiers(), ToBracketsRange);
 }
 
+ExpectedType ASTNodeImporter::VisitDependentSizedExtVectorType(
+const DependentSizedExtVectorType *T) {
+  Error Err = Error::success();
+  QualType ToElementType = importChecked(Err, T->getElementType());
+  Expr *ToSizeExpr = importChecked(Err, T->getSizeExpr());
+  SourceLocation ToAttrLoc = importChecked(Err, T->getAttributeLoc());
+  if (Err)
+return std::move

[PATCH] D157237: [clang][ASTMatcher] Add Matcher 'dependentSizedExtVectorType'

2023-08-06 Thread Ding Fei via Phabricator via cfe-commits
danix800 updated this revision to Diff 547614.
danix800 added a comment.

Add missing Matcher registration.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157237

Files:
  clang/docs/LibASTMatchersReference.html
  clang/docs/ReleaseNotes.rst
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/lib/ASTMatchers/ASTMatchersInternal.cpp
  clang/lib/ASTMatchers/Dynamic/Registry.cpp
  clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -1560,6 +1560,20 @@
  dependentSizedArrayType()));
 }
 
+TEST_P(ASTMatchersTest, DependentSizedExtVectorType) {
+  if (!GetParam().isCXX()) {
+return;
+  }
+  EXPECT_TRUE(matches("template"
+  "class vector {"
+  "  typedef T __attribute__((ext_vector_type(Size))) type;"
+  "};",
+  dependentSizedExtVectorType()));
+  EXPECT_TRUE(
+  notMatches("int a[42]; int b[] = { 2, 3 }; void f() { int c[b[0]]; }",
+ dependentSizedExtVectorType()));
+}
+
 TEST_P(ASTMatchersTest, IncompleteArrayType) {
   EXPECT_TRUE(matches("int a[] = { 2, 3 };", incompleteArrayType()));
   EXPECT_TRUE(matches("void f(int a[]) {}", incompleteArrayType()));
Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===
--- clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -227,6 +227,7 @@
   REGISTER_MATCHER(defaultStmt);
   REGISTER_MATCHER(dependentCoawaitExpr);
   REGISTER_MATCHER(dependentSizedArrayType);
+  REGISTER_MATCHER(dependentSizedExtVectorType);
   REGISTER_MATCHER(designatedInitExpr);
   REGISTER_MATCHER(designatorCountIs);
   REGISTER_MATCHER(doStmt);
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -1046,6 +1046,7 @@
 const AstTypeMatcher
 deducedTemplateSpecializationType;
 const AstTypeMatcher dependentSizedArrayType;
+const AstTypeMatcher dependentSizedExtVectorType;
 const AstTypeMatcher incompleteArrayType;
 const AstTypeMatcher variableArrayType;
 const AstTypeMatcher atomicType;
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -6938,6 +6938,21 @@
 ///   matches "T data[Size]"
 extern const AstTypeMatcher dependentSizedArrayType;
 
+/// Matches C++ extended vector type where either the type or size is
+/// dependent.
+///
+/// Given
+/// \code
+///   template
+///   class vector {
+/// typedef T __attribute__((ext_vector_type(Size))) type;
+///   };
+/// \endcode
+/// dependentSizedExtVectorType
+///   matches "T __attribute__((ext_vector_type(Size)))"
+extern const AstTypeMatcher
+dependentSizedExtVectorType;
+
 /// Matches C arrays with unspecified size.
 ///
 /// Given
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -228,6 +228,7 @@
 
 AST Matchers
 
+- Add ``dependentSizedExtVectorType``.
 
 clang-format
 
Index: clang/docs/LibASTMatchersReference.html
===
--- clang/docs/LibASTMatchersReference.html
+++ clang/docs/LibASTMatchersReference.html
@@ -2531,6 +2531,19 @@
 
 
 
+MatcherType>dependentSizedExtVectorTypeMatcherDependentSizedExtVectorType>...
+Matches C++ extended vector type where either the type or size is dependent.
+
+Given
+  template
+  class vector {
+typedef T __attribute__((ext_vector_type(Size))) type;
+  };
+dependentSizedExtVectorType
+  matches "T __attribute__((ext_vector_type(Size)))"
+
+
+
 MatcherType>elaboratedTypeMatcherElaboratedType>...
 Matches types specified with an elaborated type keyword or with a
 qualified name.
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D157237: [clang][ASTMatcher] Add Matcher 'dependentSizedExtVectorType'

2023-08-06 Thread Ding Fei via Phabricator via cfe-commits
danix800 added a comment.

In D157237#4564148 , @PiotrZSL wrote:

> Matcher registration is missing, verify if it's visible in clang-query.

Fixed. Thanks for reminding!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157237

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


  1   2   >