[clang] [clang] Prevent duplicated instantiation of enumerators of unscoped member enumerations (PR #124407)
André Brand via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 27 09:46:05 PST 2025
https://github.com/thebrandre updated https://github.com/llvm/llvm-project/pull/124407
>From e535adb5e94f89350d2e64344857e001cc1e1ca5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Brand?= <andre.brand at mailbox.org>
Date: Sat, 25 Jan 2025 14:25:32 +0100
Subject: [PATCH 1/3] [clang] Fix issues on template class enum member
redeclaration
---
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 6a2331e59477a2..fe412c2291fc3b 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1627,12 +1627,17 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
// specialization causes the implicit instantiation of the declarations, but
// not the definitions of scoped member enumerations.
//
- // DR1484 clarifies that enumeration definitions inside of a template
+ // DR1484 clarifies that enumeration definitions inside a template
// declaration aren't considered entities that can be separately instantiated
- // from the rest of the entity they are declared inside of.
+ // from the rest of the entity they are declared inside.
if (isDeclWithinFunction(D) ? D == Def : Def && !Enum->isScoped()) {
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum);
- InstantiateEnumDefinition(Enum, Def);
+ // Prevent redundant instantiation of the enumerator-definition if the
+ // definition has already been instantiated due to a prior
+ // opaque-enum-declaration.
+ if (PrevDecl == nullptr) {
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum);
+ InstantiateEnumDefinition(Enum, Def);
+ }
}
return Enum;
>From 8c6dc63c310a04ada71ef52c12d586d73b060809 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Brand?= <andre.brand at mailbox.org>
Date: Sat, 25 Jan 2025 14:25:32 +0100
Subject: [PATCH 2/3] [clang] Add tests with member enum redeclarations
---
.../test/SemaCXX/member-enum-declarations.cpp | 112 ++++++++++++++++++
1 file changed, 112 insertions(+)
create mode 100644 clang/test/SemaCXX/member-enum-declarations.cpp
diff --git a/clang/test/SemaCXX/member-enum-declarations.cpp b/clang/test/SemaCXX/member-enum-declarations.cpp
new file mode 100644
index 00000000000000..e08f6e7a3fcd6d
--- /dev/null
+++ b/clang/test/SemaCXX/member-enum-declarations.cpp
@@ -0,0 +1,112 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -verify
+// RUN: %clang_cc1 -std=c++14 -fsyntax-only %s -verify
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only %s -verify
+
+
+namespace ScopedEnumerations {
+
+template <typename T>
+struct S1 {
+ enum class E : T;
+};
+
+template <typename T>
+enum class S1<T>::E : T {
+ S1_X = 0x123
+};
+
+static_assert(static_cast<int>(S1<int>::E::S1_X) == 0x123, "");
+
+template <typename T>
+struct S2 {
+ static constexpr T f(int) { return 0; };
+ enum class E : T;
+ static constexpr T f(char) { return 1; };
+ enum class E : T { X = f(T{}) };
+};
+
+static_assert(static_cast<int>(S2<char>::E::X) == 1, "");
+
+template <typename T>
+struct S3 {
+ enum class E : T;
+ enum class E : T { X = 0x7FFFFF00 }; // expected-error {{cannot be narrowed to type 'char'}} expected-warning {{implicit conversion from 'int' to 'char'}}
+};
+template struct S3<char>; // expected-note {{in instantiation}}
+
+template <typename T>
+struct S4 {
+ enum class E : T;
+ enum class E : T { S4_X = 5 };
+};
+
+auto x4 = S4<int>::E::S4_X;
+
+template <typename T>
+T f1() {
+ enum class E : T { X_F1, Y_F1, Z_F1 };
+ return X_F1; // expected-error {{use of undeclared identifier 'X_F1'}}
+}
+
+const int resf1 = f1<int>();
+
+}
+
+
+namespace UnscopedEnumerations {
+
+template <typename T>
+struct S1 {
+ enum E : T;
+};
+
+template <typename T>
+enum S1<T>::E : T {
+ S1_X = 0x123
+};
+
+static_assert(static_cast<int>(S1<int>::S1_X) == 0x123, "");
+
+template <typename T>
+struct S2 {
+ static constexpr T f(int) { return 0; };
+ enum E : T;
+ static constexpr T f(char) { return 1; };
+ enum E : T { S2_X = f(T{}) };
+};
+
+static_assert(static_cast<int>(S2<char>::E::S2_X) == 1, "");
+
+template <typename T>
+struct S3 {
+ enum E : T;
+ enum E : T { S3_X = 0x7FFFFF00 }; // expected-error {{cannot be narrowed to type 'char'}} expected-warning {{implicit conversion from 'int' to 'char'}}
+};
+template struct S3<char>; // expected-note {{in instantiation of template class}}
+
+template <typename T>
+struct S4 {
+ enum E : T;
+ enum E : T { S4_X = 5 };
+};
+
+auto x4 = S4<int>::S4_X;
+
+template <typename T>
+struct S5 {
+ enum E : T;
+ T S5_X = 5; // expected-note {{previous definition is here}}
+ enum E : T { S5_X = 5 }; // expected-error {{redefinition of 'S5_X'}}
+};
+
+
+template <typename T>
+T f1() {
+ enum E : T { X_F2, Y_F2, Z_F2 };
+ return X_F2;
+}
+
+const int resf1 = f1<int>();
+
+}
+
>From 16fef8afdd4eae665062930caf43c5052beb2091 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Brand?= <andre.brand at mailbox.org>
Date: Sat, 25 Jan 2025 15:02:02 +0100
Subject: [PATCH 3/3] [clang] Update release notes
---
clang/docs/ReleaseNotes.rst | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 031c5d84e49f97..af3632322b8453 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1003,6 +1003,7 @@ Bug Fixes to C++ Support
- Fixed assertions or false compiler diagnostics in the case of C++ modules for
lambda functions or inline friend functions defined inside templates (#GH122493).
- Clang now rejects declaring an alias template with the same name as its template parameter. (#GH123423)
+- Fixed the rejection of valid code when referencing an enumerator of an unscoped enum member with a prior declaration. (#GH124405)
- Fixed immediate escalation of non-dependent expressions. (#GH123405)
- Fix type of expression when calling a template which returns an ``__array_rank`` querying a type depending on a
template parameter. Now, such expression can be used with ``static_assert`` and ``constexpr``. (#GH123498)
More information about the cfe-commits
mailing list