https://github.com/ipopov created https://github.com/llvm/llvm-project/pull/207071
Fixes https://github.com/llvm/llvm-project/issues/207066. When compiling with C++20 modules, Clang performs ODR merging of class definitions across different modules. During this process, `ASTContext::isSameEntity` is used to check if member declarations match between the definitions. However, `UsingEnumDecl` (representing C++20 `using enum` declarations) was not handled in `ASTContext::isSameEntity`, causing it to default to returning `false`. Consequently, identical class definitions containing a `using enum` statement failed to merge, resulting in spurious ODR mismatch errors such as: `error: 'MyStruct::MyEnum' from module 'ModuleB' is not present in definition of 'MyStruct' in module 'ModuleA'`. This patch implements merging support for `UsingEnumDecl` in `ASTContext::isSameEntity` by comparing the nested-name-specifier qualifiers and the underlying `EnumDecl` target. MARKDOWN=true >From cb84c53bdd2696f538945f3fed914a1adb029f32 Mon Sep 17 00:00:00 2001 From: ipopov <[email protected]> Date: Wed, 1 Jul 2026 12:48:10 -0700 Subject: [PATCH] [clang][Modules] Support ODR merging of `UsingEnumDecl` When compiling with C++20 modules, Clang performs ODR merging of class definitions across different modules. During this process, `ASTContext::isSameEntity` is used to check if member declarations match between the definitions. However, `UsingEnumDecl` (representing C++20 `using enum` declarations) was not handled in `ASTContext::isSameEntity`, causing it to default to returning `false`. Consequently, identical class definitions containing a `using enum` statement failed to merge, resulting in spurious ODR mismatch errors such as: `error: 'MyStruct::MyEnum' from module 'ModuleB' is not present in definition of 'MyStruct' in module 'ModuleA'`. This patch implements merging support for `UsingEnumDecl` in `ASTContext::isSameEntity` by comparing the nested-name-specifier qualifiers and the underlying `EnumDecl` target. Fixes https://github.com/llvm/llvm-project/issues/207066. MARKDOWN=true --- clang/lib/AST/ASTContext.cpp | 6 +++ .../modules-using-enum-class-scope.cppm | 53 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 clang/test/Modules/modules-using-enum-class-scope.cppm diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index abf0cd5e18c2b..ccdbb82ccc59f 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -7948,6 +7948,12 @@ bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) const { return NAX->getNamespace()->Equals(NAY->getNamespace()); } + if (const auto *UX = dyn_cast<UsingEnumDecl>(X)) { + const auto *UY = cast<UsingEnumDecl>(Y); + return isSameQualifier(UX->getQualifier(), UY->getQualifier()) && + declaresSameEntity(UX->getEnumDecl(), UY->getEnumDecl()); + } + return false; } diff --git a/clang/test/Modules/modules-using-enum-class-scope.cppm b/clang/test/Modules/modules-using-enum-class-scope.cppm new file mode 100644 index 0000000000000..ca2463b2e74ae --- /dev/null +++ b/clang/test/Modules/modules-using-enum-class-scope.cppm @@ -0,0 +1,53 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// RUN: cd %t +// +// RUN: %clang_cc1 -std=c++20 -fmodules -fimplicit-module-maps -x c++ -I%t \ +// RUN: -emit-module -fmodule-name=ModuleA -o %t/ModuleA.pcm \ +// RUN: %t/module.modulemap +// +// RUN: %clang_cc1 -std=c++20 -fmodules -fimplicit-module-maps -x c++ -I%t \ +// RUN: -emit-module -fmodule-name=ModuleB -o %t/ModuleB.pcm \ +// RUN: %t/module.modulemap +// +// RUN: %clang_cc1 -std=c++20 -fmodules -fimplicit-module-maps -x c++ -I%t \ +// RUN: -fmodule-file=%t/ModuleA.pcm \ +// RUN: -fmodule-file=%t/ModuleB.pcm \ +// RUN: -verify %t/main.cpp + +//--- common.h +#pragma once +struct MyStruct { + enum class MyEnum { A }; + using enum MyEnum; +}; + +//--- a.h +#pragma once +#include "common.h" + +//--- b.h +#pragma once +#include "common.h" + +//--- module.modulemap +module ModuleA { + header "a.h" + export * +} + +module ModuleB { + header "b.h" + export * +} + +//--- main.cpp +#include "a.h" +#include "b.h" + +inline void use() { + auto x = MyStruct::A; +} + +// expected-no-diagnostics _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
