llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Akash Manna (akash-manna-sky)

<details>
<summary>Changes</summary>

Fixes #<!-- -->213854

An ill-formed qualified member definition like `void B::foo() {}` inside a 
union gets diagnosed, but recovery keeps the declaration around: it belongs to 
`B` semantically while sitting lexically inside the union. Because `B::foo` 
overrides a virtual function, `CXXRecordDecl::addedMember` — which runs on the 
lexical class — marked the union polymorphic, and record layout later asserted 
with `"Unions cannot be dynamic classes."`. A non-union enclosing class hits 
the same bug silently and just gets a bogus vtable pointer.

The fix is to make `addedMember` ignore declarations that belong to a different 
class, right next to the existing friend/invalid filter. Only these recovery 
leftovers can end up in that position, so valid code is unaffected, and the 
recovery and assertion both stay as they are. Also added a regression test 
(reduced union/struct cases plus the verbatim reproducer) and a release note.

LLM tools were used for this contribution. I've reviewed, built, and tested the 
change myself before pushing to GitHub.


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


3 Files Affected:

- (modified) clang/docs/ReleaseNotes.md (+6) 
- (modified) clang/lib/AST/DeclCXX.cpp (+5) 
- (added) clang/test/SemaCXX/GH213854.cpp (+42) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 8c9467ca7b742..b4410f52d87e4 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -528,6 +528,12 @@ features cannot lower the translation-unit ABI level;
   parameter that follows a parameter pack (e.g.
   `template <typename... T> S::S(T..., int = 10) {}`).  (#GH216211)
 
+- Fixed a crash when an ill-formed qualified member function definition written
+  inside a class (e.g. a definition of a virtual member of a nested class)
+  incorrectly caused the enclosing class to be treated as a polymorphic class,
+  which asserted during record layout when the enclosing class was a union.
+  (#GH213854)
+
 #### Bug Fixes to AST Handling
 
 - Fixed a non-deterministic ordering of unused local typedefs that made
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index f0da56542ae7e..ed0c9512f8b6f 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -758,6 +758,11 @@ void CXXRecordDecl::addedMember(Decl *D) {
   if (D->getFriendObjectKind() || D->isInvalidDecl())
     return;
 
+  // Ignore members of a different class, which can appear here during error
+  // recovery for an ill-formed qualified member declaration.
+  if (!D->getDeclContext()->Equals(this))
+    return;
+
   auto *FunTmpl = dyn_cast<FunctionTemplateDecl>(D);
   if (FunTmpl)
     D = FunTmpl->getTemplatedDecl();
diff --git a/clang/test/SemaCXX/GH213854.cpp b/clang/test/SemaCXX/GH213854.cpp
new file mode 100644
index 0000000000000..96c4e6049aa1d
--- /dev/null
+++ b/clang/test/SemaCXX/GH213854.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace reduced {
+union Union {
+  class A {
+    virtual void foo();
+  };
+  class B : public A {
+  };
+  void B::foo() {} // expected-error {{non-friend class member 'foo' cannot 
have a qualified name}}
+};
+
+static_assert(!__is_polymorphic(Union), "");
+
+void uni(void (*fn)(Union), Union arg1) {
+  fn(arg1);
+}
+
+struct Struct {
+  class A {
+    virtual void foo();
+  };
+  class B : public A {
+  };
+  void B::foo() {} // expected-error {{non-friend class member 'foo' cannot 
have a qualified name}}
+};
+
+static_assert(!__is_polymorphic(Struct), "");
+} // namespace reduced
+
+// Verbatim reproducer from GH213854; the missing closing brace is intentional.
+union Union { // expected-note {{to match this '{'}}
+  class A {
+  virtual void foo();
+  };
+  class B : public A {
+  };
+  void B::foo() {} // expected-error {{non-friend class member 'foo' cannot 
have a qualified name}}
+void uni(void (*fn)(union Union), union Union arg1) {
+    fn(arg1);
+}
+// expected-error {{expected '}'}} expected-error@-1 {{expected ';' after 
union}}
\ No newline at end of file

``````````

</details>


https://github.com/llvm/llvm-project/pull/217942
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to