Skip to content

Commit 38eea8d

Browse files
committed
Fix implicit integer conversion for enum declared in class template
Previously, the promotion type of the instantiated enum was set only in `Sema::ActOnEnumBody`, which is not called if there are no curly braces are after the enum-base. This fixes GitHub issue #117960.
1 parent df12983 commit 38eea8d

File tree

2 files changed

+69
-0
lines changed

2 files changed

+69
-0
lines changed

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1620,6 +1620,9 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
16201620
if (isDeclWithinFunction(D) ? D == Def : Def && !Enum->isScoped()) {
16211621
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum);
16221622
InstantiateEnumDefinition(Enum, Def);
1623+
} else {
1624+
if (D->isFixed() && !Def)
1625+
Enum->setPromotionType(Enum->getIntegerType());
16231626
}
16241627

16251628
return Enum;
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -verify
2+
// RUN: %clang_cc1 -std=c++20 -fsyntax-only %s -verify
3+
4+
// This program causes clang 19 and earlier to crash because
5+
// EnumDecl::PromotionType has not been set on the instantiated enum.
6+
// See GitHub Issue #117960.
7+
namespace Issue117960 {
8+
template <typename T>
9+
struct A {
10+
enum E : T;
11+
};
12+
13+
int b = A<int>::E{} + 0;
14+
}
15+
16+
17+
namespace test {
18+
template <typename T1, typename T2>
19+
struct IsSame {
20+
static constexpr bool check() { return false; }
21+
};
22+
23+
template <typename T>
24+
struct IsSame<T, T> {
25+
static constexpr bool check() { return true; }
26+
};
27+
} // namespace test
28+
29+
30+
template <typename T>
31+
struct S1 {
32+
enum E : T;
33+
};
34+
// checks if EnumDecl::PromotionType is set
35+
int X1 = S1<int>::E{} + 0;
36+
int Y1 = S1<unsigned>::E{} + 0;
37+
static_assert(test::IsSame<decltype(S1<int>::E{}+0), int>::check(), "");
38+
static_assert(test::IsSame<decltype(S1<unsigned>::E{}+0), unsigned>::check(), "");
39+
char Z1 = S1<unsigned>::E(-1) + 0; // expected-warning{{implicit conversion from 'unsigned int' to 'char'}}
40+
41+
template <typename Traits>
42+
struct S2 {
43+
enum E : typename Traits::IntegerType;
44+
};
45+
46+
template <typename T>
47+
struct Traits {
48+
typedef T IntegerType;
49+
};
50+
51+
int X2 = S2<Traits<int>>::E{} + 0;
52+
int Y2 = S2<Traits<unsigned>>::E{} + 0;
53+
static_assert(test::IsSame<decltype(S2<Traits<int>>::E{}+0), int>::check(), "");
54+
static_assert(test::IsSame<decltype(S2<Traits<unsigned>>::E{}+0), unsigned>::check(), "");
55+
56+
57+
template <typename T>
58+
struct S3 {
59+
enum E : unsigned;
60+
};
61+
62+
int X3 = S3<float>::E{} + 0;
63+
64+
// fails in clang 19 and earlier (see the discussion on GitHub Issue #117960):
65+
static_assert(test::IsSame<decltype(S3<float>::E{}+0), unsigned>::check(), "");
66+

0 commit comments

Comments
 (0)