diff --git a/compiler/src/dmd/pragmasem.d b/compiler/src/dmd/pragmasem.d index 44597740a2ac..d8dd8858f0e9 100644 --- a/compiler/src/dmd/pragmasem.d +++ b/compiler/src/dmd/pragmasem.d @@ -39,73 +39,13 @@ import dmd.statement; */ void pragmaDeclSemantic(PragmaDeclaration pd, Scope* sc) { - import dmd.aggregate; import dmd.common.outbuffer; import dmd.dmodule; import dmd.dsymbolsem; - import dmd.identifier; - import dmd.mangle : isValidMangling; import dmd.root.rmem; - import dmd.root.utf; import dmd.target; import dmd.utils; - StringExp verifyMangleString(ref Expression e) - { - auto se = semanticString(sc, e, "mangled name"); - if (!se) - return null; - e = se; - if (!se.len) - { - .error(pd.loc, "%s `%s` - zero-length string not allowed for mangled name", pd.kind, pd.toPrettyChars); - return null; - } - if (se.sz != 1) - { - .error(pd.loc, "%s `%s` - mangled name characters can only be of type `char`", pd.kind, pd.toPrettyChars); - return null; - } - version (all) - { - import dmd.common.charactertables; - - /* Note: D language specification should not have any assumption about backend - * implementation. Ideally pragma(mangle) can accept a string of any content. - * - * Therefore, this validation is compiler implementation specific. - */ - auto slice = se.peekString(); - for (size_t i = 0; i < se.len;) - { - dchar c = slice[i]; - if (c < 0x80) - { - if (c.isValidMangling) - { - ++i; - continue; - } - else - { - .error(pd.loc, "%s `%s` char 0x%02x not allowed in mangled name", pd.kind, pd.toPrettyChars, c); - break; - } - } - if (const msg = utf_decodeChar(slice, i, c)) - { - .error(pd.loc, "%s `%s` %.*s", pd.kind, pd.toPrettyChars, cast(int)msg.length, msg.ptr); - break; - } - if (!isAnyIdentifierCharacter(c)) - { - .error(pd.loc, "%s `%s` char `0x%04x` not allowed in mangled name", pd.kind, pd.toPrettyChars, c); - break; - } - } - } - return se; - } void declarations() { if (!pd.decl) @@ -126,58 +66,6 @@ void pragmaDeclSemantic(PragmaDeclaration pd, Scope* sc) } s.dsymbolSemantic(sc2); - if (pd.ident != Id.mangle) - continue; - assert(pd.args); - if (auto ad = s.isAggregateDeclaration()) - { - Expression e = (*pd.args)[0]; - sc2 = sc2.startCTFE(); - e = e.expressionSemantic(sc); - e = resolveProperties(sc2, e); - sc2 = sc2.endCTFE(); - AggregateDeclaration agg; - if (auto tc = e.type.isTypeClass()) - agg = tc.sym; - else if (auto ts = e.type.isTypeStruct()) - agg = ts.sym; - ad.pMangleOverride = new MangleOverride; - void setString(ref Expression e) - { - if (auto se = verifyMangleString(e)) - { - const name = (cast(const(char)[])se.peekData()).xarraydup; - ad.pMangleOverride.id = Identifier.idPool(name); - e = se; - } - else - error(e.loc, "must be a string"); - } - if (agg) - { - ad.pMangleOverride.agg = agg; - if (pd.args.length == 2) - { - setString((*pd.args)[1]); - } - else - ad.pMangleOverride.id = agg.ident; - } - else - setString((*pd.args)[0]); - } - else if (auto td = s.isTemplateDeclaration()) - { - .error(pd.loc, "%s `%s` cannot apply to a template declaration", pd.kind, pd.toPrettyChars); - errorSupplemental(pd.loc, "use `template Class(Args...){ pragma(mangle, \"other_name\") class Class {} }`"); - } - else if (auto se = verifyMangleString((*pd.args)[0])) - { - const name = (cast(const(char)[])se.peekData()).xarraydup; - uint cnt = setMangleOverride(s, name); - if (cnt > 1) - .error(pd.loc, "%s `%s` can only apply to a single declaration", pd.kind, pd.toPrettyChars); - } } } @@ -264,16 +152,11 @@ void pragmaDeclSemantic(PragmaDeclaration pd, Scope* sc) } else if (pd.ident == Id.mangle) { - if (!pd.args) - pd.args = new Expressions(); - if (pd.args.length == 0 || pd.args.length > 2) - { - .error(pd.loc, pd.args.length == 0 ? "%s `%s` - string expected for mangled name" - : "%s `%s` expected 1 or 2 arguments", pd.kind, pd.toPrettyChars); - pd.args.setDim(1); - (*pd.args)[0] = ErrorExp.get(); // error recovery - } - return declarations(); + Scope* sc2 = pd.newScope(sc); + pragmaMangleSemantic(pd.loc, sc2, pd.args, pd.decl); + if (sc2 != sc) + sc2.pop(); + return; } else if (pd.ident == Id.crt_constructor || pd.ident == Id.crt_destructor) { @@ -440,20 +323,9 @@ bool pragmaStmtSemantic(PragmaStatement ps, Scope* sc) { auto es = ps._body ? ps._body.isExpStatement() : null; auto de = es ? es.exp.isDeclarationExp() : null; - if (!de) - { - error(ps.loc, "`pragma(mangle)` must be attached to a declaration"); - return false; - } - const se = ps.args && (*ps.args).length == 1 ? semanticString(sc, (*ps.args)[0], "pragma mangle argument") : null; - if (!se) - { - error(ps.loc, "`pragma(mangle)` takes a single argument that must be a string literal"); + Dsymbols decls = de ? Dsymbols(de.declaration) : Dsymbols(); + if (!pragmaMangleSemantic(ps.loc, sc, ps.args, decls.length ? &decls : null)) return false; - } - const cnt = setMangleOverride(de.declaration, cast(const(char)[])se.peekData()); - if (cnt != 1) - assert(0); } else if (!global.params.ignoreUnsupportedPragmas) { @@ -516,34 +388,6 @@ package PINLINE evalPragmaInline(Loc loc, Scope* sc, Expressions* args) return PINLINE.never; } -/** - * Apply pragma mangle to FuncDeclarations and VarDeclarations - * under `s`, poking through attribute declarations such as - * `extern(C)` but not through aggregates or function bodies. - * - * Params: - * s = symbol to apply - * sym = overriding symbol name - */ -private uint setMangleOverride(Dsymbol s, const(char)[] sym) -{ - if (s.isFuncDeclaration() || s.isVarDeclaration()) - { - s.isDeclaration().mangleOverride = sym; - return 1; - } - - if (auto ad = s.isAttribDeclaration()) - { - uint nestedCount = 0; - - ad.include(null).foreachDsymbol( (s) { nestedCount += setMangleOverride(s, sym); } ); - - return nestedCount; - } - return 0; -} - /*********************************************************** * Evaluate and print a `pragma(msg, args)` * @@ -635,3 +479,263 @@ private bool pragmaStartAddressSemantic(Loc loc, Scope* sc, Expressions* args) } return true; } + +/*********************************************************** + * Evaluate `pragma(mangle)` and store the mangled string in `decls` + * This accepts any of the following variants. + * + * pragma(mangle, StringExp) AggregateDeclaration + * pragma(mangle, StringExp) VarDeclaration + * pragma(mangle, StringExp) FuncDeclaration + * pragma(mangle, TypeExp) AggregateDeclaration + * pragma(mangle, TypeExp, StringExp) AggregateDeclaration + * pragma(mangle, StringExp, TypeExp) AggregateDeclaration + * + * Params: + * loc = location for error messages + * sc = scope for argument interpretation + * args = pragma arguments + * decls = declarations to set mangled string to + * Returns: + * `true` on success + */ +private bool pragmaMangleSemantic(Loc loc, Scope* sc, Expressions* args, Dsymbols* decls) +{ + StringExp verifyMangleString(ref Expression e) + { + import dmd.mangle : isValidMangling; + import dmd.root.utf : utf_decodeChar; + auto se = semanticString(sc, e, "pragma mangle argument"); + if (!se) + return null; + e = se; + if (!se.len) + { + error(loc, "`pragma(mangle)` zero-length string not allowed for mangled name"); + return null; + } + if (se.sz != 1) + { + error(loc, "`pragma(mangle)` mangled name characters can only be of type `char`"); + return null; + } + version (all) + { + import dmd.common.charactertables; + + /* Note: D language specification should not have any assumption about backend + * implementation. Ideally pragma(mangle) can accept a string of any content. + * + * Therefore, this validation is compiler implementation specific. + */ + auto slice = se.peekString(); + for (size_t i = 0; i < se.len;) + { + dchar c = slice[i]; + if (c < 0x80) + { + if (c.isValidMangling) + { + ++i; + continue; + } + else + { + error(loc, "`pragma(mangle)` char 0x%02x not allowed in mangled name", c); + break; + } + } + if (const msg = utf_decodeChar(slice, i, c)) + { + error(loc, "`pragma(mangle)` %.*s", cast(int)msg.length, msg.ptr); + break; + } + if (!isAnyIdentifierCharacter(c)) + { + error(loc, "`pragma(mangle)` char `0x%04x` not allowed in mangled name", c); + break; + } + } + } + return se; + } + + bool applyPragmaMangle(Dsymbols* decls, ref uint count, ref bool ignored) + { + if (decls is null) + return true; + + foreach (s; (*decls)[]) + { + import dmd.aggregate; + import dmd.common.outbuffer; + import dmd.dsymbolsem : dsymbolSemantic; + import dmd.hdrgen : arrayObjectsToBuffer; + import dmd.identifier : Identifier; + import dmd.root.rmem; + + s.dsymbolSemantic(sc); + + if (auto ad = s.isAggregateDeclaration()) + { + /* pragma(mangle) AggregateDeclaration; + For aggregates there may be one or two AssignExpressions: + - one of which must evaluate at compile time to a string literal + - one which must evaluate to a symbol + The spec does not specify which order these should be in, so we + allow any of: + pragma(mangle, "name") struct { ... } + pragma(mangle, T) struct { ... } + pragma(mangle, "name", T) struct { ... } + pragma(mangle, T, "name") struct { ... } + */ + AggregateDeclaration symbol; + StringExp literal; + + foreach (ref Expression e; (*args)[]) + { + sc = sc.startCTFE(); + e = e.expressionSemantic(sc); + e = resolveProperties(sc, e); + sc = sc.endCTFE(); + + bool expectedString() + { + error(e.loc, "`string` expected for pragma mangle argument, not `%s` of type `%s`", + e.toChars(), e.type.toChars()); + return false; + } + + bool expectedType() + { + error(e.loc, "`class` or `struct` type expected for pragma mangle argument, not `%s` of type `%s`", + e.toChars(), e.type.toChars()); + return false; + } + + // Validate arguments to pragma(mangle) + if (e.isTypeExp()) + { + /* Check for and reject: + pragma(mangle, TypeExp, TypeExp) + where the first TypeExp already resolved to a symbol. */ + if (symbol) + return expectedString(); + + /* Type must be a class or struct symbol. */ + if (auto tc = e.type.isTypeClass()) + symbol = tc.sym; + else if (auto ts = e.type.isTypeStruct()) + symbol = ts.sym; + else + return expectedType(); + } + else + { + /* Check for and reject: + pragma(mangle, StringExp, AssignExpression) + where AssignExpression did not resolve to a symbol. */ + if (literal) + return expectedType(); + + /* Must evaluate to a compile time string literal. */ + auto se = verifyMangleString(e); + if (se is null) + return false; + literal = se; + } + } + + ad.pMangleOverride = new MangleOverride; + + if (symbol) + { + ad.pMangleOverride.agg = symbol; + /* The identifier of the symbol is used when no string is supplied. */ + if (literal is null) + { + ad.pMangleOverride.id = symbol.ident; + count += 1; + continue; + } + } + + assert(literal); + const name = literal.peekString().xarraydup; + ad.pMangleOverride.id = Identifier.idPool(name); + count += 1; + } + else if (auto td = s.isTemplateDeclaration()) + { + /* pragma(mangle) TemplateDeclaration + Give an informative error message to avoid pragma(mangle) + silently ignoring the template symbol. */ + error(loc, "`pragma(mangle)` cannot apply to a template declaration"); + OutBuffer buf; + buf.arrayObjectsToBuffer(cast(Objects*)args); + errorSupplemental(loc, "use `template %s(Args...) { pragma(mangle, %s) ... }`", td.ident.toChars(), buf.peekChars()); + return false; + } + else if (auto ad = s.isAttribDeclaration()) + { + /* pragma(mangle) AttribDeclaration + Poke through the attribute to get to the underlying declaration. */ + if (!applyPragmaMangle(ad.include(null), count, ignored)) + return false; + } + else if (s.isFuncDeclaration() || s.isVarDeclaration()) + { + /* pragma(mangle) Declaration; + For all other symbols, there must be one AssignExpression and it + must evaluate at compile time to a string literal. */ + if (args.length != 1) + { + error(loc, "`pragma(mangle)` takes a single argument that must be a string literal"); + return false; + } + auto se = verifyMangleString((*args)[0]); + if (!se) + return false; + + const name = se.peekString().xarraydup; + s.isDeclaration().mangleOverride = name; + count += 1; + } + else + { + /* pragma(mangle) only applies to function and variable + symbols. Other symbols are ignored. */ + ignored = true; + } + } + return true; + } + + if (args is null) + { + error(loc, "`pragma(mangle)` expects string literal argument for mangled name"); + return false; + } + if (args.length > 2) + { + error(loc, "pragma(mangle)` expects 1 or 2 arguments"); + return false; + } + + uint count = 0; + bool ignored = false; + if (!applyPragmaMangle(decls, count, ignored)) + return false; + + if (count == 0 && !ignored) + { + error(loc, "`pragma(mangle)` must be attached to a declaration"); + return false; + } + if (count > 1) + { + error(loc, "`pragma(mangle)` can only apply to a single declaration"); + return false; + } + return true; +} diff --git a/compiler/test/compilable/pragmamangle1.d b/compiler/test/compilable/pragmamangle1.d new file mode 100644 index 000000000000..ca9bc7e80c40 --- /dev/null +++ b/compiler/test/compilable/pragmamangle1.d @@ -0,0 +1,149 @@ +// Tests for pragma mangle +module pragmamangle; + +version (Posix): // Itanium C++ ABI only + +string ctfe_function() { return "mangle_" ~ "ctfe_" ~ "function"; } +immutable string const_variable = "mangle_const"; + +// This mangle string doesn't propagate to tests that use type_symbol. +pragma(mangle, "Q_should_mangle_string_propagate") +struct type_symbol { } + +class template_symbol(T) { } + +/* 1. Overrides the default mangling for a symbol. + */ +pragma(mangle, "mangle_function") void test_fun1(); +static assert(test_fun1.mangleof == "mangle_function"); + +pragma(mangle, "mangle_attribute") extern(C) { nothrow { void test_pokeattr1(); } } +static assert(test_pokeattr1.mangleof == "mangle_attribute"); + +/* 2a. For variables and functions there must be one AssignExpression and it + * must evaluate at compile time to a string literal + */ +pragma(mangle, ctfe_function) void test_fun2a1(); +static assert(test_fun2a1.mangleof == "mangle_ctfe_function"); + +pragma(mangle, const_variable) void test_fun2a2(); +static assert(test_fun2a2.mangleof == "mangle_const"); + +pragma(mangle, ctfe_function) int test_var2a1; +static assert(test_var2a1.mangleof == "mangle_ctfe_function"); + +pragma(mangle, const_variable) int test_var2a2; +static assert(test_var2a2.mangleof == "mangle_const"); + +/* 2b. For aggregates there may be one or two AssignExpressions, one of which + * must evaluate at compile time to a string literal and one which must + * evaluate to a symbol. + * [UNDOCUMENTED] The pragma(mangle) attribute only gets applied to the + * encoded parameters types of extern(C++) functions. + */ +pragma(mangle, "mangle_struct") extern(C++) { struct S1 { } } +extern(C++) void test_struct2b1(S1); +extern(D) void externD_struct2b1(S1); +static assert(test_struct2b1.mangleof == "_Z14test_struct2b113mangle_struct"); +static assert(externD_struct2b1.mangleof == "_D12pragmamangle17externD_struct2b1FSQBj2S1Zv"); + +pragma(mangle, type_symbol, "mangle_struct") struct S2 { } +extern(C++) void test_struct2b3(S2); +extern(D) void externD_struct2b3(S2); +static assert(test_struct2b3.mangleof == "_Z14test_struct2b313mangle_struct"); +static assert(externD_struct2b3.mangleof == "_D12pragmamangle17externD_struct2b3FSQBj2S2Zv"); + +pragma(mangle, "mangle_struct", type_symbol) struct S3 { } +extern(C++) void test_struct2b4(S3); +extern(D) void externD_struct2b4(S3); +static assert(test_struct2b4.mangleof == "_Z14test_struct2b413mangle_struct"); +static assert(externD_struct2b4.mangleof == "_D12pragmamangle17externD_struct2b4FSQBj2S3Zv"); + +// Repeat struct tests on classes. + +pragma(mangle, "mangle_class") extern(C++) { class C1 { } } +extern(C++) void test_class2b1(C1); +extern(D) void externD_class2b1(C1); +static assert(test_class2b1.mangleof == "_Z13test_class2b1P12mangle_class"); +static assert(externD_class2b1.mangleof == "_D12pragmamangle16externD_class2b1FCQBi2C1Zv"); + +pragma(mangle, type_symbol, "mangle_class") class C2 { } +extern(C++) void test_class2b3(C2); +extern(D) void externD_class2b3(C2); +static assert(test_class2b3.mangleof == "_Z13test_class2b3P12mangle_class"); +static assert(externD_class2b3.mangleof == "_D12pragmamangle16externD_class2b3FCQBi2C2Zv"); + +pragma(mangle, "mangle_class", type_symbol) class C3 { } +extern(C++) void test_class2b4(C3); +extern(D) void externD_class2b4(C3); +static assert(test_class2b4.mangleof == "_Z13test_class2b4P12mangle_class"); +static assert(externD_class2b4.mangleof == "_D12pragmamangle16externD_class2b4FCQBi2C3Zv"); + +/* 2c. If that symbol is a TemplateInstance, the aggregate is treated as a + * template that has the signature and arguments of the TemplateInstance. + */ +template T1(C) +{ + pragma(mangle, C, "mangle_template") struct T1 { } +} +extern(C++) void test_template2c3(T1!(template_symbol!int)); +extern(C++) void test_template2c4(T1!(template_symbol!float)); +extern(C++) void test_template2c5(T1!(type_symbol)); +static assert(test_template2c3.mangleof == "_Z16test_template2c315mangle_templateIiE"); +static assert(test_template2c4.mangleof == "_Z16test_template2c415mangle_templateIfE"); +static assert(test_template2c5.mangleof == "_Z16test_template2c515mangle_template"); + +template T2(C) +{ + pragma(mangle, "mangle_template", C) struct T2 { } +} +extern(C++) void test_template2c6(T2!(template_symbol!int)); +extern(C++) void test_template2c7(T2!(template_symbol!float)); +extern(C++) void test_template2c8(T2!(type_symbol)); +static assert(test_template2c6.mangleof == "_Z16test_template2c615mangle_templateIiE"); +static assert(test_template2c7.mangleof == "_Z16test_template2c715mangle_templateIfE"); +static assert(test_template2c8.mangleof == "_Z16test_template2c815mangle_template"); + +/* 2d. The identifier of the symbol is used when no string is supplied. + */ +pragma(mangle, type_symbol) struct I1 { } +extern(C++) void test_struct2d1(I1); +static assert(test_struct2d1.mangleof == "_Z14test_struct2d111type_symbol"); + +pragma(mangle, type_symbol) class I2 { } +extern(C++) void test_class2d1(I2); +static assert(test_class2d1.mangleof == "_Z13test_class2d1P11type_symbol"); + +template I3(C) +{ + pragma(mangle, C) struct I3 { } +} +extern(C++) void test_template2d1(I3!(template_symbol!int)); +extern(C++) void test_template2d2(I3!(template_symbol!float)); +extern(C++) void test_template2d3(I3!(type_symbol)); +static assert(test_template2d1.mangleof == "_Z16test_template2d115template_symbolIiE"); +static assert(test_template2d2.mangleof == "_Z16test_template2d215template_symbolIfE"); +static assert(test_template2d3.mangleof == "_Z16test_template2d311type_symbol"); + +// ??? No template arguments encoded. + +pragma(mangle, template_symbol!float) struct I4 { } +extern(C++) void test_template2d4(I4); +static assert(test_template2d4.mangleof == "_Z16test_template2d415template_symbol"); + +/* 3. It only applies to function and variable symbols. Other symbols are + * ignored. + */ +pragma(mangle, "mangle_alias") +alias ignored_alias = int; + +pragma(mangle, "mangle_enum") +enum ignored_enum { a = 1 } + +pragma(mangle, "mangle_mixed_ignored") +{ + enum test_ignored1 { b } + void test_not_ignored(); + alias test_ignored2 = int delegate(int); +} +static assert(test_not_ignored.mangleof == "mangle_mixed_ignored"); diff --git a/compiler/test/compilable/pragmamangle2.d b/compiler/test/compilable/pragmamangle2.d new file mode 100644 index 000000000000..e1e6e7a28bcc --- /dev/null +++ b/compiler/test/compilable/pragmamangle2.d @@ -0,0 +1,144 @@ +// Tests for pragma mangle +module pragmamangle; + +version (Posix): // Itanium C++ ABI only + +string ctfe_function() { return "mangle_" ~ "ctfe_" ~ "function"; } +immutable string const_variable = "mangle_const"; + +// This mangle string doesn't propagate to tests that use type_symbol. +pragma(mangle, "Q_should_mangle_string_propagate") +struct type_symbol { } + +class template_symbol(T) { } + +void pragma_statement_test() +{ + /* 1. Overrides the default mangling for a symbol. + */ + pragma(mangle, "mangle_function") void test_fun1(); + static assert(test_fun1.mangleof == "mangle_function"); + + pragma(mangle, "mangle_attribute") extern(C) nothrow void test_pokeattr1(); + static assert(test_pokeattr1.mangleof == "mangle_attribute"); + + /* 2a. For variables and functions there must be one AssignExpression and it + * must evaluate at compile time to a string literal + */ + pragma(mangle, ctfe_function) void test_fun2a1(); + static assert(test_fun2a1.mangleof == "mangle_ctfe_function"); + + pragma(mangle, const_variable) void test_fun2a2(); + static assert(test_fun2a2.mangleof == "mangle_const"); + + pragma(mangle, ctfe_function) static int test_var2a1; + static assert(test_var2a1.mangleof == "mangle_ctfe_function"); + + pragma(mangle, const_variable) static int test_var2a2; + static assert(test_var2a2.mangleof == "mangle_const"); + + /* 2b. For aggregates there may be one or two AssignExpressions, one of which + * must evaluate at compile time to a string literal and one which must + * evaluate to a symbol. + * [UNDOCUMENTED] The pragma(mangle) attribute only gets applied to the + * encoded parameters types of extern(C++) functions. + */ + pragma(mangle, "mangle_struct") extern(C++) struct S1 { } + extern(C++) void test_struct2b1(S1); + extern(D) void externD_struct2b1(S1); + static assert(test_struct2b1.mangleof == "_ZN21pragma_statement_test14test_struct2b1ENS_13mangle_structE"); + static assert(externD_struct2b1.mangleof == "_D12pragmamangle21pragma_statement_testFZ17externD_struct2b1MFSQCjQByFZ2S1Zv"); + + pragma(mangle, type_symbol, "mangle_struct") struct S2 { } + extern(C++) void test_struct2b3(S2); + extern(D) void externD_struct2b3(S2); + static assert(test_struct2b3.mangleof == "_ZN21pragma_statement_test14test_struct2b3ENS_13mangle_structE"); + static assert(externD_struct2b3.mangleof == "_D12pragmamangle21pragma_statement_testFZ17externD_struct2b3MFSQCjQByFZ2S2Zv"); + + pragma(mangle, "mangle_struct", type_symbol) struct S3 { } + extern(C++) void test_struct2b4(S3); + extern(D) void externD_struct2b4(S3); + static assert(test_struct2b4.mangleof == "_ZN21pragma_statement_test14test_struct2b4ENS_13mangle_structE"); + static assert(externD_struct2b4.mangleof == "_D12pragmamangle21pragma_statement_testFZ17externD_struct2b4MFSQCjQByFZ2S3Zv"); + + // Repeat struct tests on classes. + + pragma(mangle, "mangle_class") extern(C++) class C1 { } + extern(C++) void test_class2b1(C1); + extern(D) void externD_class2b1(C1); + static assert(test_class2b1.mangleof == "_ZN21pragma_statement_test13test_class2b1EPNS_12mangle_classE"); + static assert(externD_class2b1.mangleof == "_D12pragmamangle21pragma_statement_testFZ16externD_class2b1MFCQCiQBxFZ2C1Zv"); + + pragma(mangle, type_symbol, "mangle_class") class C2 { } + extern(C++) void test_class2b3(C2); + extern(D) void externD_class2b3(C2); + static assert(test_class2b3.mangleof == "_ZN21pragma_statement_test13test_class2b3EPNS_12mangle_classE"); + static assert(externD_class2b3.mangleof == "_D12pragmamangle21pragma_statement_testFZ16externD_class2b3MFCQCiQBxFZ2C2Zv"); + + pragma(mangle, "mangle_class", type_symbol) class C3 { } + extern(C++) void test_class2b4(C3); + extern(D) void externD_class2b4(C3); + static assert(test_class2b4.mangleof == "_ZN21pragma_statement_test13test_class2b4EPNS_12mangle_classE"); + static assert(externD_class2b4.mangleof == "_D12pragmamangle21pragma_statement_testFZ16externD_class2b4MFCQCiQBxFZ2C3Zv"); + + /* 2c. If that symbol is a TemplateInstance, the aggregate is treated as a + * template that has the signature and arguments of the TemplateInstance. + */ + template T1(C) + { + pragma(mangle, C, "mangle_template") struct T1 { } + } + extern(C++) void test_template2c3(T1!(template_symbol!int)); + extern(C++) void test_template2c4(T1!(template_symbol!float)); + extern(C++) void test_template2c5(T1!(type_symbol)); + static assert(test_template2c3.mangleof == "_ZN21pragma_statement_test16test_template2c3ENS_15mangle_templateIiEE"); + static assert(test_template2c4.mangleof == "_ZN21pragma_statement_test16test_template2c4ENS_15mangle_templateIfEE"); + static assert(test_template2c5.mangleof == "_ZN21pragma_statement_test16test_template2c5ENS_15mangle_templateE"); + + template T2(C) + { + pragma(mangle, "mangle_template", C) struct T2 { } + } + extern(C++) void test_template2c6(T2!(template_symbol!int)); + extern(C++) void test_template2c7(T2!(template_symbol!float)); + extern(C++) void test_template2c8(T2!(type_symbol)); + static assert(test_template2c6.mangleof == "_ZN21pragma_statement_test16test_template2c6ENS_15mangle_templateIiEE"); + static assert(test_template2c7.mangleof == "_ZN21pragma_statement_test16test_template2c7ENS_15mangle_templateIfEE"); + static assert(test_template2c8.mangleof == "_ZN21pragma_statement_test16test_template2c8ENS_15mangle_templateE"); + + /* 2d. The identifier of the symbol is used when no string is supplied. + */ + pragma(mangle, type_symbol) struct I1 { } + extern(C++) void test_struct2d1(I1); + static assert(test_struct2d1.mangleof == "_ZN21pragma_statement_test14test_struct2d1ENS_11type_symbolE"); + + pragma(mangle, type_symbol) class I2 { } + extern(C++) void test_class2d1(I2); + static assert(test_class2d1.mangleof == "_ZN21pragma_statement_test13test_class2d1EPNS_11type_symbolE"); + + template I3(C) + { + pragma(mangle, C) struct I3 { } + } + extern(C++) void test_template2d1(I3!(template_symbol!int)); + extern(C++) void test_template2d2(I3!(template_symbol!float)); + extern(C++) void test_template2d3(I3!(type_symbol)); + static assert(test_template2d1.mangleof == "_ZN21pragma_statement_test16test_template2d1ENS_15template_symbolIiEE"); + static assert(test_template2d2.mangleof == "_ZN21pragma_statement_test16test_template2d2ENS_15template_symbolIfEE"); + static assert(test_template2d3.mangleof == "_ZN21pragma_statement_test16test_template2d3ENS_11type_symbolE"); + + // ??? No template arguments encoded. + + pragma(mangle, template_symbol!float) struct I4 { } + extern(C++) void test_template2d4(I4); + static assert(test_template2d4.mangleof == "_ZN21pragma_statement_test16test_template2d4ENS_15template_symbolE"); + + /* 3. It only applies to function and variable symbols. Other symbols are + * ignored. + */ + pragma(mangle, "mangle_alias") + alias ignored_alias = int; + + pragma(mangle, "mangle_enum") + enum ignored_enum { a = 1 } +} diff --git a/compiler/test/compilable/test3004.d b/compiler/test/compilable/test3004.d index 664452ef4e68..aefc76cddb58 100644 --- a/compiler/test/compilable/test3004.d +++ b/compiler/test/compilable/test3004.d @@ -1,7 +1,7 @@ // https://issues.dlang.org/show_bug.cgi?id=3004 /* REQUIRED_ARGS: -ignore -v -TRANSFORM_OUTPUT: remove_lines("^(predefs|binary|version|config|DFLAG|parse|import|\(imported|semantic|entry|library|function object|function core|\s*$)") +TRANSFORM_OUTPUT: remove_lines("^(predefs|binary|version|config|DFLAG|parse|inline|.*_d_newarrayU|import|\(imported|semantic|entry|library|function object|function core|\s*$)") TEST_OUTPUT: --- pragma GNU_attribute (__error) diff --git a/compiler/test/fail_compilation/ice13788.d b/compiler/test/fail_compilation/ice13788.d index 3e3989bc290a..553432da08a2 100644 --- a/compiler/test/fail_compilation/ice13788.d +++ b/compiler/test/fail_compilation/ice13788.d @@ -1,10 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/ice13788.d(11): Error: pragma `mangle` - string expected for mangled name -fail_compilation/ice13788.d(12): Error: `string` expected for mangled name, not `(1)` of type `int` -fail_compilation/ice13788.d(13): Error: pragma `mangle` - zero-length string not allowed for mangled name -fail_compilation/ice13788.d(14): Error: pragma `mangle` - mangled name characters can only be of type `char` +fail_compilation/ice13788.d(11): Error: `pragma(mangle)` expects string literal argument for mangled name +fail_compilation/ice13788.d(12): Error: `string` expected for pragma mangle argument, not `(1)` of type `int` +fail_compilation/ice13788.d(13): Error: `pragma(mangle)` zero-length string not allowed for mangled name +fail_compilation/ice13788.d(14): Error: `pragma(mangle)` mangled name characters can only be of type `char` --- */ diff --git a/compiler/test/fail_compilation/issue21203.d b/compiler/test/fail_compilation/issue21203.d index 7679d673c9e9..b2f12dfd8ff8 100644 --- a/compiler/test/fail_compilation/issue21203.d +++ b/compiler/test/fail_compilation/issue21203.d @@ -3,8 +3,8 @@ REQUIRED_ARGS: -de TEST_OUTPUT: --- -fail_compilation/issue21203.d(12): Error: pragma `mangle` cannot apply to a template declaration -fail_compilation/issue21203.d(12): use `template Class(Args...){ pragma(mangle, "other_name") class Class {} }` +fail_compilation/issue21203.d(12): Error: `pragma(mangle)` cannot apply to a template declaration +fail_compilation/issue21203.d(12): use `template F(Args...) { pragma(mangle, "gdkfjgh") ... }` --- */ diff --git a/compiler/test/fail_compilation/issue22682.d b/compiler/test/fail_compilation/issue22682.d index 80e8311b3a77..90da35da2a2f 100644 --- a/compiler/test/fail_compilation/issue22682.d +++ b/compiler/test/fail_compilation/issue22682.d @@ -1,10 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/issue22682.d(14): Error: `pragma(mangle)` must be attached to a declaration -fail_compilation/issue22682.d(15): Error: `pragma(mangle)` takes a single argument that must be a string literal -fail_compilation/issue22682.d(16): Error: `string` expected for pragma mangle argument, not `(0)` of type `int` -fail_compilation/issue22682.d(16): Error: `pragma(mangle)` takes a single argument that must be a string literal -fail_compilation/issue22682.d(17): Error: `pragma(mangle)` must be attached to a declaration +fail_compilation/issue22682.d(13): Error: `pragma(mangle)` expects string literal argument for mangled name +fail_compilation/issue22682.d(14): Error: `pragma(mangle)` expects string literal argument for mangled name +fail_compilation/issue22682.d(15): Error: `string` expected for pragma mangle argument, not `(0)` of type `int` +fail_compilation/issue22682.d(16): Error: `pragma(mangle)` expects string literal argument for mangled name --- */ module issue22682; diff --git a/compiler/test/fail_compilation/mangle1.d b/compiler/test/fail_compilation/mangle1.d index a97a55b121a5..867661666479 100644 --- a/compiler/test/fail_compilation/mangle1.d +++ b/compiler/test/fail_compilation/mangle1.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/mangle1.d(8): Error: pragma `mangle` can only apply to a single declaration +fail_compilation/mangle1.d(8): Error: `pragma(mangle)` can only apply to a single declaration --- */ diff --git a/compiler/test/fail_compilation/mangle2.d b/compiler/test/fail_compilation/mangle2.d index 69e148f7a16a..2c229dc73c91 100644 --- a/compiler/test/fail_compilation/mangle2.d +++ b/compiler/test/fail_compilation/mangle2.d @@ -1,18 +1,18 @@ /* TEST_OUTPUT: --- -fail_compilation/mangle2.d(20): Error: pragma `mangle` char 0x20 not allowed in mangled name -fail_compilation/mangle2.d(21): Error: pragma `mangle` char 0x20 not allowed in mangled name -fail_compilation/mangle2.d(24): Error: pragma `mangle` char 0x0a not allowed in mangled name -fail_compilation/mangle2.d(25): Error: pragma `mangle` char 0x0a not allowed in mangled name -fail_compilation/mangle2.d(28): Error: pragma `mangle` char 0x07 not allowed in mangled name -fail_compilation/mangle2.d(29): Error: pragma `mangle` char 0x07 not allowed in mangled name -fail_compilation/mangle2.d(32): Error: pragma `mangle` char 0x01 not allowed in mangled name -fail_compilation/mangle2.d(33): Error: pragma `mangle` char 0x01 not allowed in mangled name -fail_compilation/mangle2.d(36): Error: pragma `mangle` char 0x00 not allowed in mangled name -fail_compilation/mangle2.d(37): Error: pragma `mangle` char 0x00 not allowed in mangled name -fail_compilation/mangle2.d(40): Error: pragma `mangle` Outside Unicode code space -fail_compilation/mangle2.d(41): Error: pragma `mangle` Outside Unicode code space +fail_compilation/mangle2.d(20): Error: `pragma(mangle)` char 0x20 not allowed in mangled name +fail_compilation/mangle2.d(21): Error: `pragma(mangle)` char 0x20 not allowed in mangled name +fail_compilation/mangle2.d(24): Error: `pragma(mangle)` char 0x0a not allowed in mangled name +fail_compilation/mangle2.d(25): Error: `pragma(mangle)` char 0x0a not allowed in mangled name +fail_compilation/mangle2.d(28): Error: `pragma(mangle)` char 0x07 not allowed in mangled name +fail_compilation/mangle2.d(29): Error: `pragma(mangle)` char 0x07 not allowed in mangled name +fail_compilation/mangle2.d(32): Error: `pragma(mangle)` char 0x01 not allowed in mangled name +fail_compilation/mangle2.d(33): Error: `pragma(mangle)` char 0x01 not allowed in mangled name +fail_compilation/mangle2.d(36): Error: `pragma(mangle)` char 0x00 not allowed in mangled name +fail_compilation/mangle2.d(37): Error: `pragma(mangle)` char 0x00 not allowed in mangled name +fail_compilation/mangle2.d(40): Error: `pragma(mangle)` Outside Unicode code space +fail_compilation/mangle2.d(41): Error: `pragma(mangle)` Outside Unicode code space --- */ diff --git a/compiler/test/fail_compilation/pragmamangle1.d b/compiler/test/fail_compilation/pragmamangle1.d new file mode 100644 index 000000000000..d959705ac1ba --- /dev/null +++ b/compiler/test/fail_compilation/pragmamangle1.d @@ -0,0 +1,113 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/pragmamangle1.d(35): Error: `pragma(mangle)` expects string literal argument for mangled name +fail_compilation/pragmamangle1.d(37): Error: `pragma(mangle)` expects string literal argument for mangled name +fail_compilation/pragmamangle1.d(44): Error: `pragma(mangle)` must be attached to a declaration +fail_compilation/pragmamangle1.d(46): Error: `pragma(mangle)` must be attached to a declaration +fail_compilation/pragmamangle1.d(53): Error: `pragma(mangle)` expects string literal argument for mangled name +fail_compilation/pragmamangle1.d(56): Error: `pragma(mangle)` zero-length string not allowed for mangled name +fail_compilation/pragmamangle1.d(59): Error: pragma(mangle)` expects 1 or 2 arguments +fail_compilation/pragmamangle1.d(62): Error: `pragma(mangle)` cannot apply to a template declaration +fail_compilation/pragmamangle1.d(62): use `template cannot_apply(Args...) { pragma(mangle, "template") ... }` +fail_compilation/pragmamangle1.d(65): Error: `pragma(mangle)` takes a single argument that must be a string literal +fail_compilation/pragmamangle1.d(68): Error: `pragma(mangle)` takes a single argument that must be a string literal +fail_compilation/pragmamangle1.d(71): Error: `string` expected for pragma mangle argument, not `(T)` of type `T` +fail_compilation/pragmamangle1.d(74): Error: `string` expected for pragma mangle argument, not `(T[T])` of type `T[T]` +fail_compilation/pragmamangle1.d(77): Error: `pragma(mangle)` can only apply to a single declaration +fail_compilation/pragmamangle1.d(85): Error: `class` or `struct` type expected for pragma mangle argument, not `"mangle"` of type `string` +fail_compilation/pragmamangle1.d(88): Error: `class` or `struct` type expected for pragma mangle argument, not `F()` of type `T` +fail_compilation/pragmamangle1.d(91): Error: `class` or `struct` type expected for pragma mangle argument, not `F()` of type `T` +fail_compilation/pragmamangle1.d(94): Error: `string` expected for pragma mangle argument, not `(F())` of type `T` +fail_compilation/pragmamangle1.d(97): Error: `string` expected for pragma mangle argument, not `(F())` of type `T` +fail_compilation/pragmamangle1.d(100): Error: `string` expected for pragma mangle argument, not `(V)` of type `T` +fail_compilation/pragmamangle1.d(103): Error: `string` expected for pragma mangle argument, not `(V)` of type `T` +fail_compilation/pragmamangle1.d(106): Error: `string` expected for pragma mangle argument, not `T` of type `T` +fail_compilation/pragmamangle1.d(109): Error: `class` or `struct` type expected for pragma mangle argument, not `int` of type `int` +fail_compilation/pragmamangle1.d(112): Error: `class` or `struct` type expected for pragma mangle argument, not `T[T]` of type `T[T]` +--- +*/ +struct T { } +T F() { return T(); } +T V; +alias A = T[T]; + +pragma(mangle); + +pragma(mangle) +{ + nothrow: pure: @nogc: @property + { + } +} + +pragma(mangle, "no_declaration"); + +pragma(mangle, "no_declaration") +{ + nothrow: pure: @nogc: @property + { + } +} + +pragma(mangle) +void no_string_literal(); + +pragma(mangle, "") +void empty_string_mangle(); + +pragma(mangle, "too", "many", "arguments") +void expects_less_arguments(); + +pragma(mangle, "template") +template cannot_apply(T) { } + +pragma(mangle, "func", "mangle") +void func_too_many_arguments(); + +pragma(mangle, "var", "mangle") +int var_too_many_arguments; + +pragma(mangle, T) +void func_arg1_not_a_string(); + +pragma(mangle, A) +int var_arg1_not_a_string; + +pragma(mangle, "too_many_declarations") +{ + nothrow pure: + void func1(); + @nogc: + extern(C++) void func2(); +} + +pragma(mangle, "struct", "mangle") +struct arg2_must_be_symbol { } + +pragma(mangle, "struct", F) +struct struct_wrong_symbol { } + +pragma(mangle, "class", F) +class class_wrong_symbol { } + +pragma(mangle, F(), T) +struct arg1_not_ctfe_string { } + +pragma(mangle, T, F()) +struct arg2_not_ctfe_string { } + +pragma(mangle, V, T) +struct arg1_not_string { } + +pragma(mangle, T, V) +struct arg2_not_string { } + +pragma(mangle, T, T) +struct arg2_expect_string { } + +pragma(mangle, int) +struct arg1_not_class_or_struct { } + +pragma(mangle, "struct", A) +struct arg2_not_class_or_struct { } diff --git a/compiler/test/fail_compilation/pragmamangle2.d b/compiler/test/fail_compilation/pragmamangle2.d new file mode 100644 index 000000000000..85c461af1068 --- /dev/null +++ b/compiler/test/fail_compilation/pragmamangle2.d @@ -0,0 +1,114 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/pragmamangle2.d(37): Error: `pragma(mangle)` expects string literal argument for mangled name +fail_compilation/pragmamangle2.d(39): Error: `pragma(mangle)` expects string literal argument for mangled name +fail_compilation/pragmamangle2.d(46): Error: `pragma(mangle)` must be attached to a declaration +fail_compilation/pragmamangle2.d(48): Error: `pragma(mangle)` must be attached to a declaration +fail_compilation/pragmamangle2.d(55): Error: `pragma(mangle)` expects string literal argument for mangled name +fail_compilation/pragmamangle2.d(58): Error: `pragma(mangle)` zero-length string not allowed for mangled name +fail_compilation/pragmamangle2.d(61): Error: pragma(mangle)` expects 1 or 2 arguments +fail_compilation/pragmamangle2.d(64): Error: `pragma(mangle)` cannot apply to a template declaration +fail_compilation/pragmamangle2.d(64): use `template cannot_apply(Args...) { pragma(mangle, "template") ... }` +fail_compilation/pragmamangle2.d(67): Error: `pragma(mangle)` takes a single argument that must be a string literal +fail_compilation/pragmamangle2.d(70): Error: `pragma(mangle)` takes a single argument that must be a string literal +fail_compilation/pragmamangle2.d(73): Error: `string` expected for pragma mangle argument, not `(T)` of type `T` +fail_compilation/pragmamangle2.d(76): Error: `string` expected for pragma mangle argument, not `(T[T])` of type `T[T]` +fail_compilation/pragmamangle2.d(79): Error: `pragma(mangle)` must be attached to a declaration +fail_compilation/pragmamangle2.d(85): Error: `class` or `struct` type expected for pragma mangle argument, not `"mangle"` of type `string` +fail_compilation/pragmamangle2.d(88): Error: `class` or `struct` type expected for pragma mangle argument, not `F()` of type `T` +fail_compilation/pragmamangle2.d(91): Error: `class` or `struct` type expected for pragma mangle argument, not `F()` of type `T` +fail_compilation/pragmamangle2.d(94): Error: `string` expected for pragma mangle argument, not `(F())` of type `T` +fail_compilation/pragmamangle2.d(97): Error: `string` expected for pragma mangle argument, not `(F())` of type `T` +fail_compilation/pragmamangle2.d(100): Error: `string` expected for pragma mangle argument, not `(V)` of type `T` +fail_compilation/pragmamangle2.d(103): Error: `string` expected for pragma mangle argument, not `(V)` of type `T` +fail_compilation/pragmamangle2.d(106): Error: `string` expected for pragma mangle argument, not `T` of type `T` +fail_compilation/pragmamangle2.d(109): Error: `class` or `struct` type expected for pragma mangle argument, not `int` of type `int` +fail_compilation/pragmamangle2.d(112): Error: `class` or `struct` type expected for pragma mangle argument, not `T[T]` of type `T[T]` +--- +*/ +void pragma_statement_test() +{ + struct T { } + T F() { return T(); } + T V; + alias A = T[T]; + + pragma(mangle); + + pragma(mangle) + { + synchronized + { + } + } + + pragma(mangle, "no_declaration"); + + pragma(mangle, "no_declaration") + { + synchronized + { + } + } + + pragma(mangle) + void no_string_literal(); + + pragma(mangle, "") + void empty_string_mangle(); + + pragma(mangle, "too", "many", "arguments") + void expects_less_arguments(); + + pragma(mangle, "template") + template cannot_apply(T) { } + + pragma(mangle, "func", "mangle") + void func_too_many_arguments(); + + pragma(mangle, "var", "mangle") + static int var_too_many_arguments; + + pragma(mangle, T) + void func_arg1_not_a_string(); + + pragma(mangle, A) + static int var_arg1_not_a_string; + + pragma(mangle, "too_many_declarations") + { + nothrow pure void func1(); + @nogc extern(C++) void func2(); + } + + pragma(mangle, "struct", "mangle") + struct arg2_must_be_symbol { } + + pragma(mangle, "struct", F) + struct struct_wrong_symbol { } + + pragma(mangle, "class", F) + class class_wrong_symbol { } + + pragma(mangle, F(), T) + struct arg1_not_ctfe_string { } + + pragma(mangle, T, F()) + struct arg2_not_ctfe_string { } + + pragma(mangle, V, T) + struct arg1_not_string { } + + pragma(mangle, T, V) + struct arg2_not_string { } + + pragma(mangle, T, T) + struct arg2_expect_string { } + + pragma(mangle, int) + struct arg1_not_class_or_struct { } + + pragma(mangle, "struct", A) + struct arg2_not_class_or_struct { } +}