Skip to content

[Clang] Implement diagnostics for why std::is_standard_layout is false #144161

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jun 25, 2025

Conversation

snarang181
Copy link
Contributor

@snarang181 snarang181 commented Jun 13, 2025

As part of the effort in #141911

@snarang181 snarang181 force-pushed the clang-explain-std-layout branch from 46f2a26 to 48c17e2 Compare June 14, 2025 09:35
@snarang181 snarang181 marked this pull request as ready for review June 14, 2025 09:37
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jun 14, 2025
@snarang181
Copy link
Contributor Author

Rebased and testing the again. The Windows build failure seems largely unrelated to my changes.

@llvmbot
Copy link
Member

llvmbot commented Jun 14, 2025

@llvm/pr-subscribers-clang

Author: Samarth Narang (snarang181)

Changes

As part of the effort in #141911


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

4 Files Affected:

  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+8-1)
  • (modified) clang/lib/Sema/SemaTypeTraits.cpp (+117)
  • (modified) clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp (+50)
  • (modified) clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp (+80)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 8fe7ad6138aa0..8660ba6231998 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1767,7 +1767,8 @@ def note_unsatisfied_trait
     : Note<"%0 is not %enum_select<TraitName>{"
            "%TriviallyRelocatable{trivially relocatable}|"
            "%Replaceable{replaceable}|"
-           "%TriviallyCopyable{trivially copyable}"
+           "%TriviallyCopyable{trivially copyable}|"
+           "%StandardLayout{standard-layout}"
            "}1">;
 
 def note_unsatisfied_trait_reason
@@ -1787,6 +1788,12 @@ def note_unsatisfied_trait_reason
            "%NonReplaceableField{has a non-replaceable member %1 of type %2}|"
            "%NTCBase{has a non-trivially-copyable base %1}|"
            "%NTCField{has a non-trivially-copyable member %1 of type %2}|"
+           "%NonStdLayoutBase{has a non-standard-layout base %1}|"
+           "%MixedAccess{has mixed access specifiers}|"
+           "%MultipleDataBase{has multiple base classes with data members}|"
+           "%VirtualFunction{has virtual functions}|"
+           "%NonStdLayoutMember{has a non-standard-layout member %1 of type %2}|"
+           "%IndirectBaseWithFields{has an indirect base %1 with data members}|"
            "%DeletedDtr{has a %select{deleted|user-provided}1 destructor}|"
            "%UserProvidedCtr{has a user provided %select{copy|move}1 "
            "constructor}|"
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index 1738ab4466001..08682cc09f350 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -1947,6 +1947,7 @@ static std::optional<TypeTrait> StdNameToTypeTrait(StringRef Name) {
             TypeTrait::UTT_IsCppTriviallyRelocatable)
       .Case("is_replaceable", TypeTrait::UTT_IsReplaceable)
       .Case("is_trivially_copyable", TypeTrait::UTT_IsTriviallyCopyable)
+      .Case("is_standard_layout", TypeTrait::UTT_IsStandardLayout)
       .Default(std::nullopt);
 }
 
@@ -2276,6 +2277,119 @@ static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef,
   SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
 }
 
+static bool hasMixedAccessSpecifier(const CXXRecordDecl *D) {
+  AccessSpecifier FirstAccess = AS_none;
+  for (const FieldDecl *Field : D->fields()) {
+
+    if (Field->isUnnamedBitField())
+      continue;
+    AccessSpecifier FieldAccess = Field->getAccess();
+    if (FirstAccess == AS_none) {
+      FirstAccess = FieldAccess;
+    } else if (FieldAccess != FirstAccess) {
+      return true;
+    }
+  }
+  return false;
+}
+
+static bool hasMultipleDataBaseClassesWithFields(const CXXRecordDecl *D) {
+  int NumBasesWithFields = 0;
+  for (const CXXBaseSpecifier &Base : D->bases()) {
+    const CXXRecordDecl *BaseRD = Base.getType()->getAsCXXRecordDecl();
+    if (!BaseRD || BaseRD->isInvalidDecl())
+      continue;
+
+    for (const FieldDecl *Field : BaseRD->fields()) {
+      if (!Field->isUnnamedBitField()) {
+        ++NumBasesWithFields;
+        break; // Only count the base once.
+      }
+    }
+  }
+  return NumBasesWithFields > 1;
+}
+
+static void DiagnoseNonStandardLayoutReason(Sema &SemaRef, SourceLocation Loc,
+                                            const CXXRecordDecl *D) {
+  for (const CXXBaseSpecifier &B : D->bases()) {
+    assert(B.getType()->getAsCXXRecordDecl() && "invalid base?");
+    if (B.isVirtual()) {
+      SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+          << diag::TraitNotSatisfiedReason::VBase << B.getType()
+          << B.getSourceRange();
+    }
+    if (!B.getType()->isStandardLayoutType()) {
+      SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+          << diag::TraitNotSatisfiedReason::NonStdLayoutBase << B.getType()
+          << B.getSourceRange();
+    }
+  }
+  if (hasMixedAccessSpecifier(D)) {
+    SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::MixedAccess;
+  }
+  if (hasMultipleDataBaseClassesWithFields(D)) {
+    SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::MultipleDataBase;
+  }
+  if (D->isPolymorphic()) {
+    SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::VirtualFunction;
+  }
+  for (const FieldDecl *Field : D->fields()) {
+    if (!Field->getType()->isStandardLayoutType()) {
+      SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+          << diag::TraitNotSatisfiedReason::NonStdLayoutMember << Field
+          << Field->getType() << Field->getSourceRange();
+    }
+  }
+  // find any indirect base classes that have fields
+  if (D->hasDirectFields()) {
+    const CXXRecordDecl *Indirect = nullptr;
+    D->forallBases([&](const CXXRecordDecl *BaseDef) {
+      if (BaseDef->hasDirectFields()) {
+        Indirect = BaseDef;
+        return false; // stop traversal
+      }
+      return true; // continue to the next base
+    });
+    if (Indirect) {
+      SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+          << diag::TraitNotSatisfiedReason::IndirectBaseWithFields << Indirect
+          << Indirect->getSourceRange();
+    }
+  }
+}
+
+static void DiagnoseNonStandardLayoutReason(Sema &SemaRef, SourceLocation Loc,
+                                            QualType T) {
+  SemaRef.Diag(Loc, diag::note_unsatisfied_trait)
+      << T << diag::TraitName::StandardLayout;
+
+  // Check type-level exclusion first
+  if (T->isVariablyModifiedType()) {
+    SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::VLA;
+    return;
+  }
+
+  if (T->isReferenceType()) {
+    SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+        << diag::TraitNotSatisfiedReason::Ref;
+    return;
+  }
+  T = T.getNonReferenceType();
+  const CXXRecordDecl *D = T->getAsCXXRecordDecl();
+  if (!D || D->isInvalidDecl())
+    return;
+
+  if (D->hasDefinition())
+    DiagnoseNonStandardLayoutReason(SemaRef, Loc, D);
+
+  SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
+}
+
 void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
   E = E->IgnoreParenImpCasts();
   if (E->containsErrors())
@@ -2296,6 +2410,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
   case UTT_IsTriviallyCopyable:
     DiagnoseNonTriviallyCopyableReason(*this, E->getBeginLoc(), Args[0]);
     break;
+  case UTT_IsStandardLayout:
+    DiagnoseNonStandardLayoutReason(*this, E->getBeginLoc(), Args[0]);
+    break;
   default:
     break;
   }
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
index 329b611110c1d..59f3d95a4d215 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
@@ -20,6 +20,13 @@ struct is_trivially_copyable {
 
 template <typename T>
 constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
+
+template <typename T>
+struct is_standard_layout {
+static constexpr bool value = __is_standard_layout(T);
+};
+template <typename T>
+constexpr bool is_standard_layout_v = __is_standard_layout(T);
 #endif
 
 #ifdef STD2
@@ -44,6 +51,17 @@ using is_trivially_copyable  = __details_is_trivially_copyable<T>;
 
 template <typename T>
 constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
+
+template <typename T>
+struct __details_is_standard_layout {
+static constexpr bool value = __is_standard_layout(T);
+
+
+};
+template <typename T>
+using is_standard_layout = __details_is_standard_layout<T>;
+template <typename T>
+constexpr bool is_standard_layout_v = __is_standard_layout(T);
 #endif
 
 
@@ -73,6 +91,13 @@ using is_trivially_copyable  = __details_is_trivially_copyable<T>;
 
 template <typename T>
 constexpr bool is_trivially_copyable_v = is_trivially_copyable<T>::value;
+
+template <typename T>
+struct __details_is_standard_layout : bool_constant<__is_standard_layout(T)> {};
+template <typename T>
+using is_standard_layout = __details_is_standard_layout<T>;
+template <typename T>
+constexpr bool is_standard_layout_v = is_standard_layout<T>::value;
 #endif
 
 }
@@ -100,6 +125,21 @@ static_assert(std::is_trivially_copyable_v<int&>);
 // expected-note@-1 {{because it is a reference type}}
 
 
+ // Direct tests
+ static_assert(std::is_standard_layout<int>::value);
+ static_assert(std::is_standard_layout_v<int>);
+
+ static_assert(std::is_standard_layout<int&>::value);
+ // expected-error-re@-1 {{static assertion failed due to requirement 'std::{{.*}}is_standard_layout<int &>::value'}} \
+ // expected-note@-1 {{'int &' is not standard-layout}} \
+ // expected-note@-1 {{because it is a reference type}}
+
+ static_assert(std::is_standard_layout_v<int&>);
+ // expected-error@-1 {{static assertion failed due to requirement 'std::is_standard_layout_v<int &>'}} \
+ // expected-note@-1 {{'int &' is not standard-layout}} \
+ // expected-note@-1 {{because it is a reference type}}
+
+
 namespace test_namespace {
     using namespace std;
     static_assert(is_trivially_relocatable<int&>::value);
@@ -119,6 +159,16 @@ namespace test_namespace {
     // expected-error@-1 {{static assertion failed due to requirement 'is_trivially_copyable_v<int &>'}} \
     // expected-note@-1 {{'int &' is not trivially copyable}} \
     // expected-note@-1 {{because it is a reference type}}
+
+    static_assert(is_standard_layout<int&>::value);
+     // expected-error-re@-1 {{static assertion failed due to requirement '{{.*}}is_standard_layout<int &>::value'}} \
+     // expected-note@-1 {{'int &' is not standard-layout}} \
+     // expected-note@-1 {{because it is a reference type}}
+
+     static_assert(is_standard_layout_v<int&>);
+     // expected-error@-1 {{static assertion failed due to requirement 'is_standard_layout_v<int &>'}} \
+     // expected-note@-1 {{'int &' is not standard-layout}} \
+     // expected-note@-1 {{because it is a reference type}}
 }
 
 
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
index a8c78f6304ca9..404f6e914b3f6 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
@@ -488,3 +488,83 @@ static_assert(__is_trivially_copyable(S12));
 // expected-note@-1 {{'S12' is not trivially copyable}} \
 // expected-note@#tc-S12 {{'S12' defined here}}
 }
+
+namespace standard_layout_tests {
+struct WithVirtual { // #sl-Virtual
+    virtual void foo();
+};
+static_assert(__is_standard_layout(WithVirtual));
+// expected-error@-1 {{static assertion failed due to requirement '__is_standard_layout(standard_layout_tests::WithVirtual)'}} \
+// expected-note@-1 {{'WithVirtual' is not standard-layout}} \
+// expected-note@-1 {{because it has virtual functions}} \
+// expected-note@#sl-Virtual {{'WithVirtual' defined here}}
+
+struct MixedAccess { // #sl-Mixed
+public:
+    int a;
+private:
+    int b;
+};
+static_assert(__is_standard_layout(MixedAccess));
+// expected-error@-1 {{static assertion failed due to requirement '__is_standard_layout(standard_layout_tests::MixedAccess)'}} \
+// expected-note@-1 {{'MixedAccess' is not standard-layout}} \
+// expected-note@-1 {{because it has mixed access specifiers}} \
+// expected-note@#sl-Mixed {{'MixedAccess' defined here}}
+
+struct VirtualBase { virtual ~VirtualBase(); };               // #sl-VirtualBase
+struct VB : virtual VirtualBase {};                            // #sl-VB
+static_assert(__is_standard_layout(VB));
+// expected-error@-1 {{static assertion failed due to requirement '__is_standard_layout(standard_layout_tests::VB)'}} \
+// expected-note@-1 {{'VB' is not standard-layout}} \
+// expected-note@-1 {{because it has a virtual base 'VirtualBase'}} \
+// expected-note@-1 {{because it has a non-standard-layout base 'VirtualBase'}} \
+// expected-note@-1 {{because it has virtual functions}}
+// expected-note@#sl-VB {{'VB' defined here}}
+
+union U {      // #sl-U
+public:
+    int x;
+private:
+    int y;
+};                                                       
+static_assert(__is_standard_layout(U));
+// expected-error@-1 {{static assertion failed due to requirement '__is_standard_layout(standard_layout_tests::U)'}} \
+// expected-note@-1 {{'U' is not standard-layout}} \
+// expected-note@-1 {{because it has mixed access specifiers}}
+// expected-note@#sl-U {{'U' defined here}}
+
+// Single base class is OK
+struct BaseClass{ int a; };                                   // #sl-BaseClass
+struct DerivedOK : BaseClass {};                                // #sl-DerivedOK
+static_assert(__is_standard_layout(DerivedOK));    
+
+// Primitive types should be standard layout
+static_assert(__is_standard_layout(int));                     // #sl-Int
+static_assert(__is_standard_layout(float));                   // #sl-Float
+
+// Multi-level inheritance: Non-standard layout
+struct Base1 { int a; };                                      // #sl-Base1
+struct Base2 { int b; };                                      // #sl-Base2
+struct DerivedClass : Base1, Base2 {};                        // #sl-DerivedClass
+static_assert(__is_standard_layout(DerivedClass));               
+// expected-error@-1 {{static assertion failed due to requirement '__is_standard_layout(standard_layout_tests::DerivedClass)'}} \
+// expected-note@-1 {{'DerivedClass' is not standard-layout}} \
+// expected-note@-1 {{because it has multiple base classes with data members}} \
+// expected-note@#sl-DerivedClass {{'DerivedClass' defined here}} 
+
+// Inheritance hierarchy with multiple classes having data members
+struct BaseA { int a; };                                      // #sl-BaseA
+struct BaseB : BaseA {};                                      // inherits BaseA, has no new members
+struct BaseC: BaseB { int c; };                               // #sl-BaseC
+static_assert(__is_standard_layout(BaseC));
+// expected-error@-1 {{static assertion failed due to requirement '__is_standard_layout(standard_layout_tests::BaseC)'}} \
+// expected-note@-1 {{'BaseC' is not standard-layout}} \
+// expected-note@-1 {{because it has an indirect base 'BaseA' with data members}} \
+// expected-note@#sl-BaseC {{'BaseC' defined here}} \
+// Multiple direct base classes with no data members --> standard layout
+struct BaseX {};                                              // #sl-BaseX
+struct BaseY {};                                              // #sl-BaseY
+struct MultiBase : BaseX, BaseY {};                          // #sl-MultiBase
+static_assert(__is_standard_layout(MultiBase));
+
+ }

@snarang181 snarang181 force-pushed the clang-explain-std-layout branch from 48c17e2 to e865aeb Compare June 16, 2025 05:11
@snarang181
Copy link
Contributor Author

Looks like all tests pass now. Requesting review now.

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for working on this! I had some nits and some questions about whether we could improve the diagnostics further or not. (If my suggestions turn out to be hard, we can always move forward with what you've already got here as this is still a good set of changes by themselves.)

@snarang181 snarang181 force-pushed the clang-explain-std-layout branch from e865aeb to 541e42e Compare June 19, 2025 07:35
@philnik777 philnik777 changed the title Implement diagnostics for why std::is_standard_layout is false [Clang] Implement diagnostics for why std::is_standard_layout is false Jun 19, 2025
@snarang181 snarang181 requested a review from AaronBallman June 19, 2025 09:29
@snarang181 snarang181 self-assigned this Jun 20, 2025
@snarang181 snarang181 force-pushed the clang-explain-std-layout branch from 482c947 to e5def3a Compare June 22, 2025 01:04
Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for working on this! Please be sure to add a release note to clang/docs/ReleaseNotes.rst so users know about the improvement.

<< B.getSourceRange();
}
}
if (hasMixedAccessSpecifier(D)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than do this walk twice, it may make sense to have the lambda calculate the fields with mixed access so you don't need to have the same logic in two places.

@snarang181 snarang181 force-pushed the clang-explain-std-layout branch from e5def3a to c501f16 Compare June 25, 2025 01:25
@snarang181 snarang181 requested a review from AaronBallman June 25, 2025 01:25
@snarang181
Copy link
Contributor Author

Thank you for working on this! Please be sure to add a release note to clang/docs/ReleaseNotes.rst so users know about the improvement.

Thank you for reviewing @AaronBallman. Addressed your suggestions.

@snarang181 snarang181 force-pushed the clang-explain-std-layout branch 2 times, most recently from 54c1eea to 212df0f Compare June 25, 2025 03:04
@snarang181
Copy link
Contributor Author

Can probably rebase and test again but the Windows failure seems to be unrelated.

to diagnose virtual function failures
Diagnose fields which have different access
@snarang181 snarang181 force-pushed the clang-explain-std-layout branch from 212df0f to 8f2742f Compare June 25, 2025 11:40
Copy link
Contributor

@cor3ntin cor3ntin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy with that (modulo nits) once @AaronBallman is happy

@snarang181 snarang181 force-pushed the clang-explain-std-layout branch from 8f2742f to 5ca99e4 Compare June 25, 2025 13:08
@snarang181 snarang181 force-pushed the clang-explain-std-layout branch from 99c7117 to d5b2294 Compare June 25, 2025 13:14
Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@snarang181
Copy link
Contributor Author

Needs some manual intervention after the merge. Conflicting redundance in the tablegen descriptions of VirtualFunction

@AaronBallman
Copy link
Collaborator

Precommit CI found relevant failures:

FAILED: tools/clang/include/clang/Basic/DiagnosticAnalysisEnums.inc /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include/clang/Basic/DiagnosticAnalysisEnums.inc 
cd /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include/clang/Basic && /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang-tblgen -gen-clang-diags-enums -clang-component=Analysis -I/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include/clang/Basic -I/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/include /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include/clang/Basic/Diagnostic.td --write-if-changed -o DiagnosticAnalysisEnums.inc -d DiagnosticAnalysisEnums.inc.d && /usr/bin/cmake -E cmake_transform_depfile Ninja gccdepfile /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include/clang/Basic /home/gha/actions-runner/_work/llvm-project/llvm-project/build /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include/clang/Basic /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include/clang/Basic/DiagnosticAnalysisEnums.inc.d /home/gha/actions-runner/_work/llvm-project/llvm-project/build/CMakeFiles/d/cf0b499e292100c840f13d8fd4f9c37039043cd2a7ced2cb25ac66d1e34104e6.d
Included from /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include/clang/Basic/Diagnostic.td:236:
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include/clang/Basic/DiagnosticSemaKinds.td:1775:5: error: Duplicate enumerator name 'VirtualFunction'
def note_unsatisfied_trait_reason
    ^
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang-tblgen: 1 errors.

@snarang181
Copy link
Contributor Author

snarang181 commented Jun 25, 2025

@AaronBallman, as per the comment I left below: it is because of the conflicting definitions of the TableGen description of VirtualFunction. Will push a resolution soon.

Needs some manual intervention after the merge. Conflicting redundance in the tablegen descriptions of VirtualFunction

(This creeped in because of the is_empty PR I merged earlier in the day :))

@AaronBallman
Copy link
Collaborator

@AaronBallman, as per the comment I left below: it is because of the conflicting definitions of the TableGen description of VirtualFunction. Will push a resolution soon.

Needs some manual intervention after the merge. Conflicting redundance in the tablegen descriptions of VirtualFunction

(This creeped in because of the is_empty PR I merged earlier in the day :))

Oops! I thought you were talking about merge conflicts. :-)

to deconflict it and make it coherent with existing tablegen diagnostics.
@snarang181
Copy link
Contributor Author

Precommit CI found relevant failures:

FAILED: tools/clang/include/clang/Basic/DiagnosticAnalysisEnums.inc /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include/clang/Basic/DiagnosticAnalysisEnums.inc 
cd /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include/clang/Basic && /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang-tblgen -gen-clang-diags-enums -clang-component=Analysis -I/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include/clang/Basic -I/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/include /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include/clang/Basic/Diagnostic.td --write-if-changed -o DiagnosticAnalysisEnums.inc -d DiagnosticAnalysisEnums.inc.d && /usr/bin/cmake -E cmake_transform_depfile Ninja gccdepfile /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include/clang/Basic /home/gha/actions-runner/_work/llvm-project/llvm-project/build /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include/clang/Basic /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include/clang/Basic/DiagnosticAnalysisEnums.inc.d /home/gha/actions-runner/_work/llvm-project/llvm-project/build/CMakeFiles/d/cf0b499e292100c840f13d8fd4f9c37039043cd2a7ced2cb25ac66d1e34104e6.d
Included from /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include/clang/Basic/Diagnostic.td:236:
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include/clang/Basic/DiagnosticSemaKinds.td:1775:5: error: Duplicate enumerator name 'VirtualFunction'
def note_unsatisfied_trait_reason
    ^
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang-tblgen: 1 errors.

I think the VirtualFunction error diagnostic is better now as it emits either the virtual function or the higher-level class if a virtual method does not exist.

@snarang181 snarang181 merged commit d760f97 into llvm:main Jun 25, 2025
7 checks passed
@snarang181 snarang181 deleted the clang-explain-std-layout branch June 26, 2025 10:16
anthonyhatran pushed a commit to anthonyhatran/llvm-project that referenced this pull request Jun 26, 2025
rlavaee pushed a commit to rlavaee/llvm-project that referenced this pull request Jul 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants