[clang] [clang] Prevent duplicated instantiation of enumerators of unscoped member enumerations (PR #124407)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Jan 25 05:34:26 PST 2025
=?utf-8?q?André?= Brand <andre.brand at mailbox.org>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/124407 at github.com>
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: André Brand (thebrandre)
<details>
<summary>Changes</summary>
Fixes issue #<!-- -->124405.
---
Full diff: https://github.com/llvm/llvm-project/pull/124407.diff
2 Files Affected:
- (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+9-4)
- (added) clang/test/SemaCXX/member-enum-declarations.cpp (+112)
``````````diff
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;
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>();
+
+}
+
``````````
</details>
https://github.com/llvm/llvm-project/pull/124407
More information about the cfe-commits
mailing list