File tree Expand file tree Collapse file tree 2 files changed +106
-0
lines changed
Expand file tree Collapse file tree 2 files changed +106
-0
lines changed Original file line number Diff line number Diff line change @@ -1959,8 +1959,44 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
19591959 ed = ds.isEnumDeclaration(); // typedef'ed enum
19601960 if (! ed && te && ((ds = te.toDsymbol(sc)) ! is null ))
19611961 ed = ds.isEnumDeclaration();
1962+
1963+ // Detect circular references: enum being defined while it's used in a final switch
1964+ if (ed)
1965+ {
1966+ // Check if we're inside the initializer of one of the enum's members
1967+ for (Scope* scx = sc; scx; scx = scx.enclosing)
1968+ {
1969+ if (scx.scopesym && scx.scopesym.isEnumDeclaration() && scx.scopesym == ed)
1970+ {
1971+ error(ss.loc, " cannot use `final switch` on enum `%s` while it is being defined" , ed.toChars());
1972+ sc.pop();
1973+ return setError ();
1974+ }
1975+ }
1976+ }
1977+
19621978 if (ed && ss.cases.length < ed.members.length)
19631979 {
1980+ // Add a check for incomplete enum declaration to prevent segfault
1981+ // when the enum is being defined while it's referenced in a final switch
1982+ bool isEnumIncomplete = false ;
1983+ foreach (es; * ed.members)
1984+ {
1985+ EnumMember em = es.isEnumMember();
1986+ if (em && em.value is null )
1987+ {
1988+ isEnumIncomplete = true ;
1989+ break ;
1990+ }
1991+ }
1992+
1993+ if (isEnumIncomplete)
1994+ {
1995+ error(ss.loc, " cannot use `final switch` on enum `%s` while it is being defined" , ed.toChars());
1996+ sc.pop();
1997+ return setError ();
1998+ }
1999+
19642000 int missingMembers = 0 ;
19652001 const maxShown = global.params.v.errorSupplementCount();
19662002 Lmembers:
Original file line number Diff line number Diff line change 1+ /*
2+ TEST_OUTPUT:
3+ ---
4+ fail_compilation/fix20867.d(16): Error: cannot use `final switch` on enum `E` while it is being defined
5+ fail_compilation/fix20867.d(31): Error: cannot use `final switch` on enum `E2` while it is being defined
6+ fail_compilation/fix20867.d(63): Error: cannot use `final switch` on enum `E4` while it is being defined
7+ ---
8+ */
9+
10+ // Test case 1: The exact scenario from the GitHub issue
11+ enum E
12+ {
13+ a = 3 ,
14+ b = () {
15+ E e;
16+ final switch (e) // This should error out instead of segfaulting
17+ {
18+ case E.a: break ;
19+ }
20+ return 4 ;
21+ } ()
22+ }
23+
24+ // Test case 2: Variation with multiple members
25+ enum E2
26+ {
27+ x = 10 ,
28+ y = 20 ,
29+ z = () {
30+ E2 e;
31+ final switch (e) // Should also error out safely
32+ {
33+ case E2 .x: return 30 ;
34+ case E2 .y: return 40 ;
35+ }
36+ } ()
37+ }
38+
39+ // Test case 3: Regular use of final switch (this should still compile)
40+ enum E3
41+ {
42+ p = 1 ,
43+ q = 2
44+ }
45+
46+ void testE3 ()
47+ {
48+ E3 e = E3 .p;
49+ final switch (e)
50+ {
51+ case E3 .p: break ;
52+ case E3 .q: break ;
53+ }
54+ }
55+
56+ // Test case 4: Nested circular reference
57+ enum E4
58+ {
59+ r = 5 ,
60+ s = () {
61+ int foo () {
62+ E4 e;
63+ final switch (e) // Should error out
64+ {
65+ case E4 .r: return 6 ;
66+ }
67+ }
68+ return foo ();
69+ } ()
70+ }
You can’t perform that action at this time.
0 commit comments