[clang] clang: Make the type_info builtin declaration a singleton (PR #151277)

via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 29 23:47:13 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-modules

Author: Matt (matts1)

<details>
<summary>Changes</summary>

This fixes an ambiguous type type_info when you try and reference the `type_info` type while using clang modulemaps with `-fms-compatibility` enabled

Fixes #<!-- -->38400

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


6 Files Affected:

- (modified) clang/include/clang/AST/ASTContext.h (+12) 
- (modified) clang/include/clang/AST/DeclID.h (+3) 
- (modified) clang/lib/Sema/Sema.cpp (+1-3) 
- (modified) clang/lib/Serialization/ASTReader.cpp (+3) 
- (modified) clang/lib/Serialization/ASTWriter.cpp (+2) 
- (added) clang/test/Modules/pr151277.cpp (+15) 


``````````diff
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 0273109f8a698..3d70654314939 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1290,6 +1290,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
   // Implicitly-declared type 'struct _GUID'.
   mutable TagDecl *MSGuidTagDecl = nullptr;
 
+  // Implicitly-declared type 'struct type_info'.
+  mutable TagDecl *MSTypeInfoTagDecl = nullptr;
+
   /// Keep track of CUDA/HIP device-side variables ODR-used by host code.
   /// This does not include extern shared variables used by device host
   /// functions as addresses of shared variables are per warp, therefore
@@ -2381,6 +2384,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
     return getTagDeclType(MSGuidTagDecl);
   }
 
+  /// Retrieve the implicitly-predeclared 'struct type_info' declaration.
+  TagDecl *getMSTypeInfoTagDecl() const {
+    // Lazily create this type on demand - it's only needed for MS builds.
+    if (!MSTypeInfoTagDecl) {
+      MSTypeInfoTagDecl = buildImplicitRecord("type_info");
+    }
+    return MSTypeInfoTagDecl;
+  }
+
   /// Return whether a declaration to a builtin is allowed to be
   /// overloaded/redeclared.
   bool canBuiltinBeRedeclared(const FunctionDecl *) const;
diff --git a/clang/include/clang/AST/DeclID.h b/clang/include/clang/AST/DeclID.h
index 384f7b031e007..47ae05b2747ae 100644
--- a/clang/include/clang/AST/DeclID.h
+++ b/clang/include/clang/AST/DeclID.h
@@ -77,6 +77,9 @@ enum PredefinedDeclIDs {
   /// The internal '__NSConstantString' tag type.
   PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID,
 
+  /// The predeclared 'type_info' struct.
+  PREDEF_DECL_BUILTIN_MS_TYPE_INFO_TAG_ID,
+
 #define BuiltinTemplate(BTName) PREDEF_DECL##BTName##_ID,
 #include "clang/Basic/BuiltinTemplates.inc"
 
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index d50eeff0e4b3b..a1f707e601db3 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -443,9 +443,7 @@ void Sema::Initialize() {
   if (getLangOpts().MSVCCompat) {
     if (getLangOpts().CPlusPlus &&
         IdResolver.begin(&Context.Idents.get("type_info")) == IdResolver.end())
-      PushOnScopeChains(
-          Context.buildImplicitRecord("type_info", TagTypeKind::Class),
-          TUScope);
+      PushOnScopeChains(Context.getMSTypeInfoTagDecl(), TUScope);
 
     addImplicitTypedef("size_t", Context.getSizeType());
   }
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index f896f9f11c2b3..44b48b9b4711a 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -8318,6 +8318,9 @@ Decl *ASTReader::getPredefinedDecl(PredefinedDeclIDs ID) {
     NewLoaded = Context.getCFConstantStringTagDecl();
     break;
 
+  case PREDEF_DECL_BUILTIN_MS_TYPE_INFO_TAG_ID:
+    return Context.getMSTypeInfoTagDecl();
+
 #define BuiltinTemplate(BTName)                                                \
   case PREDEF_DECL##BTName##_ID:                                               \
     if (Context.Decl##BTName)                                                  \
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index a6957e54b66f1..2b40be3b7349d 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -5618,6 +5618,8 @@ void ASTWriter::PrepareWritingSpecialDecls(Sema &SemaRef) {
                      PREDEF_DECL_BUILTIN_MS_VA_LIST_ID);
   RegisterPredefDecl(Context.MSGuidTagDecl,
                      PREDEF_DECL_BUILTIN_MS_GUID_ID);
+  RegisterPredefDecl(Context.MSTypeInfoTagDecl,
+                     PREDEF_DECL_BUILTIN_MS_TYPE_INFO_TAG_ID);
   RegisterPredefDecl(Context.ExternCContext, PREDEF_DECL_EXTERN_C_CONTEXT_ID);
   RegisterPredefDecl(Context.CFConstantStringTypeDecl,
                      PREDEF_DECL_CF_CONSTANT_STRING_ID);
diff --git a/clang/test/Modules/pr151277.cpp b/clang/test/Modules/pr151277.cpp
new file mode 100644
index 0000000000000..2428e854d6edf
--- /dev/null
+++ b/clang/test/Modules/pr151277.cpp
@@ -0,0 +1,15 @@
+// RUN: split-file %s %t
+
+// RUN: %clang_cc1 -I%t -emit-module -o %t/a.pcm -fmodules %t/module.modulemap -fno-implicit-modules -fmodule-name=a -x c++-header -fms-compatibility
+// RUN: %clang_cc1 -I%t -emit-module -o %t/b.pcm -fmodules %t/module.modulemap -fno-implicit-modules -fmodule-name=b -x c++-header -fms-compatibility -fmodule-file=%t/a.pcm
+
+//--- module.modulemap
+module a { header "a.h" }
+module b { header "b.h" }
+
+//--- a.h
+type_info* foo;
+
+//--- b.h
+type_info* bar;
+

``````````

</details>


https://github.com/llvm/llvm-project/pull/151277


More information about the cfe-commits mailing list