[clang] [C++20] [Modules] merge the type for anony enum from import and #include (PR #214121)

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 11 05:10:59 PDT 2026


================
@@ -2667,6 +2667,22 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New,
       else
         New->setTypeSourceInfo(OldTD->getTypeSourceInfo());
 
+      // An anonymous enum is recognized as a redeclaration only when its typedef
+      // name gets merged, at which point two distinct enum types already exist.
+      // Retype the new enumerators to the old enum type, matching the typedef
+      // merge above; otherwise the merged typedef and its enumerators disagree
+      // on the type (GH213299).
+      //
+      // FIXME: The global module restriction only limits the impact of this
+      // change; relax it if the issue shows up in other contexts.
+      if (Module *M = OldTag->getOwningModule(); M && M->isGlobalModule())
+        if (auto *NewEnum = dyn_cast<EnumDecl>(NewTag))
+          if (auto *OldEnum = dyn_cast<EnumDecl>(OldTag)) {
+            QualType OldEnumType = Context.getCanonicalTagType(OldEnum);
+            for (auto *ECD : NewEnum->enumerators())
+              ECD->setType(OldEnumType);
----------------
AaronBallman wrote:

This worries me -- enumerators are expected to have the underlying type of the enumeration but that's not what we're doing here -- we're walking over the *new* enumerators and setting their type to be that of the *old* enumeration. Won't that break this kind of assumption?
```
void func(const EnumConstantDecl *ECD) {
  const DeclContext *DC = ECD->getDeclContext()->getLexicalParent();
  assert(ECD->getType() == cast<EnumDecl>(DC)->getType());
}
```


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


More information about the cfe-commits mailing list