[clang] [clang] Add clang::debug_info_type attribute for bitfields (PR #69104)

Vlad Serebrennikov via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 15 03:55:27 PDT 2023


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

>From 976aa5c8f3d936a15e7123069a49d97ad3bf7a05 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sun, 15 Oct 2023 13:14:55 +0300
Subject: [PATCH 1/3] [clang] Add clang::debug_info_type attribute

---
 clang/include/clang/Basic/Attr.td             | 11 ++++++++
 clang/include/clang/Basic/AttrDocs.td         | 12 +++++++++
 .../clang/Basic/DiagnosticSemaKinds.td        |  2 ++
 clang/lib/CodeGen/CGDebugInfo.cpp             |  2 ++
 clang/lib/Sema/SemaDeclAttr.cpp               | 26 +++++++++++++++++++
 .../CodeGen/debug-info-debug-info-type.cpp    | 14 ++++++++++
 6 files changed, 67 insertions(+)
 create mode 100644 clang/test/CodeGen/debug-info-debug-info-type.cpp

diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 5c9eb7b8a981037..024421c0583c019 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -107,6 +107,10 @@ def NonBitField : SubsetSubject<Field,
                                 [{!S->isBitField()}],
                                 "non-bit-field non-static data members">;
 
+def BitField : SubsetSubject<Field,
+                             [{S->isBitField()}],
+                             "bit-field non-static data members">;
+
 def NonStaticCXXMethod : SubsetSubject<CXXMethod,
                                        [{!S->isStatic()}],
                                        "non-static member functions">;
@@ -4264,3 +4268,10 @@ def CountedBy : InheritableAttr {
       void setCountedByFieldLoc(SourceRange Loc) { CountedByFieldLoc = Loc; }
   }];
 }
+
+def DebugInfoType: InheritableAttr {
+  let Spellings = [Clang<"debug_info_type">];
+  let Subjects = SubjectList<[BitField], ErrorDiag>;
+  let Args = [TypeArgument<"Type", 1>];
+  let Documentation = [DebugInfoTypeDocumentation];
+}
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 9f9991bdae36155..6cceba1e0e0ad01 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -7219,6 +7219,18 @@ its underlying representation to be a WebAssembly ``funcref``.
   }];
 }
 
+def DebugInfoTypeDocumentation : Documentation {
+  let Category = DocCatField;
+  let Content = [{
+This attribute allows to alter type of a bitfield in debug information.
+Such a need might arise when bitfield is intended to store an enumeration value,
+but has to be specified as having enumeration's underlying type, in order to
+facilitate compiler optimizations. But this also causes underlying type to be
+emitted in debug information, making it hard for debuggers to map bitfield's
+value back to enumeration. This attribute helps with this.
+  }];
+}
+
 def CleanupDocs : Documentation {
   let Category = DocCatType;
   let Content = [{
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index e85cd4d1a1ddc0d..b5c73494df367a6 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3153,6 +3153,8 @@ def err_invalid_branch_protection_spec : Error<
   "invalid or misplaced branch protection specification '%0'">;
 def warn_unsupported_branch_protection_spec : Warning<
   "unsupported branch protection specification '%0'">, InGroup<BranchProtection>;
+def warn_attribute_underlying_type_mismatch : Warning<
+  "underlying type %0 of enumeration %1 doesn't match bitfield type %2">;
 
 def warn_unsupported_target_attribute
     : Warning<"%select{unsupported|duplicate|unknown}0%select{| CPU|"
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index c73a63e12f03aab..85aedd87b21d41e 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -1497,6 +1497,8 @@ CGDebugInfo::createBitFieldType(const FieldDecl *BitFieldDecl,
                                 llvm::DIScope *RecordTy, const RecordDecl *RD) {
   StringRef Name = BitFieldDecl->getName();
   QualType Ty = BitFieldDecl->getType();
+  if (BitFieldDecl->hasAttr<DebugInfoTypeAttr>())
+    Ty = BitFieldDecl->getAttr<DebugInfoTypeAttr>()->getType();
   SourceLocation Loc = BitFieldDecl->getLocation();
   llvm::DIFile *VUnit = getOrCreateFile(Loc);
   llvm::DIType *DebugType = getOrCreateType(Ty, VUnit);
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index feb02cad9080e3e..8d58968b7f985c8 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -5910,6 +5910,28 @@ static void handleBuiltinAliasAttr(Sema &S, Decl *D,
   D->addAttr(::new (S.Context) BuiltinAliasAttr(S.Context, AL, Ident));
 }
 
+static void handleDebugInfoTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+  if (!AL.hasParsedType()) {
+    S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
+    return;
+  }
+
+  TypeSourceInfo *ParmTSI = nullptr;
+  QualType type = S.GetTypeFromParser(AL.getTypeArg(), &ParmTSI);
+  assert(ParmTSI && "no type source info for attribute argument");
+
+  if (type->isEnumeralType()) {
+    QualType BitfieldType = llvm::cast<FieldDecl>(D)->getType();
+    QualType EnumUnderlyingType = type->getAs<EnumType>()->getDecl()->getIntegerType();
+    if (EnumUnderlyingType != BitfieldType) {
+      S.Diag(AL.getLoc(), diag::warn_attribute_underlying_type_mismatch) << EnumUnderlyingType << type << BitfieldType;
+      return;
+    }
+  }
+
+  D->addAttr(::new (S.Context) DebugInfoTypeAttr(S.Context, AL, ParmTSI));
+}
+
 //===----------------------------------------------------------------------===//
 // Checker-specific attribute handlers.
 //===----------------------------------------------------------------------===//
@@ -9629,6 +9651,10 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
     handleBuiltinAliasAttr(S, D, AL);
     break;
 
+  case ParsedAttr::AT_DebugInfoType:
+    handleDebugInfoTypeAttr(S, D, AL);
+    break;
+
   case ParsedAttr::AT_UsingIfExists:
     handleSimpleAttribute<UsingIfExistsAttr>(S, D, AL);
     break;
diff --git a/clang/test/CodeGen/debug-info-debug-info-type.cpp b/clang/test/CodeGen/debug-info-debug-info-type.cpp
new file mode 100644
index 000000000000000..6104ce7463ef918
--- /dev/null
+++ b/clang/test/CodeGen/debug-info-debug-info-type.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang -target x86_64-linux -g -S -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -verify -DMISMATCH %s
+
+struct A {
+  enum E : unsigned {};
+  [[clang::debug_info_type(E)]] unsigned b : 2;
+#ifdef MISMATCH
+  [[clang::debug_info_type(E)]] int b2 : 2;
+  // expected-warning at -1 {{underlying type 'unsigned int' of enumeration 'E' doesn't match bitfield type 'int'}}
+#endif
+} a;
+
+// CHECK-DAG: [[ENUM:![0-9]+]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E"{{.*}}
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "b",{{.*}} baseType: [[ENUM]]
\ No newline at end of file

>From 4330b70c2fde70010f1caabbf6562b61c701ef7e Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sun, 15 Oct 2023 13:34:09 +0300
Subject: [PATCH 2/3] Add newline to the test

---
 clang/test/CodeGen/debug-info-debug-info-type.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/CodeGen/debug-info-debug-info-type.cpp b/clang/test/CodeGen/debug-info-debug-info-type.cpp
index 6104ce7463ef918..4b60d1b64be239f 100644
--- a/clang/test/CodeGen/debug-info-debug-info-type.cpp
+++ b/clang/test/CodeGen/debug-info-debug-info-type.cpp
@@ -11,4 +11,4 @@ struct A {
 } a;
 
 // CHECK-DAG: [[ENUM:![0-9]+]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "E"{{.*}}
-// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "b",{{.*}} baseType: [[ENUM]]
\ No newline at end of file
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "b",{{.*}} baseType: [[ENUM]]

>From faf8238ae2a6362214e8176e4b9b7225fa7c8bd1 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sun, 15 Oct 2023 13:55:13 +0300
Subject: [PATCH 3/3] Run clang-format

---
 clang/lib/Sema/SemaDeclAttr.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 8d58968b7f985c8..294a73d2abf2d29 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -5922,9 +5922,11 @@ static void handleDebugInfoTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
 
   if (type->isEnumeralType()) {
     QualType BitfieldType = llvm::cast<FieldDecl>(D)->getType();
-    QualType EnumUnderlyingType = type->getAs<EnumType>()->getDecl()->getIntegerType();
+    QualType EnumUnderlyingType =
+        type->getAs<EnumType>()->getDecl()->getIntegerType();
     if (EnumUnderlyingType != BitfieldType) {
-      S.Diag(AL.getLoc(), diag::warn_attribute_underlying_type_mismatch) << EnumUnderlyingType << type << BitfieldType;
+      S.Diag(AL.getLoc(), diag::warn_attribute_underlying_type_mismatch)
+          << EnumUnderlyingType << type << BitfieldType;
       return;
     }
   }



More information about the cfe-commits mailing list