Skip to content

Commit 3bac874

Browse files
committed
Fix #21619 - ICE core.exception.AssertError@src/dmd/pragmasem.d(456): Assertion failure
pragma(mangle) in a declaration and statement context had two diverging semantics, and in some cases differing error messages for the same kind of invalid case. This change merges the two implementation together into one function so that semantic is consistently applied.
1 parent e33c664 commit 3bac874

11 files changed

Lines changed: 784 additions & 175 deletions

File tree

compiler/src/dmd/pragmasem.d

Lines changed: 254 additions & 150 deletions
Large diffs are not rendered by default.
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// Tests for pragma mangle
2+
module pragmamangle;
3+
4+
version (Posix): // Itanium C++ ABI only
5+
6+
string ctfe_function() { return "mangle_" ~ "ctfe_" ~ "function"; }
7+
immutable string const_variable = "mangle_const";
8+
9+
// This mangle string doesn't propagate to tests that use type_symbol.
10+
pragma(mangle, "Q_should_mangle_string_propagate")
11+
struct type_symbol { }
12+
13+
class template_symbol(T) { }
14+
15+
/* 1. Overrides the default mangling for a symbol.
16+
*/
17+
pragma(mangle, "mangle_function") void test_fun1();
18+
static assert(test_fun1.mangleof == "mangle_function");
19+
20+
pragma(mangle, "mangle_attribute") extern(C) { nothrow { void test_pokeattr1(); } }
21+
static assert(test_pokeattr1.mangleof == "mangle_attribute");
22+
23+
/* 2a. For variables and functions there must be one AssignExpression and it
24+
* must evaluate at compile time to a string literal
25+
*/
26+
pragma(mangle, ctfe_function) void test_fun2a1();
27+
static assert(test_fun2a1.mangleof == "mangle_ctfe_function");
28+
29+
pragma(mangle, const_variable) void test_fun2a2();
30+
static assert(test_fun2a2.mangleof == "mangle_const");
31+
32+
pragma(mangle, ctfe_function) int test_var2a1();
33+
static assert(test_var2a1.mangleof == "mangle_ctfe_function");
34+
35+
pragma(mangle, const_variable) void test_var2a2();
36+
static assert(test_var2a2.mangleof == "mangle_const");
37+
38+
/* 2b. For aggregates there may be one or two AssignExpressions, one of which
39+
* must evaluate at compile time to a string literal and one which must
40+
* evaluate to a symbol.
41+
* [UNDOCUMENTED] The pragma(mangle) attribute only gets applied to the
42+
* encoded parameters types of extern(C++) functions.
43+
*/
44+
pragma(mangle, "mangle_struct") extern(C++) { struct S1 { } }
45+
extern(C++) void test_struct2b1(S1);
46+
extern(D) void externD_struct2b1(S1);
47+
static assert(test_struct2b1.mangleof == "_Z14test_struct2b113mangle_struct");
48+
static assert(externD_struct2b1.mangleof == "_D12pragmamangle17externD_struct2b1FSQBj2S1Zv");
49+
50+
pragma(mangle, type_symbol, "mangle_struct") struct S2 { }
51+
extern(C++) void test_struct2b3(S2);
52+
extern(D) void externD_struct2b3(S2);
53+
static assert(test_struct2b3.mangleof == "_Z14test_struct2b313mangle_struct");
54+
static assert(externD_struct2b3.mangleof == "_D12pragmamangle17externD_struct2b3FSQBj2S2Zv");
55+
56+
pragma(mangle, "mangle_struct", type_symbol) struct S3 { }
57+
extern(C++) void test_struct2b4(S3);
58+
extern(D) void externD_struct2b4(S3);
59+
static assert(test_struct2b4.mangleof == "_Z14test_struct2b413mangle_struct");
60+
static assert(externD_struct2b4.mangleof == "_D12pragmamangle17externD_struct2b4FSQBj2S3Zv");
61+
62+
// Repeat struct tests on classes.
63+
64+
pragma(mangle, "mangle_class") extern(C++) { class C1 { } }
65+
extern(C++) void test_class2b1(C1);
66+
extern(D) void externD_class2b1(C1);
67+
static assert(test_class2b1.mangleof == "_Z13test_class2b1P12mangle_class");
68+
static assert(externD_class2b1.mangleof == "_D12pragmamangle16externD_class2b1FCQBi2C1Zv");
69+
70+
pragma(mangle, type_symbol, "mangle_class") class C2 { }
71+
extern(C++) void test_class2b3(C2);
72+
extern(D) void externD_class2b3(C2);
73+
static assert(test_class2b3.mangleof == "_Z13test_class2b3P12mangle_class");
74+
static assert(externD_class2b3.mangleof == "_D12pragmamangle16externD_class2b3FCQBi2C2Zv");
75+
76+
pragma(mangle, "mangle_class", type_symbol) class C3 { }
77+
extern(C++) void test_class2b4(C3);
78+
extern(D) void externD_class2b4(C3);
79+
static assert(test_class2b4.mangleof == "_Z13test_class2b4P12mangle_class");
80+
static assert(externD_class2b4.mangleof == "_D12pragmamangle16externD_class2b4FCQBi2C3Zv");
81+
82+
/* 2c. If that symbol is a TemplateInstance, the aggregate is treated as a
83+
* template that has the signature and arguments of the TemplateInstance.
84+
*/
85+
template T1(C)
86+
{
87+
pragma(mangle, C, "mangle_template") struct T1 { }
88+
}
89+
extern(C++) void test_template2c3(T1!(template_symbol!int));
90+
extern(C++) void test_template2c4(T1!(template_symbol!float));
91+
extern(C++) void test_template2c5(T1!(type_symbol));
92+
static assert(test_template2c3.mangleof == "_Z16test_template2c315mangle_templateIiE");
93+
static assert(test_template2c4.mangleof == "_Z16test_template2c415mangle_templateIfE");
94+
static assert(test_template2c5.mangleof == "_Z16test_template2c515mangle_template");
95+
96+
template T2(C)
97+
{
98+
pragma(mangle, "mangle_template", C) struct T2 { }
99+
}
100+
extern(C++) void test_template2c6(T2!(template_symbol!int));
101+
extern(C++) void test_template2c7(T2!(template_symbol!float));
102+
extern(C++) void test_template2c8(T2!(type_symbol));
103+
static assert(test_template2c6.mangleof == "_Z16test_template2c615mangle_templateIiE");
104+
static assert(test_template2c7.mangleof == "_Z16test_template2c715mangle_templateIfE");
105+
static assert(test_template2c8.mangleof == "_Z16test_template2c815mangle_template");
106+
107+
/* 2d. The identifier of the symbol is used when no string is supplied.
108+
*/
109+
pragma(mangle, type_symbol) struct I1 { }
110+
extern(C++) void test_struct2d1(I1);
111+
static assert(test_struct2d1.mangleof == "_Z14test_struct2d111type_symbol");
112+
113+
pragma(mangle, type_symbol) class I2 { }
114+
extern(C++) void test_class2d1(I2);
115+
static assert(test_class2d1.mangleof == "_Z13test_class2d1P11type_symbol");
116+
117+
template I3(C)
118+
{
119+
pragma(mangle, C) struct I3 { }
120+
}
121+
extern(C++) void test_template2d1(I3!(template_symbol!int));
122+
extern(C++) void test_template2d2(I3!(template_symbol!float));
123+
extern(C++) void test_template2d3(I3!(type_symbol));
124+
static assert(test_template2d1.mangleof == "_Z16test_template2d115template_symbolIiE");
125+
static assert(test_template2d2.mangleof == "_Z16test_template2d215template_symbolIfE");
126+
static assert(test_template2d3.mangleof == "_Z16test_template2d311type_symbol");
127+
128+
// ??? No template arguments encoded.
129+
130+
pragma(mangle, template_symbol!float) struct I4 { }
131+
extern(C++) void test_template2d4(I4);
132+
static assert(test_template2d4.mangleof == "_Z16test_template2d415template_symbol");
133+
134+
/* 3. It only applies to function and variable symbols. Other symbols are
135+
* ignored.
136+
*/
137+
138+
pragma(mangle, "mangle_alias")
139+
alias ignored_alias = int;
140+
141+
pragma(mangle, "mangle_enum")
142+
enum ignored_enum { a = 1 }
143+
144+
pragma(mangle, "mangle_mixed_ignored")
145+
{
146+
enum test_ignored1 { b }
147+
void test_not_ignored();
148+
alias test_ignored2 = int delegate(int);
149+
}
150+
static assert(test_not_ignored.mangleof == "mangle_mixed_ignored");
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// Tests for pragma mangle
2+
module pragmamangle;
3+
4+
version (Posix): // Itanium C++ ABI only
5+
6+
string ctfe_function() { return "mangle_" ~ "ctfe_" ~ "function"; }
7+
immutable string const_variable = "mangle_const";
8+
9+
// This mangle string doesn't propagate to tests that use type_symbol.
10+
pragma(mangle, "Q_should_mangle_string_propagate")
11+
struct type_symbol { }
12+
13+
class template_symbol(T) { }
14+
15+
void pragma_statement_test()
16+
{
17+
/* 1. Overrides the default mangling for a symbol.
18+
*/
19+
pragma(mangle, "mangle_function") void test_fun1();
20+
static assert(test_fun1.mangleof == "mangle_function");
21+
22+
pragma(mangle, "mangle_attribute") extern(C) nothrow void test_pokeattr1();
23+
static assert(test_pokeattr1.mangleof == "mangle_attribute");
24+
25+
/* 2a. For variables and functions there must be one AssignExpression and it
26+
* must evaluate at compile time to a string literal
27+
*/
28+
pragma(mangle, ctfe_function) void test_fun2a1();
29+
static assert(test_fun2a1.mangleof == "mangle_ctfe_function");
30+
31+
pragma(mangle, const_variable) void test_fun2a2();
32+
static assert(test_fun2a2.mangleof == "mangle_const");
33+
34+
pragma(mangle, ctfe_function) int test_var2a1();
35+
static assert(test_var2a1.mangleof == "mangle_ctfe_function");
36+
37+
pragma(mangle, const_variable) void test_var2a2();
38+
static assert(test_var2a2.mangleof == "mangle_const");
39+
40+
/* 2b. For aggregates there may be one or two AssignExpressions, one of which
41+
* must evaluate at compile time to a string literal and one which must
42+
* evaluate to a symbol.
43+
* [UNDOCUMENTED] The pragma(mangle) attribute only gets applied to the
44+
* encoded parameters types of extern(C++) functions.
45+
*/
46+
pragma(mangle, "mangle_struct") extern(C++) struct S1 { }
47+
extern(C++) void test_struct2b1(S1);
48+
extern(D) void externD_struct2b1(S1);
49+
static assert(test_struct2b1.mangleof == "_ZN21pragma_statement_test14test_struct2b1ENS_13mangle_structE");
50+
static assert(externD_struct2b1.mangleof == "_D12pragmamangle21pragma_statement_testFZ17externD_struct2b1MFSQCjQByFZ2S1Zv");
51+
52+
pragma(mangle, type_symbol, "mangle_struct") struct S2 { }
53+
extern(C++) void test_struct2b3(S2);
54+
extern(D) void externD_struct2b3(S2);
55+
static assert(test_struct2b3.mangleof == "_ZN21pragma_statement_test14test_struct2b3ENS_13mangle_structE");
56+
static assert(externD_struct2b3.mangleof == "_D12pragmamangle21pragma_statement_testFZ17externD_struct2b3MFSQCjQByFZ2S2Zv");
57+
58+
pragma(mangle, "mangle_struct", type_symbol) struct S3 { }
59+
extern(C++) void test_struct2b4(S3);
60+
extern(D) void externD_struct2b4(S3);
61+
static assert(test_struct2b4.mangleof == "_ZN21pragma_statement_test14test_struct2b4ENS_13mangle_structE");
62+
static assert(externD_struct2b4.mangleof == "_D12pragmamangle21pragma_statement_testFZ17externD_struct2b4MFSQCjQByFZ2S3Zv");
63+
64+
// Repeat struct tests on classes.
65+
66+
pragma(mangle, "mangle_class") extern(C++) class C1 { }
67+
extern(C++) void test_class2b1(C1);
68+
extern(D) void externD_class2b1(C1);
69+
static assert(test_class2b1.mangleof == "_ZN21pragma_statement_test13test_class2b1EPNS_12mangle_classE");
70+
static assert(externD_class2b1.mangleof == "_D12pragmamangle21pragma_statement_testFZ16externD_class2b1MFCQCiQBxFZ2C1Zv");
71+
72+
pragma(mangle, type_symbol, "mangle_class") class C2 { }
73+
extern(C++) void test_class2b3(C2);
74+
extern(D) void externD_class2b3(C2);
75+
static assert(test_class2b3.mangleof == "_ZN21pragma_statement_test13test_class2b3EPNS_12mangle_classE");
76+
static assert(externD_class2b3.mangleof == "_D12pragmamangle21pragma_statement_testFZ16externD_class2b3MFCQCiQBxFZ2C2Zv");
77+
78+
pragma(mangle, "mangle_class", type_symbol) class C3 { }
79+
extern(C++) void test_class2b4(C3);
80+
extern(D) void externD_class2b4(C3);
81+
static assert(test_class2b4.mangleof == "_ZN21pragma_statement_test13test_class2b4EPNS_12mangle_classE");
82+
static assert(externD_class2b4.mangleof == "_D12pragmamangle21pragma_statement_testFZ16externD_class2b4MFCQCiQBxFZ2C3Zv");
83+
84+
/* 2c. If that symbol is a TemplateInstance, the aggregate is treated as a
85+
* template that has the signature and arguments of the TemplateInstance.
86+
*/
87+
template T1(C)
88+
{
89+
pragma(mangle, C, "mangle_template") struct T1 { }
90+
}
91+
extern(C++) void test_template2c3(T1!(template_symbol!int));
92+
extern(C++) void test_template2c4(T1!(template_symbol!float));
93+
extern(C++) void test_template2c5(T1!(type_symbol));
94+
static assert(test_template2c3.mangleof == "_ZN21pragma_statement_test16test_template2c3ENS_15mangle_templateIiEE");
95+
static assert(test_template2c4.mangleof == "_ZN21pragma_statement_test16test_template2c4ENS_15mangle_templateIfEE");
96+
static assert(test_template2c5.mangleof == "_ZN21pragma_statement_test16test_template2c5ENS_15mangle_templateE");
97+
98+
template T2(C)
99+
{
100+
pragma(mangle, "mangle_template", C) struct T2 { }
101+
}
102+
extern(C++) void test_template2c6(T2!(template_symbol!int));
103+
extern(C++) void test_template2c7(T2!(template_symbol!float));
104+
extern(C++) void test_template2c8(T2!(type_symbol));
105+
static assert(test_template2c6.mangleof == "_ZN21pragma_statement_test16test_template2c6ENS_15mangle_templateIiEE");
106+
static assert(test_template2c7.mangleof == "_ZN21pragma_statement_test16test_template2c7ENS_15mangle_templateIfEE");
107+
static assert(test_template2c8.mangleof == "_ZN21pragma_statement_test16test_template2c8ENS_15mangle_templateE");
108+
109+
/* 2d. The identifier of the symbol is used when no string is supplied.
110+
*/
111+
pragma(mangle, type_symbol) struct I1 { }
112+
extern(C++) void test_struct2d1(I1);
113+
static assert(test_struct2d1.mangleof == "_ZN21pragma_statement_test14test_struct2d1ENS_11type_symbolE");
114+
115+
pragma(mangle, type_symbol) class I2 { }
116+
extern(C++) void test_class2d1(I2);
117+
static assert(test_class2d1.mangleof == "_ZN21pragma_statement_test13test_class2d1EPNS_11type_symbolE");
118+
119+
template I3(C)
120+
{
121+
pragma(mangle, C) struct I3 { }
122+
}
123+
extern(C++) void test_template2d1(I3!(template_symbol!int));
124+
extern(C++) void test_template2d2(I3!(template_symbol!float));
125+
extern(C++) void test_template2d3(I3!(type_symbol));
126+
static assert(test_template2d1.mangleof == "_ZN21pragma_statement_test16test_template2d1ENS_15template_symbolIiEE");
127+
static assert(test_template2d2.mangleof == "_ZN21pragma_statement_test16test_template2d2ENS_15template_symbolIfEE");
128+
static assert(test_template2d3.mangleof == "_ZN21pragma_statement_test16test_template2d3ENS_11type_symbolE");
129+
130+
// ??? No template arguments encoded.
131+
132+
pragma(mangle, template_symbol!float) struct I4 { }
133+
extern(C++) void test_template2d4(I4);
134+
static assert(test_template2d4.mangleof == "_ZN21pragma_statement_test16test_template2d4ENS_15template_symbolE");
135+
136+
/* 3. It only applies to function and variable symbols. Other symbols are
137+
* ignored.
138+
*/
139+
140+
pragma(mangle, "mangle_alias")
141+
alias ignored_alias = int;
142+
143+
pragma(mangle, "mangle_enum")
144+
enum ignored_enum { a = 1 }
145+
}

compiler/test/compilable/test3004.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// https://issues.dlang.org/show_bug.cgi?id=3004
22
/*
33
REQUIRED_ARGS: -ignore -v
4-
TRANSFORM_OUTPUT: remove_lines("^(predefs|binary|version|config|DFLAG|parse|import|\(imported|semantic|entry|library|function object|function core|\s*$)")
4+
TRANSFORM_OUTPUT: remove_lines("^(predefs|binary|version|config|DFLAG|parse|inline|.*_d_newarrayU|import|\(imported|semantic|entry|library|function object|function core|\s*$)")
55
TEST_OUTPUT:
66
---
77
pragma GNU_attribute (__error)

compiler/test/fail_compilation/ice13788.d

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/*
22
TEST_OUTPUT:
33
---
4-
fail_compilation/ice13788.d(11): Error: pragma `mangle` - string expected for mangled name
5-
fail_compilation/ice13788.d(12): Error: `string` expected for mangled name, not `(1)` of type `int`
6-
fail_compilation/ice13788.d(13): Error: pragma `mangle` - zero-length string not allowed for mangled name
7-
fail_compilation/ice13788.d(14): Error: pragma `mangle` - mangled name characters can only be of type `char`
4+
fail_compilation/ice13788.d(11): Error: `pragma(mangle)` expects string literal argument for mangled name
5+
fail_compilation/ice13788.d(12): Error: `string` expected for pragma mangle argument, not `(1)` of type `int`
6+
fail_compilation/ice13788.d(13): Error: `pragma(mangle)` zero-length string not allowed for mangled name
7+
fail_compilation/ice13788.d(14): Error: `pragma(mangle)` mangled name characters can only be of type `char`
88
---
99
*/
1010

compiler/test/fail_compilation/issue21203.d

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
REQUIRED_ARGS: -de
44
TEST_OUTPUT:
55
---
6-
fail_compilation/issue21203.d(12): Error: pragma `mangle` cannot apply to a template declaration
7-
fail_compilation/issue21203.d(12): use `template Class(Args...){ pragma(mangle, "other_name") class Class {} }`
6+
fail_compilation/issue21203.d(12): Error: `pragma(mangle)` cannot apply to a template declaration
7+
fail_compilation/issue21203.d(12): use `template F(Args...) { pragma(mangle, "gdkfjgh") ... }`
88
---
99
*/
1010

compiler/test/fail_compilation/issue22682.d

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
/* TEST_OUTPUT:
22
---
3-
fail_compilation/issue22682.d(14): Error: `pragma(mangle)` must be attached to a declaration
4-
fail_compilation/issue22682.d(15): Error: `pragma(mangle)` takes a single argument that must be a string literal
5-
fail_compilation/issue22682.d(16): Error: `string` expected for pragma mangle argument, not `(0)` of type `int`
6-
fail_compilation/issue22682.d(16): Error: `pragma(mangle)` takes a single argument that must be a string literal
7-
fail_compilation/issue22682.d(17): Error: `pragma(mangle)` must be attached to a declaration
3+
fail_compilation/issue22682.d(13): Error: `pragma(mangle)` must be attached to a declaration
4+
fail_compilation/issue22682.d(14): Error: `pragma(mangle)` expects string literal argument for mangled name
5+
fail_compilation/issue22682.d(15): Error: `string` expected for pragma mangle argument, not `(0)` of type `int`
6+
fail_compilation/issue22682.d(16): Error: `pragma(mangle)` must be attached to a declaration
87
---
98
*/
109
module issue22682;

compiler/test/fail_compilation/mangle1.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
TEST_OUTPUT:
33
---
4-
fail_compilation/mangle1.d(8): Error: pragma `mangle` can only apply to a single declaration
4+
fail_compilation/mangle1.d(8): Error: `pragma(mangle)` can only apply to a single declaration
55
---
66
*/
77

compiler/test/fail_compilation/mangle2.d

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
/*
22
TEST_OUTPUT:
33
---
4-
fail_compilation/mangle2.d(20): Error: pragma `mangle` char 0x20 not allowed in mangled name
5-
fail_compilation/mangle2.d(21): Error: pragma `mangle` char 0x20 not allowed in mangled name
6-
fail_compilation/mangle2.d(24): Error: pragma `mangle` char 0x0a not allowed in mangled name
7-
fail_compilation/mangle2.d(25): Error: pragma `mangle` char 0x0a not allowed in mangled name
8-
fail_compilation/mangle2.d(28): Error: pragma `mangle` char 0x07 not allowed in mangled name
9-
fail_compilation/mangle2.d(29): Error: pragma `mangle` char 0x07 not allowed in mangled name
10-
fail_compilation/mangle2.d(32): Error: pragma `mangle` char 0x01 not allowed in mangled name
11-
fail_compilation/mangle2.d(33): Error: pragma `mangle` char 0x01 not allowed in mangled name
12-
fail_compilation/mangle2.d(36): Error: pragma `mangle` char 0x00 not allowed in mangled name
13-
fail_compilation/mangle2.d(37): Error: pragma `mangle` char 0x00 not allowed in mangled name
14-
fail_compilation/mangle2.d(40): Error: pragma `mangle` Outside Unicode code space
15-
fail_compilation/mangle2.d(41): Error: pragma `mangle` Outside Unicode code space
4+
fail_compilation/mangle2.d(20): Error: `pragma(mangle)` char 0x20 not allowed in mangled name
5+
fail_compilation/mangle2.d(21): Error: `pragma(mangle)` char 0x20 not allowed in mangled name
6+
fail_compilation/mangle2.d(24): Error: `pragma(mangle)` char 0x0a not allowed in mangled name
7+
fail_compilation/mangle2.d(25): Error: `pragma(mangle)` char 0x0a not allowed in mangled name
8+
fail_compilation/mangle2.d(28): Error: `pragma(mangle)` char 0x07 not allowed in mangled name
9+
fail_compilation/mangle2.d(29): Error: `pragma(mangle)` char 0x07 not allowed in mangled name
10+
fail_compilation/mangle2.d(32): Error: `pragma(mangle)` char 0x01 not allowed in mangled name
11+
fail_compilation/mangle2.d(33): Error: `pragma(mangle)` char 0x01 not allowed in mangled name
12+
fail_compilation/mangle2.d(36): Error: `pragma(mangle)` char 0x00 not allowed in mangled name
13+
fail_compilation/mangle2.d(37): Error: `pragma(mangle)` char 0x00 not allowed in mangled name
14+
fail_compilation/mangle2.d(40): Error: `pragma(mangle)` Outside Unicode code space
15+
fail_compilation/mangle2.d(41): Error: `pragma(mangle)` Outside Unicode code space
1616
---
1717
*/
1818

0 commit comments

Comments
 (0)