From 0db39e3eb02be4cc98ffbe266721aae68a09112d Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Mon, 1 May 2023 13:19:59 -0700 Subject: [PATCH 001/176] fix Issue 23870 - ImportC doesn't accept '\' followed by newline, whereas VC does --- dmd/lexer.d | 9 +++++++++ tests/dmd/compilable/test23870.i | 4 ++++ 2 files changed, 13 insertions(+) create mode 100644 tests/dmd/compilable/test23870.i diff --git a/dmd/lexer.d b/dmd/lexer.d index 6e6add1dfbc..0ec468b3245 100644 --- a/dmd/lexer.d +++ b/dmd/lexer.d @@ -393,6 +393,15 @@ class Lexer } } continue; // skip white space + + case '\\': + if (Ccompile && (p[1] == '\r' || p[1] == '\n')) + { + ++p; // ignore \ followed by new line, like VC does + continue; + } + goto default; + case '0': if (!isZeroSecond(p[1])) // if numeric literal does not continue { diff --git a/tests/dmd/compilable/test23870.i b/tests/dmd/compilable/test23870.i new file mode 100644 index 00000000000..43bfe7e9e5d --- /dev/null +++ b/tests/dmd/compilable/test23870.i @@ -0,0 +1,4 @@ +// https://issues.dlang.org/show_bug.cgi?id=23870 + +void test() { \ +} From 7bd74278c4ab037efafb05abe61c2242dc41dc01 Mon Sep 17 00:00:00 2001 From: Dennis Korpel Date: Tue, 2 May 2023 00:06:32 +0200 Subject: [PATCH 002/176] Document dmd.backend not shared by DMC anymore --- dmd/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmd/README.md b/dmd/README.md index cecd008e608..57f56f3f0f0 100644 --- a/dmd/README.md +++ b/dmd/README.md @@ -19,7 +19,7 @@ this license for that file. | Folder | Purpose | |--------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [dmd/](https://github.com/dlang/dmd/tree/master/compiler/src/dmd) | The dmd driver and front-end | -| [dmd/backend/](https://github.com/dlang/dmd/tree/master/compiler/src/dmd/backend) | Code generation for x86 or x86-64. Shared by the [Digital Mars C compiler](https://github.com/DigitalMars/Compiler/), but not [LDC](https://github.com/ldc-developers/ldc) or [GDC](https://gdcproject.org/). | +| [dmd/backend/](https://github.com/dlang/dmd/tree/master/compiler/src/dmd/backend) | Code generation for x86 or x86-64. Based on [DMC](https://github.com/DigitalMars/Compiler/)'s backend, but not kept in sync anymore. Not used by [LDC](https://github.com/ldc-developers/ldc) or [GDC](https://gdcproject.org/). | | [dmd/common/](https://github.com/dlang/dmd/tree/master/compiler/src/dmd/common) | Code shared by the front-end and back-end | | [dmd/root/](https://github.com/dlang/dmd/tree/master/compiler/src/dmd/root) | Meant as a portable utility library, but ["it wasn't very good and the only project left using it is dmd"](https://github.com/dlang/dmd/pull/9844#issuecomment-498479516). | From 6a21607a1c8cd87743d5df09669f6b0b3e0f945d Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Mon, 1 May 2023 17:21:29 -0700 Subject: [PATCH 003/176] fix Issue 23871 - ImportC: __attribute not recognized --- runtime/druntime/src/importc.h | 1 + tests/dmd/compilable/test23871.c | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 tests/dmd/compilable/test23871.c diff --git a/runtime/druntime/src/importc.h b/runtime/druntime/src/importc.h index 66c4eb7aa8c..10a7af20800 100644 --- a/runtime/druntime/src/importc.h +++ b/runtime/druntime/src/importc.h @@ -30,6 +30,7 @@ #define __inline__ inline #define __inline inline #define __volatile__ volatile +#define __attribute __attribute__ /******************** * Clang nullability extension used by macOS headers. diff --git a/tests/dmd/compilable/test23871.c b/tests/dmd/compilable/test23871.c new file mode 100644 index 00000000000..c3e82c9015e --- /dev/null +++ b/tests/dmd/compilable/test23871.c @@ -0,0 +1,6 @@ +// https://issues.dlang.org/show_bug.cgi?id=23871 + +extern void foo() __attribute((noreturn)); + +typedef void (*fp_t)(); +extern void bar(fp_t __attribute((noreturn))); From 9216bf7b637a1d30b3da07bb037b922b685b10cb Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Tue, 2 May 2023 12:50:55 +0100 Subject: [PATCH 004/176] =?UTF-8?q?Fix=20Issue=C2=A021415=20-=20catch=20im?= =?UTF-8?q?mutable=20exceptions=20breaks=20immutable=20(dlang/dmd!14707)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix Issue 21415 - catch immutable exceptions breaks immutable * Disallow catching inout and shared too * Workaround catch(shared) in eh2.d --- dmd/statementsem.d | 7 +++++++ tests/dmd/fail_compilation/fail2456.d | 14 ++++++++++++++ tests/dmd/runnable/eh2.d | 4 ++-- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/dmd/statementsem.d b/dmd/statementsem.d index f849ce1f69a..210c29c72ac 100644 --- a/dmd/statementsem.d +++ b/dmd/statementsem.d @@ -4045,6 +4045,13 @@ void catchSemantic(Catch c, Scope* sc) // reference .object.Throwable c.type = getThrowable(); } + else if (!c.type.isNaked() && !c.type.isConst()) + { + // @@@DEPRECATED_2.113@@@ + // Deprecated in 2.103, change into an error & uncomment in 2.113 + deprecation(c.loc, "can only catch mutable or const qualified types, not `%s`", c.type.toChars()); + //c.errors = true; + } c.type = c.type.typeSemantic(c.loc, sc); if (c.type == Type.terror) { diff --git a/tests/dmd/fail_compilation/fail2456.d b/tests/dmd/fail_compilation/fail2456.d index 08e11da2017..5d7d6eebd2e 100644 --- a/tests/dmd/fail_compilation/fail2456.d +++ b/tests/dmd/fail_compilation/fail2456.d @@ -108,3 +108,17 @@ void test2456b() catch (Throwable) {} // NG } } + +/* +TEST_OUTPUT: +--- +fail_compilation/fail2456.d(121): Deprecation: can only catch mutable or const qualified types, not `immutable(Exception)` +--- +*/ +void main() { + try { + throw new Exception(""); + } catch (immutable Exception e) { + assert(0); + } +} diff --git a/tests/dmd/runnable/eh2.d b/tests/dmd/runnable/eh2.d index 2b469d2f803..775e83d3bf6 100644 --- a/tests/dmd/runnable/eh2.d +++ b/tests/dmd/runnable/eh2.d @@ -72,11 +72,11 @@ int main() a.test(); Abc.x |= 0x40; } - catch (shared(Abc) b) + catch (Abc b) { Abc.x |= 0x80; printf("Caught %p, x = x%x\n", b, Abc.x); - assert(a is b); + assert(cast() a is b); assert(Abc.x == 0xB5); } printf("Success!\n"); From 66a2c102a1d53951a8f886cae6689dcd5a1ce551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20S=C3=A9chet?= Date: Tue, 18 Apr 2023 22:35:22 +0000 Subject: [PATCH 005/176] Simplify _d_isbaseof by calling _d_isbaseof2 --- runtime/druntime/src/rt/cast_.d | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/runtime/druntime/src/rt/cast_.d b/runtime/druntime/src/rt/cast_.d index 1604510b427..925599e0159 100644 --- a/runtime/druntime/src/rt/cast_.d +++ b/runtime/druntime/src/rt/cast_.d @@ -117,22 +117,6 @@ int _d_isbaseof2(scope ClassInfo oc, scope const ClassInfo c, scope ref size_t o int _d_isbaseof(scope ClassInfo oc, scope const ClassInfo c) @safe { - if (areClassInfosEqual(oc, c)) - return true; - - do - { - if (oc.base && areClassInfosEqual(oc.base, c)) - return true; - - foreach (iface; oc.interfaces) - { - if (areClassInfosEqual(iface.classinfo, c) || _d_isbaseof(iface.classinfo, c)) - return true; - } - - oc = oc.base; - } while (oc); - - return false; + size_t offset = 0; + return _d_isbaseof2(oc, c, offset); } From 16d01ed143fc873a823f968b11e1d834d78bb172 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Thu, 4 May 2023 02:54:28 -0700 Subject: [PATCH 006/176] fix Issue 23879 - ImportC: Windows system headers use __alignof (dlang/dmd!15174) --- runtime/druntime/src/importc.h | 1 + tests/dmd/compilable/test23879.c | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 tests/dmd/compilable/test23879.c diff --git a/runtime/druntime/src/importc.h b/runtime/druntime/src/importc.h index 10a7af20800..640ff297091 100644 --- a/runtime/druntime/src/importc.h +++ b/runtime/druntime/src/importc.h @@ -31,6 +31,7 @@ #define __inline inline #define __volatile__ volatile #define __attribute __attribute__ +#define __alignof _Alignof /******************** * Clang nullability extension used by macOS headers. diff --git a/tests/dmd/compilable/test23879.c b/tests/dmd/compilable/test23879.c new file mode 100644 index 00000000000..6d6e26637a5 --- /dev/null +++ b/tests/dmd/compilable/test23879.c @@ -0,0 +1,6 @@ +// https://issues.dlang.org/show_bug.cgi?id=23879 + +struct S { int x; }; + +int x = __alignof(struct S); +int y = _Alignof(struct S); From 8bb543c82985b449f2450fd11e97d3202580ba72 Mon Sep 17 00:00:00 2001 From: Razvan Nitu Date: Thu, 4 May 2023 15:50:38 +0300 Subject: [PATCH 007/176] Reduce FuncDeclaration size (dlang/dmd!15155) --- dmd/declaration.h | 29 +++++++++++++++++------- dmd/frontend.h | 28 ++++++++++++++++------- dmd/func.d | 57 ++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 93 insertions(+), 21 deletions(-) diff --git a/dmd/declaration.h b/dmd/declaration.h index 7a69382e6ba..197091e1d89 100644 --- a/dmd/declaration.h +++ b/dmd/declaration.h @@ -534,22 +534,19 @@ enum class BUILTIN : unsigned char Expression *eval_builtin(const Loc &loc, FuncDeclaration *fd, Expressions *arguments); BUILTIN isBuiltin(FuncDeclaration *fd); +struct ContractInfo; + class FuncDeclaration : public Declaration { public: - Statements *frequires; // in contracts - Ensures *fensures; // out contracts - Statement *frequire; // lowered in contract - Statement *fensure; // lowered out contract Statement *fbody; FuncDeclarations foverrides; // functions this function overrides - FuncDeclaration *fdrequire; // function that does the in contract - FuncDeclaration *fdensure; // function that does the out contract - Expressions *fdrequireParams; // argument list for __require - Expressions *fdensureParams; // argument list for __ensure +private: + ContractInfo *contracts; // contract information +public: const char *mangleString; // mangled symbol created from mangleExact() VarDeclaration *vresult; // result variable for out contracts @@ -686,6 +683,22 @@ class FuncDeclaration : public Declaration static FuncDeclaration *create(const Loc &loc, const Loc &endloc, Identifier *id, StorageClass storage_class, Type *type, bool noreturn = false); FuncDeclaration *syntaxCopy(Dsymbol *) override; + Statements *frequires(); + Ensures *fensures(); + Statement *frequire(); + Statement *fensure(); + FuncDeclaration *fdrequire(); + FuncDeclaration *fdensure(); + Expressions *fdrequireParams(); + Expressions *fdensureParams(); + Statements *frequires(Statements *frs); + Ensures *fensures(Statements *fes); + Statement *frequire(Statement *fr); + Statement *fensure(Statement *fe); + FuncDeclaration *fdrequire(FuncDeclaration *fdr); + FuncDeclaration *fdensure(FuncDeclaration *fde); + Expressions *fdrequireParams(Expressions *fdrp); + Expressions *fdensureParams(Expressions *fdep); bool functionSemantic(); bool functionSemantic3(); bool equals(const RootObject * const o) const override final; diff --git a/dmd/frontend.h b/dmd/frontend.h index e8c2acc134a..7c36da4f584 100644 --- a/dmd/frontend.h +++ b/dmd/frontend.h @@ -287,6 +287,7 @@ class GotoCaseStatement; class GotoStatement; class ReturnStatement; class ScopeStatement; +struct ContractInfo; struct ObjcSelector; class PeelStatement; class CompoundStatement; @@ -2429,16 +2430,11 @@ struct ParameterList final class FuncDeclaration : public Declaration { public: - Array* frequires; - Array* fensures; - Statement* frequire; - Statement* fensure; Statement* fbody; Array foverrides; - FuncDeclaration* fdrequire; - FuncDeclaration* fdensure; - Array* fdrequireParams; - Array* fdensureParams; +private: + ContractInfo* contracts; +public: const char* mangleString; VarDeclaration* vresult; LabelDsymbol* returnLabel; @@ -2538,6 +2534,22 @@ class FuncDeclaration : public Declaration public: ObjcFuncDeclaration objc; static FuncDeclaration* create(const Loc& loc, const Loc& endloc, Identifier* id, StorageClass storage_class, Type* type, bool noreturn = false); + Array* frequires(); + Array* fensures(); + Statement* frequire(); + Statement* fensure(); + FuncDeclaration* fdrequire(); + FuncDeclaration* fdensure(); + Array* fdrequireParams(); + Array* fdensureParams(); + Array* frequires(Array* param); + Array* fensures(Array* param); + Statement* frequire(Statement* param); + Statement* fensure(Statement* param); + FuncDeclaration* fdrequire(FuncDeclaration* param); + FuncDeclaration* fdensure(FuncDeclaration* param); + Array* fdrequireParams(Array* param); + Array* fdensureParams(Array* param); FuncDeclaration* syntaxCopy(Dsymbol* s) override; bool functionSemantic(); bool functionSemantic3(); diff --git a/dmd/func.d b/dmd/func.d index 8e11ab1bb4c..22927444762 100644 --- a/dmd/func.d +++ b/dmd/func.d @@ -259,21 +259,30 @@ extern (C++) struct Ensure } /*********************************************************** + * Most functions don't have contracts, so save memory by grouping + * this information into a separate struct */ -extern (C++) class FuncDeclaration : Declaration +private struct ContractInfo { Statements* frequires; /// in contracts Ensures* fensures; /// out contracts Statement frequire; /// lowered in contract Statement fensure; /// lowered out contract - Statement fbody; /// function body - - FuncDeclarations foverrides; /// functions this function overrides FuncDeclaration fdrequire; /// function that does the in contract FuncDeclaration fdensure; /// function that does the out contract - Expressions* fdrequireParams; /// argument list for __require Expressions* fdensureParams; /// argument list for __ensure +} + +/*********************************************************** + */ +extern (C++) class FuncDeclaration : Declaration +{ + Statement fbody; /// function body + + FuncDeclarations foverrides; /// functions this function overrides + + private ContractInfo* contracts; /// contract information const(char)* mangleString; /// mangled symbol created from mangleExact() @@ -403,6 +412,44 @@ extern (C++) class FuncDeclaration : Declaration return new FuncDeclaration(loc, endloc, id, storage_class, type, noreturn); } + final nothrow pure @safe + { + private ref ContractInfo getContracts() + { + if (!contracts) + contracts = new ContractInfo(); + return *contracts; + } + + // getters + inout(Statements*) frequires() inout { return contracts ? contracts.frequires : null; } + inout(Ensures*) fensures() inout { return contracts ? contracts.fensures : null; } + inout(Statement) frequire() inout { return contracts ? contracts.frequire: null; } + inout(Statement) fensure() inout { return contracts ? contracts.fensure : null; } + inout(FuncDeclaration) fdrequire() inout { return contracts ? contracts.fdrequire : null; } + inout(FuncDeclaration) fdensure() inout { return contracts ? contracts.fdensure: null; } + inout(Expressions*) fdrequireParams() inout { return contracts ? contracts.fdrequireParams: null; } + inout(Expressions*) fdensureParams() inout { return contracts ? contracts.fdensureParams: null; } + + extern (D) private static string generateContractSetter(string field, string type) + { + return type ~ " " ~ field ~ "(" ~ type ~ " param)" ~ + "{ + if (!param && !contracts) return null; + return getContracts()." ~ field ~ " = param; + }"; + } + + mixin(generateContractSetter("frequires", "Statements*")); + mixin(generateContractSetter("fensures", "Ensures*")); + mixin(generateContractSetter("frequire", "Statement")); + mixin(generateContractSetter("fensure", "Statement")); + mixin(generateContractSetter("fdrequire", "FuncDeclaration")); + mixin(generateContractSetter("fdensure", "FuncDeclaration")); + mixin(generateContractSetter("fdrequireParams", "Expressions*")); + mixin(generateContractSetter("fdensureParams", "Expressions*")); + } + override FuncDeclaration syntaxCopy(Dsymbol s) { //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); From f9565730efb059363b9ecd05254f779ec1b05b05 Mon Sep 17 00:00:00 2001 From: Dennis Date: Thu, 4 May 2023 15:23:05 +0200 Subject: [PATCH 008/176] Deduplicate getting `TypeFunction` from `CallExp` (dlang/dmd!15176) --- dmd/canthrow.d | 9 +-------- dmd/escape.d | 29 +++++++---------------------- dmd/expression.d | 20 ++++++++++++++++++++ dmd/optimize.d | 5 +---- 4 files changed, 29 insertions(+), 34 deletions(-) diff --git a/dmd/canthrow.d b/dmd/canthrow.d index 7dfec8a043a..be721dc9c01 100644 --- a/dmd/canthrow.d +++ b/dmd/canthrow.d @@ -133,16 +133,9 @@ extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustN */ if (ce.f && ce.f == func) return; - Type t = ce.e1.type.toBasetype(); - auto tf = t.isTypeFunction(); + const tf = ce.calledFunctionType(); if (tf && tf.isnothrow) return; - else - { - auto td = t.isTypeDelegate(); - if (td && td.nextOf().isTypeFunction().isnothrow) - return; - } if (ce.f) checkFuncThrows(ce, ce.f); diff --git a/dmd/escape.d b/dmd/escape.d index 4f1edaa4d05..19748dc2f21 100644 --- a/dmd/escape.d +++ b/dmd/escape.d @@ -1746,20 +1746,8 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re /* Check each argument that is * passed as 'return scope'. */ - Type t1 = e.e1.type.toBasetype(); - TypeFunction tf; - TypeDelegate dg; - if (t1.ty == Tdelegate) - { - dg = t1.isTypeDelegate(); - tf = dg.next.isTypeFunction(); - } - else if (t1.ty == Tfunction) - tf = t1.isTypeFunction(); - else - return; - - if (!e.type.hasPointers()) + TypeFunction tf = e.calledFunctionType(); + if (!tf || !e.type.hasPointers()) return; if (e.arguments && e.arguments.length) @@ -1815,6 +1803,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re } } // If 'this' is returned, check it too + Type t1 = e.e1.type.toBasetype(); if (e.e1.op == EXP.dotVariable && t1.ty == Tfunction) { DotVarExp dve = e.e1.isDotVarExp(); @@ -1880,7 +1869,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re /* If returning the result of a delegate call, the .ptr * field of the delegate must be checked. */ - if (dg) + if (t1.isTypeDelegate()) { if (tf.isreturn) escapeByValue(e.e1, er, live, retRefTransition); @@ -2066,13 +2055,8 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retR /* If the function returns by ref, check each argument that is * passed as 'return ref'. */ - Type t1 = e.e1.type.toBasetype(); - TypeFunction tf; - if (t1.ty == Tdelegate) - tf = t1.isTypeDelegate().next.isTypeFunction(); - else if (t1.ty == Tfunction) - tf = t1.isTypeFunction(); - else + TypeFunction tf = e.calledFunctionType(); + if (!tf) return; if (tf.isref) { @@ -2107,6 +2091,7 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retR } } // If 'this' is returned by ref, check it too + Type t1 = e.e1.type.toBasetype(); if (e.e1.op == EXP.dotVariable && t1.ty == Tfunction) { DotVarExp dve = e.e1.isDotVarExp(); diff --git a/dmd/expression.d b/dmd/expression.d index 067d22fe130..dcc03c0d9fc 100644 --- a/dmd/expression.d +++ b/dmd/expression.d @@ -5329,6 +5329,26 @@ extern (C++) final class CallExp : UnaExp } } +/** + * Get the called function type from a call expression + * Params: + * ce = function call expression. Must have had semantic analysis done. + * Returns: called function type, or `null` if error / no semantic analysis done + */ +TypeFunction calledFunctionType(CallExp ce) +{ + Type t = ce.e1.type; + if (!t) + return null; + t = t.toBasetype(); + if (auto tf = t.isTypeFunction()) + return tf; + else if (auto td = t.isTypeDelegate()) + return td.nextOf().isTypeFunction(); + else + return null; +} + FuncDeclaration isFuncAddress(Expression e, bool* hasOverloads = null) { if (auto ae = e.isAddrExp()) diff --git a/dmd/optimize.d b/dmd/optimize.d index 61c385fc061..335310de65d 100644 --- a/dmd/optimize.d +++ b/dmd/optimize.d @@ -769,11 +769,8 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) return; if (e.arguments) { - Type t1 = e.e1.type.toBasetype(); - if (auto td = t1.isTypeDelegate()) - t1 = td.next; // t1 can apparently be void for __ArrayDtor(T) calls - if (auto tf = t1.isTypeFunction()) + if (auto tf = e.calledFunctionType()) { foreach (i, ref arg; (*e.arguments)[]) { From e1564b3a28b72f8d03290650824f59eb5354217c Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Thu, 4 May 2023 18:34:03 +0100 Subject: [PATCH 009/176] =?UTF-8?q?Fix=20Issue=2023475=20-=20confusing=20p?= =?UTF-8?q?rintf=20deprecation=20message=20with=20ulong/lon=E2=80=A6=20(dl?= =?UTF-8?q?ang/dmd!14641)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix Issue 23475 - confusing printf deprecation message with ulong/long on Windows * Fix non-windows test output --------- Co-authored-by: Dennis Korpel --- dmd/chkformat.d | 2 ++ tests/dmd/fail_compilation/chkformat.d | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/dmd/chkformat.d b/dmd/chkformat.d index 21a1b5e6def..feaa3c7ee6b 100644 --- a/dmd/chkformat.d +++ b/dmd/chkformat.d @@ -177,6 +177,8 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre errorMsg(null, e, (c_longsize == 4 ? "uint" : "ulong"), t); else errorMsg(null, e, (c_longsize == 4 ? "int" : "long"), t); + if (t.isintegral() && t.size() != c_longsize) + errorSupplemental(e.loc, "C `long` is %d bytes on your system", c_longsize); } break; diff --git a/tests/dmd/fail_compilation/chkformat.d b/tests/dmd/fail_compilation/chkformat.d index fa8915e5fa9..eb75f4267b9 100644 --- a/tests/dmd/fail_compilation/chkformat.d +++ b/tests/dmd/fail_compilation/chkformat.d @@ -19,7 +19,11 @@ fail_compilation/chkformat.d(115): Deprecation: argument `& u` for format specif fail_compilation/chkformat.d(116): Deprecation: argument `16L` for format specification `"%c"` must be `char`, not `long` fail_compilation/chkformat.d(117): Deprecation: argument `17L` for format specification `"%c"` must be `char`, not `long` fail_compilation/chkformat.d(118): Deprecation: argument `& u` for format specification `"%s"` must be `char*`, not `int*` -fail_compilation/chkformat.d(119): Deprecation: argument `& u` for format specification `"%ls"` must be `wchar_t*`, not `int*` +fail_compilation/chkformat.d(119): Deprecation: argument `& u` for format specification `"%ls"` must be `wchar_t*`, not `int*`$?:windows= +fail_compilation/chkformat.d(122): Deprecation: argument `0LU` for format specification `"%lu"` must be `uint`, not `ulong` +fail_compilation/chkformat.d(122): C `long` is 4 bytes on your system|32= +fail_compilation/chkformat.d(122): Deprecation: argument `0LU` for format specification `"%lu"` must be `uint`, not `ulong` +fail_compilation/chkformat.d(122): C `long` is 4 bytes on your system$ fail_compilation/chkformat.d(201): Deprecation: argument `0L` for format specification `"%d"` must be `int*`, not `long` fail_compilation/chkformat.d(202): Deprecation: more format specifiers than 1 arguments fail_compilation/chkformat.d(203): Deprecation: argument `0L` for format specification `"%d"` must be `int*`, not `long` @@ -81,6 +85,7 @@ void test18() { int u; printf("%s\n", &u); } void test19() { int u; printf("%ls\n", &u); } //void test20() { int u; char[] s; sprintf(&s[0], "%d\n", &u); } //void test21() { int u; fprintf(null, "%d\n", &u); } +void test20() { printf("%lu", ulong.init); } #line 200 From bdeb73e80f221ef298955fbc38a1c4bc6832f0ce Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Thu, 4 May 2023 18:00:37 +0100 Subject: [PATCH 010/176] [parse.d] Show token when expecting semicolon --- dmd/parse.d | 2 +- tests/dmd/fail_compilation/diag_template_alias.d | 2 +- tests/dmd/fail_compilation/diag_template_this.d | 2 +- tests/dmd/fail_compilation/e15876_3.d | 2 +- tests/dmd/fail_compilation/failcontracts.d | 4 ++-- tests/dmd/fail_compilation/udaparams.d | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dmd/parse.d b/dmd/parse.d index 68a25064fc0..6f2896e1455 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -5331,7 +5331,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer error("cannot use function constraints for non-template functions. Use `static if` instead"); } else - error("semicolon expected following function declaration"); + error("semicolon expected following function declaration, not `%s`", token.toChars()); } break; } diff --git a/tests/dmd/fail_compilation/diag_template_alias.d b/tests/dmd/fail_compilation/diag_template_alias.d index bbfb5a0e9d2..151bb426574 100644 --- a/tests/dmd/fail_compilation/diag_template_alias.d +++ b/tests/dmd/fail_compilation/diag_template_alias.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/diag_template_alias.d(1): Error: identifier expected for template `alias` parameter fail_compilation/diag_template_alias.d(1): Error: found `alias` when expecting `(` -fail_compilation/diag_template_alias.d(1): Error: semicolon expected following function declaration +fail_compilation/diag_template_alias.d(1): Error: semicolon expected following function declaration, not `(` fail_compilation/diag_template_alias.d(1): Error: declaration expected, not `(` --- */ diff --git a/tests/dmd/fail_compilation/diag_template_this.d b/tests/dmd/fail_compilation/diag_template_this.d index 778f68e8842..25de03ce19e 100644 --- a/tests/dmd/fail_compilation/diag_template_this.d +++ b/tests/dmd/fail_compilation/diag_template_this.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/diag_template_this.d(1): Error: identifier expected for template `this` parameter fail_compilation/diag_template_this.d(1): Error: found `this` when expecting `(` -fail_compilation/diag_template_this.d(1): Error: semicolon expected following function declaration +fail_compilation/diag_template_this.d(1): Error: semicolon expected following function declaration, not `(` fail_compilation/diag_template_this.d(1): Error: declaration expected, not `(` --- */ diff --git a/tests/dmd/fail_compilation/e15876_3.d b/tests/dmd/fail_compilation/e15876_3.d index fe7d546f51b..0ac72296639 100644 --- a/tests/dmd/fail_compilation/e15876_3.d +++ b/tests/dmd/fail_compilation/e15876_3.d @@ -21,7 +21,7 @@ __error__ } } )` -fail_compilation/e15876_3.d(28): Error: semicolon expected following function declaration +fail_compilation/e15876_3.d(28): Error: semicolon expected following function declaration, not `End of File` --- */ d(={for diff --git a/tests/dmd/fail_compilation/failcontracts.d b/tests/dmd/fail_compilation/failcontracts.d index 6612a67e1e0..9ba29700020 100644 --- a/tests/dmd/fail_compilation/failcontracts.d +++ b/tests/dmd/fail_compilation/failcontracts.d @@ -4,8 +4,8 @@ fail_compilation/failcontracts.d(18): Error: missing `{ ... }` for function lite fail_compilation/failcontracts.d(18): Error: semicolon expected following auto declaration, not `bode` fail_compilation/failcontracts.d(19): Error: function declaration without return type. (Note that constructors are always named `this`) fail_compilation/failcontracts.d(19): Error: no identifier for declarator `test1()` -fail_compilation/failcontracts.d(19): Error: semicolon expected following function declaration -fail_compilation/failcontracts.d(20): Error: semicolon expected following function declaration +fail_compilation/failcontracts.d(19): Error: semicolon expected following function declaration, not `bode` +fail_compilation/failcontracts.d(20): Error: semicolon expected following function declaration, not `bode` fail_compilation/failcontracts.d(22): Error: unexpected `(` in declarator fail_compilation/failcontracts.d(22): Error: found `T` when expecting `)` fail_compilation/failcontracts.d(22): Error: enum declaration is invalid diff --git a/tests/dmd/fail_compilation/udaparams.d b/tests/dmd/fail_compilation/udaparams.d index 453ebba4e09..76df55fcfd7 100644 --- a/tests/dmd/fail_compilation/udaparams.d +++ b/tests/dmd/fail_compilation/udaparams.d @@ -23,7 +23,7 @@ fail_compilation/udaparams.d(57): Error: identifier expected for template value fail_compilation/udaparams.d(57): Error: found `@` when expecting `)` fail_compilation/udaparams.d(57): Error: basic type expected, not `3` fail_compilation/udaparams.d(57): Error: found `3` when expecting `)` -fail_compilation/udaparams.d(57): Error: semicolon expected following function declaration +fail_compilation/udaparams.d(57): Error: semicolon expected following function declaration, not `)` fail_compilation/udaparams.d(57): Error: declaration expected, not `)` --- */ From 61e4fdf01cac68376547931de25ad5b1d546e4f8 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Fri, 5 May 2023 00:20:29 -0700 Subject: [PATCH 011/176] fix Issue 23875 23880 (dlang/dmd!15172) --- dmd/cparse.d | 62 ++++++++++++++++++-------- dmd/initsem.d | 3 ++ runtime/druntime/src/importc.h | 1 + tests/dmd/compilable/test23875.c | 28 ++++++++++++ tests/dmd/fail_compilation/test23875.c | 13 ++++++ 5 files changed, 89 insertions(+), 18 deletions(-) create mode 100644 tests/dmd/compilable/test23875.c create mode 100644 tests/dmd/fail_compilation/test23875.c diff --git a/dmd/cparse.d b/dmd/cparse.d index 9b7db1f33f4..189b2b44c07 100644 --- a/dmd/cparse.d +++ b/dmd/cparse.d @@ -324,6 +324,8 @@ final class CParser(AST) : Parser!AST // atomic-type-specifier or type_qualifier case TOK._Atomic: + case TOK.__attribute__: + Ldeclaration: { cparseDeclaration(LVL.local); @@ -2710,7 +2712,7 @@ final class CParser(AST) : Parser!AST * * Params: * declarator = declarator kind - * t = base type to start with + * tbase = base type to start with * pident = set to Identifier if there is one, null if not * specifier = specifiers in and out * Returns: @@ -2718,12 +2720,26 @@ final class CParser(AST) : Parser!AST * symbol table for the parameter-type-list, which will contain any * declared struct, union or enum tags. */ - private AST.Type cparseDeclarator(DTR declarator, AST.Type t, + private AST.Type cparseDeclarator(DTR declarator, AST.Type tbase, out Identifier pident, ref Specifier specifier) { //printf("cparseDeclarator(%d, %p)\n", declarator, t); AST.Types constTypes; // all the Types that will need `const` applied to them + /* Insert tx -> t into + * ts -> ... -> t + * so that + * ts -> ... -> tx -> t + */ + static void insertTx(ref AST.Type ts, AST.Type tx, AST.Type t) + { + AST.Type* pt; + for (pt = &ts; *pt != t; pt = &(cast(AST.TypeNext)*pt).next) + { + } + *pt = tx; + } + AST.Type parseDecl(AST.Type t) { AST.Type ts; @@ -2789,20 +2805,6 @@ final class CParser(AST) : Parser!AST // parse DeclaratorSuffixes while (1) { - /* Insert tx -> t into - * ts -> ... -> t - * so that - * ts -> ... -> tx -> t - */ - static void insertTx(ref AST.Type ts, AST.Type tx, AST.Type t) - { - AST.Type* pt; - for (pt = &ts; *pt != t; pt = &(cast(AST.TypeNext)*pt).next) - { - } - *pt = tx; - } - switch (token.value) { case TOK.leftBracket: @@ -2915,7 +2917,17 @@ final class CParser(AST) : Parser!AST return ts; } - t = parseDecl(t); + auto t = parseDecl(tbase); + + if (specifier.vector_size) + { + auto length = new AST.IntegerExp(token.loc, specifier.vector_size / tbase.size(), AST.Type.tuns32); + auto tsa = new AST.TypeSArray(tbase, length); + AST.Type tv = new AST.TypeVector(tsa); + specifier.vector_size = 0; // used it up + + insertTx(t, tv, tbase); // replace tbase with tv + } /* Because const is transitive, cannot assemble types from * fragments. Instead, types to be annotated with const are put @@ -3553,7 +3565,19 @@ final class CParser(AST) : Parser!AST { nextToken(); check(TOK.leftParenthesis); - cparseConstantExp(); // TODO implement + if (token.value == TOK.int32Literal) + { + const n = token.unsvalue; + if (n < 1 || n & (n - 1) || ushort.max < n) + error("__attribute__((vector_size(%lld))) must be an integer positive power of 2 and be <= 32,768", cast(ulong)n); + specifier.vector_size = cast(uint) n; + nextToken(); + } + else + { + error("value for vector_size expected, not `%s`", token.toChars()); + nextToken(); + } check(TOK.rightParenthesis); } else @@ -4694,6 +4718,7 @@ final class CParser(AST) : Parser!AST // atomic-type-specifier case TOK._Atomic: case TOK.typeof_: + case TOK.__attribute__: t = peek(t); if (t.value != TOK.leftParenthesis || !skipParens(t, &t)) @@ -4959,6 +4984,7 @@ final class CParser(AST) : Parser!AST bool dllexport; /// dllexport attribute bool _deprecated; /// deprecated attribute AST.Expression depMsg; /// deprecated message + uint vector_size; /// positive power of 2 multipe of base type size SCW scw; /// storage-class specifiers MOD mod; /// type qualifiers diff --git a/dmd/initsem.d b/dmd/initsem.d index 893d2a627c3..ca770bd77b6 100644 --- a/dmd/initsem.d +++ b/dmd/initsem.d @@ -587,6 +587,9 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ */ t = t.toBasetype(); + if (auto tv = t.isTypeVector()) + t = tv.basetype; + /* If `{ expression }` return the expression initializer */ ExpInitializer isBraceExpression() diff --git a/runtime/druntime/src/importc.h b/runtime/druntime/src/importc.h index 640ff297091..a9027ffce56 100644 --- a/runtime/druntime/src/importc.h +++ b/runtime/druntime/src/importc.h @@ -32,6 +32,7 @@ #define __volatile__ volatile #define __attribute __attribute__ #define __alignof _Alignof +#define __vector_size__ vector_size /******************** * Clang nullability extension used by macOS headers. diff --git a/tests/dmd/compilable/test23875.c b/tests/dmd/compilable/test23875.c new file mode 100644 index 00000000000..6d6f44ec75a --- /dev/null +++ b/tests/dmd/compilable/test23875.c @@ -0,0 +1,28 @@ +/* DISABLED: win32 linux32 + */ + +// https://issues.dlang.org/show_bug.cgi?id=23875 +// https://issues.dlang.org/show_bug.cgi?id=23880 + +int __attribute__((vector_size(16))) neptune() +{ + int __attribute__((vector_size (16))) v = { 4,1,2,3 }; + return v; +} + +__attribute__((__vector_size__(16))) int pluto(int i) +{ + int __attribute__((__vector_size__ (16))) * p1; + int * __attribute__((__vector_size__ (16))) p2; + + int __attribute__((__vector_size__ (16))) v1; + __attribute__((__vector_size__ (16))) int v2; + + v1 = (__attribute__((__vector_size__ (16))) int) {4,1,2,3}; + + p1 = p2; + *p1 = v1; + v1 = (__attribute__((__vector_size__ (16))) int) v2; + + return i ? v1 : v2; +} diff --git a/tests/dmd/fail_compilation/test23875.c b/tests/dmd/fail_compilation/test23875.c new file mode 100644 index 00000000000..e54f62ea46e --- /dev/null +++ b/tests/dmd/fail_compilation/test23875.c @@ -0,0 +1,13 @@ +/* DISABLED: win32 linux32 +TEST_OUTPUT: +--- +fail_compilation/test23875.c(12): Error: __attribute__((vector_size(10))) must be an integer positive power of 2 and be <= 32,768 +fail_compilation/test23875.c(13): Error: value for vector_size expected, not `x` +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=23875 +// https://issues.dlang.org/show_bug.cgi?id=23880 + +int __attribute__((vector_size(10))) neptune(); +int __attribute__((vector_size(x))) saturn(); From d82222f2647003ab720171d9a484841888104d9a Mon Sep 17 00:00:00 2001 From: Dennis Date: Sun, 7 May 2023 22:53:18 +0200 Subject: [PATCH 012/176] Revert "fix Issue 23875 23880 (dlang/dmd!15172)" (dlang/dmd!15196) This reverts commit 61e4fdf01cac68376547931de25ad5b1d546e4f8. --- dmd/cparse.d | 62 ++++++++------------------ dmd/initsem.d | 3 -- runtime/druntime/src/importc.h | 1 - tests/dmd/compilable/test23875.c | 28 ------------ tests/dmd/fail_compilation/test23875.c | 13 ------ 5 files changed, 18 insertions(+), 89 deletions(-) delete mode 100644 tests/dmd/compilable/test23875.c delete mode 100644 tests/dmd/fail_compilation/test23875.c diff --git a/dmd/cparse.d b/dmd/cparse.d index 189b2b44c07..9b7db1f33f4 100644 --- a/dmd/cparse.d +++ b/dmd/cparse.d @@ -324,8 +324,6 @@ final class CParser(AST) : Parser!AST // atomic-type-specifier or type_qualifier case TOK._Atomic: - case TOK.__attribute__: - Ldeclaration: { cparseDeclaration(LVL.local); @@ -2712,7 +2710,7 @@ final class CParser(AST) : Parser!AST * * Params: * declarator = declarator kind - * tbase = base type to start with + * t = base type to start with * pident = set to Identifier if there is one, null if not * specifier = specifiers in and out * Returns: @@ -2720,26 +2718,12 @@ final class CParser(AST) : Parser!AST * symbol table for the parameter-type-list, which will contain any * declared struct, union or enum tags. */ - private AST.Type cparseDeclarator(DTR declarator, AST.Type tbase, + private AST.Type cparseDeclarator(DTR declarator, AST.Type t, out Identifier pident, ref Specifier specifier) { //printf("cparseDeclarator(%d, %p)\n", declarator, t); AST.Types constTypes; // all the Types that will need `const` applied to them - /* Insert tx -> t into - * ts -> ... -> t - * so that - * ts -> ... -> tx -> t - */ - static void insertTx(ref AST.Type ts, AST.Type tx, AST.Type t) - { - AST.Type* pt; - for (pt = &ts; *pt != t; pt = &(cast(AST.TypeNext)*pt).next) - { - } - *pt = tx; - } - AST.Type parseDecl(AST.Type t) { AST.Type ts; @@ -2805,6 +2789,20 @@ final class CParser(AST) : Parser!AST // parse DeclaratorSuffixes while (1) { + /* Insert tx -> t into + * ts -> ... -> t + * so that + * ts -> ... -> tx -> t + */ + static void insertTx(ref AST.Type ts, AST.Type tx, AST.Type t) + { + AST.Type* pt; + for (pt = &ts; *pt != t; pt = &(cast(AST.TypeNext)*pt).next) + { + } + *pt = tx; + } + switch (token.value) { case TOK.leftBracket: @@ -2917,17 +2915,7 @@ final class CParser(AST) : Parser!AST return ts; } - auto t = parseDecl(tbase); - - if (specifier.vector_size) - { - auto length = new AST.IntegerExp(token.loc, specifier.vector_size / tbase.size(), AST.Type.tuns32); - auto tsa = new AST.TypeSArray(tbase, length); - AST.Type tv = new AST.TypeVector(tsa); - specifier.vector_size = 0; // used it up - - insertTx(t, tv, tbase); // replace tbase with tv - } + t = parseDecl(t); /* Because const is transitive, cannot assemble types from * fragments. Instead, types to be annotated with const are put @@ -3565,19 +3553,7 @@ final class CParser(AST) : Parser!AST { nextToken(); check(TOK.leftParenthesis); - if (token.value == TOK.int32Literal) - { - const n = token.unsvalue; - if (n < 1 || n & (n - 1) || ushort.max < n) - error("__attribute__((vector_size(%lld))) must be an integer positive power of 2 and be <= 32,768", cast(ulong)n); - specifier.vector_size = cast(uint) n; - nextToken(); - } - else - { - error("value for vector_size expected, not `%s`", token.toChars()); - nextToken(); - } + cparseConstantExp(); // TODO implement check(TOK.rightParenthesis); } else @@ -4718,7 +4694,6 @@ final class CParser(AST) : Parser!AST // atomic-type-specifier case TOK._Atomic: case TOK.typeof_: - case TOK.__attribute__: t = peek(t); if (t.value != TOK.leftParenthesis || !skipParens(t, &t)) @@ -4984,7 +4959,6 @@ final class CParser(AST) : Parser!AST bool dllexport; /// dllexport attribute bool _deprecated; /// deprecated attribute AST.Expression depMsg; /// deprecated message - uint vector_size; /// positive power of 2 multipe of base type size SCW scw; /// storage-class specifiers MOD mod; /// type qualifiers diff --git a/dmd/initsem.d b/dmd/initsem.d index ca770bd77b6..893d2a627c3 100644 --- a/dmd/initsem.d +++ b/dmd/initsem.d @@ -587,9 +587,6 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ */ t = t.toBasetype(); - if (auto tv = t.isTypeVector()) - t = tv.basetype; - /* If `{ expression }` return the expression initializer */ ExpInitializer isBraceExpression() diff --git a/runtime/druntime/src/importc.h b/runtime/druntime/src/importc.h index a9027ffce56..640ff297091 100644 --- a/runtime/druntime/src/importc.h +++ b/runtime/druntime/src/importc.h @@ -32,7 +32,6 @@ #define __volatile__ volatile #define __attribute __attribute__ #define __alignof _Alignof -#define __vector_size__ vector_size /******************** * Clang nullability extension used by macOS headers. diff --git a/tests/dmd/compilable/test23875.c b/tests/dmd/compilable/test23875.c deleted file mode 100644 index 6d6f44ec75a..00000000000 --- a/tests/dmd/compilable/test23875.c +++ /dev/null @@ -1,28 +0,0 @@ -/* DISABLED: win32 linux32 - */ - -// https://issues.dlang.org/show_bug.cgi?id=23875 -// https://issues.dlang.org/show_bug.cgi?id=23880 - -int __attribute__((vector_size(16))) neptune() -{ - int __attribute__((vector_size (16))) v = { 4,1,2,3 }; - return v; -} - -__attribute__((__vector_size__(16))) int pluto(int i) -{ - int __attribute__((__vector_size__ (16))) * p1; - int * __attribute__((__vector_size__ (16))) p2; - - int __attribute__((__vector_size__ (16))) v1; - __attribute__((__vector_size__ (16))) int v2; - - v1 = (__attribute__((__vector_size__ (16))) int) {4,1,2,3}; - - p1 = p2; - *p1 = v1; - v1 = (__attribute__((__vector_size__ (16))) int) v2; - - return i ? v1 : v2; -} diff --git a/tests/dmd/fail_compilation/test23875.c b/tests/dmd/fail_compilation/test23875.c deleted file mode 100644 index e54f62ea46e..00000000000 --- a/tests/dmd/fail_compilation/test23875.c +++ /dev/null @@ -1,13 +0,0 @@ -/* DISABLED: win32 linux32 -TEST_OUTPUT: ---- -fail_compilation/test23875.c(12): Error: __attribute__((vector_size(10))) must be an integer positive power of 2 and be <= 32,768 -fail_compilation/test23875.c(13): Error: value for vector_size expected, not `x` ---- -*/ - -// https://issues.dlang.org/show_bug.cgi?id=23875 -// https://issues.dlang.org/show_bug.cgi?id=23880 - -int __attribute__((vector_size(10))) neptune(); -int __attribute__((vector_size(x))) saturn(); From 160adb91ab92c2cd2da27f950283fba6d8d2ff41 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Sun, 7 May 2023 16:50:33 -0700 Subject: [PATCH 013/176] fix char type in core.internal.string --- runtime/druntime/src/core/internal/string.d | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/runtime/druntime/src/core/internal/string.d b/runtime/druntime/src/core/internal/string.d index e09bba4707b..7bb319ecfa5 100644 --- a/runtime/druntime/src/core/internal/string.d +++ b/runtime/druntime/src/core/internal/string.d @@ -152,7 +152,7 @@ T[] signedToTempString(uint radix = 10, bool upperCase = false, T)(long value, r if (neg) { // about to do a slice without a bounds check - auto trustedSlice(return scope char[] r) @trusted { assert(r.ptr > buf.ptr); return (r.ptr-1)[0..r.length+1]; } + auto trustedSlice(return scope T[] r) @trusted { assert(r.ptr > buf.ptr); return (r.ptr-1)[0..r.length+1]; } r = trustedSlice(r); r[0] = '-'; } @@ -190,6 +190,12 @@ unittest assert(long.max.signedToTempString(buf) == "9223372036854775807"); assert(long.min.signedToTempString(buf) == "-9223372036854775808"); + wchar[65] wbuf = void; + assert(1.signedToTempString(wbuf) == "1"w); + + dchar[65] dbuf = void; + assert(1.signedToTempString(dbuf) == "1"d); + // use stack allocated struct version assert(0.signedToTempString() == "0"); assert(1.signedToTempString == "1"); From 9760164567ed94da328bc6b38303534f61868169 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Mon, 8 May 2023 01:09:10 -0700 Subject: [PATCH 014/176] fix Issue 23886 - ImportC preprocessor directive #ident not supported (dlang/dmd!15190) --- dmd/cparse.d | 18 ++++++++++++++++++ dmd/frontend.h | 1 + dmd/id.d | 1 + tests/dmd/fail_compilation/test23886.i | 20 ++++++++++++++++++++ 4 files changed, 40 insertions(+) create mode 100644 tests/dmd/fail_compilation/test23886.i diff --git a/dmd/cparse.d b/dmd/cparse.d index 9b7db1f33f4..68f67e0bad9 100644 --- a/dmd/cparse.d +++ b/dmd/cparse.d @@ -5400,6 +5400,24 @@ final class CParser(AST) : Parser!AST pragmaDirective(scanloc); return true; } + else if (n.ident == Id.ident) // #ident "string" + { + scan(&n); + if (n.value == TOK.string_ && n.ptr[0] == '"' && n.postfix == 0) + { + /* gcc inserts string into the .comment section in the object file. + * Just ignore it for now, but can support it later by writing + * the string to obj_exestr() + */ + //auto comment = n.ustring; + + scan(&n); + if (n.value == TOK.endOfFile || n.value == TOK.endOfLine) + return true; + } + error("\"string\" expected after `#ident`"); + return false; + } } if (n.ident != Id.undef) error("C preprocessor directive `#%s` is not supported", n.toChars()); diff --git a/dmd/frontend.h b/dmd/frontend.h index 7c36da4f584..c430fd9f7a2 100644 --- a/dmd/frontend.h +++ b/dmd/frontend.h @@ -8912,6 +8912,7 @@ struct Id final static Identifier* _pure; static Identifier* define; static Identifier* undef; + static Identifier* ident; static void initialize(); Id() { diff --git a/dmd/id.d b/dmd/id.d index a2271d51017..9ff97dccbaf 100644 --- a/dmd/id.d +++ b/dmd/id.d @@ -549,6 +549,7 @@ immutable Msgtable[] msgtable = { "_pure", "pure" }, { "define" }, { "undef" }, + { "ident" }, ]; diff --git a/tests/dmd/fail_compilation/test23886.i b/tests/dmd/fail_compilation/test23886.i new file mode 100644 index 00000000000..8668af14555 --- /dev/null +++ b/tests/dmd/fail_compilation/test23886.i @@ -0,0 +1,20 @@ +/* TEST_OUTPUT: +--- +fail_compilation/test23886.i(103): Error: "string" expected after `#ident` +fail_compilation/test23886.i(103): Error: no type for declarator before `#` +fail_compilation/test23886.i(104): Error: "string" expected after `#ident` +fail_compilation/test23886.i(105): Error: "string" expected after `#ident` +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=23886 + +#line 100 + +#ident "abc" + +#ident 7 +#ident "def" x +#ident + +void test() { } From 2a76b4d28e59ce084db1d2f6729507028005044a Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Mon, 8 May 2023 02:33:22 -0700 Subject: [PATCH 015/176] Issue 23889 - ImportC: alloca() not supported (dlang/dmd!15191) --- runtime/druntime/src/importc.h | 1 + tests/dmd/runnable/test23889.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 tests/dmd/runnable/test23889.c diff --git a/runtime/druntime/src/importc.h b/runtime/druntime/src/importc.h index 640ff297091..5f1b1027d2b 100644 --- a/runtime/druntime/src/importc.h +++ b/runtime/druntime/src/importc.h @@ -78,6 +78,7 @@ #define __builtin_isnan(x) isnan(x) #define __builtin_isfinite(x) finite(x) +#define __builtin_alloca(x) alloca(x) /******************************** * __has_extension is a clang thing: diff --git a/tests/dmd/runnable/test23889.c b/tests/dmd/runnable/test23889.c new file mode 100644 index 00000000000..8e875833bef --- /dev/null +++ b/tests/dmd/runnable/test23889.c @@ -0,0 +1,13 @@ +// DISABLED: win32mscoff win64 freebsd + +// https://issues.dlang.org/show_bug.cgi?id=23886 + +#include + +int main() +{ + int *p = (int*)alloca(100 * sizeof(int)); + for (int i = 0; i < 100; ++i) + p[i] = i; + return 0; +} From 1cd64b21b9666d635a393d93a4d08248ef15e55d Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Sat, 6 May 2023 18:46:07 +0100 Subject: [PATCH 016/176] Fix 'overloads' error when there are no overloads Part of Issue 23897 - Bad diagnostic "none of the overloads of template" for lamdba. --- dmd/func.d | 5 +++- tests/dmd/fail_compilation/bug9631.d | 4 +-- tests/dmd/fail_compilation/constraints_aggr.d | 4 +-- .../dmd/fail_compilation/constraints_func1.d | 26 ++++++++--------- .../dmd/fail_compilation/constraints_func2.d | 28 +++++++++---------- .../dmd/fail_compilation/constraints_func3.d | 8 +++--- .../dmd/fail_compilation/constraints_func4.d | 8 +++--- tests/dmd/fail_compilation/diag13942.d | 2 +- tests/dmd/fail_compilation/diag16977.d | 2 +- tests/dmd/fail_compilation/diag20268.d | 2 +- tests/dmd/fail_compilation/diag23355.d | 4 +-- tests/dmd/fail_compilation/diag8101.d | 2 +- tests/dmd/fail_compilation/diag8648.d | 6 ++-- tests/dmd/fail_compilation/diag9004.d | 2 +- tests/dmd/fail_compilation/diagin.d | 2 +- tests/dmd/fail_compilation/fail12744.d | 4 +-- tests/dmd/fail_compilation/fail14669.d | 2 +- tests/dmd/fail_compilation/fail162.d | 2 +- tests/dmd/fail_compilation/fail20730b.d | 2 +- tests/dmd/fail_compilation/fail236.d | 2 +- tests/dmd/fail_compilation/fail8009.d | 2 +- tests/dmd/fail_compilation/fail95.d | 2 +- tests/dmd/fail_compilation/ice11856_1.d | 2 +- tests/dmd/fail_compilation/ice14130.d | 2 +- tests/dmd/fail_compilation/ice14907.d | 2 +- tests/dmd/fail_compilation/ice6538.d | 2 +- tests/dmd/fail_compilation/ice9284.d | 2 +- .../fail_compilation/named_arguments_error.d | 2 +- tests/dmd/fail_compilation/test19107.d | 2 +- 29 files changed, 69 insertions(+), 66 deletions(-) diff --git a/dmd/func.d b/dmd/func.d index 22927444762..f234e28c4fd 100644 --- a/dmd/func.d +++ b/dmd/func.d @@ -3368,7 +3368,10 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, // all of overloads are templates if (td) { - .error(loc, "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`", + const(char)* msg = "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`"; + if (!od && !td.overnext) + msg = "%s `%s.%s` is not callable using argument types `!(%s)%s`"; + .error(loc, msg, td.kind(), td.parent.toPrettyChars(), td.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars()); diff --git a/tests/dmd/fail_compilation/bug9631.d b/tests/dmd/fail_compilation/bug9631.d index 802d1c2983e..f0a9456035b 100644 --- a/tests/dmd/fail_compilation/bug9631.d +++ b/tests/dmd/fail_compilation/bug9631.d @@ -91,9 +91,9 @@ TEST_OUTPUT: --- fail_compilation/bug9631.d(106): Error: function `bug9631.targ.ft!().ft(S __param_0)` is not callable using argument types `(S)` fail_compilation/bug9631.d(106): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S __param_0` -fail_compilation/bug9631.d(107): Error: none of the overloads of template `bug9631.targ.ft` are callable using argument types `!()(S)` +fail_compilation/bug9631.d(107): Error: template `bug9631.targ.ft` is not callable using argument types `!()(S)` fail_compilation/bug9631.d(105): Candidate is: `ft()(tem!().S)` -fail_compilation/bug9631.d(109): Error: none of the overloads of template `bug9631.targ.ft2` are callable using argument types `!()(S, int)` +fail_compilation/bug9631.d(109): Error: template `bug9631.targ.ft2` is not callable using argument types `!()(S, int)` fail_compilation/bug9631.d(108): Candidate is: `ft2(T)(S, T)` --- */ diff --git a/tests/dmd/fail_compilation/constraints_aggr.d b/tests/dmd/fail_compilation/constraints_aggr.d index 9f12ae69835..a3ad34a0ea3 100755 --- a/tests/dmd/fail_compilation/constraints_aggr.d +++ b/tests/dmd/fail_compilation/constraints_aggr.d @@ -2,12 +2,12 @@ EXTRA_FILES: imports/constraints.d TEST_OUTPUT: --- -fail_compilation/constraints_aggr.d(32): Error: none of the overloads of template `imports.constraints.C.f` are callable using argument types `!()(int)` +fail_compilation/constraints_aggr.d(32): Error: template `imports.constraints.C.f` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(60): Candidate is: `f(T)(T v)` with `T = int` must satisfy the following constraint: ` !P!T` -fail_compilation/constraints_aggr.d(33): Error: none of the overloads of template `imports.constraints.C.g` are callable using argument types `!()()` +fail_compilation/constraints_aggr.d(33): Error: template `imports.constraints.C.g` is not callable using argument types `!()()` fail_compilation/imports/constraints.d(63): Candidate is: `g(this T)()` with `T = imports.constraints.C` must satisfy the following constraint: diff --git a/tests/dmd/fail_compilation/constraints_func1.d b/tests/dmd/fail_compilation/constraints_func1.d index aac87601eb9..fbb4aa94d53 100755 --- a/tests/dmd/fail_compilation/constraints_func1.d +++ b/tests/dmd/fail_compilation/constraints_func1.d @@ -2,72 +2,72 @@ EXTRA_FILES: imports/constraints.d TEST_OUTPUT: --- -fail_compilation/constraints_func1.d(79): Error: none of the overloads of template `imports.constraints.test1` are callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(79): Error: template `imports.constraints.test1` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(9): Candidate is: `test1(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func1.d(80): Error: none of the overloads of template `imports.constraints.test2` are callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(80): Error: template `imports.constraints.test2` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(10): Candidate is: `test2(T)(T v)` with `T = int` must satisfy the following constraint: ` !P!T` -fail_compilation/constraints_func1.d(81): Error: none of the overloads of template `imports.constraints.test3` are callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(81): Error: template `imports.constraints.test3` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(11): Candidate is: `test3(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func1.d(82): Error: none of the overloads of template `imports.constraints.test4` are callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(82): Error: template `imports.constraints.test4` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(12): Candidate is: `test4(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func1.d(83): Error: none of the overloads of template `imports.constraints.test5` are callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(83): Error: template `imports.constraints.test5` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(13): Candidate is: `test5(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T` -fail_compilation/constraints_func1.d(84): Error: none of the overloads of template `imports.constraints.test6` are callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(84): Error: template `imports.constraints.test6` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(14): Candidate is: `test6(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T !P!T` -fail_compilation/constraints_func1.d(85): Error: none of the overloads of template `imports.constraints.test7` are callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(85): Error: template `imports.constraints.test7` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(15): Candidate is: `test7(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T` -fail_compilation/constraints_func1.d(86): Error: none of the overloads of template `imports.constraints.test8` are callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(86): Error: template `imports.constraints.test8` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(16): Candidate is: `test8(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func1.d(87): Error: none of the overloads of template `imports.constraints.test9` are callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(87): Error: template `imports.constraints.test9` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(17): Candidate is: `test9(T)(T v)` with `T = int` must satisfy the following constraint: ` !P!T` -fail_compilation/constraints_func1.d(88): Error: none of the overloads of template `imports.constraints.test10` are callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(88): Error: template `imports.constraints.test10` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(18): Candidate is: `test10(T)(T v)` with `T = int` must satisfy the following constraint: ` !P!T` -fail_compilation/constraints_func1.d(89): Error: none of the overloads of template `imports.constraints.test11` are callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(89): Error: template `imports.constraints.test11` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(19): Candidate is: `test11(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T !P!T` -fail_compilation/constraints_func1.d(90): Error: none of the overloads of template `imports.constraints.test12` are callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(90): Error: template `imports.constraints.test12` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(20): Candidate is: `test12(T)(T v)` with `T = int` must satisfy the following constraint: ` !P!T` -fail_compilation/constraints_func1.d(92): Error: none of the overloads of template `imports.constraints.test1` are callable using argument types `!()(int, int)` +fail_compilation/constraints_func1.d(92): Error: template `imports.constraints.test1` is not callable using argument types `!()(int, int)` fail_compilation/imports/constraints.d(9): Candidate is: `test1(T)(T v)` --- */ diff --git a/tests/dmd/fail_compilation/constraints_func2.d b/tests/dmd/fail_compilation/constraints_func2.d index a20426d35dc..4b8ebd5da2b 100755 --- a/tests/dmd/fail_compilation/constraints_func2.d +++ b/tests/dmd/fail_compilation/constraints_func2.d @@ -2,83 +2,83 @@ EXTRA_FILES: imports/constraints.d TEST_OUTPUT: --- -fail_compilation/constraints_func2.d(94): Error: none of the overloads of template `imports.constraints.test13` are callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(94): Error: template `imports.constraints.test13` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(23): Candidate is: `test13(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T !P!T` -fail_compilation/constraints_func2.d(95): Error: none of the overloads of template `imports.constraints.test14` are callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(95): Error: template `imports.constraints.test14` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(24): Candidate is: `test14(T)(T v)` with `T = int` must satisfy one of the following constraints: ` !P!T N!T` -fail_compilation/constraints_func2.d(96): Error: none of the overloads of template `imports.constraints.test15` are callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(96): Error: template `imports.constraints.test15` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(25): Candidate is: `test15(T)(T v)` with `T = int` must satisfy one of the following constraints: ` !P!T !P!T` -fail_compilation/constraints_func2.d(97): Error: none of the overloads of template `imports.constraints.test16` are callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(97): Error: template `imports.constraints.test16` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(26): Candidate is: `test16(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T` -fail_compilation/constraints_func2.d(98): Error: none of the overloads of template `imports.constraints.test17` are callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(98): Error: template `imports.constraints.test17` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(27): Candidate is: `test17(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func2.d(99): Error: none of the overloads of template `imports.constraints.test18` are callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(99): Error: template `imports.constraints.test18` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(28): Candidate is: `test18(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T` -fail_compilation/constraints_func2.d(100): Error: none of the overloads of template `imports.constraints.test19` are callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(100): Error: template `imports.constraints.test19` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(29): Candidate is: `test19(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T !P!T N!T` -fail_compilation/constraints_func2.d(101): Error: none of the overloads of template `imports.constraints.test20` are callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(101): Error: template `imports.constraints.test20` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(30): Candidate is: `test20(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func2.d(102): Error: none of the overloads of template `imports.constraints.test21` are callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(102): Error: template `imports.constraints.test21` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(31): Candidate is: `test21(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T` -fail_compilation/constraints_func2.d(103): Error: none of the overloads of template `imports.constraints.test22` are callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(103): Error: template `imports.constraints.test22` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(32): Candidate is: `test22(T)(T v)` with `T = int` must satisfy one of the following constraints: ` !P!T !P!T` -fail_compilation/constraints_func2.d(104): Error: none of the overloads of template `imports.constraints.test23` are callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(104): Error: template `imports.constraints.test23` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(33): Candidate is: `test23(T)(T v)` with `T = int` must satisfy one of the following constraints: ` !P!T N!T !P!T` -fail_compilation/constraints_func2.d(105): Error: none of the overloads of template `imports.constraints.test24` are callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(105): Error: template `imports.constraints.test24` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(34): Candidate is: `test24(R)(R r)` with `R = int` must satisfy the following constraint: ` __traits(hasMember, R, "stuff")` -fail_compilation/constraints_func2.d(106): Error: none of the overloads of template `imports.constraints.test25` are callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(106): Error: template `imports.constraints.test25` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(35): Candidate is: `test25(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func2.d(107): Error: none of the overloads of template `imports.constraints.test26` are callable using argument types `!(float)(int)` +fail_compilation/constraints_func2.d(107): Error: template `imports.constraints.test26` is not callable using argument types `!(float)(int)` fail_compilation/imports/constraints.d(36): Candidate is: `test26(T, U)(U u)` with `T = float, U = int` diff --git a/tests/dmd/fail_compilation/constraints_func3.d b/tests/dmd/fail_compilation/constraints_func3.d index 6f214b9f07e..d16bdf0959c 100755 --- a/tests/dmd/fail_compilation/constraints_func3.d +++ b/tests/dmd/fail_compilation/constraints_func3.d @@ -23,21 +23,21 @@ fail_compilation/imports/constraints.d(42): `overload(T, must satisfy one of the following constraints: ` N!T N!V` -fail_compilation/constraints_func3.d(56): Error: none of the overloads of template `imports.constraints.variadic` are callable using argument types `!()()` +fail_compilation/constraints_func3.d(56): Error: template `imports.constraints.variadic` is not callable using argument types `!()()` fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` -fail_compilation/constraints_func3.d(57): Error: none of the overloads of template `imports.constraints.variadic` are callable using argument types `!()(int)` +fail_compilation/constraints_func3.d(57): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` with `A = int, T = ()` must satisfy the following constraint: ` N!int` -fail_compilation/constraints_func3.d(58): Error: none of the overloads of template `imports.constraints.variadic` are callable using argument types `!()(int, int)` +fail_compilation/constraints_func3.d(58): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int, int)` fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` with `A = int, T = (int)` must satisfy the following constraint: ` N!int` -fail_compilation/constraints_func3.d(59): Error: none of the overloads of template `imports.constraints.variadic` are callable using argument types `!()(int, int, int)` +fail_compilation/constraints_func3.d(59): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int, int, int)` fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` with `A = int, T = (int, int)` diff --git a/tests/dmd/fail_compilation/constraints_func4.d b/tests/dmd/fail_compilation/constraints_func4.d index 4048baed69c..c4dea0ec451 100755 --- a/tests/dmd/fail_compilation/constraints_func4.d +++ b/tests/dmd/fail_compilation/constraints_func4.d @@ -44,13 +44,13 @@ fail_compilation/imports/constraints.d(42): `overload(T, N!V` void overload(T, V)(T v1, V v2) if (N!T || N!V); ^ -fail_compilation/constraints_func4.d(93): Error: none of the overloads of template `imports.constraints.variadic` are callable using argument types `!()()` +fail_compilation/constraints_func4.d(93): Error: template `imports.constraints.variadic` is not callable using argument types `!()()` variadic(); ^ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` void variadic(A, T...)(A a, T v) if (N!int); ^ -fail_compilation/constraints_func4.d(94): Error: none of the overloads of template `imports.constraints.variadic` are callable using argument types `!()(int)` +fail_compilation/constraints_func4.d(94): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int)` variadic(0); ^ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` @@ -60,7 +60,7 @@ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T. ` N!int` void variadic(A, T...)(A a, T v) if (N!int); ^ -fail_compilation/constraints_func4.d(95): Error: none of the overloads of template `imports.constraints.variadic` are callable using argument types `!()(int, int)` +fail_compilation/constraints_func4.d(95): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int, int)` variadic(0, 1); ^ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` @@ -70,7 +70,7 @@ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T. ` N!int` void variadic(A, T...)(A a, T v) if (N!int); ^ -fail_compilation/constraints_func4.d(96): Error: none of the overloads of template `imports.constraints.variadic` are callable using argument types `!()(int, int, int)` +fail_compilation/constraints_func4.d(96): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int, int, int)` variadic(0, 1, 2); ^ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` diff --git a/tests/dmd/fail_compilation/diag13942.d b/tests/dmd/fail_compilation/diag13942.d index aeee10749c1..25e0515a5bc 100644 --- a/tests/dmd/fail_compilation/diag13942.d +++ b/tests/dmd/fail_compilation/diag13942.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/diag13942.d(18): Error: template instance `isRawStaticArray!()` does not match template declaration `isRawStaticArray(T, A...)` -fail_compilation/diag13942.d(26): Error: none of the overloads of template `diag13942.to!double.to` are callable using argument types `!()()` +fail_compilation/diag13942.d(26): Error: template `diag13942.to!double.to` is not callable using argument types `!()()` fail_compilation/diag13942.d(17): Candidate is: `to(A...)(A args)` --- */ diff --git a/tests/dmd/fail_compilation/diag16977.d b/tests/dmd/fail_compilation/diag16977.d index 73d628584d5..fc8f66032e2 100644 --- a/tests/dmd/fail_compilation/diag16977.d +++ b/tests/dmd/fail_compilation/diag16977.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/diag16977.d(25): Error: undefined identifier `undefined`, did you mean function `undefinedId`? fail_compilation/diag16977.d(26): Error: cannot implicitly convert expression `"\x01string"` of type `string` to `int` -fail_compilation/diag16977.d(27): Error: none of the overloads of template `diag16977.templ` are callable using argument types `!()(int)` +fail_compilation/diag16977.d(27): Error: template `diag16977.templ` is not callable using argument types `!()(int)` fail_compilation/diag16977.d(20): Candidate is: `templ(S)(S s)` with `S = int` must satisfy the following constraint: diff --git a/tests/dmd/fail_compilation/diag20268.d b/tests/dmd/fail_compilation/diag20268.d index a314561892a..053626a603c 100644 --- a/tests/dmd/fail_compilation/diag20268.d +++ b/tests/dmd/fail_compilation/diag20268.d @@ -3,7 +3,7 @@ /* TEST_OUTPUT: --- -fail_compilation/diag20268.d(12): Error: none of the overloads of template `diag20268.__lambda4` are callable using argument types `!()(int)` +fail_compilation/diag20268.d(12): Error: template `diag20268.__lambda4` is not callable using argument types `!()(int)` fail_compilation/diag20268.d(11): Candidate is: `__lambda4(__T1, __T2)(x, y)` --- */ diff --git a/tests/dmd/fail_compilation/diag23355.d b/tests/dmd/fail_compilation/diag23355.d index 586cbb0fce8..a530eb60ef0 100644 --- a/tests/dmd/fail_compilation/diag23355.d +++ b/tests/dmd/fail_compilation/diag23355.d @@ -2,10 +2,10 @@ TEST_OUTPUT: --- fail_compilation/diag23355.d(1): Error: undefined identifier `n` -fail_compilation/diag23355.d(4): Error: none of the overloads of template `diag23355.ffi1` are callable using argument types `!()(int[4])` +fail_compilation/diag23355.d(4): Error: template `diag23355.ffi1` is not callable using argument types `!()(int[4])` fail_compilation/diag23355.d(1): Candidate is: `ffi1(T)(T[n] s)` fail_compilation/diag23355.d(2): Error: undefined identifier `n` -fail_compilation/diag23355.d(4): Error: none of the overloads of template `diag23355.ffi2` are callable using argument types `!()(int[4])` +fail_compilation/diag23355.d(4): Error: template `diag23355.ffi2` is not callable using argument types `!()(int[4])` fail_compilation/diag23355.d(2): Candidate is: `ffi2()(T[n] s)` --- */ diff --git a/tests/dmd/fail_compilation/diag8101.d b/tests/dmd/fail_compilation/diag8101.d index ddc74e28131..4c8dfe881ab 100644 --- a/tests/dmd/fail_compilation/diag8101.d +++ b/tests/dmd/fail_compilation/diag8101.d @@ -14,7 +14,7 @@ fail_compilation/diag8101.d(41): `diag8101.f_2(int, int, fail_compilation/diag8101.d(42): `diag8101.f_2(int, int, int, int, int)` fail_compilation/diag8101.d(43): `diag8101.f_2(int, int, int, int, int, int)` fail_compilation/diag8101.d(63): ... (1 more, -v to show) ... -fail_compilation/diag8101.d(65): Error: none of the overloads of template `diag8101.t_0` are callable using argument types `!()()` +fail_compilation/diag8101.d(65): Error: template `diag8101.t_0` is not callable using argument types `!()()` fail_compilation/diag8101.d(46): Candidate is: `t_0(T1)()` fail_compilation/diag8101.d(66): Error: none of the overloads of template `diag8101.t_1` are callable using argument types `!()()` fail_compilation/diag8101.d(48): Candidates are: `t_1(T1)()` diff --git a/tests/dmd/fail_compilation/diag8648.d b/tests/dmd/fail_compilation/diag8648.d index a04ed7c0a42..e48f569b74d 100644 --- a/tests/dmd/fail_compilation/diag8648.d +++ b/tests/dmd/fail_compilation/diag8648.d @@ -2,13 +2,13 @@ TEST_OUTPUT: --- fail_compilation/diag8648.d(18): Error: undefined identifier `X` -fail_compilation/diag8648.d(29): Error: none of the overloads of template `diag8648.foo` are callable using argument types `!()(Foo!(int, 1))` +fail_compilation/diag8648.d(29): Error: template `diag8648.foo` is not callable using argument types `!()(Foo!(int, 1))` fail_compilation/diag8648.d(18): Candidate is: `foo(T, n)(X!(T, n))` fail_compilation/diag8648.d(20): Error: undefined identifier `a` -fail_compilation/diag8648.d(31): Error: none of the overloads of template `diag8648.bar` are callable using argument types `!()(Foo!(int, 1))` +fail_compilation/diag8648.d(31): Error: template `diag8648.bar` is not callable using argument types `!()(Foo!(int, 1))` fail_compilation/diag8648.d(20): Candidate is: `bar(T)(Foo!(T, a))` fail_compilation/diag8648.d(20): Error: undefined identifier `a` -fail_compilation/diag8648.d(32): Error: none of the overloads of template `diag8648.bar` are callable using argument types `!()(Foo!(int, f))` +fail_compilation/diag8648.d(32): Error: template `diag8648.bar` is not callable using argument types `!()(Foo!(int, f))` fail_compilation/diag8648.d(20): Candidate is: `bar(T)(Foo!(T, a))` --- */ diff --git a/tests/dmd/fail_compilation/diag9004.d b/tests/dmd/fail_compilation/diag9004.d index 37d5bd84f32..30589bf0cac 100644 --- a/tests/dmd/fail_compilation/diag9004.d +++ b/tests/dmd/fail_compilation/diag9004.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/diag9004.d(21): Error: none of the overloads of template `diag9004.bar` are callable using argument types `!()(Foo!int, int)` +fail_compilation/diag9004.d(21): Error: template `diag9004.bar` is not callable using argument types `!()(Foo!int, int)` fail_compilation/diag9004.d(14): Candidate is: `bar(FooT)(FooT foo, FooT.T x)` --- */ diff --git a/tests/dmd/fail_compilation/diagin.d b/tests/dmd/fail_compilation/diagin.d index 0d1f8f14fea..1748e92a841 100644 --- a/tests/dmd/fail_compilation/diagin.d +++ b/tests/dmd/fail_compilation/diagin.d @@ -4,7 +4,7 @@ TEST_OUTPUT: --- fail_compilation/diagin.d(14): Error: function `diagin.foo(in int)` is not callable using argument types `()` fail_compilation/diagin.d(14): too few arguments, expected 1, got 0 -fail_compilation/diagin.d(16): Error: none of the overloads of template `diagin.foo1` are callable using argument types `!()(bool[])` +fail_compilation/diagin.d(16): Error: template `diagin.foo1` is not callable using argument types `!()(bool[])` fail_compilation/diagin.d(20): Candidate is: `foo1(T)(in T v, string)` --- */ diff --git a/tests/dmd/fail_compilation/fail12744.d b/tests/dmd/fail_compilation/fail12744.d index 2056c0e2a27..711e57fad30 100644 --- a/tests/dmd/fail_compilation/fail12744.d +++ b/tests/dmd/fail_compilation/fail12744.d @@ -14,10 +14,10 @@ fail_compilation/fail12744.d(61): Error: template instance `fail12744.bar12744L! fail_compilation/fail12744.d(40): Error: incompatible parameter storage classes `lazy` and `out` fail_compilation/fail12744.d(62): Error: template instance `fail12744.bar12744L!(foo12744O)` error instantiating fail_compilation/fail12744.d(41): Error: incompatible parameter storage classes `auto ref` and `out` -fail_compilation/fail12744.d(67): Error: none of the overloads of template `fail12744.bar12744A` are callable using argument types `!(foo12744O)(int)` +fail_compilation/fail12744.d(67): Error: template `fail12744.bar12744A` is not callable using argument types `!(foo12744O)(int)` fail_compilation/fail12744.d(41): Candidate is: `bar12744A(alias f)(auto ref PTT12744!f args)` fail_compilation/fail12744.d(41): Error: incompatible parameter storage classes `auto ref` and `lazy` -fail_compilation/fail12744.d(68): Error: none of the overloads of template `fail12744.bar12744A` are callable using argument types `!(foo12744L)(int)` +fail_compilation/fail12744.d(68): Error: template `fail12744.bar12744A` is not callable using argument types `!(foo12744L)(int)` fail_compilation/fail12744.d(41): Candidate is: `bar12744A(alias f)(auto ref PTT12744!f args)` --- */ diff --git a/tests/dmd/fail_compilation/fail14669.d b/tests/dmd/fail_compilation/fail14669.d index 5621ecceda8..45fe1463551 100644 --- a/tests/dmd/fail_compilation/fail14669.d +++ b/tests/dmd/fail_compilation/fail14669.d @@ -4,7 +4,7 @@ TEST_OUTPUT: fail_compilation/fail14669.d(11): Error: `auto` can only be used as part of `auto ref` for template function parameters fail_compilation/fail14669.d(16): Error: template instance `fail14669.foo1!()` error instantiating fail_compilation/fail14669.d(12): Error: `auto` can only be used as part of `auto ref` for template function parameters -fail_compilation/fail14669.d(17): Error: none of the overloads of template `fail14669.foo2` are callable using argument types `!()(int)` +fail_compilation/fail14669.d(17): Error: template `fail14669.foo2` is not callable using argument types `!()(int)` fail_compilation/fail14669.d(12): Candidate is: `foo2()(auto int a)` --- */ diff --git a/tests/dmd/fail_compilation/fail162.d b/tests/dmd/fail_compilation/fail162.d index a537f108e28..c79f8d8d548 100644 --- a/tests/dmd/fail_compilation/fail162.d +++ b/tests/dmd/fail_compilation/fail162.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail162.d(25): Error: none of the overloads of template `fail162.testHelper` are callable using argument types `!()(string, string)` +fail_compilation/fail162.d(25): Error: template `fail162.testHelper` is not callable using argument types `!()(string, string)` fail_compilation/fail162.d(10): Candidate is: `testHelper(A...)()` fail_compilation/fail162.d(30): Error: template instance `fail162.test!("hello", "world")` error instantiating --- diff --git a/tests/dmd/fail_compilation/fail20730b.d b/tests/dmd/fail_compilation/fail20730b.d index 00dd9fd7cba..d36bb0b6e89 100644 --- a/tests/dmd/fail_compilation/fail20730b.d +++ b/tests/dmd/fail_compilation/fail20730b.d @@ -3,7 +3,7 @@ REQUIRED_ARGS: -verrors=spec -o- TEST_OUTPUT: --- (spec:1) fail_compilation/fail20730b.d-mixin-43(43): Error: C style cast illegal, use `cast(int)mod` -fail_compilation/fail20730b.d(26): Error: none of the overloads of template `fail20730b.atomicOp` are callable using argument types `!("+=")(shared(uint), int)` +fail_compilation/fail20730b.d(26): Error: template `fail20730b.atomicOp` is not callable using argument types `!("+=")(shared(uint), int)` fail_compilation/fail20730b.d(41): Candidate is: `atomicOp(string op, T, V1)(shared ref T val, V1 mod)` with `op = "+=", T = uint, diff --git a/tests/dmd/fail_compilation/fail236.d b/tests/dmd/fail_compilation/fail236.d index 626ec0090f1..accc0e17dd2 100644 --- a/tests/dmd/fail_compilation/fail236.d +++ b/tests/dmd/fail_compilation/fail236.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/fail236.d(14): Error: undefined identifier `x` -fail_compilation/fail236.d(22): Error: none of the overloads of template `fail236.Templ2` are callable using argument types `!()(int)` +fail_compilation/fail236.d(22): Error: template `fail236.Templ2` is not callable using argument types `!()(int)` fail_compilation/fail236.d(12): Candidate is: `Templ2(alias a)(x)` --- */ diff --git a/tests/dmd/fail_compilation/fail8009.d b/tests/dmd/fail_compilation/fail8009.d index 96489d9a77d..a4844bf66f5 100644 --- a/tests/dmd/fail_compilation/fail8009.d +++ b/tests/dmd/fail_compilation/fail8009.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail8009.d(9): Error: none of the overloads of template `fail8009.filter` are callable using argument types `!()(void)` +fail_compilation/fail8009.d(9): Error: template `fail8009.filter` is not callable using argument types `!()(void)` fail_compilation/fail8009.d(8): Candidate is: `filter(R)(scope bool delegate(ref BAD!R) func)` --- */ diff --git a/tests/dmd/fail_compilation/fail95.d b/tests/dmd/fail_compilation/fail95.d index a1b3906dc6c..7065bc11516 100644 --- a/tests/dmd/fail_compilation/fail95.d +++ b/tests/dmd/fail_compilation/fail95.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail95.d(19): Error: none of the overloads of template `fail95.A` are callable using argument types `!()(int)` +fail_compilation/fail95.d(19): Error: template `fail95.A` is not callable using argument types `!()(int)` fail_compilation/fail95.d(11): Candidate is: `A(alias T)(T)` --- */ diff --git a/tests/dmd/fail_compilation/ice11856_1.d b/tests/dmd/fail_compilation/ice11856_1.d index 24e39da85bb..afee32abfa7 100644 --- a/tests/dmd/fail_compilation/ice11856_1.d +++ b/tests/dmd/fail_compilation/ice11856_1.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ice11856_1.d(16): Error: none of the overloads of template `ice11856_1.g` are callable using argument types `!()(A)` +fail_compilation/ice11856_1.d(16): Error: template `ice11856_1.g` is not callable using argument types `!()(A)` fail_compilation/ice11856_1.d(14): Candidate is: `g(T)(T x)` with `T = A` must satisfy the following constraint: diff --git a/tests/dmd/fail_compilation/ice14130.d b/tests/dmd/fail_compilation/ice14130.d index c64fb848484..151bf17535c 100644 --- a/tests/dmd/fail_compilation/ice14130.d +++ b/tests/dmd/fail_compilation/ice14130.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/ice14130.d(10): Error: undefined identifier `Undef` -fail_compilation/ice14130.d(14): Error: none of the overloads of template `ice14130.foo` are callable using argument types `!()(int)` +fail_compilation/ice14130.d(14): Error: template `ice14130.foo` is not callable using argument types `!()(int)` fail_compilation/ice14130.d(10): Candidate is: `foo(R, F = Undef)(R r, F s = 0)` --- */ diff --git a/tests/dmd/fail_compilation/ice14907.d b/tests/dmd/fail_compilation/ice14907.d index e1d7aac9f3c..5d676cd1a12 100644 --- a/tests/dmd/fail_compilation/ice14907.d +++ b/tests/dmd/fail_compilation/ice14907.d @@ -6,7 +6,7 @@ fail_compilation/ice14907.d(19): while looking for match for `S!()` fail_compilation/ice14907.d(15): Error: template `ice14907.f(int v = f)()` recursive template expansion fail_compilation/ice14907.d(20): while looking for match for `f!()` fail_compilation/ice14907.d(15): Error: template `ice14907.f(int v = f)()` recursive template expansion -fail_compilation/ice14907.d(21): Error: none of the overloads of template `ice14907.f` are callable using argument types `!()()` +fail_compilation/ice14907.d(21): Error: template `ice14907.f` is not callable using argument types `!()()` fail_compilation/ice14907.d(15): Candidate is: `f(int v = f)()` --- */ diff --git a/tests/dmd/fail_compilation/ice6538.d b/tests/dmd/fail_compilation/ice6538.d index 1c6cf4b1505..af7c5543228 100644 --- a/tests/dmd/fail_compilation/ice6538.d +++ b/tests/dmd/fail_compilation/ice6538.d @@ -7,7 +7,7 @@ TEST_OUTPUT: --- fail_compilation/ice6538.d(23): Error: expression `super` is not a valid template value argument -fail_compilation/ice6538.d(28): Error: none of the overloads of template `ice6538.D.foo` are callable using argument types `!()()` +fail_compilation/ice6538.d(28): Error: template `ice6538.D.foo` is not callable using argument types `!()()` fail_compilation/ice6538.d(23): Candidate is: `foo()()` --- */ diff --git a/tests/dmd/fail_compilation/ice9284.d b/tests/dmd/fail_compilation/ice9284.d index 00602d2de81..47fd44c6b01 100644 --- a/tests/dmd/fail_compilation/ice9284.d +++ b/tests/dmd/fail_compilation/ice9284.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ice9284.d(14): Error: none of the overloads of template `ice9284.C.__ctor` are callable using argument types `!()(int)` +fail_compilation/ice9284.d(14): Error: template `ice9284.C.__ctor` is not callable using argument types `!()(int)` fail_compilation/ice9284.d(12): Candidate is: `__ctor()(string)` fail_compilation/ice9284.d(20): Error: template instance `ice9284.C.__ctor!()` error instantiating --- diff --git a/tests/dmd/fail_compilation/named_arguments_error.d b/tests/dmd/fail_compilation/named_arguments_error.d index 0900e6010d1..5129f301460 100644 --- a/tests/dmd/fail_compilation/named_arguments_error.d +++ b/tests/dmd/fail_compilation/named_arguments_error.d @@ -15,7 +15,7 @@ fail_compilation/named_arguments_error.d(38): Error: no named argument `element` fail_compilation/named_arguments_error.d(39): Error: no named argument `number` allowed for scalar fail_compilation/named_arguments_error.d(40): Error: cannot implicitly convert expression `g(x: 3, y: 4, z: 5)` of type `int` to `string` fail_compilation/named_arguments_error.d(41): Error: named arguments with Implicit Function Template Instantiation are not supported yet -fail_compilation/named_arguments_error.d(41): Error: none of the overloads of template `named_arguments_error.tempfun` are callable using argument types `!()(string, int)` +fail_compilation/named_arguments_error.d(41): Error: template `named_arguments_error.tempfun` is not callable using argument types `!()(string, int)` fail_compilation/named_arguments_error.d(45): Candidate is: `tempfun(T, U)(T t, U u)` --- */ diff --git a/tests/dmd/fail_compilation/test19107.d b/tests/dmd/fail_compilation/test19107.d index 93d86bf381b..c8021229427 100644 --- a/tests/dmd/fail_compilation/test19107.d +++ b/tests/dmd/fail_compilation/test19107.d @@ -2,7 +2,7 @@ EXTRA_FILES: imports/imp19661.d imports/test19107a.d imports/test19107b.d TEST_OUTPUT: --- -fail_compilation/test19107.d(24): Error: none of the overloads of template `test19107.all` are callable using argument types `!((c) => c)(string[])` +fail_compilation/test19107.d(24): Error: template `test19107.all` is not callable using argument types `!((c) => c)(string[])` fail_compilation/test19107.d(18): Candidate is: `all(alias pred, T)(T t)` with `pred = __lambda2, T = string[]` From 00c8be59dd3baffbdf35a929b5abb6370abb8c0e Mon Sep 17 00:00:00 2001 From: Dennis Korpel Date: Mon, 8 May 2023 17:45:23 +0200 Subject: [PATCH 017/176] Add test for "static import cannot have an import bind list" --- tests/dmd/fail_compilation/static_import.d | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tests/dmd/fail_compilation/static_import.d diff --git a/tests/dmd/fail_compilation/static_import.d b/tests/dmd/fail_compilation/static_import.d new file mode 100644 index 00000000000..24b7bc19546 --- /dev/null +++ b/tests/dmd/fail_compilation/static_import.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/static_import.d(8): Error: static import `core` cannot have an import bind list +--- +*/ + +static import core.stdc.stdio : p = q; From 5cb47a8b9cba3fc539a78ee7706842b11f0606b3 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Mon, 8 May 2023 17:07:38 -0700 Subject: [PATCH 018/176] reduce Loc.sizeof by 8 bytes (dlang/dmd!15199) --- dmd/doc.d | 6 +-- dmd/frontend.h | 46 +++++++++-------- dmd/globals.h | 11 ++-- dmd/lexer.d | 4 +- dmd/location.d | 50 +++++++++++++++---- .../interfaces/check_implementations_20861.d | 8 +-- .../unit/objc/protocols/diagnostic_messages.d | 4 +- .../unit/objc/protocols/optional_methods.d | 16 +++--- 8 files changed, 90 insertions(+), 55 deletions(-) diff --git a/dmd/doc.d b/dmd/doc.d index 7674f775e3e..a8e6a6260a5 100644 --- a/dmd/doc.d +++ b/dmd/doc.d @@ -429,9 +429,9 @@ extern(C++) void gendocfile(Module m) if (m.filetype == FileType.ddoc) { const ploc = m.md ? &m.md.loc : &m.loc; - const loc = Loc(ploc.filename ? ploc.filename : srcfilename.ptr, - ploc.linnum, - ploc.charnum); + Loc loc = *ploc; + if (!loc.fileIndex) + loc.filename = srcfilename.ptr; size_t commentlen = strlen(cast(char*)m.comment); Dsymbols a; diff --git a/dmd/frontend.h b/dmd/frontend.h index c430fd9f7a2..c4e1699f83d 100644 --- a/dmd/frontend.h +++ b/dmd/frontend.h @@ -377,18 +377,20 @@ enum class MessageStyle : uint8_t struct Loc final { - const char* filename; uint32_t linnum; - uint32_t charnum; + uint16_t charnum; + uint16_t fileIndex; static bool showColumns; static MessageStyle messageStyle; static void set(bool showColumns, MessageStyle messageStyle); + const char* filename() const; + void filename(const char* name); const char* toChars(bool showColumns = showColumns, MessageStyle messageStyle = messageStyle) const; bool equals(const Loc& loc) const; Loc() : - filename(), linnum(), - charnum() + charnum(), + fileIndex() { } }; @@ -2345,7 +2347,7 @@ struct AttributeViolation final RootObject* arg1; RootObject* arg2; AttributeViolation() : - loc(Loc(nullptr, 0u, 0u)), + loc(Loc(0u, 0u, 0u)), fmtStr(nullptr), arg0(nullptr), arg1(nullptr), @@ -7004,23 +7006,23 @@ struct UnionExp final private: union __AnonStruct__u { - char exp[34LLU]; - char integerexp[48LLU]; - char errorexp[34LLU]; - char realexp[64LLU]; - char complexexp[80LLU]; - char symoffexp[72LLU]; - char stringexp[58LLU]; - char arrayliteralexp[56LLU]; - char assocarrayliteralexp[56LLU]; - char structliteralexp[84LLU]; - char compoundliteralexp[48LLU]; - char nullexp[34LLU]; - char dotvarexp[57LLU]; - char addrexp[48LLU]; - char indexexp[82LLU]; - char sliceexp[73LLU]; - char vectorexp[61LLU]; + char exp[26LLU]; + char integerexp[40LLU]; + char errorexp[26LLU]; + char realexp[48LLU]; + char complexexp[64LLU]; + char symoffexp[64LLU]; + char stringexp[50LLU]; + char arrayliteralexp[48LLU]; + char assocarrayliteralexp[48LLU]; + char structliteralexp[76LLU]; + char compoundliteralexp[40LLU]; + char nullexp[26LLU]; + char dotvarexp[49LLU]; + char addrexp[40LLU]; + char indexexp[74LLU]; + char sliceexp[65LLU]; + char vectorexp[53LLU]; }; #pragma pack(pop) diff --git a/dmd/globals.h b/dmd/globals.h index 902cf83f81f..45f14fa51cb 100644 --- a/dmd/globals.h +++ b/dmd/globals.h @@ -353,9 +353,9 @@ typedef unsigned long long uinteger_t; // file location struct Loc { - const char *filename; // either absolute or relative to cwd unsigned linnum; - unsigned charnum; + unsigned short charnum; + unsigned short fileIndex; static void set(bool showColumns, MessageStyle messageStyle); @@ -366,16 +366,19 @@ struct Loc { linnum = 0; charnum = 0; - filename = NULL; + fileIndex = 0; } Loc(const char *filename, unsigned linnum, unsigned charnum) { this->linnum = linnum; this->charnum = charnum; - this->filename = filename; + this->filename(filename); } + const char *filename() const; + void filename(const char *name); + const char *toChars( bool showColumns = Loc::showColumns, MessageStyle messageStyle = Loc::messageStyle) const; diff --git a/dmd/lexer.d b/dmd/lexer.d index 0ec468b3245..6801b2cb0da 100644 --- a/dmd/lexer.d +++ b/dmd/lexer.d @@ -119,7 +119,7 @@ class Lexer this(const(char)* filename, const(char)* base, size_t begoffset, size_t endoffset, bool doDocComment, bool commentToken, ErrorSink errorSink, - const CompileEnv* compileEnv) pure scope + const CompileEnv* compileEnv) scope { scanloc = Loc(filename, 1, 1); // debug printf("Lexer::Lexer(%p)\n", base); @@ -2674,7 +2674,7 @@ class Lexer final Loc loc() pure @nogc { - scanloc.charnum = cast(uint)(1 + p - line); + scanloc.charnum = cast(ushort)(1 + p - line); version (LocOffset) scanloc.fileOffset = cast(uint)(p - base); return scanloc; diff --git a/dmd/location.d b/dmd/location.d index 020d297b06d..08b44a23720 100644 --- a/dmd/location.d +++ b/dmd/location.d @@ -11,7 +11,10 @@ module dmd.location; +import core.stdc.stdio; + import dmd.common.outbuffer; +import dmd.root.array; import dmd.root.filename; version (DMDLIB) @@ -34,10 +37,9 @@ debug info etc. */ struct Loc { - /// zero-terminated filename string, either absolute or relative to cwd - const(char)* filename; uint linnum; /// line number, starting from 1 - uint charnum; /// utf8 code unit index relative to start of line, starting from 1 + ushort charnum; /// utf8 code unit index relative to start of line, starting from 1 + ushort fileIndex; // index into filenames[], starting from 1 (0 means no filename) version (LocOffset) uint fileOffset; /// utf8 code unit index relative to start of file, starting from 0 @@ -46,6 +48,8 @@ struct Loc extern (C++) __gshared bool showColumns; extern (C++) __gshared MessageStyle messageStyle; + __gshared Array!(const(char)*) filenames; + nothrow: /******************************* @@ -60,19 +64,45 @@ nothrow: this.messageStyle = messageStyle; } - extern (D) this(const(char)* filename, uint linnum, uint charnum) pure + extern (D) this(const(char)* filename, uint linnum, uint charnum) { this.linnum = linnum; - this.charnum = charnum; + this.charnum = cast(ushort)charnum; this.filename = filename; } + /*** + * Returns: filename for this location, null if none + */ + extern (C++) const(char)* filename() const @nogc + { + return fileIndex ? filenames[fileIndex - 1] : null; + } + + /*** + * Set file name for this location + * Params: + * name = file name for location, null for no file name + */ + extern (C++) void filename(const(char)* name) + { + if (name) + { + //printf("setting %s\n", name); + filenames.push(name); + fileIndex = cast(ushort)filenames.length; + assert(fileIndex); // no overflow + } + else + fileIndex = 0; + } + extern (C++) const(char)* toChars( bool showColumns = Loc.showColumns, - MessageStyle messageStyle = Loc.messageStyle) const pure nothrow + MessageStyle messageStyle = Loc.messageStyle) const nothrow { OutBuffer buf; - if (filename) + if (fileIndex) { buf.writestring(filename); } @@ -126,7 +156,7 @@ nothrow: * may lead to multiple equivalent filenames (`foo.d-mixin-`), * e.g., for test/runnable/test18880.d. */ - extern (D) bool opEquals(ref const(Loc) loc) const @trusted pure nothrow @nogc + extern (D) bool opEquals(ref const(Loc) loc) const @trusted nothrow @nogc { import core.stdc.string : strcmp; @@ -137,7 +167,7 @@ nothrow: } /// ditto - extern (D) size_t toHash() const @trusted pure nothrow + extern (D) size_t toHash() const @trusted nothrow { import dmd.root.string : toDString; @@ -153,6 +183,6 @@ nothrow: */ bool isValid() const pure { - return filename !is null; + return fileIndex != 0; } } diff --git a/tests/dmd/unit/interfaces/check_implementations_20861.d b/tests/dmd/unit/interfaces/check_implementations_20861.d index bb6c67fd242..269fab36a95 100644 --- a/tests/dmd/unit/interfaces/check_implementations_20861.d +++ b/tests/dmd/unit/interfaces/check_implementations_20861.d @@ -45,7 +45,7 @@ import support : afterEach, beforeEach, compiles, stripDelimited, Diagnostic; }.stripDelimited; enum message = "Error: class test.Bar interface function void foo() is not implemented"; - enum expected = Diagnostic(Loc(filename, 6, 1), message); + const expected = Diagnostic(Loc(filename, 6, 1), message); const diagnostics = compiles(code, filename); assert(diagnostics == [expected], "\n" ~ diagnostics.toString); @@ -67,7 +67,7 @@ import support : afterEach, beforeEach, compiles, stripDelimited, Diagnostic; }.stripDelimited; enum message = "Error: class test.Bar interface function void foo() is not implemented"; - enum expected = Diagnostic(Loc(filename, 6, 1), message); + const expected = Diagnostic(Loc(filename, 6, 1), message); const diagnostics = compiles(code, filename); assert(diagnostics == [expected], "\n" ~ diagnostics.toString); @@ -94,7 +94,7 @@ import support : afterEach, beforeEach, compiles, stripDelimited, Diagnostic; }.stripDelimited; enum message = "Error: class test.Bar interface function void foo() is not implemented"; - enum expected = Diagnostic(Loc(filename, 11, 1), message); + const expected = Diagnostic(Loc(filename, 11, 1), message); const diagnostics = compiles(code, filename); assert(diagnostics == [expected], "\n" ~ diagnostics.toString); @@ -123,7 +123,7 @@ import support : afterEach, beforeEach, compiles, stripDelimited, Diagnostic; }.stripDelimited; enum message = "Error: class test.B interface function void foo() is not implemented"; - enum expected = Diagnostic(Loc(filename, 11, 1), message); + const expected = Diagnostic(Loc(filename, 11, 1), message); const diagnostics = compiles(code, filename); assert(diagnostics == [expected], "\n" ~ diagnostics.toString); diff --git a/tests/dmd/unit/objc/protocols/diagnostic_messages.d b/tests/dmd/unit/objc/protocols/diagnostic_messages.d index 8e40a21c832..ce673c93118 100644 --- a/tests/dmd/unit/objc/protocols/diagnostic_messages.d +++ b/tests/dmd/unit/objc/protocols/diagnostic_messages.d @@ -41,7 +41,7 @@ unittest }.stripDelimited; enum message = "Error: class test.Bar interface function extern (Objective-C) static void foo() is not implemented"; - enum expected = Diagnostic(Loc(filename, 8, 1), message); + auto expected = Diagnostic(Loc(filename, 8, 1), message); const diagnostics = compiles(code, filename); assert(diagnostics == [expected], "\n" ~ diagnostics.toString); @@ -65,7 +65,7 @@ unittest }.stripDelimited; enum message = "Error: function test.Foo.foo function body only allowed in final functions in interface Foo"; - enum expected = Diagnostic(Loc(filename, 4, 17), message); + auto expected = Diagnostic(Loc(filename, 4, 17), message); const diagnostics = compiles(code, filename); assert(diagnostics == [expected], "\n" ~ diagnostics.toString); diff --git a/tests/dmd/unit/objc/protocols/optional_methods.d b/tests/dmd/unit/objc/protocols/optional_methods.d index d8f88565781..4a87f85cac6 100644 --- a/tests/dmd/unit/objc/protocols/optional_methods.d +++ b/tests/dmd/unit/objc/protocols/optional_methods.d @@ -129,10 +129,10 @@ unittest } }.stripDelimited; - enum loc = Loc(filename, 5, 20); + Loc loc = Loc(filename, 5, 20); enum message = "Error: function test.Foo.foo only functions with Objective-C linkage can be declared as optional"; enum supplemental = "function is declared with D linkage"; - enum expected = [Diagnostic(loc, message), Diagnostic(loc, supplemental)]; + auto expected = [Diagnostic(loc, message), Diagnostic(loc, supplemental)]; const diagnostics = compiles(code, filename); assert(diagnostics == expected, "\n" ~ diagnostics.toString); @@ -154,9 +154,9 @@ unittest } }.stripDelimited; - enum loc = Loc(filename, 6, 30); + Loc loc = Loc(filename, 6, 30); enum message = "Error: function test.Foo.foo can only declare a function as optional once"; - enum expected = Diagnostic(loc, message); + auto expected = Diagnostic(loc, message); const diagnostics = compiles(code, filename); assert(diagnostics == [expected], "\n" ~ diagnostics.toString); @@ -184,9 +184,9 @@ unittest } }.stripDelimited; - enum loc = Loc(filename, 6, 20); + Loc loc = Loc(filename, 6, 20); - enum expected = [ + auto expected = [ Diagnostic( Loc(filename, 6, 20), "Error: function test.Foo.foo!().foo template cannot be optional" @@ -223,10 +223,10 @@ unittest } }.stripDelimited; - enum loc = Loc(filename, 6, 20); + Loc loc = Loc(filename, 6, 20); enum message = "Error: function test.Foo.foo only functions declared inside interfaces can be optional"; enum supplemental = "function is declared inside class"; - enum expected = [Diagnostic(loc, message), Diagnostic(loc, supplemental)]; + auto expected = [Diagnostic(loc, message), Diagnostic(loc, supplemental)]; const diagnostics = compiles(code, filename); assert(diagnostics == expected, "\n" ~ diagnostics.toString); From 3e133b007f144d7a29dc6d6dfd6e5d7faf5cc0c1 Mon Sep 17 00:00:00 2001 From: Dennis Date: Tue, 9 May 2023 07:55:01 +0200 Subject: [PATCH 019/176] Allocate farg arrays with `new` (dlang/dmd!15204) --- dmd/clone.d | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/dmd/clone.d b/dmd/clone.d index 60e373c502b..3586f20ddbe 100644 --- a/dmd/clone.d +++ b/dmd/clone.d @@ -106,18 +106,18 @@ FuncDeclaration hasIdentityOpAssign(AggregateDeclaration ad, Scope* sc) scope er = new NullExp(ad.loc, ad.type); // dummy rvalue scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue el.type = ad.type; - auto a = Expressions(1); + auto a = new Expressions(1); const errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it. sc = sc.push(); sc.tinst = null; sc.minst = null; - a[0] = er; - auto f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, ArgumentList(&a), FuncResolveFlag.quiet); + (*a)[0] = er; + auto f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, ArgumentList(a), FuncResolveFlag.quiet); if (!f) { - a[0] = el; - f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, ArgumentList(&a), FuncResolveFlag.quiet); + (*a)[0] = el; + f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, ArgumentList(a), FuncResolveFlag.quiet); } sc = sc.pop(); @@ -465,7 +465,7 @@ private FuncDeclaration hasIdentityOpEquals(AggregateDeclaration ad, Scope* sc) */ scope er = new NullExp(ad.loc, null); // dummy rvalue scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue - auto a = Expressions(1); + auto a = new Expressions(1); bool hasIt(Type tthis) { @@ -476,9 +476,9 @@ private FuncDeclaration hasIdentityOpEquals(AggregateDeclaration ad, Scope* sc) FuncDeclaration rfc(Expression e) { - a[0] = e; - a[0].type = tthis; - return resolveFuncCall(ad.loc, sc, eq, null, tthis, ArgumentList(&a), FuncResolveFlag.quiet); + (*a)[0] = e; + (*a)[0].type = tthis; + return resolveFuncCall(ad.loc, sc, eq, null, tthis, ArgumentList(a), FuncResolveFlag.quiet); } f = rfc(er); From 33a4eff9de430591b4b27b54c103a6c10cdac054 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Mon, 8 May 2023 20:06:23 -0700 Subject: [PATCH 020/176] optimize idPool() a bit --- dmd/compiler.d | 4 ++-- dmd/cond.d | 2 +- dmd/declaration.d | 4 +--- dmd/func.d | 2 +- dmd/identifier.d | 21 ++++++++------------- dmd/lexer.d | 2 +- dmd/mtype.d | 2 +- dmd/tokens.d | 2 +- dmd/typesem.d | 2 +- 9 files changed, 17 insertions(+), 24 deletions(-) diff --git a/dmd/compiler.d b/dmd/compiler.d index 1c6f236ba42..403712dd2ed 100644 --- a/dmd/compiler.d +++ b/dmd/compiler.d @@ -401,7 +401,7 @@ private void parseModulePattern(const(char)* modulePattern, MatcherNode* dst, us if (*modulePattern == '.') { assert(modulePattern > idStart, "empty module pattern"); - *dst = MatcherNode(Identifier.idPool(idStart, cast(uint)(modulePattern - idStart))); + *dst = MatcherNode(Identifier.idPool(idStart[0 .. modulePattern - idStart])); modulePattern++; idStart = modulePattern; break; @@ -413,7 +413,7 @@ private void parseModulePattern(const(char)* modulePattern, MatcherNode* dst, us if (*modulePattern == '\0') { assert(modulePattern > idStart, "empty module pattern"); - *lastNode = MatcherNode(Identifier.idPool(idStart, cast(uint)(modulePattern - idStart))); + *lastNode = MatcherNode(Identifier.idPool(idStart[0 .. modulePattern - idStart])); break; } } diff --git a/dmd/cond.d b/dmd/cond.d index c40936c78d1..fcb50e0a648 100644 --- a/dmd/cond.d +++ b/dmd/cond.d @@ -259,7 +259,7 @@ extern (C++) final class StaticForeach : RootObject auto sdecl = new StructDeclaration(loc, sid, false); sdecl.storage_class |= STC.static_; sdecl.members = new Dsymbols(); - auto fid = Identifier.idPool(tupleFieldName.ptr, tupleFieldName.length); + auto fid = Identifier.idPool(tupleFieldName); auto ty = new TypeTypeof(loc, new TupleExp(loc, e)); sdecl.members.push(new VarDeclaration(loc, ty, fid, null, 0)); auto r = cast(TypeStruct)sdecl.type; diff --git a/dmd/declaration.d b/dmd/declaration.d index 0e5df5eb550..b505a99e6d4 100644 --- a/dmd/declaration.d +++ b/dmd/declaration.d @@ -633,9 +633,7 @@ extern (C++) final class TupleDeclaration : Declaration version (none) { buf.printf("_%s_%d", ident.toChars(), i); - const len = buf.offset; - const name = buf.extractSlice().ptr; - auto id = Identifier.idPool(name, len); + auto id = Identifier.idPool(buf.extractSlice()); auto arg = new Parameter(STC.in_, t, id, null); } else diff --git a/dmd/func.d b/dmd/func.d index f234e28c4fd..0801dc7b3de 100644 --- a/dmd/func.d +++ b/dmd/func.d @@ -2764,7 +2764,7 @@ extern (C++) class FuncDeclaration : Declaration */ static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, const(char)* name, StorageClass stc = 0) { - return genCfunc(fparams, treturn, Identifier.idPool(name, cast(uint)strlen(name)), stc); + return genCfunc(fparams, treturn, Identifier.idPool(name[0 .. strlen(name)]), stc); } static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, Identifier id, StorageClass stc = 0) diff --git a/dmd/identifier.d b/dmd/identifier.d index 2233d777770..b1c421c1c59 100644 --- a/dmd/identifier.d +++ b/dmd/identifier.d @@ -274,12 +274,7 @@ nothrow: return idPool(s[0 .. len]); } - extern (D) static Identifier idPool(const(char)[] s) - { - return idPool(s, false); - } - - extern (D) private static Identifier idPool(const(char)[] s, bool isAnonymous) + extern (D) static Identifier idPool(const(char)[] s, bool isAnonymous = false) { auto sv = stringtable.update(s); auto id = sv.value; @@ -291,18 +286,18 @@ nothrow: return id; } - extern (D) static Identifier idPool(const(char)* s, size_t len, int value) - { - return idPool(s[0 .. len], value); - } - - extern (D) static Identifier idPool(const(char)[] s, int value) + /****************************************** + * Used for inserting keywords into the string table. + * Params: + * s = string for keyword + * value = TOK.xxxx for the keyword + */ + extern (D) static void idPool(const(char)[] s, TOK value) { auto sv = stringtable.insert(s, null); assert(sv); auto id = new Identifier(sv.toString(), value); sv.value = id; - return id; } /********************************** diff --git a/dmd/lexer.d b/dmd/lexer.d index 6801b2cb0da..1d5fb7f7d0d 100644 --- a/dmd/lexer.d +++ b/dmd/lexer.d @@ -573,7 +573,7 @@ class Lexer } break; } - Identifier id = Identifier.idPool(cast(char*)t.ptr, cast(uint)(p - t.ptr)); + Identifier id = Identifier.idPool((cast(char*)t.ptr)[0 .. p - t.ptr], false); t.ident = id; t.value = cast(TOK)id.getValue(); diff --git a/dmd/mtype.d b/dmd/mtype.d index badc5795547..06706ecebfa 100644 --- a/dmd/mtype.d +++ b/dmd/mtype.d @@ -2448,7 +2448,7 @@ extern (C++) abstract class Type : ASTNode //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name); assert(0 < length && length < namelen); // don't overflow the buffer - auto id = Identifier.idPool(name, length); + auto id = Identifier.idPool(name[0 .. length]); if (name != namebuf.ptr) free(name); diff --git a/dmd/tokens.d b/dmd/tokens.d index 352c89ef164..58717625cac 100644 --- a/dmd/tokens.d +++ b/dmd/tokens.d @@ -593,7 +593,7 @@ shared static this() nothrow foreach (kw; keywords) { //printf("keyword[%d] = '%s'\n",kw, Token.tochars[kw].ptr); - Identifier.idPool(Token.tochars[kw].ptr, Token.tochars[kw].length, cast(uint)kw); + Identifier.idPool(Token.tochars[kw], kw); } } diff --git a/dmd/typesem.d b/dmd/typesem.d index f0decf2a48d..09eef83ba08 100644 --- a/dmd/typesem.d +++ b/dmd/typesem.d @@ -163,7 +163,7 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb /* Look for what user might have intended */ const p = mt.mutableOf().unSharedOf().toChars(); - auto id = Identifier.idPool(p, cast(uint)strlen(p)); + auto id = Identifier.idPool(p[0 .. strlen(p)]); if (const n = importHint(id.toString())) error(loc, "`%s` is not defined, perhaps `import %.*s;` ?", p, cast(int)n.length, n.ptr); else if (auto s2 = sc.search_correct(id)) From cbef12801c66f58cea032b655861599ead735505 Mon Sep 17 00:00:00 2001 From: Dennis Korpel Date: Tue, 9 May 2023 12:18:53 +0200 Subject: [PATCH 021/176] Fix 23908 - confusing nonexistent import hint on cyclic import --- dmd/dsymbolsem.d | 4 +++- tests/dmd/fail_compilation/imports/spell23908a.d | 3 +++ tests/dmd/fail_compilation/imports/spell23908b.d | 3 +++ tests/dmd/fail_compilation/spell23908.d | 11 +++++++++++ 4 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 tests/dmd/fail_compilation/imports/spell23908a.d create mode 100644 tests/dmd/fail_compilation/imports/spell23908b.d create mode 100644 tests/dmd/fail_compilation/spell23908.d diff --git a/dmd/dsymbolsem.d b/dmd/dsymbolsem.d index 506946fe458..ffbca608d58 100644 --- a/dmd/dsymbolsem.d +++ b/dmd/dsymbolsem.d @@ -1463,7 +1463,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor else { Dsymbol s = imp.mod.search_correct(imp.names[i]); - if (s) + // https://issues.dlang.org/show_bug.cgi?id=23908 + // Don't suggest symbols from the importer's module + if (s && s.parent != importer) imp.mod.error(imp.loc, "import `%s` not found, did you mean %s `%s`?", imp.names[i].toChars(), s.kind(), s.toPrettyChars()); else imp.mod.error(imp.loc, "import `%s` not found", imp.names[i].toChars()); diff --git a/tests/dmd/fail_compilation/imports/spell23908a.d b/tests/dmd/fail_compilation/imports/spell23908a.d new file mode 100644 index 00000000000..4c369e3c46a --- /dev/null +++ b/tests/dmd/fail_compilation/imports/spell23908a.d @@ -0,0 +1,3 @@ +module imports.spell23908a; + +import imports.spell23908b : nonexistent; diff --git a/tests/dmd/fail_compilation/imports/spell23908b.d b/tests/dmd/fail_compilation/imports/spell23908b.d new file mode 100644 index 00000000000..316b4feff01 --- /dev/null +++ b/tests/dmd/fail_compilation/imports/spell23908b.d @@ -0,0 +1,3 @@ +module imports.spell23908b; + +import imports.spell23908a; diff --git a/tests/dmd/fail_compilation/spell23908.d b/tests/dmd/fail_compilation/spell23908.d new file mode 100644 index 00000000000..a7501e1ca54 --- /dev/null +++ b/tests/dmd/fail_compilation/spell23908.d @@ -0,0 +1,11 @@ +/* +EXTRA_FILES: imports/spell23908a.d imports/spell23908b.d +TEST_OUTPUT: +--- +fail_compilation/imports/spell23908a.d(3): Error: module `imports.spell23908b` import `nonexistent` not found +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=23908 + +import imports.spell23908a; From aaa8463d21d2d0bffe45e3c17b263266d023ff36 Mon Sep 17 00:00:00 2001 From: Dennis Korpel Date: Tue, 9 May 2023 14:03:13 +0200 Subject: [PATCH 022/176] Encapsulate `Loc` member access --- dmd/doc.d | 6 +++--- dmd/frontend.h | 14 ++++++++++---- dmd/globals.h | 19 ++++++++++++------- dmd/lexer.d | 6 +++--- dmd/location.d | 34 +++++++++++++++++++++++++++++----- 5 files changed, 57 insertions(+), 22 deletions(-) diff --git a/dmd/doc.d b/dmd/doc.d index a8e6a6260a5..3e60dc4f9d8 100644 --- a/dmd/doc.d +++ b/dmd/doc.d @@ -430,7 +430,7 @@ extern(C++) void gendocfile(Module m) { const ploc = m.md ? &m.md.loc : &m.loc; Loc loc = *ploc; - if (!loc.fileIndex) + if (!loc.filename) loc.filename = srcfilename.ptr; size_t commentlen = strlen(cast(char*)m.comment); @@ -4151,7 +4151,7 @@ private size_t endRowAndTable(ref OutBuffer buf, size_t iStart, size_t iEnd, con private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t offset) { const incrementLoc = loc.linnum == 0 ? 1 : 0; - loc.linnum += incrementLoc; + loc.linnum = loc.linnum + incrementLoc; loc.charnum = 0; //printf("highlightText()\n"); bool leadingBlank = true; @@ -4256,7 +4256,7 @@ private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s lineQuoted = false; tableRowDetected = false; iLineStart = i + 1; - loc.linnum += incrementLoc; + loc.linnum = loc.linnum + incrementLoc; // update the paragraph start if we just entered a macro if (previousMacroLevel < macroLevel && iParagraphStart < iLineStart) diff --git a/dmd/frontend.h b/dmd/frontend.h index c4e1699f83d..0ebb733d789 100644 --- a/dmd/frontend.h +++ b/dmd/frontend.h @@ -377,19 +377,25 @@ enum class MessageStyle : uint8_t struct Loc final { - uint32_t linnum; - uint16_t charnum; +private: + uint32_t _linnum; + uint16_t _charnum; uint16_t fileIndex; +public: static bool showColumns; static MessageStyle messageStyle; static void set(bool showColumns, MessageStyle messageStyle); + uint32_t charnum() const; + uint32_t charnum(uint32_t num); + uint32_t linnum() const; + uint32_t linnum(uint32_t num); const char* filename() const; void filename(const char* name); const char* toChars(bool showColumns = showColumns, MessageStyle messageStyle = messageStyle) const; bool equals(const Loc& loc) const; Loc() : - linnum(), - charnum(), + _linnum(), + _charnum(), fileIndex() { } diff --git a/dmd/globals.h b/dmd/globals.h index 45f14fa51cb..66345acc88b 100644 --- a/dmd/globals.h +++ b/dmd/globals.h @@ -353,10 +353,11 @@ typedef unsigned long long uinteger_t; // file location struct Loc { - unsigned linnum; - unsigned short charnum; +private: + unsigned _linnum; + unsigned short _charnum; unsigned short fileIndex; - +public: static void set(bool showColumns, MessageStyle messageStyle); static bool showColumns; @@ -364,18 +365,22 @@ struct Loc Loc() { - linnum = 0; - charnum = 0; + _linnum = 0; + _charnum = 0; fileIndex = 0; } Loc(const char *filename, unsigned linnum, unsigned charnum) { - this->linnum = linnum; - this->charnum = charnum; + this->linnum(linnum); + this->charnum(charnum); this->filename(filename); } + uint32_t charnum() const; + uint32_t charnum(uint32_t num); + uint32_t linnum() const; + uint32_t linnum(uint32_t num); const char *filename() const; void filename(const char *name); diff --git a/dmd/lexer.d b/dmd/lexer.d index 1d5fb7f7d0d..a878cc9523d 100644 --- a/dmd/lexer.d +++ b/dmd/lexer.d @@ -2672,7 +2672,7 @@ class Lexer return result; } - final Loc loc() pure @nogc + final Loc loc() @nogc { scanloc.charnum = cast(ushort)(1 + p - line); version (LocOffset) @@ -3098,9 +3098,9 @@ class Lexer /************************** * `p` should be at start of next line */ - private void endOfLine() pure @nogc @safe + private void endOfLine() @nogc @safe { - scanloc.linnum++; + scanloc.linnum = scanloc.linnum + 1; line = p; } } diff --git a/dmd/location.d b/dmd/location.d index 08b44a23720..b2b366130ca 100644 --- a/dmd/location.d +++ b/dmd/location.d @@ -37,9 +37,9 @@ debug info etc. */ struct Loc { - uint linnum; /// line number, starting from 1 - ushort charnum; /// utf8 code unit index relative to start of line, starting from 1 - ushort fileIndex; // index into filenames[], starting from 1 (0 means no filename) + private uint _linnum; + private ushort _charnum; + private ushort fileIndex; // index into filenames[], starting from 1 (0 means no filename) version (LocOffset) uint fileOffset; /// utf8 code unit index relative to start of file, starting from 0 @@ -66,11 +66,35 @@ nothrow: extern (D) this(const(char)* filename, uint linnum, uint charnum) { - this.linnum = linnum; - this.charnum = cast(ushort)charnum; + this._linnum = linnum; + this._charnum = cast(ushort) charnum; this.filename = filename; } + /// utf8 code unit index relative to start of line, starting from 1 + extern (C++) uint charnum() const @nogc @safe + { + return _charnum; + } + + /// ditto + extern (C++) uint charnum(uint num) @nogc @safe + { + return _charnum = cast(ushort) num; + } + + /// line number, starting from 1 + extern (C++) uint linnum() const @nogc @safe + { + return _linnum; + } + + /// ditto + extern (C++) uint linnum(uint num) @nogc @safe + { + return _linnum = num; + } + /*** * Returns: filename for this location, null if none */ From 1cf533001b9de35cfa7171720913aaeac70bd913 Mon Sep 17 00:00:00 2001 From: Boris Carvajal Date: Thu, 19 Mar 2020 19:42:16 -0300 Subject: [PATCH 023/176] Fix Issue 20687 - Allow member function address as const initializer of static data --- tests/dmd/runnable/test20687.d | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/dmd/runnable/test20687.d diff --git a/tests/dmd/runnable/test20687.d b/tests/dmd/runnable/test20687.d new file mode 100644 index 00000000000..47c33f17b73 --- /dev/null +++ b/tests/dmd/runnable/test20687.d @@ -0,0 +1,28 @@ +// PERMUTE_ARGS: +// https://issues.dlang.org/show_bug.cgi?id=20687 + +struct S +{ + void foo(){} +} + +void main() +{ + S i; + enum fpe = &S.foo; + const fp = &S.foo; + const dg = &i.foo; + + // Allow these + static dgfp = &S.foo; + static const dgfpc = &S.foo; + static immutable dgfpi = &S.foo; + __gshared dgfpg = &S.foo; + __gshared const dgfpgc = &S.foo; + __gshared immutable dgfpgi = &S.foo; + + static foreach (v; [fp, dgfpc, dgfpi, dgfpgc, dgfpgi]) + static assert(fpe == v); + + assert(fp == dg.funcptr && fp == dgfp && fp == dgfpg); +} From ebc3a677ca04223f9a797792d61320c1cc94011f Mon Sep 17 00:00:00 2001 From: Paul Backus Date: Sun, 23 Apr 2023 15:16:56 -0400 Subject: [PATCH 024/176] Allow `alias this` to use assignment-style syntax When assignment-style syntax for alias declarations was first implemented in DMD 2.061 [1][2], `alias this = identifier;` was accepted as equivalent to the existing `alias identifier this;`. One release later, in DMD 2.062, it was removed. [3] The rationale for this change, given in both the changelog [4] and a related spec PR thread [5], was to allow for the possibility that, in the future, the syntax `alias this = super.this;` might be used to merge a derived class's constructor overload set with that of its base class. However, this proposal was never implemented, and seems to have been abandoned in the intervening years. For the sake of consistency, and since the rationale for its removal no longer applies, this commit reinstates `alias this = identifier;` as valid syntax for an `alias this` declaration. [1] https://github.com/dlang/dmd/pull/1187 [2] https://dlang.org/changelog/2.061.html [3] https://github.com/dlang/dmd/pull/1413 [4] https://dlang.org/changelog/2.062.html [5] https://github.com/dlang/dlang.org/pull/200#issuecomment-11711854 --- dmd/parse.d | 34 +++++++++++---------------- tests/dmd/compilable/aliasdecl.d | 6 ++--- tests/dmd/fail_compilation/diag9574.d | 19 --------------- 3 files changed, 17 insertions(+), 42 deletions(-) delete mode 100644 tests/dmd/fail_compilation/diag9574.d diff --git a/dmd/parse.d b/dmd/parse.d index 6f2896e1455..601c14e3cb7 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -4515,10 +4515,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } if (_init) { - if (isThis) - error(token.loc, "cannot use syntax `alias this = %s`, use `alias %s this` instead", _init.toChars(), _init.toChars()); - else - error("alias cannot have initializer"); + error("alias cannot have initializer"); } v = new AST.AliasDeclaration(aliasLoc, ident, t); @@ -4780,23 +4777,20 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer addComment(s, comment); return a; } - version (none) + /* Look for: + * alias this = identifier; + */ + if (token.value == TOK.this_ && peekNext() == TOK.assign && peekNext2() == TOK.identifier) { - /* Look for: - * alias this = identifier; - */ - if (token.value == TOK.this_ && peekNext() == TOK.assign && peekNext2() == TOK.identifier) - { - check(TOK.this_); - check(TOK.assign); - auto s = new AliasThis(loc, token.ident); - nextToken(); - check(TOK.semicolon, "`alias this = Identifier`"); - auto a = new Dsymbols(); - a.push(s); - addComment(s, comment); - return a; - } + check(TOK.this_); + check(TOK.assign); + auto s = new AST.AliasThis(loc, token.ident); + nextToken(); + check(TOK.semicolon, "`alias this = Identifier`"); + auto a = new AST.Dsymbols(); + a.push(s); + addComment(s, comment); + return a; } /* Look for: * alias identifier = type; diff --git a/tests/dmd/compilable/aliasdecl.d b/tests/dmd/compilable/aliasdecl.d index 5bacbc62347..74a674d43a9 100644 --- a/tests/dmd/compilable/aliasdecl.d +++ b/tests/dmd/compilable/aliasdecl.d @@ -36,12 +36,12 @@ void main() enum a = 1; } - /+ struct S + struct S2 { int value; alias this = value; } - auto s = S(10); + auto s = S2(10); int n = s; - assert(n == 10); +/ + assert(n == 10); } diff --git a/tests/dmd/fail_compilation/diag9574.d b/tests/dmd/fail_compilation/diag9574.d deleted file mode 100644 index b280b3bda92..00000000000 --- a/tests/dmd/fail_compilation/diag9574.d +++ /dev/null @@ -1,19 +0,0 @@ -/* -TEST_OUTPUT: ---- -fail_compilation/diag9574.d(12): Error: cannot use syntax `alias this = x`, use `alias x this` instead -fail_compilation/diag9574.d(18): Error: cannot use syntax `alias this = x`, use `alias x this` instead ---- -*/ - -struct S -{ - int x; - alias this = x; -} - -class C -{ - int x; - alias this = x; -} From 79bb04778071ba08c37e6280b1e99faeb8598096 Mon Sep 17 00:00:00 2001 From: Dennis Korpel Date: Wed, 10 May 2023 15:06:33 +0200 Subject: [PATCH 025/176] Turn overloading extern(C) functions into an error --- dmd/semantic2.d | 4 +-- tests/dmd/compilable/test18385.d | 42 ------------------------- tests/dmd/fail_compilation/fail23626a.d | 2 +- tests/dmd/fail_compilation/fail2789.d | 4 +-- tests/dmd/fail_compilation/test18385.d | 2 +- 5 files changed, 5 insertions(+), 49 deletions(-) delete mode 100644 tests/dmd/compilable/test18385.d diff --git a/dmd/semantic2.d b/dmd/semantic2.d index 440e4cbc8e7..b0b993ca25a 100644 --- a/dmd/semantic2.d +++ b/dmd/semantic2.d @@ -447,14 +447,12 @@ private extern(C++) final class Semantic2Visitor : Visitor const sameParams = tf1.parameterList == tf2.parameterList; // Allow the hack to declare overloads with different parameters/STC's - // @@@DEPRECATED_2.104@@@ - // Deprecated in 2020-08, make this an error in 2.104 if (parent1.isModule() && linkage1 != LINK.d && linkage1 != LINK.cpp && (!sameAttr || !sameParams) ) { - f2.deprecation("cannot overload `extern(%s)` function at %s", + f2.error("cannot overload `extern(%s)` function at %s", linkageToChars(f1._linkage), f1.loc.toChars()); return 0; diff --git a/tests/dmd/compilable/test18385.d b/tests/dmd/compilable/test18385.d deleted file mode 100644 index 5c789cb835c..00000000000 --- a/tests/dmd/compilable/test18385.d +++ /dev/null @@ -1,42 +0,0 @@ -/* -Reduced from the assertion failure in the glue layer when compiling DWT. -A `compilable` test because it needs codegen. - -Remove this test once the deprecation for conflicting deprecations ends, -see visit(FuncDeclaration) in semantic2.d for details. - -TEST_OUTPUT: ---- -compilable/test18385.d(23): Deprecation: function `test18385.is_paragraph_start` cannot overload `extern(C)` function at compilable/test18385.d(22) -compilable/test18385.d(26): Deprecation: function `test18385.foo` cannot overload `extern(C)` function at compilable/test18385.d(25) -compilable/test18385.d(29): Deprecation: function `test18385.trust` cannot overload `extern(C)` function at compilable/test18385.d(28) -compilable/test18385.d(32): Deprecation: function `test18385.purity` cannot overload `extern(C)` function at compilable/test18385.d(31) -compilable/test18385.d(35): Deprecation: function `test18385.nogc` cannot overload `extern(C)` function at compilable/test18385.d(34) -compilable/test18385.d(38): Deprecation: function `test18385.nothrow_` cannot overload `extern(C)` function at compilable/test18385.d(37) -compilable/test18385.d(41): Deprecation: function `test18385.live` cannot overload `extern(C)` function at compilable/test18385.d(40) ---- -*/ - -extern(C) -{ - uint is_paragraph_start(){ return 0; } - uint is_paragraph_start(int){ return 0; } - - void foo(char, bool) {} - void foo(byte, char) {} - - void trust() {} - void trust() @safe {} - - void purity() {} - void purity() pure {} - - void nogc() {} - void nogc() @safe {} - - void nothrow_() {} - void nothrow_() nothrow {} - - void live() {} - void live() @live {} -} diff --git a/tests/dmd/fail_compilation/fail23626a.d b/tests/dmd/fail_compilation/fail23626a.d index 2943f1a6c4f..559e0e2de0a 100644 --- a/tests/dmd/fail_compilation/fail23626a.d +++ b/tests/dmd/fail_compilation/fail23626a.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- fail_compilation/fail23626a.d(10): Deprecation: function `fail23626a.ambig` cannot overload `extern(D)` function at fail_compilation/fail23626a.d(9) -fail_compilation/fail23626a.d(13): Deprecation: function `fail23626a.ambigC` cannot overload `extern(C)` function at fail_compilation/fail23626a.d(12) +fail_compilation/fail23626a.d(13): Error: function `fail23626a.ambigC` cannot overload `extern(C)` function at fail_compilation/fail23626a.d(12) fail_compilation/fail23626a.d(16): Error: function `fail23626a.ambigCxx(int a)` conflicts with previous declaration at fail_compilation/fail23626a.d(15) --- */ diff --git a/tests/dmd/fail_compilation/fail2789.d b/tests/dmd/fail_compilation/fail2789.d index 2d6c8e2651a..261e4126d41 100644 --- a/tests/dmd/fail_compilation/fail2789.d +++ b/tests/dmd/fail_compilation/fail2789.d @@ -61,8 +61,8 @@ auto f6() { return ""; } // string(), conflict TEST_OUTPUT: --- fail_compilation/fail2789.d(67): Error: function `fail2789.f_ExternC1()` conflicts with previous declaration at fail_compilation/fail2789.d(66) -fail_compilation/fail2789.d(70): Deprecation: function `fail2789.f_ExternC2` cannot overload `extern(C)` function at fail_compilation/fail2789.d(69) -fail_compilation/fail2789.d(73): Deprecation: function `fail2789.f_ExternC3` cannot overload `extern(C)` function at fail_compilation/fail2789.d(72) +fail_compilation/fail2789.d(70): Error: function `fail2789.f_ExternC2` cannot overload `extern(C)` function at fail_compilation/fail2789.d(69) +fail_compilation/fail2789.d(73): Error: function `fail2789.f_ExternC3` cannot overload `extern(C)` function at fail_compilation/fail2789.d(72) --- */ diff --git a/tests/dmd/fail_compilation/test18385.d b/tests/dmd/fail_compilation/test18385.d index 3f87885cb91..2e48192ab64 100644 --- a/tests/dmd/fail_compilation/test18385.d +++ b/tests/dmd/fail_compilation/test18385.d @@ -2,7 +2,7 @@ REQUIRED_ARGS: -de TEST_OUTPUT: --- -fail_compilation/test18385.d(13): Deprecation: function `test18385.foo` cannot overload `extern(C)` function at fail_compilation/test18385.d(12) +fail_compilation/test18385.d(13): Error: function `test18385.foo` cannot overload `extern(C)` function at fail_compilation/test18385.d(12) --- */ From bb5f26250b203bf66887344e6626f78e1bfdc705 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Sat, 6 May 2023 18:03:30 +0100 Subject: [PATCH 026/176] Fix Issue 23900 - @safe is allowed in inline asm --- dmd/statementsem.d | 4 +++- tests/dmd/fail_compilation/fail327.d | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/dmd/statementsem.d b/dmd/statementsem.d index 210c29c72ac..734adbde594 100644 --- a/dmd/statementsem.d +++ b/dmd/statementsem.d @@ -3593,7 +3593,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc) cas.error("`asm` statement is assumed to be impure - mark it with `pure` if it is not"); if (!(cas.stc & STC.nogc) && sc.func.setGC(cas.loc, "`asm` statement in %s `%s` is assumed to use the GC - mark it with `@nogc` if it does not")) cas.error("`asm` statement is assumed to use the GC - mark it with `@nogc` if it does not"); - if (!(cas.stc & (STC.trusted | STC.safe))) + if (cas.stc & STC.safe) + cas.error("`asm` statement cannot be marked `@safe`, use `@system` or `@trusted` instead"); + else if (!(cas.stc & (STC.trusted))) { sc.setUnsafe(false, cas.loc, "`asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not"); } diff --git a/tests/dmd/fail_compilation/fail327.d b/tests/dmd/fail_compilation/fail327.d index e476baf4149..b18b1e3c610 100644 --- a/tests/dmd/fail_compilation/fail327.d +++ b/tests/dmd/fail_compilation/fail327.d @@ -1,11 +1,16 @@ /* TEST_OUTPUT: --- -fail_compilation/fail327.d(10): Error: `asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not +fail_compilation/fail327.d(11): Error: `asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not +fail_compilation/fail327.d(12): Error: `asm` statement cannot be marked `@safe`, use `@system` or `@trusted` instead --- */ @safe void foo() { asm { xor EAX,EAX; } + asm @safe + { + mov [RIP], 0; + } } From 61ca15656599ebc2221ba60dd8194a6b660a0f37 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Sat, 6 May 2023 18:18:01 +0100 Subject: [PATCH 027/176] Make it a deprecation first --- dmd/statementsem.d | 7 +++++-- tests/dmd/fail_compilation/fail327.d | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/dmd/statementsem.d b/dmd/statementsem.d index 734adbde594..e0972a3b778 100644 --- a/dmd/statementsem.d +++ b/dmd/statementsem.d @@ -3593,9 +3593,12 @@ Statement statementSemanticVisit(Statement s, Scope* sc) cas.error("`asm` statement is assumed to be impure - mark it with `pure` if it is not"); if (!(cas.stc & STC.nogc) && sc.func.setGC(cas.loc, "`asm` statement in %s `%s` is assumed to use the GC - mark it with `@nogc` if it does not")) cas.error("`asm` statement is assumed to use the GC - mark it with `@nogc` if it does not"); + // @@@DEPRECATED_2.114@@@ + // change deprecation() to error(), add `else` and remove `| STC.safe` + // to turn deprecation into an error when deprecation cycle is over if (cas.stc & STC.safe) - cas.error("`asm` statement cannot be marked `@safe`, use `@system` or `@trusted` instead"); - else if (!(cas.stc & (STC.trusted))) + cas.deprecation("`asm` statement cannot be marked `@safe`, use `@system` or `@trusted` instead"); + if (!(cas.stc & (STC.trusted | STC.safe))) { sc.setUnsafe(false, cas.loc, "`asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not"); } diff --git a/tests/dmd/fail_compilation/fail327.d b/tests/dmd/fail_compilation/fail327.d index b18b1e3c610..f080eaf904e 100644 --- a/tests/dmd/fail_compilation/fail327.d +++ b/tests/dmd/fail_compilation/fail327.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/fail327.d(11): Error: `asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not -fail_compilation/fail327.d(12): Error: `asm` statement cannot be marked `@safe`, use `@system` or `@trusted` instead +fail_compilation/fail327.d(12): Deprecation: `asm` statement cannot be marked `@safe`, use `@system` or `@trusted` instead --- */ From 73af909f9e2857e243f36f056eb19ae1d028fe0e Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Sat, 6 May 2023 18:35:41 +0100 Subject: [PATCH 028/176] Remove deprecated test that is in fail_compilation --- tests/dmd/compilable/test12979a.d | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/dmd/compilable/test12979a.d b/tests/dmd/compilable/test12979a.d index 14ca6efc0ee..77b6def00d4 100644 --- a/tests/dmd/compilable/test12979a.d +++ b/tests/dmd/compilable/test12979a.d @@ -1,5 +1,4 @@ void parse() { asm pure nothrow @nogc @trusted {} - asm @safe {} } From 5720c9b6385b0c6a74e8673c2ff0ca7736c9fe95 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Sat, 6 May 2023 19:05:11 +0100 Subject: [PATCH 029/176] Fix test to show unsafe behaviour --- tests/dmd/fail_compilation/fail327.d | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/dmd/fail_compilation/fail327.d b/tests/dmd/fail_compilation/fail327.d index f080eaf904e..6d387fe6c0e 100644 --- a/tests/dmd/fail_compilation/fail327.d +++ b/tests/dmd/fail_compilation/fail327.d @@ -6,11 +6,14 @@ fail_compilation/fail327.d(12): Deprecation: `asm` statement cannot be marked `@ --- */ -@safe void foo() +@safe void* foo() { asm { xor EAX,EAX; } asm @safe { mov [RIP], 0; } + void* p; +RIP: + return p; } From 52fabd10cef2401e0d26a07f6da5b3ca3b8d7739 Mon Sep 17 00:00:00 2001 From: Dennis Date: Thu, 11 May 2023 08:59:50 +0200 Subject: [PATCH 030/176] Better UFCS failure diagnostic (dlang/dmd!15208) The Windows runners have all completed successfully if you check the azure web page, however, they seem to be stuck in sending the success ACK to github. --- dmd/expression.d | 1 + dmd/expression.h | 1 + dmd/expressionsem.d | 12 +++++++-- dmd/frontend.h | 2 ++ dmd/func.d | 8 ++++++ tests/dmd/fail_compilation/ice11856_1.d | 6 +++-- tests/dmd/fail_compilation/ufcs.d | 34 +++++++++++++++++++++++++ 7 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 tests/dmd/fail_compilation/ufcs.d diff --git a/dmd/expression.d b/dmd/expression.d index dcc03c0d9fc..0b1ebf04cc7 100644 --- a/dmd/expression.d +++ b/dmd/expression.d @@ -5188,6 +5188,7 @@ extern (C++) final class CallExp : UnaExp bool directcall; // true if a virtual call is devirtualized bool inDebugStatement; /// true if this was in a debug statement bool ignoreAttributes; /// don't enforce attributes (e.g. call @gc function in @nogc code) + bool isUfcsRewrite; /// the first argument was pushed in here by a UFCS rewrite VarDeclaration vthis2; // container for multi-context /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around. diff --git a/dmd/expression.h b/dmd/expression.h index a4b18b9fe9e..ead112bbc49 100644 --- a/dmd/expression.h +++ b/dmd/expression.h @@ -839,6 +839,7 @@ class CallExp final : public UnaExp d_bool directcall; // true if a virtual call is devirtualized d_bool inDebugStatement; // true if this was in a debug statement d_bool ignoreAttributes; // don't enforce attributes (e.g. call @gc function in @nogc code) + d_bool isUfcsRewrite; // the first argument was pushed in here by a UFCS rewrite VarDeclaration *vthis2; // container for multi-context static CallExp *create(const Loc &loc, Expression *e, Expressions *exps); diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index cf4aac4a889..32e56e6bb5a 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -653,7 +653,7 @@ private Expression resolveUFCS(Scope* sc, CallExp ce) if (!ce.names) ce.names = new Identifiers(); ce.names.shift(null); - + ce.isUfcsRewrite = true; return null; } @@ -5192,7 +5192,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { s = (cast(TemplateExp)exp.e1).td; L2: - exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.argumentList, FuncResolveFlag.standard); + exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.argumentList, + exp.isUfcsRewrite ? FuncResolveFlag.ufcs : FuncResolveFlag.standard); if (!exp.f || exp.f.errors) return setError(); if (exp.f.needThis()) @@ -5301,6 +5302,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor buf.writeByte(')'); //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco); + if (exp.isUfcsRewrite) + { + const arg = (*exp.argumentList.arguments)[0]; + .error(exp.loc, "no property `%s` for `%s` of type `%s`", exp.f.ident.toChars(), arg.toChars(), arg.type.toChars()); + .errorSupplemental(exp.loc, "the following error occured while looking for a UFCS match"); + } + .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`", exp.f.kind(), exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList), buf.peekChars()); if (failMessage) diff --git a/dmd/frontend.h b/dmd/frontend.h index 0ebb733d789..83f8cb99ef7 100644 --- a/dmd/frontend.h +++ b/dmd/frontend.h @@ -2681,6 +2681,7 @@ enum class FuncResolveFlag : uint8_t standard = 0u, quiet = 1u, overloadOnly = 2u, + ufcs = 4u, }; class InvariantDeclaration final : public FuncDeclaration @@ -7559,6 +7560,7 @@ class CallExp final : public UnaExp bool directcall; bool inDebugStatement; bool ignoreAttributes; + bool isUfcsRewrite; VarDeclaration* vthis2; static CallExp* create(const Loc& loc, Expression* e, Array* exps); static CallExp* create(const Loc& loc, Expression* e); diff --git a/dmd/func.d b/dmd/func.d index 0801dc7b3de..c49a1e8f86e 100644 --- a/dmd/func.d +++ b/dmd/func.d @@ -3246,6 +3246,7 @@ enum FuncResolveFlag : ubyte quiet = 1, /// do not issue error message on no match, just return `null`. overloadOnly = 2, /// only resolve overloads, i.e. do not issue error on ambiguous /// matches and need explicit this. + ufcs = 4, /// trying to resolve UFCS call } /******************************************* @@ -3363,6 +3364,13 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, } // no match, generate an error messages + if (flags & FuncResolveFlag.ufcs) + { + auto arg = (*fargs)[0]; + .error(loc, "no property `%s` for `%s` of type `%s`", s.ident.toChars(), arg.toChars(), arg.type.toChars()); + .errorSupplemental(loc, "the following error occured while looking for a UFCS match"); + } + if (!fd) { // all of overloads are templates diff --git a/tests/dmd/fail_compilation/ice11856_1.d b/tests/dmd/fail_compilation/ice11856_1.d index afee32abfa7..448e629602d 100644 --- a/tests/dmd/fail_compilation/ice11856_1.d +++ b/tests/dmd/fail_compilation/ice11856_1.d @@ -1,8 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/ice11856_1.d(16): Error: template `ice11856_1.g` is not callable using argument types `!()(A)` -fail_compilation/ice11856_1.d(14): Candidate is: `g(T)(T x)` +fail_compilation/ice11856_1.d(18): Error: no property `g` for `A()` of type `A` +fail_compilation/ice11856_1.d(18): the following error occured while looking for a UFCS match +fail_compilation/ice11856_1.d(18): Error: template `ice11856_1.g` is not callable using argument types `!()(A)` +fail_compilation/ice11856_1.d(16): Candidate is: `g(T)(T x)` with `T = A` must satisfy the following constraint: ` is(typeof(x.f()))` diff --git a/tests/dmd/fail_compilation/ufcs.d b/tests/dmd/fail_compilation/ufcs.d new file mode 100644 index 00000000000..501ef81927f --- /dev/null +++ b/tests/dmd/fail_compilation/ufcs.d @@ -0,0 +1,34 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ufcs.d(25): Error: no property `regularF` for `s` of type `S` +fail_compilation/ufcs.d(25): the following error occured while looking for a UFCS match +fail_compilation/ufcs.d(25): Error: function `ufcs.regularF()` is not callable using argument types `(S)` +fail_compilation/ufcs.d(25): expected 0 argument(s), not 1 +fail_compilation/ufcs.d(26): Error: no property `templateF` for `s` of type `S` +fail_compilation/ufcs.d(26): the following error occured while looking for a UFCS match +fail_compilation/ufcs.d(26): Error: template `ufcs.templateF` is not callable using argument types `!()(S)` +fail_compilation/ufcs.d(31): Candidate is: `templateF()()` +fail_compilation/ufcs.d(27): Error: no property `templateO` for `s` of type `S` +fail_compilation/ufcs.d(27): the following error occured while looking for a UFCS match +fail_compilation/ufcs.d(27): Error: none of the overloads of template `ufcs.templateO` are callable using argument types `!()(S)` +fail_compilation/ufcs.d(33): Candidates are: `templateO()(int x)` +fail_compilation/ufcs.d(34): `templateO()(float y)` +--- +*/ + +struct S { } + +void f() +{ + S s; + s.regularF(); + s.templateF(); + s.templateO(); +} + +void regularF(); +void templateF()(); + +void templateO()(int x); +void templateO()(float y); From 2b1d03ff1eac7286fb8ca2b44310db461a5500a6 Mon Sep 17 00:00:00 2001 From: Dennis Date: Thu, 11 May 2023 10:05:26 +0200 Subject: [PATCH 031/176] Don't allocate argument list on the stack (dlang/dmd!15213) --- dmd/expressionsem.d | 8 +++---- dmd/mtype.d | 4 ++-- dmd/opover.d | 52 ++++++++++++++++++++++----------------------- dmd/statementsem.d | 3 +-- 4 files changed, 33 insertions(+), 34 deletions(-) diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index 32e56e6bb5a..6b123d1ecbc 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -1254,12 +1254,12 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = return ErrorExp.get(); e2 = resolveProperties(sc, e2); - Expressions a; + Expressions* a = new Expressions(); a.push(e2); for (size_t i = 0; i < os.a.length; i++) { - if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(&a), FuncResolveFlag.quiet)) + if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(a), FuncResolveFlag.quiet)) { if (f.errors) return ErrorExp.get(); @@ -1378,10 +1378,10 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = return ErrorExp.get(); e2 = resolveProperties(sc, e2); - Expressions a; + Expressions* a = new Expressions(); a.push(e2); - FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(&a), FuncResolveFlag.quiet); + FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(a), FuncResolveFlag.quiet); if (fd && fd.type) { if (fd.errors) diff --git a/dmd/mtype.d b/dmd/mtype.d index 06706ecebfa..cb3e6cddd20 100644 --- a/dmd/mtype.d +++ b/dmd/mtype.d @@ -7119,9 +7119,9 @@ bool isCopyable(Type t) assert(ctor); scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue el.type = cast() ts; - Expressions args; + Expressions* args = new Expressions(); args.push(el); - FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(&args), FuncResolveFlag.quiet); + FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(args), FuncResolveFlag.quiet); if (!f || f.storage_class & STC.disable) return false; } diff --git a/dmd/opover.d b/dmd/opover.d index d7b90d7635f..0e64d9c7c8d 100644 --- a/dmd/opover.d +++ b/dmd/opover.d @@ -607,8 +607,6 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) //printf("BinExp::op_overload() (%s)\n", e.toChars()); Identifier id = opId(e); Identifier id_r = opId_r(e); - Expressions args1; - Expressions args2; int argsset = 0; AggregateDeclaration ad1 = isAggregate(e.e1.type); AggregateDeclaration ad2 = isAggregate(e.e2.type); @@ -701,6 +699,8 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) } } } + Expressions* args1 = new Expressions(); + Expressions* args2 = new Expressions(); if (s || s_r) { /* Try: @@ -709,16 +709,16 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) * and see which is better. */ args1.setDim(1); - args1[0] = e.e1; - expandTuples(&args1); + (*args1)[0] = e.e1; + expandTuples(args1); args2.setDim(1); - args2[0] = e.e2; - expandTuples(&args2); + (*args2)[0] = e.e2; + expandTuples(args2); argsset = 1; MatchAccumulator m; if (s) { - functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(&args2)); + functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(args2)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { return ErrorExp.get(); @@ -727,7 +727,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) FuncDeclaration lastf = m.lastf; if (s_r) { - functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, ArgumentList(&args1)); + functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, ArgumentList(args1)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { return ErrorExp.get(); @@ -791,16 +791,16 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) if (!argsset) { args1.setDim(1); - args1[0] = e.e1; - expandTuples(&args1); + (*args1)[0] = e.e1; + expandTuples(args1); args2.setDim(1); - args2[0] = e.e2; - expandTuples(&args2); + (*args2)[0] = e.e2; + expandTuples(args2); } MatchAccumulator m; if (s_r) { - functionResolve(m, s_r, e.loc, sc, tiargs, e.e1.type, ArgumentList(&args2)); + functionResolve(m, s_r, e.loc, sc, tiargs, e.e1.type, ArgumentList(args2)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { return ErrorExp.get(); @@ -809,7 +809,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) FuncDeclaration lastf = m.lastf; if (s) { - functionResolve(m, s, e.loc, sc, tiargs, e.e2.type, ArgumentList(&args1)); + functionResolve(m, s, e.loc, sc, tiargs, e.e2.type, ArgumentList(args1)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { return ErrorExp.get(); @@ -1197,7 +1197,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) return ErrorExp.get(); } Identifier id = opId(e); - Expressions args2; + Expressions* args2 = new Expressions(); AggregateDeclaration ad1 = isAggregate(e.e1.type); Dsymbol s = null; Objects* tiargs = null; @@ -1240,10 +1240,10 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) * a.opOpAssign(b) */ args2.setDim(1); - args2[0] = e.e2; - expandTuples(&args2); + (*args2)[0] = e.e2; + expandTuples(args2); MatchAccumulator m; - functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(&args2)); + functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(args2)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { return ErrorExp.get(); @@ -1322,12 +1322,12 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop * b.opEquals(a) * and see which is better. */ - Expressions args1 = Expressions(1); - args1[0] = e.e1; - expandTuples(&args1); - Expressions args2 = Expressions(1); - args2[0] = e.e2; - expandTuples(&args2); + Expressions* args1 = new Expressions(1); + (*args1)[0] = e.e1; + expandTuples(args1); + Expressions* args2 = new Expressions(1); + (*args2)[0] = e.e2; + expandTuples(args2); MatchAccumulator m; if (0 && s && s_r) { @@ -1336,7 +1336,7 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop } if (s) { - functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(&args2)); + functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(args2)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) return ErrorExp.get(); } @@ -1344,7 +1344,7 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop int count = m.count; if (s_r) { - functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, ArgumentList(&args1)); + functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, ArgumentList(args1)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) return ErrorExp.get(); } diff --git a/dmd/statementsem.d b/dmd/statementsem.d index e0972a3b778..6174a3448c0 100644 --- a/dmd/statementsem.d +++ b/dmd/statementsem.d @@ -1273,8 +1273,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) } else if (auto td = sfront.isTemplateDeclaration()) { - Expressions a; - if (auto f = resolveFuncCall(loc, sc, td, null, tab, ArgumentList(&a), FuncResolveFlag.quiet)) + if (auto f = resolveFuncCall(loc, sc, td, null, tab, ArgumentList(), FuncResolveFlag.quiet)) tfront = f.type; } else if (auto d = sfront.toAlias().isDeclaration()) From 86faabc3d805ad0ef73d4a290b068d014089254b Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Thu, 11 May 2023 04:06:00 -0700 Subject: [PATCH 032/176] fix Issue 23877 - ImportC: Importing byteswap.h results in undefined reference to core.bitop.byteswap (dlang/dmd!15224) --- runtime/druntime/src/__builtins.di | 3 +-- tests/dmd/runnable/test23877.c | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 tests/dmd/runnable/test23877.c diff --git a/runtime/druntime/src/__builtins.di b/runtime/druntime/src/__builtins.di index 1c490358904..74147a095cd 100644 --- a/runtime/druntime/src/__builtins.di +++ b/runtime/druntime/src/__builtins.di @@ -67,8 +67,7 @@ version (DigitalMars) ushort __builtin_bswap16()(ushort value) { - import core.bitop; - return core.bitop.byteswap(value); + return cast(ushort) (((value >> 8) & 0xFF) | ((value << 8) & 0xFF00U)); } uint __builtin_bswap32()(uint value) diff --git a/tests/dmd/runnable/test23877.c b/tests/dmd/runnable/test23877.c new file mode 100644 index 00000000000..9c667752ed4 --- /dev/null +++ b/tests/dmd/runnable/test23877.c @@ -0,0 +1,23 @@ +// https://issues.dlang.org/show_bug.cgi?id=23877 + +unsigned short __bswap_16 (unsigned short __bsx) +{ + return __builtin_bswap16 (__bsx); +} + +unsigned __bswap_32 (unsigned __bsx) +{ + return __builtin_bswap32 (__bsx); +} + +unsigned long long __bswap_64 (unsigned long long __bsx) +{ + return __builtin_bswap64 (__bsx); +} + +int main() +{ + unsigned short y = 0x1234; + unsigned short x = __bswap_16(y); + return x - 0x3412; +} From 33d5523dcd23c3fff3ed3cf7752a367e6646128d Mon Sep 17 00:00:00 2001 From: Razvan Nitu Date: Thu, 11 May 2023 17:16:13 +0300 Subject: [PATCH 033/176] Delete unused enforceTypedArrayConformable from druntime/src/core/internal/util/array.d (dlang/dmd!15225) --- runtime/druntime/src/core/internal/util/array.d | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/runtime/druntime/src/core/internal/util/array.d b/runtime/druntime/src/core/internal/util/array.d index 6136cfef17d..066ee7e72db 100644 --- a/runtime/druntime/src/core/internal/util/array.d +++ b/runtime/druntime/src/core/internal/util/array.d @@ -26,14 +26,6 @@ private char[] errorMessage(Args...)(scope const(char*) format, @safe /* pure dmd @@@BUG11461@@@ */ nothrow: -void enforceTypedArraysConformable(T)(const char[] action, - const T[] a1, const T[] a2, const bool allowOverlap = false) -{ - _enforceSameLength(action, a1.length, a2.length); - if (!allowOverlap) - _enforceNoOverlap(action, arrayToPtr(a1), arrayToPtr(a2), T.sizeof * a1.length); -} - void enforceRawArraysConformable(const char[] action, const size_t elementSize, const void[] a1, const void[] a2, const bool allowOverlap = false) { @@ -76,14 +68,6 @@ private void _enforceNoOverlap(const char[] action, assert(0, msg); } -void enforceTypedArraysConformableNogc(T)(const char[] action, - const T[] a1, const T[] a2, const bool allowOverlap = false) -{ - _enforceSameLengthNogc(action, a1.length, a2.length); - if (!allowOverlap) - _enforceNoOverlapNogc(action, arrayToPtr(a1), arrayToPtr(a2), T.sizeof * a1.length); -} - void enforceRawArraysConformableNogc(const char[] action, const size_t elementSize, const void[] a1, const void[] a2, const bool allowOverlap = false) { From d7bf213b31879202341c4152cc0a9575c917fcf8 Mon Sep 17 00:00:00 2001 From: Dennis Date: Thu, 11 May 2023 21:29:17 +0200 Subject: [PATCH 034/176] Replace gluelayer prototypes with imports (dlang/dmd!15229) --- dmd/gluelayer.d | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/dmd/gluelayer.d b/dmd/gluelayer.d index 7b52eff663d..4768e4c6b23 100644 --- a/dmd/gluelayer.d +++ b/dmd/gluelayer.d @@ -54,18 +54,9 @@ else version (MARS) public import dmd.backend.type : type; public import dmd.backend.el : elem; public import dmd.backend.code_x86 : code; - - extern (C++) - { - Statement asmSemantic(AsmStatement s, Scope* sc); - - void toObjFile(Dsymbol ds, bool multiobj); - - extern(C++) abstract class ObjcGlue - { - static void initialize(); - } - } + public import dmd.iasm : asmSemantic; + public import dmd.objc_glue : ObjcGlue; + public import dmd.toobj : toObjFile; } else version (IN_GCC) { From 1555e57cfa4ba974b0b645a34f54c3348eaacdbd Mon Sep 17 00:00:00 2001 From: Nicholas Wilson Date: Thu, 26 May 2022 16:06:12 +0800 Subject: [PATCH 035/176] move apply from apply to aggregate apply is only used by aggregate.d, dclass.d, and tocvdebug.d and doesn't really belong in apply which should probably be named postorderVisitor --- dmd/aggregate.d | 48 +++++++++++++++++++++++++++++++++++++++--------- dmd/apply.d | 35 ----------------------------------- dmd/dclass.d | 8 ++++---- dmd/dsymbolsem.d | 7 ++++--- 4 files changed, 47 insertions(+), 51 deletions(-) diff --git a/dmd/aggregate.d b/dmd/aggregate.d index 1306a104fff..b9526affcfb 100644 --- a/dmd/aggregate.d +++ b/dmd/aggregate.d @@ -764,21 +764,18 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol if (s) { // Finish all constructors semantics to determine this.noDefaultCtor. - struct SearchCtor + static int searchCtor(Dsymbol s, void*) { - extern (C++) static int fp(Dsymbol s, void* ctxt) - { - auto f = s.isCtorDeclaration(); - if (f && f.semanticRun == PASS.initial) - f.dsymbolSemantic(null); - return 0; - } + auto f = s.isCtorDeclaration(); + if (f && f.semanticRun == PASS.initial) + f.dsymbolSemantic(null); + return 0; } for (size_t i = 0; i < members.length; i++) { auto sm = (*members)[i]; - sm.apply(&SearchCtor.fp, null); + sm.apply(&searchCtor, null); } } return s; @@ -814,3 +811,36 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol v.visit(this); } } + +/********************************* + * Iterate this dsymbol or members of this scoped dsymbol, then + * call `fp` with the found symbol and `params`. + * Params: + * symbol = the dsymbol or parent of members to call fp on + * fp = function pointer to process the iterated symbol. + * If it returns nonzero, the iteration will be aborted. + * ctx = context parameter passed to fp. + * Returns: + * nonzero if the iteration is aborted by the return value of fp, + * or 0 if it's completed. + */ +int apply(Dsymbol symbol, int function(Dsymbol, void*) fp, void* ctx) +{ + if (auto nd = symbol.isNspace()) + { + return nd.members.foreachDsymbol( (s) { return s && s.apply(fp, ctx); } ); + } + if (auto ad = symbol.isAttribDeclaration()) + { + return ad.include(ad._scope).foreachDsymbol( (s) { return s && s.apply(fp, ctx); } ); + } + if (auto tm = symbol.isTemplateMixin()) + { + if (tm._scope) // if fwd reference + dsymbolSemantic(tm, null); // try to resolve it + + return tm.members.foreachDsymbol( (s) { return s && s.apply(fp, ctx); } ); + } + + return fp(symbol, ctx); +} diff --git a/dmd/apply.d b/dmd/apply.d index d18b81f044f..77aa6b70824 100644 --- a/dmd/apply.d +++ b/dmd/apply.d @@ -12,8 +12,6 @@ module dmd.apply; import dmd.arraytypes; -import dmd.dsymbol; -import dmd.dsymbolsem; import dmd.dtemplate; import dmd.expression; import dmd.root.array; @@ -26,39 +24,6 @@ bool walkPostorder(Expression e, StoppableVisitor v) return v.stop; } -/********************************* - * Iterate this dsymbol or members of this scoped dsymbol, then - * call `fp` with the found symbol and `params`. - * Params: - * symbol = the dsymbol or parent of members to call fp on - * fp = function pointer to process the iterated symbol. - * If it returns nonzero, the iteration will be aborted. - * params = any parameters passed to fp. - * Returns: - * nonzero if the iteration is aborted by the return value of fp, - * or 0 if it's completed. - */ -int apply(FP, Params...)(Dsymbol symbol, FP fp, Params params) -{ - if (auto nd = symbol.isNspace()) - { - return nd.members.foreachDsymbol( (s) { return s && s.apply(fp, params); } ); - } - if (auto ad = symbol.isAttribDeclaration()) - { - return ad.include(ad._scope).foreachDsymbol( (s) { return s && s.apply(fp, params); } ); - } - if (auto tm = symbol.isTemplateMixin()) - { - if (tm._scope) // if fwd reference - dsymbolSemantic(tm, null); // try to resolve it - - return tm.members.foreachDsymbol( (s) { return s && s.apply(fp, params); } ); - } - - return fp(symbol, params); -} - /************************************** * An Expression tree walker that will visit each Expression e in the tree, * in depth-first evaluation order, and call fp(e,param) on it. diff --git a/dmd/dclass.d b/dmd/dclass.d index e4585934089..c53a063a229 100644 --- a/dmd/dclass.d +++ b/dmd/dclass.d @@ -867,7 +867,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration * Resolve forward references to all class member functions, * and determine whether this class is abstract. */ - static int func(Dsymbol s) + static int func(Dsymbol s, void*) { auto fd = s.isFuncDeclaration(); if (!fd) @@ -883,7 +883,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration for (size_t i = 0; i < members.length; i++) { auto s = (*members)[i]; - if (s.apply(&func)) + if (s.apply(&func, null)) { return yes(); } @@ -910,7 +910,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration * each of the virtual functions, * which will fill in the vtbl[] overrides. */ - static int virtualSemantic(Dsymbol s) + static int virtualSemantic(Dsymbol s, void*) { auto fd = s.isFuncDeclaration(); if (fd && !(fd.storage_class & STC.static_) && !fd.isUnitTestDeclaration()) @@ -921,7 +921,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration for (size_t i = 0; i < members.length; i++) { auto s = (*members)[i]; - s.apply(&virtualSemantic); + s.apply(&virtualSemantic,null); } } diff --git a/dmd/dsymbolsem.d b/dmd/dsymbolsem.d index ffbca608d58..b88f5515b8b 100644 --- a/dmd/dsymbolsem.d +++ b/dmd/dsymbolsem.d @@ -7126,8 +7126,9 @@ bool determineFields(AggregateDeclaration ad) // determineFields can be called recursively from one of the fields's v.semantic ad.fields.setDim(0); - static int func(Dsymbol s, AggregateDeclaration ad) + static int func(Dsymbol s, void* ctx) { + auto ad = cast(AggregateDeclaration)ctx; auto v = s.isVarDeclaration(); if (!v) return 0; @@ -7143,7 +7144,7 @@ bool determineFields(AggregateDeclaration ad) if (v.aliasTuple) { // If this variable was really a tuple, process each element. - return v.aliasTuple.foreachVar(tv => tv.apply(&func, ad)); + return v.aliasTuple.foreachVar(tv => tv.apply(&func, cast(void*) ad)); } if (v.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.ctfe | STC.templateparameter)) @@ -7175,7 +7176,7 @@ bool determineFields(AggregateDeclaration ad) for (size_t i = 0; i < ad.members.length; i++) { auto s = (*ad.members)[i]; - if (s.apply(&func, ad)) + if (s.apply(&func, cast(void *)ad)) { if (ad.sizeok != Sizeok.none) { From cc90d6b3eac9007d004eb8d74940157170b4f6b8 Mon Sep 17 00:00:00 2001 From: Teodor Dutu Date: Fri, 12 May 2023 11:29:10 +0300 Subject: [PATCH 036/176] Translate `_d_newitem{U,T,iT}` to a single template (dlang/dmd!14664) This makes the following changes: - Replace `_d_newitem{U,T,iT}` with a template `_d_newitemT` that allocates memory for the new `struct` and performs the required initialisation - Move lowering call to `_d_newitemT` from e2ir.d to expressionsem.d - Add `lowering` field to `NewExp` that contains the lowered call and use it in e2ir.d - Remove `_d_newitem{,i}T` from rt.lifetime Signed-off-by: Teodor Dutu --- dmd/expression.d | 7 +- dmd/expressionsem.d | 47 +++++ dmd/frontend.h | 2 + dmd/id.d | 2 + runtime/druntime/src/core/lifetime.d | 197 +++++++++++++++++- runtime/druntime/src/object.d | 2 + runtime/druntime/src/rt/lifetime.d | 122 +---------- runtime/druntime/src/rt/tracegc.d | 2 - runtime/druntime/test/profile/bothgc.log.exp | 3 +- runtime/druntime/test/profile/bothnew.def.exp | 3 + .../profile/myprofilegc.log.freebsd.32.exp | 2 + .../profile/myprofilegc.log.freebsd.64.exp | 2 + .../test/profile/myprofilegc.log.linux.32.exp | 2 + .../test/profile/myprofilegc.log.linux.64.exp | 2 + .../test/profile/myprofilegc.log.osx.32.exp | 2 + .../test/profile/myprofilegc.log.osx.64.exp | 2 + 16 files changed, 268 insertions(+), 131 deletions(-) diff --git a/dmd/expression.d b/dmd/expression.d index 0b1ebf04cc7..412764ae975 100644 --- a/dmd/expression.d +++ b/dmd/expression.d @@ -1530,6 +1530,11 @@ extern (C++) abstract class Expression : ASTNode return false; if (sc.flags & (SCOPE.ctfe | SCOPE.debug_)) return false; + /* The original expression (`new S(...)`) will be verified instead. This + * is to keep errors related to the original code and not the lowering. + */ + if (f.ident == Id._d_newitemT) + return false; if (!f.isNogc()) { @@ -3672,7 +3677,7 @@ extern (C++) final class NewExp : Expression bool onstack; // allocate on stack bool thrownew; // this NewExp is the expression of a ThrowStatement - Expression lowering; // lowered druntime hook: `_d_newclass` + Expression lowering; // lowered druntime hook: `_d_new{class,itemT}` /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around. /// The fields are still separate for backwards compatibility diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index 6b123d1ecbc..3e89c71476b 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -3574,6 +3574,51 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = exp; } + /** + * Sets the `lowering` field of a `NewExp` to a call to `_d_newitemT` unless + * compiling with `-betterC` or within `__traits(compiles)`. + * + * Params: + * ne = the `NewExp` to lower + */ + private void tryLowerToNewItem(NewExp ne) + { + if (global.params.betterC || !sc.needsCodegen()) + return; + + auto hook = global.params.tracegc ? Id._d_newitemTTrace : Id._d_newitemT; + if (!verifyHookExist(ne.loc, *sc, hook, "new struct")) + return; + + /* Lower the memory allocation and initialization of `new T()` to + * `_d_newitemT!T()`. + */ + Expression id = new IdentifierExp(ne.loc, Id.empty); + id = new DotIdExp(ne.loc, id, Id.object); + auto tiargs = new Objects(); + /* + * Remove `inout`, `const`, `immutable` and `shared` to reduce the + * number of generated `_d_newitemT` instances. + */ + auto t = ne.type.nextOf.unqualify(MODFlags.wild | MODFlags.const_ | + MODFlags.immutable_ | MODFlags.shared_); + tiargs.push(t); + id = new DotTemplateInstanceExp(ne.loc, id, hook, tiargs); + + auto arguments = new Expressions(); + if (global.params.tracegc) + { + auto funcname = (sc.callsc && sc.callsc.func) ? + sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); + arguments.push(new StringExp(ne.loc, ne.loc.filename.toDString())); + arguments.push(new IntegerExp(ne.loc, ne.loc.linnum, Type.tint32)); + arguments.push(new StringExp(ne.loc, funcname.toDString())); + } + id = new CallExp(ne.loc, id, arguments); + + ne.lowering = id.expressionSemantic(sc); + } + override void visit(NewExp exp) { static if (LOGSEMANTIC) @@ -4007,6 +4052,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } exp.type = exp.type.pointerTo(); + tryLowerToNewItem(exp); } else if (tb.ty == Tarray) { @@ -4078,6 +4124,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } exp.type = exp.type.pointerTo(); + tryLowerToNewItem(exp); } else if (tb.ty == Taarray) { diff --git a/dmd/frontend.h b/dmd/frontend.h index 83f8cb99ef7..f73d1bd55c8 100644 --- a/dmd/frontend.h +++ b/dmd/frontend.h @@ -8725,6 +8725,8 @@ struct Id final static Identifier* _d_newThrowable; static Identifier* _d_newclassT; static Identifier* _d_newclassTTrace; + static Identifier* _d_newitemT; + static Identifier* _d_newitemTTrace; static Identifier* _d_assert_fail; static Identifier* dup; static Identifier* _aaApply; diff --git a/dmd/id.d b/dmd/id.d index 9ff97dccbaf..a2daf6064d3 100644 --- a/dmd/id.d +++ b/dmd/id.d @@ -315,6 +315,8 @@ immutable Msgtable[] msgtable = { "_d_newThrowable" }, { "_d_newclassT" }, { "_d_newclassTTrace" }, + { "_d_newitemT" }, + { "_d_newitemTTrace" }, { "_d_assert_fail" }, { "dup" }, { "_aaApply" }, diff --git a/runtime/druntime/src/core/lifetime.d b/runtime/druntime/src/core/lifetime.d index 5e339c041d1..ae047cb730e 100644 --- a/runtime/druntime/src/core/lifetime.d +++ b/runtime/druntime/src/core/lifetime.d @@ -2777,6 +2777,70 @@ if (is(T == class)) return cast(T) p; } +/** + * TraceGC wrapper around $(REF _d_newclassT, core,lifetime). + */ +T _d_newclassTTrace(T)(string file, int line, string funcname) @trusted +{ + version (D_TypeInfo) + { + import core.internal.array.utils : TraceHook, gcStatsPure, accumulatePure; + mixin(TraceHook!(T.stringof, "_d_newclassT")); + + return _d_newclassT!T(); + } + else + assert(0, "Cannot create new class if compiling without support for runtime type information!"); +} + +/** + * Allocate an initialized non-array item. + * + * This is an optimization to avoid things needed for arrays like the __arrayPad(size). + * Used to allocate struct instances on the heap. + * + * --- + * struct Sz {int x = 0;} + * struct Si {int x = 3;} + * + * void main() + * { + * new Sz(); // uses zero-initialization + * new Si(); // uses Si.init + * } + * --- + * + * Returns: + * newly allocated item + */ +T* _d_newitemT(T)() @trusted +{ + import core.internal.lifetime : emplaceInitializer; + import core.internal.traits : hasElaborateDestructor, hasIndirections; + import core.memory : GC; + + auto flags = !hasIndirections!T ? GC.BlkAttr.NO_SCAN : GC.BlkAttr.NONE; + immutable tiSize = hasElaborateDestructor!T ? size_t.sizeof : 0; + immutable itemSize = T.sizeof; + immutable totalSize = itemSize + tiSize; + if (tiSize) + flags |= GC.BlkAttr.STRUCTFINAL | GC.BlkAttr.FINALIZE; + + auto blkInfo = GC.qalloc(totalSize, flags, null); + auto p = blkInfo.base; + + if (tiSize) + { + // The GC might not have cleared the padding area in the block. + *cast(TypeInfo*) (p + (itemSize & ~(size_t.sizeof - 1))) = null; + *cast(TypeInfo*) (p + blkInfo.size - tiSize) = cast() typeid(T); + } + + emplaceInitializer(*(cast(T*) p)); + + return cast(T*) p; +} + // Test allocation @safe unittest { @@ -2805,15 +2869,134 @@ if (is(T == class)) } } -T _d_newclassTTrace(T)(string file, int line, string funcname) @trusted +// Test allocation +@safe unittest +{ + struct S { } + S* s = _d_newitemT!S(); + + assert(s !is null); +} + +// Test initializers +@safe unittest { - version (D_TypeInfo) { - import core.internal.array.utils: TraceHook, gcStatsPure, accumulatePure; - mixin(TraceHook!(T.stringof, "_d_newclassT")); + // zero-initialization + struct S { int x, y; } + S* s = _d_newitemT!S(); - return _d_newclassT!T(); + assert(s.x == 0); + assert(s.y == 0); + } + { + // S.init + struct S { int x = 2, y = 3; } + S* s = _d_newitemT!S(); + + assert(s.x == 2); + assert(s.y == 3); + } +} + +// Test GC attributes +version (CoreUnittest) +{ + struct S1 + { + int x = 5; + } + struct S2 + { + int x; + this(int x) { this.x = x; } + } + struct S3 + { + int[4] x; + this(int x) { this.x[] = x; } + } + struct S4 + { + int *x; + } + +} +@system unittest +{ + import core.memory : GC; + + auto s1 = new S1; + assert(s1.x == 5); + assert(GC.getAttr(s1) == GC.BlkAttr.NO_SCAN); + + auto s2 = new S2(3); + assert(s2.x == 3); + assert(GC.getAttr(s2) == GC.BlkAttr.NO_SCAN); + + auto s3 = new S3(1); + assert(s3.x == [1, 1, 1, 1]); + assert(GC.getAttr(s3) == GC.BlkAttr.NO_SCAN); + debug(SENTINEL) {} else + assert(GC.sizeOf(s3) == 16); + + auto s4 = new S4; + assert(s4.x == null); + assert(GC.getAttr(s4) == 0); +} + +// Test struct finalizers exception handling +debug(SENTINEL) {} else +@system unittest +{ + import core.memory : GC; + + bool test(E)() + { + import core.exception; + static struct S1 + { + E exc; + ~this() { throw exc; } + } + + bool caught = false; + S1* s = new S1(new E("test onFinalizeError")); + try + { + GC.runFinalizers((cast(char*)(typeid(S1).xdtor))[0 .. 1]); + } + catch (FinalizeError err) + { + caught = true; + } + catch (E) + { + } + GC.free(s); + return caught; + } + + assert(test!Exception); + import core.exception : InvalidMemoryOperationError; + assert(!test!InvalidMemoryOperationError); +} + +version (D_ProfileGC) +{ + /** + * TraceGC wrapper around $(REF _d_newitemT, core,lifetime). + */ + T* _d_newitemTTrace(T)(string file, int line, string funcname) @trusted + { + version (D_TypeInfo) + { + import core.internal.array.utils : TraceHook, gcStatsPure, accumulatePure; + mixin(TraceHook!(T.stringof, "_d_newitemT")); + + return _d_newitemT!T(); + } + else + assert(0, "Cannot create new `struct` if compiling without support for runtime type information!"); } - else - assert(0, "Cannot create new class if compiling without support for runtime type information!"); } diff --git a/runtime/druntime/src/object.d b/runtime/druntime/src/object.d index 610cb7a30a1..3b3cdda7a68 100644 --- a/runtime/druntime/src/object.d +++ b/runtime/druntime/src/object.d @@ -4532,6 +4532,7 @@ version (D_ProfileGC) { public import core.internal.array.appending : _d_arrayappendTTrace; public import core.internal.array.concatenation : _d_arraycatnTXTrace; + public import core.lifetime : _d_newitemTTrace; } public import core.internal.array.appending : _d_arrayappendcTXImpl; public import core.internal.array.comparison : __cmp; @@ -4560,6 +4561,7 @@ public import core.lifetime : _d_delstructImpl; public import core.lifetime : _d_newThrowable; public import core.lifetime : _d_newclassT; public import core.lifetime : _d_newclassTTrace; +public import core.lifetime : _d_newitemT; public @trusted @nogc nothrow pure extern (C) void _d_delThrowable(scope Throwable); diff --git a/runtime/druntime/src/rt/lifetime.d b/runtime/druntime/src/rt/lifetime.d index a37541bf01f..947bdee245f 100644 --- a/runtime/druntime/src/rt/lifetime.d +++ b/runtime/druntime/src/rt/lifetime.d @@ -1148,25 +1148,8 @@ extern (C) void[] _d_newarraymiTX(const TypeInfo ti, size_t[] dims) @weak } /** -Allocate an uninitialized non-array item. - -This is an optimization to avoid things needed for arrays like the __arrayPad(size). - -- `_d_newitemU` leaves the item uninitialized -- `_d_newitemT` zero initializes the item -- `_d_newitemiT` uses a non-zero initializer from `TypeInfo` - -Used to allocate struct instances on the heap. ---- -struct Sz {int x = 0;} -struct Si {int x = 3;} - -void main() -{ - new Sz(); // _d_newitemT(typeid(Sz)) - new Si(); // _d_newitemiT(typeid(Si)) -} ---- +Non-template version of $(REF _d_newitemT, core,lifetime) that does not perform +initialization. Needed for $(REF allocEntry, rt,aaA). Params: _ti = `TypeInfo` of item to allocate @@ -1196,26 +1179,6 @@ extern (C) void* _d_newitemU(scope const TypeInfo _ti) pure nothrow @weak return p; } -/// ditto -extern (C) void* _d_newitemT(const TypeInfo _ti) pure nothrow @weak -{ - import core.stdc.string; - auto p = _d_newitemU(_ti); - memset(p, 0, _ti.tsize); - return p; -} - -/// Same as above, for item with non-zero initializer. -extern (C) void* _d_newitemiT(const TypeInfo _ti) pure nothrow @weak -{ - import core.stdc.string; - auto p = _d_newitemU(_ti); - auto init = _ti.initializer(); - assert(init.length <= _ti.tsize); - memcpy(p, init.ptr, init.length); - return p; -} - debug(PRINTF) { extern(C) void printArrayCache() @@ -2361,52 +2324,6 @@ unittest testPostBlit!(const(S))(); } -// cannot define structs inside unit test block, or they become nested structs. -version (CoreUnittest) -{ - struct S1 - { - int x = 5; - } - struct S2 - { - int x; - this(int x) {this.x = x;} - } - struct S3 - { - int[4] x; - this(int x) - {this.x[] = x;} - } - struct S4 - { - int *x; - } - -} - -unittest -{ - auto s1 = new S1; - assert(s1.x == 5); - assert(GC.getAttr(s1) == BlkAttr.NO_SCAN); - - auto s2 = new S2(3); - assert(s2.x == 3); - assert(GC.getAttr(s2) == BlkAttr.NO_SCAN); - - auto s3 = new S3(1); - assert(s3.x == [1,1,1,1]); - assert(GC.getAttr(s3) == BlkAttr.NO_SCAN); - debug(SENTINEL) {} else - assert(GC.sizeOf(s3) == 16); - - auto s4 = new S4; - assert(s4.x == null); - assert(GC.getAttr(s4) == 0); -} - unittest { // Bugzilla 3454 - Inconsistent flag setting in GC.realloc() @@ -2731,41 +2648,6 @@ unittest assert(!test!InvalidMemoryOperationError); } -// test struct finalizers exception handling -debug(SENTINEL) {} else -unittest -{ - bool test(E)() - { - import core.exception; - static struct S1 - { - E exc; - ~this() { throw exc; } - } - - bool caught = false; - S1* s = new S1(new E("test onFinalizeError")); - try - { - GC.runFinalizers((cast(char*)(typeid(S1).xdtor))[0..1]); - } - catch (FinalizeError err) - { - caught = true; - } - catch (E) - { - } - GC.free(s); - return caught; - } - - assert( test!Exception); - import core.exception : InvalidMemoryOperationError; - assert(!test!InvalidMemoryOperationError); -} - // test bug 14126 unittest { diff --git a/runtime/druntime/src/rt/tracegc.d b/runtime/druntime/src/rt/tracegc.d index ab65cb9887a..2864a7d724f 100644 --- a/runtime/druntime/src/rt/tracegc.d +++ b/runtime/druntime/src/rt/tracegc.d @@ -22,8 +22,6 @@ extern (C) void[] _d_newarrayU(const scope TypeInfo ti, size_t length); extern (C) void[] _d_newarrayiT(const TypeInfo ti, size_t length); extern (C) void[] _d_newarraymTX(const TypeInfo ti, size_t[] dims); extern (C) void[] _d_newarraymiTX(const TypeInfo ti, size_t[] dims); -extern (C) void* _d_newitemT(const TypeInfo ti); -extern (C) void* _d_newitemiT(const TypeInfo ti); extern (C) void _d_callfinalizer(void* p); extern (C) void _d_callinterfacefinalizer(void *p); extern (C) void _d_delclass(Object* p); diff --git a/runtime/druntime/test/profile/bothgc.log.exp b/runtime/druntime/test/profile/bothgc.log.exp index 884f24c2a30..3cb975fc0d7 100644 --- a/runtime/druntime/test/profile/bothgc.log.exp +++ b/runtime/druntime/test/profile/bothgc.log.exp @@ -1,2 +1,3 @@ bytes allocated, allocations, type, function, file:line - 16000 1000 both.Num both.foo src/both.d:15 + 16000 1000 Num both.foo src/both.d:15 + 16000 1000 void[] core.lifetime._d_newitemT!(Num)._d_newitemT ../../src/core/lifetime.d:2829 diff --git a/runtime/druntime/test/profile/bothnew.def.exp b/runtime/druntime/test/profile/bothnew.def.exp index 502c3a41ee0..c6b652b5b45 100644 --- a/runtime/druntime/test/profile/bothnew.def.exp +++ b/runtime/druntime/test/profile/bothnew.def.exp @@ -3,3 +3,6 @@ FUNCTIONS _Dmain _D4both3fooFkZPSQo3Num _D4both3Num6__ctorMFNckZSQxQu + _D4core8internal8lifetime__T18emplaceInitializerTS4both3NumZQBgFNaNbNiNeMKQzZv + _D4core8lifetime__T11_d_newitemTTS4both3NumZQzFNaNbNeZPQw + _D4core8lifetime__T16_d_newitemTTraceTS4both3NumZQBeFNaNbNeAyaiQeZPQBd diff --git a/runtime/druntime/test/profile/myprofilegc.log.freebsd.32.exp b/runtime/druntime/test/profile/myprofilegc.log.freebsd.32.exp index 15b5e41fd7c..cbd9e21cf10 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.freebsd.32.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.freebsd.32.exp @@ -17,4 +17,6 @@ bytes allocated, allocations, type, function, file:line 16 1 int[] D main src/profilegc.d:22 16 1 int[] D main src/profilegc.d:37 16 1 profilegc.main.C core.lifetime._d_newclassT!(C)._d_newclassT ../../src/core/lifetime.d:2755 + 16 1 void[] core.lifetime._d_newitemT!float._d_newitemT ../../src/core/lifetime.d:2829 + 16 1 void[] core.lifetime._d_newitemT!int._d_newitemT ../../src/core/lifetime.d:2829 16 1 wchar[] D main src/profilegc.d:35 diff --git a/runtime/druntime/test/profile/myprofilegc.log.freebsd.64.exp b/runtime/druntime/test/profile/myprofilegc.log.freebsd.64.exp index 79c86edcfb3..b93a332a8cf 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.freebsd.64.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.freebsd.64.exp @@ -17,4 +17,6 @@ bytes allocated, allocations, type, function, file:line 16 1 int[] D main src/profilegc.d:14 16 1 int[] D main src/profilegc.d:22 16 1 int[] D main src/profilegc.d:37 + 16 1 void[] core.lifetime._d_newitemT!float._d_newitemT ../../src/core/lifetime.d:2829 + 16 1 void[] core.lifetime._d_newitemT!int._d_newitemT ../../src/core/lifetime.d:2829 16 1 wchar[] D main src/profilegc.d:35 diff --git a/runtime/druntime/test/profile/myprofilegc.log.linux.32.exp b/runtime/druntime/test/profile/myprofilegc.log.linux.32.exp index 15b5e41fd7c..cbd9e21cf10 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.linux.32.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.linux.32.exp @@ -17,4 +17,6 @@ bytes allocated, allocations, type, function, file:line 16 1 int[] D main src/profilegc.d:22 16 1 int[] D main src/profilegc.d:37 16 1 profilegc.main.C core.lifetime._d_newclassT!(C)._d_newclassT ../../src/core/lifetime.d:2755 + 16 1 void[] core.lifetime._d_newitemT!float._d_newitemT ../../src/core/lifetime.d:2829 + 16 1 void[] core.lifetime._d_newitemT!int._d_newitemT ../../src/core/lifetime.d:2829 16 1 wchar[] D main src/profilegc.d:35 diff --git a/runtime/druntime/test/profile/myprofilegc.log.linux.64.exp b/runtime/druntime/test/profile/myprofilegc.log.linux.64.exp index 79c86edcfb3..b93a332a8cf 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.linux.64.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.linux.64.exp @@ -17,4 +17,6 @@ bytes allocated, allocations, type, function, file:line 16 1 int[] D main src/profilegc.d:14 16 1 int[] D main src/profilegc.d:22 16 1 int[] D main src/profilegc.d:37 + 16 1 void[] core.lifetime._d_newitemT!float._d_newitemT ../../src/core/lifetime.d:2829 + 16 1 void[] core.lifetime._d_newitemT!int._d_newitemT ../../src/core/lifetime.d:2829 16 1 wchar[] D main src/profilegc.d:35 diff --git a/runtime/druntime/test/profile/myprofilegc.log.osx.32.exp b/runtime/druntime/test/profile/myprofilegc.log.osx.32.exp index 4faa76ae777..55ff209c046 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.osx.32.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.osx.32.exp @@ -17,4 +17,6 @@ bytes allocated, allocations, type, function, file:line 16 1 int[] D main src/profilegc.d:22 16 1 int[] D main src/profilegc.d:37 16 1 profilegc.main.C core.lifetime._d_newclassT!(C)._d_newclassT ../../src/core/lifetime.d:2755 + 16 1 void[] core.lifetime._d_newitemT!float._d_newitemT ../../src/core/lifetime.d:2829 + 16 1 void[] core.lifetime._d_newitemT!int._d_newitemT ../../src/core/lifetime.d:2829 16 1 wchar[] D main src/profilegc.d:35 diff --git a/runtime/druntime/test/profile/myprofilegc.log.osx.64.exp b/runtime/druntime/test/profile/myprofilegc.log.osx.64.exp index 79c86edcfb3..b93a332a8cf 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.osx.64.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.osx.64.exp @@ -17,4 +17,6 @@ bytes allocated, allocations, type, function, file:line 16 1 int[] D main src/profilegc.d:14 16 1 int[] D main src/profilegc.d:22 16 1 int[] D main src/profilegc.d:37 + 16 1 void[] core.lifetime._d_newitemT!float._d_newitemT ../../src/core/lifetime.d:2829 + 16 1 void[] core.lifetime._d_newitemT!int._d_newitemT ../../src/core/lifetime.d:2829 16 1 wchar[] D main src/profilegc.d:35 From cfa602f6479d0fc77fb55e0f3f020b9d36ed2886 Mon Sep 17 00:00:00 2001 From: Nicholas Wilson Date: Fri, 12 May 2023 17:45:06 +0800 Subject: [PATCH 037/176] rename `apply.d` -> `postordervisitor.d` (dlang/dmd!15233) * rename `apply.d` -> `postordervisitor.d` remove imports made redundant by dlang/dmd!12596 * Update compiler/src/dmd/README.md --------- Co-authored-by: Dennis --- dmd/README.md | 2 +- dmd/aggregate.d | 1 - dmd/canthrow.d | 2 +- dmd/dclass.d | 1 - dmd/delegatize.d | 2 +- dmd/dinterpret.d | 1 - dmd/dsymbolsem.d | 1 - dmd/expression.d | 2 +- dmd/foreachvar.d | 2 +- dmd/inline.d | 2 +- dmd/inlinecost.d | 2 +- dmd/nogc.d | 2 +- dmd/ob.d | 1 - dmd/{apply.d => postordervisitor.d} | 2 +- dmd/sideeffect.d | 2 +- 15 files changed, 10 insertions(+), 15 deletions(-) rename dmd/{apply.d => postordervisitor.d} (99%) diff --git a/dmd/README.md b/dmd/README.md index 57f56f3f0f0..79215b7a0ea 100644 --- a/dmd/README.md +++ b/dmd/README.md @@ -99,7 +99,7 @@ Note that these groups have no strict meaning, the category assignments are a bi | [strictvisitor.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/strictvisitor.d) | Visitor that forces derived classes to implement `visit` for every possible node | | [visitor.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/visitor.d) | A visitor implementing `visit` for all nodes present in the compiler | | [transitivevisitor.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/transitivevisitor.d) | Provide a mixin template with visit methods for the parse time AST | -| [apply.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/apply.d) | Depth-first expression visitor | +| [postordervisitor.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/postordervisitor.d) | Depth-first expression visitor | | [sapply.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/sapply.d) | Depth-first statement visitor | | [statement_rewrite_walker.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/statement_rewrite_walker.d) | Statement visitor that allows replacing the currently visited node | diff --git a/dmd/aggregate.d b/dmd/aggregate.d index b9526affcfb..42b926be453 100644 --- a/dmd/aggregate.d +++ b/dmd/aggregate.d @@ -18,7 +18,6 @@ import core.stdc.stdio; import core.checkedint; import dmd.aliasthis; -import dmd.apply; import dmd.arraytypes; import dmd.astenums; import dmd.attrib; diff --git a/dmd/canthrow.d b/dmd/canthrow.d index be721dc9c01..09d39ca6f1c 100644 --- a/dmd/canthrow.d +++ b/dmd/canthrow.d @@ -14,7 +14,6 @@ module dmd.canthrow; import dmd.aggregate; -import dmd.apply; import dmd.arraytypes; import dmd.attrib; import dmd.astenums; @@ -26,6 +25,7 @@ import dmd.func; import dmd.globals; import dmd.init; import dmd.mtype; +import dmd.postordervisitor; import dmd.root.rootobject; import dmd.tokens; import dmd.visitor; diff --git a/dmd/dclass.d b/dmd/dclass.d index c53a063a229..1b8e8ef1880 100644 --- a/dmd/dclass.d +++ b/dmd/dclass.d @@ -17,7 +17,6 @@ import core.stdc.stdio; import core.stdc.string; import dmd.aggregate; -import dmd.apply; import dmd.arraytypes; import dmd.astenums; import dmd.attrib; diff --git a/dmd/delegatize.d b/dmd/delegatize.d index fd9569105b5..b135bfacbf9 100644 --- a/dmd/delegatize.d +++ b/dmd/delegatize.d @@ -14,7 +14,6 @@ module dmd.delegatize; import core.stdc.stdio; -import dmd.apply; import dmd.astenums; import dmd.declaration; import dmd.dscope; @@ -27,6 +26,7 @@ import dmd.init; import dmd.initsem; import dmd.location; import dmd.mtype; +import dmd.postordervisitor; import dmd.statement; import dmd.tokens; import dmd.visitor; diff --git a/dmd/dinterpret.d b/dmd/dinterpret.d index 4ef6a392073..5b27a07339a 100644 --- a/dmd/dinterpret.d +++ b/dmd/dinterpret.d @@ -16,7 +16,6 @@ module dmd.dinterpret; import core.stdc.stdio; import core.stdc.stdlib; import core.stdc.string; -import dmd.apply; import dmd.arraytypes; import dmd.astenums; import dmd.attrib; diff --git a/dmd/dsymbolsem.d b/dmd/dsymbolsem.d index b88f5515b8b..931de59cec8 100644 --- a/dmd/dsymbolsem.d +++ b/dmd/dsymbolsem.d @@ -17,7 +17,6 @@ import core.stdc.string; import dmd.aggregate; import dmd.aliasthis; -import dmd.apply; import dmd.arraytypes; import dmd.astcodegen; import dmd.astenums; diff --git a/dmd/expression.d b/dmd/expression.d index 412764ae975..c034cbb0efd 100644 --- a/dmd/expression.d +++ b/dmd/expression.d @@ -19,7 +19,6 @@ import core.stdc.string; import dmd.aggregate; import dmd.aliasthis; -import dmd.apply; import dmd.arrayop; import dmd.arraytypes; import dmd.astenums; @@ -56,6 +55,7 @@ import dmd.nspace; import dmd.objc; import dmd.opover; import dmd.optimize; +import dmd.postordervisitor; import dmd.root.complex; import dmd.root.ctfloat; import dmd.root.filename; diff --git a/dmd/foreachvar.d b/dmd/foreachvar.d index 7a964695f45..1293057fe83 100644 --- a/dmd/foreachvar.d +++ b/dmd/foreachvar.d @@ -15,7 +15,6 @@ import core.stdc.stdio; import core.stdc.stdlib; import core.stdc.string; -import dmd.apply; import dmd.arraytypes; import dmd.astenums; import dmd.attrib; @@ -33,6 +32,7 @@ import dmd.identifier; import dmd.init; import dmd.initsem; import dmd.mtype; +import dmd.postordervisitor; import dmd.printast; import dmd.root.array; import dmd.root.rootobject; diff --git a/dmd/inline.d b/dmd/inline.d index 2989b6e39e7..2b8ab623099 100644 --- a/dmd/inline.d +++ b/dmd/inline.d @@ -18,7 +18,6 @@ import core.stdc.stdio; import core.stdc.string; import dmd.aggregate; -import dmd.apply; import dmd.arraytypes; import dmd.astenums; import dmd.attrib; @@ -40,6 +39,7 @@ import dmd.location; import dmd.mtype; import dmd.opover; import dmd.printast; +import dmd.postordervisitor; import dmd.statement; import dmd.tokens; import dmd.visitor; diff --git a/dmd/inlinecost.d b/dmd/inlinecost.d index 2dd25e2c0f5..696c0a719dc 100644 --- a/dmd/inlinecost.d +++ b/dmd/inlinecost.d @@ -15,7 +15,6 @@ import core.stdc.stdio; import core.stdc.string; import dmd.aggregate; -import dmd.apply; import dmd.arraytypes; import dmd.astenums; import dmd.attrib; @@ -33,6 +32,7 @@ import dmd.identifier; import dmd.init; import dmd.mtype; import dmd.opover; +import dmd.postordervisitor; import dmd.statement; import dmd.tokens; import dmd.visitor; diff --git a/dmd/nogc.d b/dmd/nogc.d index a0f3e60861b..9a8f2422746 100644 --- a/dmd/nogc.d +++ b/dmd/nogc.d @@ -16,7 +16,6 @@ module dmd.nogc; import core.stdc.stdio; import dmd.aggregate; -import dmd.apply; import dmd.astenums; import dmd.declaration; import dmd.dscope; @@ -26,6 +25,7 @@ import dmd.func; import dmd.globals; import dmd.init; import dmd.mtype; +import dmd.postordervisitor; import dmd.tokens; import dmd.visitor; diff --git a/dmd/ob.d b/dmd/ob.d index 89728b64486..56243a0e035 100644 --- a/dmd/ob.d +++ b/dmd/ob.d @@ -20,7 +20,6 @@ import dmd.root.rootobject; import dmd.root.rmem; import dmd.aggregate; -import dmd.apply; import dmd.arraytypes; import dmd.astenums; import dmd.declaration; diff --git a/dmd/apply.d b/dmd/postordervisitor.d similarity index 99% rename from dmd/apply.d rename to dmd/postordervisitor.d index 77aa6b70824..a0c71150c0f 100644 --- a/dmd/apply.d +++ b/dmd/postordervisitor.d @@ -9,7 +9,7 @@ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/apply.d */ -module dmd.apply; +module dmd.postordervisitor; import dmd.arraytypes; import dmd.dtemplate; diff --git a/dmd/sideeffect.d b/dmd/sideeffect.d index 3f3e7e6377a..024719e3748 100644 --- a/dmd/sideeffect.d +++ b/dmd/sideeffect.d @@ -11,7 +11,6 @@ module dmd.sideeffect; -import dmd.apply; import dmd.astenums; import dmd.declaration; import dmd.dscope; @@ -22,6 +21,7 @@ import dmd.globals; import dmd.identifier; import dmd.init; import dmd.mtype; +import dmd.postordervisitor; import dmd.tokens; import dmd.visitor; From bd045315f7d12f7924e14d4ae0c227b791e43c50 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Sun, 14 May 2023 23:43:29 -0700 Subject: [PATCH 038/176] remove need for Expression.parens part 1 --- dmd/parse.d | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/dmd/parse.d b/dmd/parse.d index 601c14e3cb7..ce76a795b6e 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -7075,7 +7075,7 @@ LagainStc: private void checkParens(TOK value, AST.Expression e) { - if (precedence[e.op] == PREC.rel && !e.parens) + if (precedence[e.op] == PREC.rel) error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`", e.toChars(), Token.toChars(value)); } @@ -9109,14 +9109,18 @@ LagainStc: private AST.Expression parseAndExp() { Loc loc = token.loc; + bool parens = token.value == TOK.leftParenthesis; auto e = parseCmpExp(); while (token.value == TOK.and) { - checkParens(TOK.and, e); - nextToken(); + if (!parens) + checkParens(TOK.and, e); + parens = nextToken() == TOK.leftParenthesis; auto e2 = parseCmpExp(); - checkParens(TOK.and, e2); + if (!parens) + checkParens(TOK.and, e2); e = new AST.AndExp(loc, e, e2); + parens = true; // don't call checkParens() for And loc = token.loc; } return e; @@ -9124,32 +9128,42 @@ LagainStc: private AST.Expression parseXorExp() { - const loc = token.loc; + Loc loc = token.loc; + bool parens = token.value == TOK.leftParenthesis; auto e = parseAndExp(); while (token.value == TOK.xor) { - checkParens(TOK.xor, e); - nextToken(); + if (!parens) + checkParens(TOK.xor, e); + parens = nextToken() == TOK.leftParenthesis; auto e2 = parseAndExp(); - checkParens(TOK.xor, e2); + if (!parens) + checkParens(TOK.xor, e2); e = new AST.XorExp(loc, e, e2); + parens = true; + loc = token.loc; } return e; } private AST.Expression parseOrExp() { - const loc = token.loc; + Loc loc = token.loc; + bool parens = token.value == TOK.leftParenthesis; auto e = parseXorExp(); while (token.value == TOK.or) { - checkParens(TOK.or, e); - nextToken(); + if (!parens) + checkParens(TOK.or, e); + parens = nextToken() == TOK.leftParenthesis; auto e2 = parseXorExp(); - checkParens(TOK.or, e2); + if (!parens) + checkParens(TOK.or, e2); e = new AST.OrExp(loc, e, e2); + parens = true; + loc = token.loc; } return e; } From c83a56a706ddff705139f2ec4d7ee9025f9c6fe5 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Wed, 10 May 2023 19:12:18 -0700 Subject: [PATCH 039/176] Revert "Revert "fix Issue 23875 23880 (dlang/dmd!15172)" (dlang/dmd!15196)" This reverts commit d82222f2647003ab720171d9a484841888104d9a. --- dmd/cparse.d | 62 ++++++++++++++++++-------- dmd/initsem.d | 3 ++ runtime/druntime/src/importc.h | 1 + tests/dmd/compilable/test23875.c | 28 ++++++++++++ tests/dmd/fail_compilation/test23875.c | 13 ++++++ 5 files changed, 89 insertions(+), 18 deletions(-) create mode 100644 tests/dmd/compilable/test23875.c create mode 100644 tests/dmd/fail_compilation/test23875.c diff --git a/dmd/cparse.d b/dmd/cparse.d index 68f67e0bad9..a3918ec123f 100644 --- a/dmd/cparse.d +++ b/dmd/cparse.d @@ -324,6 +324,8 @@ final class CParser(AST) : Parser!AST // atomic-type-specifier or type_qualifier case TOK._Atomic: + case TOK.__attribute__: + Ldeclaration: { cparseDeclaration(LVL.local); @@ -2710,7 +2712,7 @@ final class CParser(AST) : Parser!AST * * Params: * declarator = declarator kind - * t = base type to start with + * tbase = base type to start with * pident = set to Identifier if there is one, null if not * specifier = specifiers in and out * Returns: @@ -2718,12 +2720,26 @@ final class CParser(AST) : Parser!AST * symbol table for the parameter-type-list, which will contain any * declared struct, union or enum tags. */ - private AST.Type cparseDeclarator(DTR declarator, AST.Type t, + private AST.Type cparseDeclarator(DTR declarator, AST.Type tbase, out Identifier pident, ref Specifier specifier) { //printf("cparseDeclarator(%d, %p)\n", declarator, t); AST.Types constTypes; // all the Types that will need `const` applied to them + /* Insert tx -> t into + * ts -> ... -> t + * so that + * ts -> ... -> tx -> t + */ + static void insertTx(ref AST.Type ts, AST.Type tx, AST.Type t) + { + AST.Type* pt; + for (pt = &ts; *pt != t; pt = &(cast(AST.TypeNext)*pt).next) + { + } + *pt = tx; + } + AST.Type parseDecl(AST.Type t) { AST.Type ts; @@ -2789,20 +2805,6 @@ final class CParser(AST) : Parser!AST // parse DeclaratorSuffixes while (1) { - /* Insert tx -> t into - * ts -> ... -> t - * so that - * ts -> ... -> tx -> t - */ - static void insertTx(ref AST.Type ts, AST.Type tx, AST.Type t) - { - AST.Type* pt; - for (pt = &ts; *pt != t; pt = &(cast(AST.TypeNext)*pt).next) - { - } - *pt = tx; - } - switch (token.value) { case TOK.leftBracket: @@ -2915,7 +2917,17 @@ final class CParser(AST) : Parser!AST return ts; } - t = parseDecl(t); + auto t = parseDecl(tbase); + + if (specifier.vector_size) + { + auto length = new AST.IntegerExp(token.loc, specifier.vector_size / tbase.size(), AST.Type.tuns32); + auto tsa = new AST.TypeSArray(tbase, length); + AST.Type tv = new AST.TypeVector(tsa); + specifier.vector_size = 0; // used it up + + insertTx(t, tv, tbase); // replace tbase with tv + } /* Because const is transitive, cannot assemble types from * fragments. Instead, types to be annotated with const are put @@ -3553,7 +3565,19 @@ final class CParser(AST) : Parser!AST { nextToken(); check(TOK.leftParenthesis); - cparseConstantExp(); // TODO implement + if (token.value == TOK.int32Literal) + { + const n = token.unsvalue; + if (n < 1 || n & (n - 1) || ushort.max < n) + error("__attribute__((vector_size(%lld))) must be an integer positive power of 2 and be <= 32,768", cast(ulong)n); + specifier.vector_size = cast(uint) n; + nextToken(); + } + else + { + error("value for vector_size expected, not `%s`", token.toChars()); + nextToken(); + } check(TOK.rightParenthesis); } else @@ -4694,6 +4718,7 @@ final class CParser(AST) : Parser!AST // atomic-type-specifier case TOK._Atomic: case TOK.typeof_: + case TOK.__attribute__: t = peek(t); if (t.value != TOK.leftParenthesis || !skipParens(t, &t)) @@ -4959,6 +4984,7 @@ final class CParser(AST) : Parser!AST bool dllexport; /// dllexport attribute bool _deprecated; /// deprecated attribute AST.Expression depMsg; /// deprecated message + uint vector_size; /// positive power of 2 multipe of base type size SCW scw; /// storage-class specifiers MOD mod; /// type qualifiers diff --git a/dmd/initsem.d b/dmd/initsem.d index 893d2a627c3..ca770bd77b6 100644 --- a/dmd/initsem.d +++ b/dmd/initsem.d @@ -587,6 +587,9 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ */ t = t.toBasetype(); + if (auto tv = t.isTypeVector()) + t = tv.basetype; + /* If `{ expression }` return the expression initializer */ ExpInitializer isBraceExpression() diff --git a/runtime/druntime/src/importc.h b/runtime/druntime/src/importc.h index 5f1b1027d2b..88cd1353bd1 100644 --- a/runtime/druntime/src/importc.h +++ b/runtime/druntime/src/importc.h @@ -32,6 +32,7 @@ #define __volatile__ volatile #define __attribute __attribute__ #define __alignof _Alignof +#define __vector_size__ vector_size /******************** * Clang nullability extension used by macOS headers. diff --git a/tests/dmd/compilable/test23875.c b/tests/dmd/compilable/test23875.c new file mode 100644 index 00000000000..6d6f44ec75a --- /dev/null +++ b/tests/dmd/compilable/test23875.c @@ -0,0 +1,28 @@ +/* DISABLED: win32 linux32 + */ + +// https://issues.dlang.org/show_bug.cgi?id=23875 +// https://issues.dlang.org/show_bug.cgi?id=23880 + +int __attribute__((vector_size(16))) neptune() +{ + int __attribute__((vector_size (16))) v = { 4,1,2,3 }; + return v; +} + +__attribute__((__vector_size__(16))) int pluto(int i) +{ + int __attribute__((__vector_size__ (16))) * p1; + int * __attribute__((__vector_size__ (16))) p2; + + int __attribute__((__vector_size__ (16))) v1; + __attribute__((__vector_size__ (16))) int v2; + + v1 = (__attribute__((__vector_size__ (16))) int) {4,1,2,3}; + + p1 = p2; + *p1 = v1; + v1 = (__attribute__((__vector_size__ (16))) int) v2; + + return i ? v1 : v2; +} diff --git a/tests/dmd/fail_compilation/test23875.c b/tests/dmd/fail_compilation/test23875.c new file mode 100644 index 00000000000..e54f62ea46e --- /dev/null +++ b/tests/dmd/fail_compilation/test23875.c @@ -0,0 +1,13 @@ +/* DISABLED: win32 linux32 +TEST_OUTPUT: +--- +fail_compilation/test23875.c(12): Error: __attribute__((vector_size(10))) must be an integer positive power of 2 and be <= 32,768 +fail_compilation/test23875.c(13): Error: value for vector_size expected, not `x` +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=23875 +// https://issues.dlang.org/show_bug.cgi?id=23880 + +int __attribute__((vector_size(10))) neptune(); +int __attribute__((vector_size(x))) saturn(); From afd438311587af18f79947475668f0dda3e94abf Mon Sep 17 00:00:00 2001 From: RazvanN7 Date: Tue, 16 May 2023 13:07:01 +0300 Subject: [PATCH 040/176] Fix Issue 23912 - Destructor disables scope inference --- dmd/expression.d | 14 ++++++++++++++ tests/dmd/compilable/test23912.d | 17 +++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 tests/dmd/compilable/test23912.d diff --git a/dmd/expression.d b/dmd/expression.d index c034cbb0efd..a441a554686 100644 --- a/dmd/expression.d +++ b/dmd/expression.d @@ -699,6 +699,20 @@ VarDeclaration expToVariable(Expression e) case EXP.super_: return (cast(ThisExp)e).var.isVarDeclaration(); + // Temporaries for rvalues that need destruction + // are of form: (T s = rvalue, s). For these cases + // we can just return var declaration of `s`. However, + // this is intentionally not calling `Expression.extractLast` + // because at this point we cannot infer the var declaration + // of more complex generated comma expressions such as the + // one for the array append hook. + case EXP.comma: + { + if (auto ve = e.isCommaExp().e2.isVarExp()) + return ve.var.isVarDeclaration(); + + return null; + } default: return null; } diff --git a/tests/dmd/compilable/test23912.d b/tests/dmd/compilable/test23912.d new file mode 100644 index 00000000000..d89d3026e8f --- /dev/null +++ b/tests/dmd/compilable/test23912.d @@ -0,0 +1,17 @@ +// https://issues.dlang.org/show_bug.cgi?id=23912 +// REQUIRED_ARGS: -preview=dip1000 + +struct Test +{ + string val; + + this(return scope string val) scope @safe {} + ~this() scope @safe {} +} + +void giver(scope string input) @safe +{ + accepts(Test(input)); +} + +void accepts(scope Test test) @safe {} From 1b325134087ae6662bf90121c4dc9a8c684a9f9e Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Mon, 15 May 2023 23:04:28 -0700 Subject: [PATCH 041/176] remove e.parens part 2 --- dmd/parse.d | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dmd/parse.d b/dmd/parse.d index ce76a795b6e..21eb29f44e6 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -9214,6 +9214,7 @@ LagainStc: AST.Expression parseAssignExp() { + bool parens = token.value == TOK.leftParenthesis; AST.Expression e; e = parseCondExp(); if (e is null) @@ -9222,7 +9223,7 @@ LagainStc: // require parens for e.g. `t ? a = 1 : b = 2` void checkRequiredParens() { - if (e.op == EXP.question && !e.parens) + if (e.op == EXP.question && !parens) eSink.error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`", e.toChars(), Token.toChars(token.value)); } From a5f8b9ebf2ff89bdfee661c7129a3341212f4d17 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Tue, 16 May 2023 22:28:32 -0700 Subject: [PATCH 042/176] remove Expression.parens --- dmd/expression.d | 4 +++- dmd/expression.h | 2 +- dmd/frontend.h | 9 +++++---- dmd/importc.d | 7 ++++--- dmd/parse.d | 7 +++---- 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/dmd/expression.d b/dmd/expression.d index a441a554686..14c31591a98 100644 --- a/dmd/expression.d +++ b/dmd/expression.d @@ -737,7 +737,6 @@ extern (C++) abstract class Expression : ASTNode Type type; // !=null means that semantic() has been run Loc loc; // file location const EXP op; // to minimize use of dynamic_cast - bool parens; // if this is a parenthesized expression extern (D) this(const ref Loc loc, EXP op) scope { @@ -2357,6 +2356,7 @@ extern (C++) final class ComplexExp : Expression extern (C++) class IdentifierExp : Expression { Identifier ident; + bool parens; // if it appears as (identifier) extern (D) this(const ref Loc loc, Identifier ident) scope { @@ -3539,6 +3539,8 @@ extern (C++) final class CompoundLiteralExp : Expression */ extern (C++) final class TypeExp : Expression { + bool parens; // if this is a parenthesized expression + extern (D) this(const ref Loc loc, Type type) { super(loc, EXP.type); diff --git a/dmd/expression.h b/dmd/expression.h index ead112bbc49..770c3e7ae3d 100644 --- a/dmd/expression.h +++ b/dmd/expression.h @@ -83,7 +83,6 @@ class Expression : public ASTNode Type *type; // !=NULL means that semantic() has been run Loc loc; // file location EXP op; // to minimize use of dynamic_cast - d_bool parens; // if this is a parenthesized expression size_t size() const; static void _init(); @@ -316,6 +315,7 @@ class IdentifierExp : public Expression { public: Identifier *ident; + d_bool parens; static IdentifierExp *create(const Loc &loc, Identifier *ident); bool isLvalue() override final; diff --git a/dmd/frontend.h b/dmd/frontend.h index f73d1bd55c8..6b65a58d1c4 100644 --- a/dmd/frontend.h +++ b/dmd/frontend.h @@ -979,7 +979,6 @@ class Expression : public ASTNode Type* type; Loc loc; const EXP op; - bool parens; size_t size() const; static void _init(); static void deinitialize(); @@ -7013,9 +7012,9 @@ struct UnionExp final private: union __AnonStruct__u { - char exp[26LLU]; + char exp[25LLU]; char integerexp[40LLU]; - char errorexp[26LLU]; + char errorexp[25LLU]; char realexp[48LLU]; char complexexp[64LLU]; char symoffexp[64LLU]; @@ -7024,7 +7023,7 @@ struct UnionExp final char assocarrayliteralexp[48LLU]; char structliteralexp[76LLU]; char compoundliteralexp[40LLU]; - char nullexp[26LLU]; + char nullexp[25LLU]; char dotvarexp[49LLU]; char addrexp[40LLU]; char indexexp[74LLU]; @@ -7117,6 +7116,7 @@ class IdentifierExp : public Expression { public: Identifier* ident; + bool parens; static IdentifierExp* create(const Loc& loc, Identifier* ident); bool isLvalue() final override; Expression* toLvalue(Scope* sc, Expression* e) final override; @@ -7277,6 +7277,7 @@ class CompoundLiteralExp final : public Expression class TypeExp final : public Expression { public: + bool parens; TypeExp* syntaxCopy() override; bool checkType() override; bool checkValue() override; diff --git a/dmd/importc.d b/dmd/importc.d index 97710b88199..05f92b07a75 100644 --- a/dmd/importc.d +++ b/dmd/importc.d @@ -237,15 +237,16 @@ Expression castCallAmbiguity(Expression e, Scope* sc) case EXP.call: auto ce = (*pe).isCallExp(); - if (ce.e1.parens) + auto ie = ce.e1.isIdentifierExp(); + if (ie && ie.parens) { - ce.e1 = expressionSemantic(ce.e1, sc); + ce.e1 = expressionSemantic(ie, sc); if (ce.e1.op == EXP.type) { const numArgs = ce.arguments ? ce.arguments.length : 0; if (numArgs >= 1) { - ce.e1.parens = false; + ie.parens = false; Expression arg; foreach (a; (*ce.arguments)[]) { diff --git a/dmd/parse.d b/dmd/parse.d index 21eb29f44e6..10f42a0d17c 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -8479,7 +8479,6 @@ LagainStc: // ( expression ) nextToken(); e = parseExpression(); - e.parens = true; check(loc, TOK.rightParenthesis); break; } @@ -8800,9 +8799,9 @@ LagainStc: nextToken(); return AST.ErrorExp.get(); } - e = new AST.TypeExp(loc, t); - e.parens = true; - e = parsePostExp(e); + auto te = new AST.TypeExp(loc, t); + te.parens = true; + e = parsePostExp(te); } else { From 523765588ee802eb17c7c99c059db6be21a8f3f2 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Wed, 17 May 2023 13:31:05 +0200 Subject: [PATCH 043/176] make deprecation message less confusing the deprecation message talks about the function we are using, not some arbitrary example that you would use "such as" with. --- dmd/traits.d | 4 ++-- tests/dmd/fail_compilation/fail15414.d | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dmd/traits.d b/dmd/traits.d index 0f363536d8e..53c8fb08b50 100644 --- a/dmd/traits.d +++ b/dmd/traits.d @@ -1215,7 +1215,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) { if (fd.overnext) { - deprecation(e.loc, "`__traits(getAttributes)` may only be used for individual functions, not overload sets such as: `%s`", fd.toChars()); + deprecation(e.loc, "`__traits(getAttributes)` may only be used for individual functions, not the overload set `%s`", fd.toChars()); deprecationSupplemental(e.loc, "the result of `__traits(getOverloads)` may be used to select the desired function to extract attributes from"); } } @@ -1225,7 +1225,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) { if (td.overnext || td.funcroot) { - deprecation(e.loc, "`__traits(getAttributes)` may only be used for individual functions, not overload sets such as: `%s`", td.ident.toChars()); + deprecation(e.loc, "`__traits(getAttributes)` may only be used for individual functions, not the overload set `%s`", td.ident.toChars()); deprecationSupplemental(e.loc, "the result of `__traits(getOverloads)` may be used to select the desired function to extract attributes from"); } } diff --git a/tests/dmd/fail_compilation/fail15414.d b/tests/dmd/fail_compilation/fail15414.d index 1fb6e23aedb..ed576b57fe6 100644 --- a/tests/dmd/fail_compilation/fail15414.d +++ b/tests/dmd/fail_compilation/fail15414.d @@ -5,7 +5,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail15414.d(20): Deprecation: `__traits(getAttributes)` may only be used for individual functions, not overload sets such as: `fun` +fail_compilation/fail15414.d(20): Deprecation: `__traits(getAttributes)` may only be used for individual functions, not the overload set `fun` fail_compilation/fail15414.d(20): the result of `__traits(getOverloads)` may be used to select the desired function to extract attributes from --- */ From bdbf18497099dc771f36375018d6bb408cd41590 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Wed, 17 May 2023 16:37:50 +0100 Subject: [PATCH 044/176] Fix optional type & parameters for `function` literal --- dmd/parse.d | 3 ++- tests/dmd/runnable/funclit.d | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dmd/parse.d b/dmd/parse.d index 10f42a0d17c..b7e07911cb9 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -5026,7 +5026,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer stc = STC.ref_; nextToken(); } - if (token.value != TOK.leftParenthesis && token.value != TOK.leftCurly) + if (token.value != TOK.leftParenthesis && token.value != TOK.leftCurly && + token.value != TOK.goesTo) { // function type (parameters) { statements... } // delegate type (parameters) { statements... } diff --git a/tests/dmd/runnable/funclit.d b/tests/dmd/runnable/funclit.d index e6e4fec1c54..c4b70dcb509 100644 --- a/tests/dmd/runnable/funclit.d +++ b/tests/dmd/runnable/funclit.d @@ -1263,6 +1263,7 @@ void assign16271(T)(ref T a, T b) void test16271() { int x; + (delegate ref => x)() = -1; assert(x == -1); (ref () => x )() = 1; assert(x == 1); func16271!(ref () => x) = 2; assert(x == 2); assign16271(x, 3); assert(x == 3); From 3420f1af24b8809ce0c3bc9a0f61e13c5fcc4eb1 Mon Sep 17 00:00:00 2001 From: Atila Neves Date: Thu, 18 May 2023 17:45:26 +0200 Subject: [PATCH 045/176] Make atomicStore work with -preview=nosharedaccess --- runtime/druntime/src/core/atomic.d | 2 +- .../dmd/compilable/atomic_store_2_shared_classes.d | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 tests/dmd/compilable/atomic_store_2_shared_classes.d diff --git a/runtime/druntime/src/core/atomic.d b/runtime/druntime/src/core/atomic.d index 1fba06cc021..5a7d00c38db 100644 --- a/runtime/druntime/src/core/atomic.d +++ b/runtime/druntime/src/core/atomic.d @@ -162,7 +162,7 @@ void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref shared T val, V new } /// Ditto -void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref shared T val, shared V newval) pure nothrow @nogc @trusted +void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref shared T val, auto ref shared V newval) pure nothrow @nogc @trusted if (is(T == class)) { static assert (is (V : T), "Can't assign `newval` of type `shared " ~ V.stringof ~ "` to `shared " ~ T.stringof ~ "`."); diff --git a/tests/dmd/compilable/atomic_store_2_shared_classes.d b/tests/dmd/compilable/atomic_store_2_shared_classes.d new file mode 100644 index 00000000000..0d8cd748937 --- /dev/null +++ b/tests/dmd/compilable/atomic_store_2_shared_classes.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -preview=nosharedaccess +import core.atomic; + +class Foo +{ +} + +void oops() +{ + auto f0 = new shared Foo; + auto f1 = new shared Foo; + atomicStore(f0, f1); +} From b0313472c1e2dc4f6f310d5c89009835ec0be567 Mon Sep 17 00:00:00 2001 From: Razvan Nitu Date: Fri, 19 May 2023 10:54:22 +0300 Subject: [PATCH 046/176] Fix Issue 23914 - auto ref resolution on return value prevented by noreturn (dlang/dmd!15240) --- dmd/statementsem.d | 3 ++- tests/dmd/compilable/noreturn3.d | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/dmd/statementsem.d b/dmd/statementsem.d index 6174a3448c0..f0454163224 100644 --- a/dmd/statementsem.d +++ b/dmd/statementsem.d @@ -2732,7 +2732,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc) tbret = tret.toBasetype(); } - if (inferRef) // deduce 'auto ref' + // https://issues.dlang.org/show_bug.cgi?id=23914 + if (inferRef && !resType.isTypeNoreturn()) // deduce 'auto ref' tf.isref = false; if (tbret.ty != Tvoid && !resType.isTypeNoreturn()) // if non-void return diff --git a/tests/dmd/compilable/noreturn3.d b/tests/dmd/compilable/noreturn3.d index 69689d24d85..2538a0d0231 100644 --- a/tests/dmd/compilable/noreturn3.d +++ b/tests/dmd/compilable/noreturn3.d @@ -91,8 +91,8 @@ auto ref forwardOrExit(ref int num) static assert( is(typeof(forwardOrExit(global)) == int)); -// // Must not infer ref due to the noreturn rvalue -static assert(!is(typeof(&forwardOrExit(global)))); +// Noreturn types do not affect `auto ref` deduction +static assert(is(typeof(&forwardOrExit(global)))); auto ref forwardOrExit2(ref int num) { @@ -104,8 +104,8 @@ auto ref forwardOrExit2(ref int num) static assert( is(typeof(forwardOrExit2(global)) == int)); -// // Must not infer ref due to the noreturn rvalue -static assert(!is(typeof(&forwardOrExit2(global)))); +// Noreturn types do not affect `auto ref` deduction +static assert(is(typeof(&forwardOrExit2(global)))); /*****************************************************************************/ From acc4961564e05b2063693c0af9c68ca8106b17ed Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Fri, 19 May 2023 00:22:26 -0700 Subject: [PATCH 047/176] fix Issue 23928 - improve error msg: scope variable s assigned to non-scope parameter this calling abc --- dmd/escape.d | 7 ++++++- tests/dmd/fail_compilation/retscope.d | 2 +- tests/dmd/fail_compilation/test20245.d | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/dmd/escape.d b/dmd/escape.d index 19748dc2f21..c0dd17f2ea6 100644 --- a/dmd/escape.d +++ b/dmd/escape.d @@ -377,13 +377,18 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId, desc ~ " `%s` assigned to non-scope parameter calling `assert()`", v); return; } + + bool isThis = fdc && fdc.needThis() && fdc.vthis == vPar; // implicit `this` parameter to member function + const(char)* msg = + (isThis) ? (desc ~ " `%s` calling non-scope member function `%s.%s()`") : (fdc && parId) ? (desc ~ " `%s` assigned to non-scope parameter `%s` calling `%s`") : (fdc && !parId) ? (desc ~ " `%s` assigned to non-scope anonymous parameter calling `%s`") : (!fdc && parId) ? (desc ~ " `%s` assigned to non-scope parameter `%s`") : (desc ~ " `%s` assigned to non-scope anonymous parameter"); - if (sc.setUnsafeDIP1000(gag, arg.loc, msg, v, parId ? parId : fdc, fdc)) + auto param = isThis ? v : (parId ? parId : fdc); + if (sc.setUnsafeDIP1000(gag, arg.loc, msg, v, param, fdc)) { result = true; printScopeFailure(previewSupplementalFunc(sc.isDeprecated(), global.params.useDIP1000), vPar, 10); diff --git a/tests/dmd/fail_compilation/retscope.d b/tests/dmd/fail_compilation/retscope.d index 7bc5e96bef8..50cfdd3ef9c 100644 --- a/tests/dmd/fail_compilation/retscope.d +++ b/tests/dmd/fail_compilation/retscope.d @@ -403,7 +403,7 @@ class Foo13 /* TEST_OUTPUT: --- -fail_compilation/retscope.d(1205): Error: scope variable `f14` assigned to non-scope parameter `this` calling `foo` +fail_compilation/retscope.d(1205): Error: scope variable `f14` calling non-scope member function `f14.foo()` --- */ diff --git a/tests/dmd/fail_compilation/test20245.d b/tests/dmd/fail_compilation/test20245.d index 98caa03b2f5..3c43c5cfe4b 100644 --- a/tests/dmd/fail_compilation/test20245.d +++ b/tests/dmd/fail_compilation/test20245.d @@ -9,7 +9,7 @@ fail_compilation/test20245.d(27): Error: cannot take address of `scope` variable fail_compilation/test20245.d(33): Error: reference to local variable `x` assigned to non-scope parameter `ptr` calling `escape` fail_compilation/test20245.d(34): Error: copying `&x` into allocated memory escapes a reference to parameter `x` fail_compilation/test20245.d(50): Error: reference to local variable `price` assigned to non-scope `this.minPrice` -fail_compilation/test20245.d(69): Error: reference to local variable `this` assigned to non-scope parameter `msg` calling `this` +fail_compilation/test20245.d(69): Error: reference to local variable `this` calling non-scope member function `this.this()` fail_compilation/test20245.d(89): Error: reference to local variable `this` assigned to non-scope parameter `content` calling `listUp` fail_compilation/test20245.d(82): which is not `scope` because of `charPtr = content` --- From 16cb5e761e19ea54bfd43bdba1b44d3739c7cc16 Mon Sep 17 00:00:00 2001 From: Dennis Korpel Date: Fri, 19 May 2023 18:55:37 +0200 Subject: [PATCH 048/176] Remove need to set version=MARS --- dmd/declaration.d | 4 ++++ dmd/dsymbolsem.d | 4 ++++ dmd/func.d | 4 ++++ dmd/globals.d | 4 ++++ dmd/gluelayer.d | 20 +++++++++----------- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/dmd/declaration.d b/dmd/declaration.d index b505a99e6d4..cfa6988a861 100644 --- a/dmd/declaration.d +++ b/dmd/declaration.d @@ -44,6 +44,10 @@ import dmd.tokens; import dmd.typesem; import dmd.visitor; +version (IN_GCC) {} +else version (IN_LLVM) {} +else version = MARS; + /************************************ * Check to see the aggregate type is nested and its context pointer is * accessible from the current scope. diff --git a/dmd/dsymbolsem.d b/dmd/dsymbolsem.d index 840d91e86db..a5cd63b1d4f 100644 --- a/dmd/dsymbolsem.d +++ b/dmd/dsymbolsem.d @@ -77,6 +77,10 @@ import dmd.templateparamsem; import dmd.typesem; import dmd.visitor; +version (IN_GCC) {} +else version (IN_LLVM) {} +else version = MARS; + enum LOG = false; private uint setMangleOverride(Dsymbol s, const(char)[] sym) diff --git a/dmd/func.d b/dmd/func.d index c49a1e8f86e..a714d2d281a 100644 --- a/dmd/func.d +++ b/dmd/func.d @@ -59,6 +59,10 @@ import dmd.statementsem; import dmd.tokens; import dmd.visitor; +version (IN_GCC) {} +else version (IN_LLVM) {} +else version = MARS; + /// Inline Status enum ILS : ubyte { diff --git a/dmd/globals.d b/dmd/globals.d index 45b4528c204..0ac60420ef7 100644 --- a/dmd/globals.d +++ b/dmd/globals.d @@ -26,6 +26,10 @@ import dmd.location; import dmd.lexer : CompileEnv; import dmd.utils; +version (IN_GCC) {} +else version (IN_LLVM) {} +else version = MARS; + /// Defines a setting for how compiler warnings and deprecations are handled enum DiagnosticReporting : ubyte { diff --git a/dmd/gluelayer.d b/dmd/gluelayer.d index 4768e4c6b23..1793700463c 100644 --- a/dmd/gluelayer.d +++ b/dmd/gluelayer.d @@ -48,16 +48,6 @@ version (NoBackend) } } } -else version (MARS) -{ - public import dmd.backend.cc : block, Blockx, Symbol; - public import dmd.backend.type : type; - public import dmd.backend.el : elem; - public import dmd.backend.code_x86 : code; - public import dmd.iasm : asmSemantic; - public import dmd.objc_glue : ObjcGlue; - public import dmd.toobj : toObjFile; -} else version (IN_GCC) { extern (C++) union tree_node; @@ -79,4 +69,12 @@ else version (IN_GCC) } } else - static assert(false, "Unsupported compiler backend"); +{ + public import dmd.backend.cc : block, Blockx, Symbol; + public import dmd.backend.type : type; + public import dmd.backend.el : elem; + public import dmd.backend.code_x86 : code; + public import dmd.iasm : asmSemantic; + public import dmd.objc_glue : ObjcGlue; + public import dmd.toobj : toObjFile; +} From 43724c5d529fc9ec6fe6f24c39e706431bf8ada2 Mon Sep 17 00:00:00 2001 From: Lucipetus Date: Tue, 23 May 2023 19:21:27 +0800 Subject: [PATCH 049/176] Extract code matching parameters to template instance into a function (dlang/dmd!15263) * extract code that matches parameters to template instance into a function to be reused: resolveTemplateInstantiation * improve doc for resolveTemplateInstantiation --- dmd/dtemplate.d | 318 ++++++++++++++++++++++++++---------------------- 1 file changed, 170 insertions(+), 148 deletions(-) diff --git a/dmd/dtemplate.d b/dmd/dtemplate.d index ef743d60fd9..5b98d2f4877 100644 --- a/dmd/dtemplate.d +++ b/dmd/dtemplate.d @@ -4141,185 +4141,207 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param goto Lnomatch; L2: - for (size_t i = 0; 1; i++) + if (!resolveTemplateInstantiation(t.tempinst.tiargs, &t.tempinst.tdtypes, tempdecl, tp, dedtypes)) + goto Lnomatch; + } + visit(cast(Type)t); + return; + + Lnomatch: + //printf("no match\n"); + result = MATCH.nomatch; + } + + /******************** + * Match template `parameters` to the target template instance. + * Example: + * struct Temp(U, int Z) {} + * void foo(T)(Temp!(T, 3)); + * foo(Temp!(int, 3)()); + * Input: + * this.parameters = template params of foo -> [T] + * tiargs = .tiargs -> [int, 3] + * tdtypes = .tdtypes -> [int, 3] + * tempdecl = -> [T, Z] + * tp = + * Output: + * dedtypes = deduced params of `foo(Temp!(int, 3)())` -> [int] + */ + private bool resolveTemplateInstantiation(Objects* tiargs, Objects* tdtypes, TemplateDeclaration tempdecl, TypeInstance tp, Objects* dedtypes) + { + for (size_t i = 0; 1; i++) + { + //printf("\ttest: tempinst.tiargs[%zu]\n", i); + RootObject o1 = null; + if (i < tiargs.length) + o1 = (*tiargs)[i]; + else if (i < tdtypes.length && i < tp.tempinst.tiargs.length) { - //printf("\ttest: tempinst.tiargs[%zu]\n", i); - RootObject o1 = null; - if (i < t.tempinst.tiargs.length) - o1 = (*t.tempinst.tiargs)[i]; - else if (i < t.tempinst.tdtypes.length && i < tp.tempinst.tiargs.length) - { - // Pick up default arg - o1 = t.tempinst.tdtypes[i]; - } - else if (i >= tp.tempinst.tiargs.length) - break; - //printf("\ttest: o1 = %s\n", o1.toChars()); - if (i >= tp.tempinst.tiargs.length) + // Pick up default arg + o1 = (*tdtypes)[i]; + } + else if (i >= tp.tempinst.tiargs.length) + break; + //printf("\ttest: o1 = %s\n", o1.toChars()); + if (i >= tp.tempinst.tiargs.length) + { + size_t dim = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0); + while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg())) { - size_t dim = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0); - while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg())) - { - i++; - } - if (i >= dim) - break; // match if all remained parameters are dependent - goto Lnomatch; + i++; } + if (i >= dim) + break; // match if all remained parameters are dependent + return false; + } - RootObject o2 = (*tp.tempinst.tiargs)[i]; - Type t2 = isType(o2); - //printf("\ttest: o2 = %s\n", o2.toChars()); - size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.length - 1) - ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND; - if (j != IDX_NOTFOUND && j == parameters.length - 1 && - (*parameters)[j].isTemplateTupleParameter()) - { - /* Given: + RootObject o2 = (*tp.tempinst.tiargs)[i]; + Type t2 = isType(o2); + //printf("\ttest: o2 = %s\n", o2.toChars()); + size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.length - 1) + ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND; + if (j != IDX_NOTFOUND && j == parameters.length - 1 && + (*parameters)[j].isTemplateTupleParameter()) + { + /* Given: * struct A(B...) {} * alias A!(int, float) X; * static if (is(X Y == A!(Z), Z...)) {} * deduce that Z is a tuple(int, float) */ - /* Create tuple from remaining args + /* Create tuple from remaining args */ - size_t vtdim = (tempdecl.isVariadic() ? t.tempinst.tiargs.length : t.tempinst.tdtypes.length) - i; - auto vt = new Tuple(vtdim); - for (size_t k = 0; k < vtdim; k++) - { - RootObject o; - if (k < t.tempinst.tiargs.length) - o = (*t.tempinst.tiargs)[i + k]; - else // Pick up default arg - o = t.tempinst.tdtypes[i + k]; - vt.objects[k] = o; - } - - Tuple v = cast(Tuple)(*dedtypes)[j]; - if (v) - { - if (!match(v, vt)) - goto Lnomatch; - } - else - (*dedtypes)[j] = vt; - break; - } - else if (!o1) - break; - - Type t1 = isType(o1); - Dsymbol s1 = isDsymbol(o1); - Dsymbol s2 = isDsymbol(o2); - Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1)); - Expression e2 = isExpression(o2); - version (none) + size_t vtdim = (tempdecl.isVariadic() ? tiargs.length : tdtypes.length) - i; + auto vt = new Tuple(vtdim); + for (size_t k = 0; k < vtdim; k++) { - Tuple v1 = isTuple(o1); - Tuple v2 = isTuple(o2); - if (t1) - printf("t1 = %s\n", t1.toChars()); - if (t2) - printf("t2 = %s\n", t2.toChars()); - if (e1) - printf("e1 = %s\n", e1.toChars()); - if (e2) - printf("e2 = %s\n", e2.toChars()); - if (s1) - printf("s1 = %s\n", s1.toChars()); - if (s2) - printf("s2 = %s\n", s2.toChars()); - if (v1) - printf("v1 = %s\n", v1.toChars()); - if (v2) - printf("v2 = %s\n", v2.toChars()); + RootObject o; + if (k < tiargs.length) + o = (*tiargs)[i + k]; + else // Pick up default arg + o = (*tdtypes)[i + k]; + vt.objects[k] = o; } - if (t1 && t2) + Tuple v = cast(Tuple)(*dedtypes)[j]; + if (v) { - if (!deduceType(t1, sc, t2, parameters, dedtypes)) - goto Lnomatch; + if (!match(v, vt)) + return false; } - else if (e1 && e2) - { - Le: - e1 = e1.ctfeInterpret(); + else + (*dedtypes)[j] = vt; + break; + } + else if (!o1) + break; - /* If it is one of the template parameters for this template, + Type t1 = isType(o1); + Dsymbol s1 = isDsymbol(o1); + Dsymbol s2 = isDsymbol(o2); + Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1)); + Expression e2 = isExpression(o2); + version (none) + { + Tuple v1 = isTuple(o1); + Tuple v2 = isTuple(o2); + if (t1) + printf("t1 = %s\n", t1.toChars()); + if (t2) + printf("t2 = %s\n", t2.toChars()); + if (e1) + printf("e1 = %s\n", e1.toChars()); + if (e2) + printf("e2 = %s\n", e2.toChars()); + if (s1) + printf("s1 = %s\n", s1.toChars()); + if (s2) + printf("s2 = %s\n", s2.toChars()); + if (v1) + printf("v1 = %s\n", v1.toChars()); + if (v2) + printf("v2 = %s\n", v2.toChars()); + } + + if (t1 && t2) + { + if (!deduceType(t1, sc, t2, parameters, dedtypes)) + return false; + } + else if (e1 && e2) + { + Le: + e1 = e1.ctfeInterpret(); + + /* If it is one of the template parameters for this template, * we should not attempt to interpret it. It already has a value. */ - if (e2.op == EXP.variable && (e2.isVarExp().var.storage_class & STC.templateparameter)) - { - /* + if (e2.op == EXP.variable && (e2.isVarExp().var.storage_class & STC.templateparameter)) + { + /* * (T:Number!(e2), int e2) */ - j = templateIdentifierLookup(e2.isVarExp().var.ident, parameters); - if (j != IDX_NOTFOUND) - goto L1; - // The template parameter was not from this template - // (it may be from a parent template, for example) - } - - e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417 - e2 = e2.ctfeInterpret(); + j = templateIdentifierLookup(e2.isVarExp().var.ident, parameters); + if (j != IDX_NOTFOUND) + goto L1; + // The template parameter was not from this template + // (it may be from a parent template, for example) + } - //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty); - //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty); - if (!e1.equals(e2)) - { - if (!e2.implicitConvTo(e1.type)) - goto Lnomatch; + e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417 + e2 = e2.ctfeInterpret(); - e2 = e2.implicitCastTo(sc, e1.type); - e2 = e2.ctfeInterpret(); - if (!e1.equals(e2)) - goto Lnomatch; - } - } - else if (e1 && t2 && t2.ty == Tident) + //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty); + //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty); + if (!e1.equals(e2)) { - j = templateParameterLookup(t2, parameters); - L1: - if (j == IDX_NOTFOUND) - { - t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); - if (e2) - goto Le; - goto Lnomatch; - } - if (!(*parameters)[j].matchArg(sc, e1, j, parameters, dedtypes, null)) - goto Lnomatch; + if (!e2.implicitConvTo(e1.type)) + return false; + + e2 = e2.implicitCastTo(sc, e1.type); + e2 = e2.ctfeInterpret(); + if (!e1.equals(e2)) + return false; } - else if (s1 && s2) + } + else if (e1 && t2 && t2.ty == Tident) + { + j = templateParameterLookup(t2, parameters); + L1: + if (j == IDX_NOTFOUND) { - Ls: - if (!s1.equals(s2)) - goto Lnomatch; + t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); + if (e2) + goto Le; + return false; } - else if (s1 && t2 && t2.ty == Tident) + if (!(*parameters)[j].matchArg(sc, e1, j, parameters, dedtypes, null)) + return false; + } + else if (s1 && s2) + { + Ls: + if (!s1.equals(s2)) + return false; + } + else if (s1 && t2 && t2.ty == Tident) + { + j = templateParameterLookup(t2, parameters); + if (j == IDX_NOTFOUND) { - j = templateParameterLookup(t2, parameters); - if (j == IDX_NOTFOUND) - { - t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); - if (s2) - goto Ls; - goto Lnomatch; - } - if (!(*parameters)[j].matchArg(sc, s1, j, parameters, dedtypes, null)) - goto Lnomatch; + t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); + if (s2) + goto Ls; + return false; } - else - goto Lnomatch; + if (!(*parameters)[j].matchArg(sc, s1, j, parameters, dedtypes, null)) + return false; } + else + return false; } - visit(cast(Type)t); - return; - - Lnomatch: - //printf("no match\n"); - result = MATCH.nomatch; + return true; } override void visit(TypeStruct t) From 234e39dfbb89e518207b1a4dd838b13713be925c Mon Sep 17 00:00:00 2001 From: Lucian Danescu Date: Thu, 25 May 2023 18:12:31 +0300 Subject: [PATCH 050/176] add visit method in transitive visitor for static foreach --- dmd/frontend.h | 1 + dmd/transitivevisitor.d | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/dmd/frontend.h b/dmd/frontend.h index 6b65a58d1c4..5903e3a89e5 100644 --- a/dmd/frontend.h +++ b/dmd/frontend.h @@ -8324,6 +8324,7 @@ class SemanticTimeTransitiveVisitor : public SemanticTimePermissiveVisitor void visit(ForStatement* s) override; void visit(ForeachStatement* s) override; void visit(ForeachRangeStatement* s) override; + void visit(StaticForeachStatement* s) override; void visit(IfStatement* s) override; void visit(ConditionalStatement* s) override; void visit(PragmaStatement* s) override; diff --git a/dmd/transitivevisitor.d b/dmd/transitivevisitor.d index c58827063d2..a82a268eb66 100644 --- a/dmd/transitivevisitor.d +++ b/dmd/transitivevisitor.d @@ -161,6 +161,16 @@ package mixin template ParseVisitMethods(AST) s._body.accept(this); } + override void visit(AST.StaticForeachStatement s) + { + // printf("Visiting StaticForeachStatement\n"); + if (s.sfe.aggrfe) + s.sfe.aggrfe.accept(this); + + if (s.sfe.rangefe) + s.sfe.rangefe.accept(this); + } + override void visit(AST.IfStatement s) { //printf("Visiting IfStatement\n"); From 041d909a097ce36736fedac9cc01196a70df3407 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Wed, 24 May 2023 20:57:54 -0700 Subject: [PATCH 051/176] fix Issue 21425 - Using va_start twice results in wrong values --- tests/dmd/runnable/variadic.d | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/dmd/runnable/variadic.d b/tests/dmd/runnable/variadic.d index 2d0736ded66..7e9473c332e 100644 --- a/tests/dmd/runnable/variadic.d +++ b/tests/dmd/runnable/variadic.d @@ -1118,6 +1118,53 @@ void test15417() } +/***************************************/ +// https://issues.dlang.org/show_bug.cgi?id=21425 + +import core.stdc.stdarg; +import core.stdc.stdio; + +extern(C) void f5(int dummy, ...) +{ + va_list ap; + + va_start(ap, dummy); + int x = va_arg!int(ap); + assert(x == 5); + va_end(ap); + + va_start(ap, dummy); + int y = va_arg!int(ap); + assert(y == 5); + va_end(ap); +} + +void test21425() +{ + f5(0, 5); +} + +/*********************************************/ +// https://issues.dlang.org/show_bug.cgi?id=23409 + +import core.stdc.string; + +void printf10(const(char)* fmt, ...){ + char[30] s; + for(int i = 0; i < 10; i++){ + va_list args; + va_start(args, fmt); + vsprintf(s.ptr, fmt, args); + va_end(args); + assert(strcmp(s.ptr, "Hello world\n") == 0); + } +} + +void test23409() +{ + printf10("Hello %s\n".ptr, "world".ptr); +} + /***************************************/ int main() @@ -1169,6 +1216,8 @@ int main() testCopy(); test14179(); test15417(); + test21425(); + test23409(); return 0; } From 4b2a6f84775cd11e7a24882731524307af22deb4 Mon Sep 17 00:00:00 2001 From: Ernesto Castellotti Date: Sun, 28 May 2023 16:06:50 +0200 Subject: [PATCH 052/176] Remove unused Darwin version After this commit the Darwin version is not used in this code https://github.com/dlang/druntime/commit/12454dfe028ea0379764ab88879f07450a101453 --- runtime/druntime/src/rt/alloca.d | 9 --------- 1 file changed, 9 deletions(-) diff --git a/runtime/druntime/src/rt/alloca.d b/runtime/druntime/src/rt/alloca.d index fe877f8bd34..0df157f014a 100644 --- a/runtime/druntime/src/rt/alloca.d +++ b/runtime/druntime/src/rt/alloca.d @@ -14,15 +14,6 @@ module rt.alloca; version (Posix) { version = alloca; - - version (OSX) - version = Darwin; - else version (iOS) - version = Darwin; - else version (TVOS) - version = Darwin; - else version (WatchOS) - version = Darwin; } else version (CRuntime_Microsoft) { From 3739de73a413eac03de77067d97ebf72ab189299 Mon Sep 17 00:00:00 2001 From: Ernesto Castellotti Date: Sun, 28 May 2023 23:37:06 +0200 Subject: [PATCH 053/176] Remove unused DOS386 and Unix in alloca These versions don't seem defined anywhere, plus the code is broken anyway because _x386_break and _pastdata have been commented out --- runtime/druntime/src/rt/alloca.d | 37 +------------------------------- 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/runtime/druntime/src/rt/alloca.d b/runtime/druntime/src/rt/alloca.d index 0df157f014a..28c205df6e2 100644 --- a/runtime/druntime/src/rt/alloca.d +++ b/runtime/druntime/src/rt/alloca.d @@ -25,14 +25,6 @@ else version (CRuntime_Microsoft) version (alloca) { -/+ -#if DOS386 -extern size_t _x386_break; -#else -extern size_t _pastdata; -#endif -+/ - /******************************************* * Allocate data from the caller's stack frame. * This is a 'magic' function that needs help from the compiler to @@ -84,23 +76,6 @@ extern (C) void* __alloca(int nbytes) test [ECX],EBX ; // bring in last page } } - version (DOS386) - { - asm - { - // is ESP off bottom? - cmp EAX,_x386_break ; - jbe Aoverflow ; - } - } - version (Unix) - { - asm - { - cmp EAX,_pastdata ; - jbe Aoverflow ; // Unlikely - ~2 Gbytes under UNIX - } - } asm { // Copy down to [ESP] the temps on the stack. @@ -212,17 +187,7 @@ extern (C) void* __alloca(int nbytes) neg RAX ; add RAX,RSP ; // RAX is now what the new RSP will be. jae Aoverflow ; - } - version (Unix) - { - asm - { - cmp RAX,_pastdata ; - jbe Aoverflow ; // Unlikely - ~2 Gbytes under UNIX - } - } - asm - { + // Copy down to [RSP] the temps on the stack. // The number of temps is (RBP - RSP - locals). mov RCX,RBP ; From e9d9a249b3e86bb87d8e65ad4b9b22bd917b206c Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Mon, 29 May 2023 17:43:46 -0700 Subject: [PATCH 054/176] fix Issue 23936 - ImportC: pragma pack is not working for structs --- dmd/cparse.d | 4 ++++ tests/dmd/compilable/pragmapack.c | 4 ++-- tests/dmd/compilable/test23936.i | 32 +++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 tests/dmd/compilable/test23936.i diff --git a/dmd/cparse.d b/dmd/cparse.d index a3918ec123f..5efa2e904fd 100644 --- a/dmd/cparse.d +++ b/dmd/cparse.d @@ -3876,6 +3876,10 @@ final class CParser(AST) : Parser!AST else if (!tag) error("missing tag `identifier` after `%s`", Token.toChars(structOrUnion)); + // many ways and places to declare alignment + if (packalign.isUnknown() && !this.packalign.isUnknown()) + packalign.set(this.packalign.get()); + /* Need semantic information to determine if this is a declaration, * redeclaration, or reference to existing declaration. * Defer to the semantic() pass with a TypeTag. diff --git a/tests/dmd/compilable/pragmapack.c b/tests/dmd/compilable/pragmapack.c index 52a07384713..7c2470e5664 100644 --- a/tests/dmd/compilable/pragmapack.c +++ b/tests/dmd/compilable/pragmapack.c @@ -51,7 +51,7 @@ struct S2 #pragma pack(pop) #pragma pack(show) -_Static_assert(sizeof(struct S2) == 1 + 1, "2"); +_Static_assert(sizeof(struct S2) == 8, "2"); #pragma pack(push, 8) #pragma pack(show) @@ -63,7 +63,7 @@ struct S3 #pragma pack(pop) #pragma pack(show) -_Static_assert(sizeof(struct S3) == 4, "3"); +_Static_assert(sizeof(struct S3) == 8, "3"); #pragma pack() #pragma pack(show) diff --git a/tests/dmd/compilable/test23936.i b/tests/dmd/compilable/test23936.i new file mode 100644 index 00000000000..9630d7d0e19 --- /dev/null +++ b/tests/dmd/compilable/test23936.i @@ -0,0 +1,32 @@ +// https://issues.dlang.org/show_bug.cgi?ide=23936 + +#pragma pack(push,16) +typedef struct AAATAG { + int LastExceptionFromRip; +} AAA; +#pragma pack(pop) + +#pragma pack(push, 16) +typedef struct { + long long val; +} BBB; +#pragma pack(pop) + + +__pragma(pack(push,16)) +typedef struct XXXTAG { + int LastExceptionFromRip; +} XXX; +__pragma(pack(pop)) + +__pragma(pack(push, 16)) +typedef struct { + long long val; +} YYY; +__pragma(pack(pop)) + + +_Static_assert(_Alignof(AAA) == 16, "1"); +_Static_assert(_Alignof(BBB) == 16, "2"); +_Static_assert(_Alignof(XXX) == 16, "3"); +_Static_assert(_Alignof(YYY) == 16, "4"); From 41ccf738dfd3e62b6604998e6303679129315cb2 Mon Sep 17 00:00:00 2001 From: Atila Neves Date: Tue, 30 May 2023 16:44:00 +0200 Subject: [PATCH 055/176] Make object.d compile with -preview=nosharedaccess (dlang/dmd!15281) --- runtime/druntime/src/object.d | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtime/druntime/src/object.d b/runtime/druntime/src/object.d index 3b3cdda7a68..337eabf64db 100644 --- a/runtime/druntime/src/object.d +++ b/runtime/druntime/src/object.d @@ -527,7 +527,8 @@ private extern(C) void _d_setSameMutex(shared Object ownee, shared Object owner) void setSameMutex(shared Object ownee, shared Object owner) { - _d_setSameMutex(ownee, owner); + import core.atomic : atomicLoad; + _d_setSameMutex(atomicLoad(ownee), atomicLoad(owner)); } @system unittest From 6d31e241f0bd7891a8d8838bb376e5436485806e Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Tue, 30 May 2023 09:01:18 -0700 Subject: [PATCH 056/176] fix Issue 23935 - ImportC: __pragma not allowed between struct and tag name (dlang/dmd!15279) --- dmd/cparse.d | 33 ++++++++++++++++++++++++++------ tests/dmd/compilable/test23935.i | 12 ++++++++++++ 2 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 tests/dmd/compilable/test23935.i diff --git a/dmd/cparse.d b/dmd/cparse.d index 5efa2e904fd..33669e38c41 100644 --- a/dmd/cparse.d +++ b/dmd/cparse.d @@ -2358,6 +2358,8 @@ final class CParser(AST) : Parser!AST cparseGnuAttributes(tagSpecifier); else if (token.value == TOK.__declspec) cparseDeclspec(tagSpecifier); + else if (token.value == TOK.__pragma) + uupragmaDirective(sloc); else break; } @@ -5464,20 +5466,39 @@ final class CParser(AST) : Parser!AST private void uupragmaDirective(const ref Loc startloc) { const loc = startloc; - nextToken(); + nextToken(); // move past __pragma if (token.value != TOK.leftParenthesis) { - error(loc, "left parenthesis expected to follow `__pragma`"); + error(loc, "left parenthesis expected to follow `__pragma` instead of `%s`", token.toChars()); + nextToken(); return; } nextToken(); - if (token.value == TOK.identifier && token.ident == Id.pack) - pragmaPack(startloc, false); + + if (token.value == TOK.identifier) + { + if (token.ident == Id.pack) + pragmaPack(startloc, false); + else + { + nextToken(); + if (token.value == TOK.leftParenthesis) + cparseParens(); + } + + } + else if (token.value == TOK.endOfFile) + { + } + else if (token.value == TOK.rightParenthesis) + { + } else - error(loc, "unrecognized __pragma"); + error(loc, "unrecognized `__pragma(%s)`", token.toChars()); + if (token.value != TOK.rightParenthesis) { - error(loc, "right parenthesis expected to close `__pragma(...)`"); + error(loc, "right parenthesis expected to close `__pragma(...)` instead of `%s`", token.toChars()); return; } nextToken(); diff --git a/tests/dmd/compilable/test23935.i b/tests/dmd/compilable/test23935.i new file mode 100644 index 00000000000..90f4024e138 --- /dev/null +++ b/tests/dmd/compilable/test23935.i @@ -0,0 +1,12 @@ +// https://issues.dlang.org/show_bug.cgi?id=23935 + +typedef struct + __declspec(align(16)) + __pragma(warning(push)) + __pragma(warning(disable:4845)) + __declspec(no_init_all) + __pragma(warning(pop)) + _CONTEXT +{ + int i; +} _CONTEXT; From 8d75360ada91a909edda7b0285892ac43ede052b Mon Sep 17 00:00:00 2001 From: Ernesto Castellotti Date: Wed, 31 May 2023 12:37:05 +0200 Subject: [PATCH 057/176] Fix issue 23948 - __FILE__ and __MODULE__ cannot be implicitly converted to const(char)* as default paramenter (dlang/dmd!15283) --- dmd/expression.d | 15 ++++----------- tests/dmd/compilable/test23948.d | 29 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 11 deletions(-) create mode 100644 tests/dmd/compilable/test23948.d diff --git a/dmd/expression.d b/dmd/expression.d index 14c31591a98..473efb8c99a 100644 --- a/dmd/expression.d +++ b/dmd/expression.d @@ -7100,9 +7100,7 @@ extern (C++) final class FileInitExp : DefaultInitExp s = loc.isValid() ? loc.filename : sc._module.ident.toChars(); Expression e = new StringExp(loc, s.toDString()); - e = e.expressionSemantic(sc); - e = e.castTo(sc, type); - return e; + return e.expressionSemantic(sc); } override void accept(Visitor v) @@ -7124,8 +7122,7 @@ extern (C++) final class LineInitExp : DefaultInitExp override Expression resolveLoc(const ref Loc loc, Scope* sc) { Expression e = new IntegerExp(loc, loc.linnum, Type.tint32); - e = e.castTo(sc, type); - return e; + return e.expressionSemantic(sc); } override void accept(Visitor v) @@ -7148,9 +7145,7 @@ extern (C++) final class ModuleInitExp : DefaultInitExp { const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString(); Expression e = new StringExp(loc, s); - e = e.expressionSemantic(sc); - e = e.castTo(sc, type); - return e; + return e.expressionSemantic(sc); } override void accept(Visitor v) @@ -7179,9 +7174,7 @@ extern (C++) final class FuncInitExp : DefaultInitExp else s = ""; Expression e = new StringExp(loc, s.toDString()); - e = e.expressionSemantic(sc); - e.type = Type.tstring; - return e; + return e.expressionSemantic(sc); } override void accept(Visitor v) diff --git a/tests/dmd/compilable/test23948.d b/tests/dmd/compilable/test23948.d new file mode 100644 index 00000000000..4f7b8da093a --- /dev/null +++ b/tests/dmd/compilable/test23948.d @@ -0,0 +1,29 @@ +// https://issues.dlang.org/show_bug.cgi?id=23948 + +void foo1(const(char)* fun = __FILE__)() { + +} + +void foo2(const(char)* fun = __FILE_FULL_PATH__)() { + +} + +void foo3(const(char)* fun = __MODULE__)() { + +} + +void foo4(const(char)* fun = __FUNCTION__)() { + +} + +void foo5(const(char)* fun = __PRETTY_FUNCTION__)() { + +} + +void main() { + foo1(); + foo2(); + foo3(); + foo4(); + foo5(); +} From be5850938f72cc56334538ccc47c836f3adbb0e2 Mon Sep 17 00:00:00 2001 From: Ernesto Castellotti Date: Wed, 31 May 2023 13:53:37 +0200 Subject: [PATCH 058/176] Add noreturn to core.stdc.assert_ (dlang/dmd!15284) We now have noreturn so we don't need to use void anymore and it makes these functions easier to use --- runtime/druntime/src/core/stdc/assert_.d | 31 ++++++++++++------------ 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/runtime/druntime/src/core/stdc/assert_.d b/runtime/druntime/src/core/stdc/assert_.d index fc9402f6051..556b56cbd29 100644 --- a/runtime/druntime/src/core/stdc/assert_.d +++ b/runtime/druntime/src/core/stdc/assert_.d @@ -12,7 +12,6 @@ /**************************** * These are the various functions called by the assert() macro. - * They are all noreturn functions, although D doesn't have a specific attribute for that. */ module core.stdc.assert_; @@ -36,7 +35,7 @@ version (CRuntime_DigitalMars) /*** * Assert failure function in the Digital Mars C library. */ - void _assert(const(void)* exp, const(void)* file, uint line); + noreturn _assert(const(void)* exp, const(void)* file, uint line); } else version (CRuntime_Microsoft) { @@ -44,37 +43,37 @@ else version (CRuntime_Microsoft) * Assert failure function in the Microsoft C library. * `_assert` is not in assert.h, but it is in the library. */ - void _wassert(const(wchar)* exp, const(wchar)* file, uint line); + noreturn _wassert(const(wchar)* exp, const(wchar)* file, uint line); /// - void _assert(const(char)* exp, const(char)* file, uint line); + noreturn _assert(const(char)* exp, const(char)* file, uint line); } else version (Darwin) { /*** * Assert failure function in the Darwin C library. */ - void __assert_rtn(const(char)* func, const(char)* file, uint line, const(char)* exp); + noreturn __assert_rtn(const(char)* func, const(char)* file, uint line, const(char)* exp); } else version (FreeBSD) { /*** * Assert failure function in the FreeBSD C library. */ - void __assert(const(char)* exp, const(char)* file, uint line); + noreturn __assert(const(char)* exp, const(char)* file, uint line); } else version (NetBSD) { /*** * Assert failure function in the NetBSD C library. */ - void __assert(const(char)* file, int line, const(char)* exp); + noreturn __assert(const(char)* file, int line, const(char)* exp); } else version (OpenBSD) { /*** * Assert failure function in the OpenBSD C library. */ - void __assert(const(char)* file, int line, const(char)* exp); + noreturn __assert(const(char)* file, int line, const(char)* exp); /// void __assert2(const(char)* file, int line, const(char)* func, const(char)* exp); } @@ -83,37 +82,37 @@ else version (DragonFlyBSD) /*** * Assert failure function in the DragonFlyBSD C library. */ - void __assert(const(char)* exp, const(char)* file, uint line); + noreturn __assert(const(char)* exp, const(char)* file, uint line); } else version (CRuntime_Glibc) { /*** * Assert failure functions in the GLIBC library. */ - void __assert(const(char)* exp, const(char)* file, uint line); + noreturn __assert(const(char)* exp, const(char)* file, uint line); /// - void __assert_fail(const(char)* exp, const(char)* file, uint line, const(char)* func); + noreturn __assert_fail(const(char)* exp, const(char)* file, uint line, const(char)* func); /// - void __assert_perror_fail(int errnum, const(char)* file, uint line, const(char)* func); + noreturn __assert_perror_fail(int errnum, const(char)* file, uint line, const(char)* func); } else version (CRuntime_Bionic) { - void __assert(const(char)* __file, int __line, const(char)* __msg); + noreturn __assert(const(char)* __file, int __line, const(char)* __msg); } else version (CRuntime_Musl) { /*** * Assert failure function in the Musl C library. */ - void __assert_fail(const(char)* exp, const(char)* file, uint line, const(char)* func); + noreturn __assert_fail(const(char)* exp, const(char)* file, uint line, const(char)* func); } else version (CRuntime_UClibc) { - void __assert(const(char)* exp, const(char)* file, uint line, const(char)* func); + noreturn __assert(const(char)* exp, const(char)* file, uint line, const(char)* func); } else version (Solaris) { - void __assert_c99(const(char)* exp, const(char)* file, uint line, const(char)* func); + noreturn __assert_c99(const(char)* exp, const(char)* file, uint line, const(char)* func); } else { From b283f4a32864a53c5ed1a49848010d9e8870819d Mon Sep 17 00:00:00 2001 From: Razvan Nitu Date: Thu, 1 Jun 2023 06:09:48 +0300 Subject: [PATCH 059/176] Fix Issue 16384 - Invariant not called with multiple defined. (dlang/dmd!15280) --- dmd/sideeffect.d | 6 ++-- tests/dmd/runnable/testinvariant.d | 53 ++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/dmd/sideeffect.d b/dmd/sideeffect.d index 024719e3748..90b86df0418 100644 --- a/dmd/sideeffect.d +++ b/dmd/sideeffect.d @@ -101,9 +101,11 @@ extern (C++) bool hasSideEffect(Expression e, bool assumeImpureCalls = false) int callSideEffectLevel(FuncDeclaration f) { /* https://issues.dlang.org/show_bug.cgi?id=12760 - * ctor call always has side effects. + * https://issues.dlang.org/show_bug.cgi?id=16384 + * + * ctor calls and invariant calls always have side effects */ - if (f.isCtorDeclaration()) + if (f.isCtorDeclaration() || f.isInvariantDeclaration()) return 0; assert(f.type.ty == Tfunction); TypeFunction tf = cast(TypeFunction)f.type; diff --git a/tests/dmd/runnable/testinvariant.d b/tests/dmd/runnable/testinvariant.d index d3b3b6ffa16..0ce85571911 100644 --- a/tests/dmd/runnable/testinvariant.d +++ b/tests/dmd/runnable/testinvariant.d @@ -176,6 +176,58 @@ void test13147() s.test(); } +/***************************************************/ +// https://issues.dlang.org/show_bug.cgi?id=16384 + +struct S(T) +{ + T x = 5; + invariant { assert(x == 6); } + invariant { assert(x > 0); } + + void foo() {} +} + +void f(int i) pure { assert( i == 6); } + +struct S2(T) +{ + T x = 5; + invariant { f(x); } + invariant { assert(x > 0); } + + void foo() {} +} + +void test16384() +{ + string s; + S!int y; + try + { + y.foo(); + } + catch(Error) + { + s = "needs to be thrown"; + } + + assert(s == "needs to be thrown"); + + S2!int y2; + + try + { + y2.foo(); + } + catch(Error) + { + s = "needs to be thrown2"; + } + + assert(s == "needs to be thrown2"); +} + /***************************************************/ @@ -183,6 +235,7 @@ void main() { testinvariant(); test6453(); + test16384(); test13113(); test13147(); } From 99f366197d681372bb59450b4c2c9a7e53e1467c Mon Sep 17 00:00:00 2001 From: RazvanN7 Date: Thu, 1 Jun 2023 07:51:15 +0300 Subject: [PATCH 060/176] Make druntime/src/rt/lifetime._d_arrayshrinkfit trully nothrow --- runtime/druntime/src/rt/lifetime.d | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/runtime/druntime/src/rt/lifetime.d b/runtime/druntime/src/rt/lifetime.d index 947bdee245f..40fa3e00b45 100644 --- a/runtime/druntime/src/rt/lifetime.d +++ b/runtime/druntime/src/rt/lifetime.d @@ -676,7 +676,7 @@ Params: ti = `TypeInfo` of array type arr = array to shrink. Its `.length` is element length, not byte length, despite `void` type */ -extern(C) void _d_arrayshrinkfit(const TypeInfo ti, void[] arr) /+nothrow+/ +extern(C) void _d_arrayshrinkfit(const TypeInfo ti, void[] arr) nothrow { // note, we do not care about shared. We are setting the length no matter // what, so no lock is required. @@ -701,7 +701,17 @@ extern(C) void _d_arrayshrinkfit(const TypeInfo ti, void[] arr) /+nothrow+/ { auto oldsize = __arrayAllocLength(info, tinext); if (oldsize > cursize) - finalize_array(arr.ptr + cursize, oldsize - cursize, sti); + { + try + { + finalize_array(arr.ptr + cursize, oldsize - cursize, sti); + } + catch (Exception e) + { + import core.exception : onFinalizeError; + onFinalizeError(sti, e); + } + } } } // Note: Since we "assume" the append is safe, it means it is not shared. From c048cd834a002a9ccecc2cf88297ae7d45c45941 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Thu, 1 Jun 2023 04:06:41 -0700 Subject: [PATCH 061/176] fix Issue 23719 - runnable/test22071.c:22:16: error: .abc. is a pointer; did you mean to use .->.? (dlang/dmd!15287) --- dmd/expressionsem.d | 4 ++-- dmd/importc.d | 6 +++++- tests/dmd/fail_compilation/fix22253.c | 2 +- tests/dmd/fail_compilation/test23719.c | 19 +++++++++++++++++++ tests/dmd/runnable/test22071.c | 2 +- 5 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 tests/dmd/fail_compilation/test23719.c diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index 01462b2cadd..8ac8866a85b 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -6788,7 +6788,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (exp.ident != Id.__sizeof) { - result = fieldLookup(exp.e1, sc, exp.ident); + result = fieldLookup(exp.e1, sc, exp.ident, exp.arrow); return; } } @@ -9123,7 +9123,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor else if (sc.flags & SCOPE.Cfile && e1x.isDotIdExp()) { auto die = e1x.isDotIdExp(); - e1x = fieldLookup(die.e1, sc, die.ident); + e1x = fieldLookup(die.e1, sc, die.ident, die.arrow); } else if (auto die = e1x.isDotIdExp()) { diff --git a/dmd/importc.d b/dmd/importc.d index 05f92b07a75..fe0aa171d98 100644 --- a/dmd/importc.d +++ b/dmd/importc.d @@ -108,11 +108,12 @@ Expression arrayFuncConv(Expression e, Scope* sc) * e = evaluates to an instance of a struct * sc = context * id = identifier of a field in that struct + * arrow = -> was used * Returns: * if successful `e.ident` * if not then `ErrorExp` and message is printed */ -Expression fieldLookup(Expression e, Scope* sc, Identifier id) +Expression fieldLookup(Expression e, Scope* sc, Identifier id, bool arrow) { e = e.expressionSemantic(sc); if (e.isErrorExp()) @@ -123,6 +124,9 @@ Expression fieldLookup(Expression e, Scope* sc, Identifier id) if (t.isTypePointer()) { t = t.isTypePointer().next; + auto pe = e.toChars(); + if (!arrow) + e.error("since `%s` is a pointer, use `%s->%s` instead of `%s.%s`", pe, pe, id.toChars(), pe, id.toChars()); e = new PtrExp(e.loc, e); } if (auto ts = t.isTypeStruct()) diff --git a/tests/dmd/fail_compilation/fix22253.c b/tests/dmd/fail_compilation/fix22253.c index 22ddf96d607..c7f41345142 100644 --- a/tests/dmd/fail_compilation/fix22253.c +++ b/tests/dmd/fail_compilation/fix22253.c @@ -19,7 +19,7 @@ void test() char *p = a.ptr; unsigned i = a.length; char *q = a.dup.ptr; - p = p.init; + p = p->init; struct S { int a, b; }; struct S s; s.a = s.b; diff --git a/tests/dmd/fail_compilation/test23719.c b/tests/dmd/fail_compilation/test23719.c new file mode 100644 index 00000000000..f8675e750b9 --- /dev/null +++ b/tests/dmd/fail_compilation/test23719.c @@ -0,0 +1,19 @@ +/* TEST_OUTPUT: +--- +fail_compilation/test23719.c(15): Error: since `abc` is a pointer, use `abc->b` instead of `abc.b` +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=23719 + +struct S { int a, b; }; + +struct S *abc = &(struct S){ 1, 2 }; + +int main() +{ + int j = abc.b; + if (j != 2) + return 1; + return 0; +} diff --git a/tests/dmd/runnable/test22071.c b/tests/dmd/runnable/test22071.c index 31c1485bb4a..3ab85b69d14 100644 --- a/tests/dmd/runnable/test22071.c +++ b/tests/dmd/runnable/test22071.c @@ -19,7 +19,7 @@ int main() int i = test(); if (i != 2) return 1; - int j = abc.b; + int j = abc->b; if (j != 2) return 1; return 0; From 2ef3ed939ce7b481794aaa63deac2d9122a57fcd Mon Sep 17 00:00:00 2001 From: Atila Neves Date: Fri, 2 Jun 2023 16:41:16 +0200 Subject: [PATCH 062/176] Make usage of std{in,out,err} compile with -preview=nosharedaccess (dlang/dmd!15138) * Make usage of std{in,out,err} compile with -preview=nosharedaccess * atomicLoad takes parameter by auto ref instead of ref --- runtime/druntime/src/core/atomic.d | 6 +++--- runtime/druntime/src/core/internal/gc/proxy.d | 7 +++++-- runtime/druntime/src/core/internal/parseoptions.d | 12 +++++++++--- runtime/druntime/src/core/stdc/wchar_.d | 5 +++-- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/runtime/druntime/src/core/atomic.d b/runtime/druntime/src/core/atomic.d index 5a7d00c38db..940ed1fae66 100644 --- a/runtime/druntime/src/core/atomic.d +++ b/runtime/druntime/src/core/atomic.d @@ -85,7 +85,7 @@ enum MemoryOrder * Returns: * The value of 'val'. */ -T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(ref return scope const T val) pure nothrow @nogc @trusted +T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(auto ref return scope const T val) pure nothrow @nogc @trusted if (!is(T == shared U, U) && !is(T == shared inout U, U) && !is(T == shared const U, U)) { static if (__traits(isFloating, T)) @@ -99,7 +99,7 @@ T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(ref return scope const T val) } /// Ditto -T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(ref return scope shared const T val) pure nothrow @nogc @trusted +T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(auto ref return scope shared const T val) pure nothrow @nogc @trusted if (!hasUnsharedIndirections!T) { import core.internal.traits : hasUnsharedIndirections; @@ -109,7 +109,7 @@ T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(ref return scope shared const } /// Ditto -TailShared!T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(ref shared const T val) pure nothrow @nogc @trusted +TailShared!T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(auto ref shared const T val) pure nothrow @nogc @trusted if (hasUnsharedIndirections!T) { // HACK: DEPRECATE THIS FUNCTION, IT IS INVALID TO DO ATOMIC LOAD OF SHARED CLASS diff --git a/runtime/druntime/src/core/internal/gc/proxy.d b/runtime/druntime/src/core/internal/gc/proxy.d index 695ef061a81..abc8c6ac2ea 100644 --- a/runtime/druntime/src/core/internal/gc/proxy.d +++ b/runtime/druntime/src/core/internal/gc/proxy.d @@ -62,8 +62,9 @@ extern (C) { import core.stdc.stdio : fprintf, stderr; import core.stdc.stdlib : exit; + import core.atomic : atomicLoad; - fprintf(stderr, "No GC was initialized, please recheck the name of the selected GC ('%.*s').\n", cast(int)config.gc.length, config.gc.ptr); + fprintf(atomicLoad(stderr), "No GC was initialized, please recheck the name of the selected GC ('%.*s').\n", cast(int)config.gc.length, config.gc.ptr); instanceLock.unlock(); exit(1); @@ -97,7 +98,9 @@ extern (C) { default: import core.stdc.stdio : fprintf, stderr; - fprintf(stderr, "Unknown GC cleanup method, please recheck ('%.*s').\n", + import core.atomic : atomicLoad; + + fprintf(atomicLoad(stderr), "Unknown GC cleanup method, please recheck ('%.*s').\n", cast(int)config.cleanup.length, config.cleanup.ptr); break; case "none": diff --git a/runtime/druntime/src/core/internal/parseoptions.d b/runtime/druntime/src/core/internal/parseoptions.d index ed6251f758b..ac0eb826b35 100644 --- a/runtime/druntime/src/core/internal/parseoptions.d +++ b/runtime/druntime/src/core/internal/parseoptions.d @@ -146,9 +146,11 @@ private: bool optError(const scope char[] msg, const scope char[] name, const(char)[] errName) { + import core.atomic : atomicLoad; + version (CoreUnittest) if (inUnittest) return false; - fprintf(stderr, "%.*s %.*s option '%.*s'.\n", + fprintf(atomicLoad(stderr), "%.*s %.*s option '%.*s'.\n", cast(int)msg.length, msg.ptr, cast(int)errName.length, errName.ptr, cast(int)name.length, name.ptr); @@ -332,9 +334,11 @@ do bool parseError(const scope char[] exp, const scope char[] opt, const scope char[] got, const(char)[] errName) { + import core.atomic : atomicLoad; + version (CoreUnittest) if (inUnittest) return false; - fprintf(stderr, "Expecting %.*s as argument for %.*s option '%.*s', got '%.*s' instead.\n", + fprintf(atomicLoad(stderr), "Expecting %.*s as argument for %.*s option '%.*s', got '%.*s' instead.\n", cast(int)exp.length, exp.ptr, cast(int)errName.length, errName.ptr, cast(int)opt.length, opt.ptr, @@ -344,9 +348,11 @@ bool parseError(const scope char[] exp, const scope char[] opt, const scope char bool overflowedError(const scope char[] opt, const scope char[] got) { + import core.atomic : atomicLoad; + version (CoreUnittest) if (inUnittest) return false; - fprintf(stderr, "Argument for %.*s option '%.*s' is too big.\n", + fprintf(atomicLoad(stderr), "Argument for %.*s option '%.*s' is too big.\n", cast(int)opt.length, opt.ptr, cast(int)got.length, got.ptr); return false; diff --git a/runtime/druntime/src/core/stdc/wchar_.d b/runtime/druntime/src/core/stdc/wchar_.d index fe5fce481cd..2d01e2634dc 100644 --- a/runtime/druntime/src/core/stdc/wchar_.d +++ b/runtime/druntime/src/core/stdc/wchar_.d @@ -17,6 +17,7 @@ module core.stdc.wchar_; import core.stdc.config; import core.stdc.stdarg; // for va_list import core.stdc.stdio; // for FILE, not exposed per spec +import core.atomic : atomicLoad; public import core.stdc.stddef; // for wchar_t public import core.stdc.time; // for tm public import core.stdc.stdint; // for WCHAR_MIN, WCHAR_MAX @@ -211,9 +212,9 @@ int fputws(const scope wchar_t* s, FILE* stream); extern (D) @trusted { /// - wint_t getwchar() { return fgetwc(stdin); } + wint_t getwchar() { return fgetwc(atomicLoad(stdin)); } /// - wint_t putwchar(wchar_t c) { return fputwc(c,stdout); } + wint_t putwchar(wchar_t c) { return fputwc(c,atomicLoad(stdout)); } } /// From 96d1e301cba67eaecd5b31401d0ea3730d8a86a4 Mon Sep 17 00:00:00 2001 From: Ernesto Castellotti Date: Sat, 3 Jun 2023 00:26:45 +0200 Subject: [PATCH 063/176] Add missing functions and noreturn to core.stdc.assert_ --- runtime/druntime/src/core/stdc/assert_.d | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/runtime/druntime/src/core/stdc/assert_.d b/runtime/druntime/src/core/stdc/assert_.d index a8909e26126..d6cb8a608a0 100644 --- a/runtime/druntime/src/core/stdc/assert_.d +++ b/runtime/druntime/src/core/stdc/assert_.d @@ -59,7 +59,7 @@ else version (FreeBSD) /*** * Assert failure function in the FreeBSD C library. */ - noreturn __assert(const(char)* exp, const(char)* file, uint line, const(char)* exp); + noreturn __assert(const(char)* func, const(char)* file, uint line, const(char)* exp); } else version (NetBSD) { @@ -67,6 +67,8 @@ else version (NetBSD) * Assert failure function in the NetBSD C library. */ noreturn __assert(const(char)* file, int line, const(char)* exp); + /// + noreturn __assert13(const(char)* file, int line, const(char)* func, const(char)* exp); } else version (OpenBSD) { @@ -75,14 +77,14 @@ else version (OpenBSD) */ noreturn __assert(const(char)* file, int line, const(char)* exp); /// - void __assert2(const(char)* file, int line, const(char)* func, const(char)* exp); + noreturn __assert2(const(char)* file, int line, const(char)* func, const(char)* exp); } else version (DragonFlyBSD) { /*** * Assert failure function in the DragonFlyBSD C library. */ - noreturn __assert(const(char)* exp, const(char)* file, uint line, const(char)* exp); + noreturn __assert(const(char)* func, const(char)* file, uint line, const(char)* exp); } else version (CRuntime_Glibc) { @@ -97,7 +99,12 @@ else version (CRuntime_Glibc) } else version (CRuntime_Bionic) { + /*** + * Assert failure functions in the Bionic library. + */ noreturn __assert(const(char)* __file, int __line, const(char)* __msg); + /// + noreturn __assert2(const(char)* __file, int __line, const(char)* __function, const(char)* __msg); } else version (CRuntime_Musl) { From cfb59161e990760b4175c2f7c7fc830868542ce8 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Tue, 6 Jun 2023 06:37:25 -0700 Subject: [PATCH 064/176] core.sys.windows.dll improve documentation (dlang/dmd!15291) --- runtime/druntime/src/core/sys/windows/dll.d | 49 +++++++++++++++------ 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/runtime/druntime/src/core/sys/windows/dll.d b/runtime/druntime/src/core/sys/windows/dll.d index d6fde15f05c..cb2e84aeaa2 100644 --- a/runtime/druntime/src/core/sys/windows/dll.d +++ b/runtime/druntime/src/core/sys/windows/dll.d @@ -325,6 +325,8 @@ public: * first access to a __declspec(thread) variable occurs, that is." * * _tls_index is initialized by the compiler to 0, so we can use this as a test. + * Returns: + * true for success, false for failure */ bool dll_fixTLS( HINSTANCE hInstance, void* tlsstart, void* tlsend, void* tls_callbacks_a, int* tlsindex ) nothrow { @@ -431,8 +433,13 @@ int dll_getRefCount( HINSTANCE hInstance ) nothrow @nogc return ldrMod.LoadCount; } -// fixup TLS storage, initialize runtime and attach to threads -// to be called from DllMain with reason DLL_PROCESS_ATTACH +/***************************** + * To be called from DllMain with reason DLL_PROCESS_ATTACH + * + * fixup TLS storage, initialize runtime and attach to threads + * Returns: + * true = success, false = failure + */ bool dll_process_attach( HINSTANCE hInstance, bool attach_threads, void* tlsstart, void* tlsend, void* tls_callbacks_a, int* tlsindex ) { @@ -463,7 +470,8 @@ bool dll_process_attach( HINSTANCE hInstance, bool attach_threads, }, null ); } -// same as above, but only usable if druntime is linked statically +/** same as above, but only usable if druntime is linked statically + */ bool dll_process_attach( HINSTANCE hInstance, bool attach_threads = true ) { version (Win64) @@ -478,7 +486,9 @@ bool dll_process_attach( HINSTANCE hInstance, bool attach_threads = true ) } } -// to be called from DllMain with reason DLL_PROCESS_DETACH +/** + * to be called from DllMain with reason DLL_PROCESS_DETACH + */ void dll_process_detach( HINSTANCE hInstance, bool detach_threads = true ) { // notify core.thread.joinLowLevelThread that the DLL is about to be unloaded @@ -510,7 +520,11 @@ static bool tlsCtorRun; static this() { tlsCtorRun = true; } static ~this() { tlsCtorRun = false; } -// to be called from DllMain with reason DLL_THREAD_ATTACH +/** + * To be called from DllMain with reason DLL_THREAD_ATTACH + * Returns: + * true for success, false for failure + */ bool dll_thread_attach( bool attach_thread = true, bool initTls = true ) { // if the OS has not prepared TLS for us, don't attach to the thread @@ -529,7 +543,11 @@ bool dll_thread_attach( bool attach_thread = true, bool initTls = true ) return true; } -// to be called from DllMain with reason DLL_THREAD_DETACH +/** + * To be called from DllMain with reason DLL_THREAD_DETACH + * Returns: + * true for success, false for failure + */ bool dll_thread_detach( bool detach_thread = true, bool exitTls = true ) { // if the OS has not prepared TLS for us, we did not attach to the thread @@ -545,14 +563,17 @@ bool dll_thread_detach( bool detach_thread = true, bool exitTls = true ) return true; } -/// A simple mixin to provide a $(D DllMain) which calls the necessary -/// runtime initialization and termination functions automatically. -/// -/// Instead of writing a custom $(D DllMain), simply write: -/// -/// --- -/// mixin SimpleDllMain; -/// --- +/********************************** + * A mixin to provide a $(D DllMain) which calls the necessary + * D runtime initialization and termination functions automatically. + * + * Example: + * --- + * module dllmain; + * import core.sys.windows.dll; + * mixin SimpleDllMain; + * --- + */ mixin template SimpleDllMain() { import core.sys.windows.windef : HINSTANCE, BOOL, DWORD, LPVOID; From a2517344050756d409c6998fc3999799834f14cf Mon Sep 17 00:00:00 2001 From: Dennis Date: Mon, 12 Jun 2023 14:47:10 +0200 Subject: [PATCH 065/176] Refactor local variables in `deduceFunctionTemplateMatch` (dlang/dmd!15311) --- dmd/dtemplate.d | 64 ++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/dmd/dtemplate.d b/dmd/dtemplate.d index 5b98d2f4877..f2ab69444bc 100644 --- a/dmd/dtemplate.d +++ b/dmd/dtemplate.d @@ -1302,36 +1302,19 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol /************************************************* * Match function arguments against a specific template function. - * Input: - * ti - * sc instantiation scope - * fd - * tthis 'this' argument if !NULL - * argumentList arguments to function - * Output: - * fd Partially instantiated function declaration - * ti.tdtypes Expression/Type deduced template arguments + * + * Params: + * ti = template instance. `ti.tdtypes` will be set to Expression/Type deduced template arguments + * sc = instantiation scope + * fd = Partially instantiated function declaration, which is set to an instantiated function declaration + * tthis = 'this' argument if !NULL + * argumentList = arguments to function + * * Returns: * match pair of initial and inferred template arguments */ extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateInstance ti, Scope* sc, ref FuncDeclaration fd, Type tthis, ArgumentList argumentList) { - size_t nfparams; - size_t nfargs; - size_t ntargs; // array size of tiargs - size_t fptupindex = IDX_NOTFOUND; - MATCH match = MATCH.exact; - MATCH matchTiargs = MATCH.exact; - ParameterList fparameters; // function parameter list - VarArg fvarargs; // function varargs - uint wildmatch = 0; - size_t inferStart = 0; - - Loc instLoc = ti.loc; - Objects* tiargs = ti.tiargs; - auto dedargs = new Objects(parameters.length); - Objects* dedtypes = &ti.tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T - version (none) { printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", toChars()); @@ -1348,8 +1331,10 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol assert(_scope); + auto dedargs = new Objects(parameters.length); dedargs.zero(); + Objects* dedtypes = &ti.tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T dedtypes.setDim(parameters.length); dedtypes.zero(); @@ -1393,8 +1378,12 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } } - ntargs = 0; - if (tiargs) + size_t ntargs = 0; // array size of tiargs + size_t inferStart = 0; // index of first parameter to infer + const Loc instLoc = ti.loc; + MATCH matchTiargs = MATCH.exact; + + if (auto tiargs = ti.tiargs) { // Set initial template arguments ntargs = tiargs.length; @@ -1460,9 +1449,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } } - fparameters = fd.getParameterList(); - nfparams = fparameters.length; // number of function parameters - nfargs = argumentList.length; // number of function arguments + ParameterList fparameters = fd.getParameterList(); // function parameter list + const nfparams = fparameters.length; // number of function parameters + const nfargs = argumentList.length; // number of function arguments if (argumentList.hasNames) return matcherror(); // TODO: resolve named args Expressions* fargs = argumentList.arguments; // TODO: resolve named args @@ -1473,6 +1462,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol * void foo(T, A...)(T t, A a); * void main() { foo(1,2,3); } */ + size_t fptupindex = IDX_NOTFOUND; if (tp) // if variadic { // TemplateTupleParameter always makes most lesser matching. @@ -1515,6 +1505,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } } + MATCH match = MATCH.exact; if (toParent().isModule()) tthis = null; if (tthis) @@ -1579,6 +1570,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL); size_t argi = 0; size_t nfargs2 = nfargs; // nfargs + supplied defaultArgs + uint inoutMatch = 0; // for debugging only for (size_t parami = 0; parami < nfparams; parami++) { Parameter fparam = fparameters[parami]; @@ -1643,7 +1635,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol MATCH m; if (ubyte wm = deduceWildHelper(farg.type, &tt, tid)) { - wildmatch |= wm; + inoutMatch |= wm; m = MATCH.constant; } else @@ -1896,10 +1888,10 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < nfargs) goto Lvarargs; - uint wm = 0; - MATCH m = deduceType(oarg, paramscope, prmtype, parameters, dedtypes, &wm, inferStart); - //printf("\tL%d deduceType m = %d, wm = x%x, wildmatch = x%x\n", __LINE__, m, wm, wildmatch); - wildmatch |= wm; + uint im = 0; + MATCH m = deduceType(oarg, paramscope, prmtype, parameters, dedtypes, &im, inferStart); + //printf("\tL%d deduceType m = %d, im = x%x, inoutMatch = x%x\n", __LINE__, m, im, inoutMatch); + inoutMatch |= im; /* If no match, see if the argument can be matched by using * implicit conversions. @@ -2087,7 +2079,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol { uint wm = 0; m = deduceType(arg, paramscope, ta.next, parameters, dedtypes, &wm, inferStart); - wildmatch |= wm; + inoutMatch |= wm; } if (m == MATCH.nomatch) return nomatch(); From 04b811528479fc03c2197984b0aeb96a200efd65 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Mon, 12 Jun 2023 06:46:15 -0700 Subject: [PATCH 066/176] riden should be ridden (dlang/dmd!15309) --- dmd/canthrow.d | 2 +- dmd/cli.d | 6 +++--- dmd/compiler.d | 2 +- dmd/dsymbolsem.d | 6 +++--- dmd/dtoh.d | 2 +- dmd/expression.d | 10 +++++----- dmd/semantic3.d | 2 +- tests/dmd/fail_compilation/dtor_attributes.d | 2 +- tests/dmd/fail_compilation/fail19209.d | 2 +- tests/dmd/fail_compilation/fail23745.d | 2 +- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/dmd/canthrow.d b/dmd/canthrow.d index 09d39ca6f1c..5ffa4260e46 100644 --- a/dmd/canthrow.d +++ b/dmd/canthrow.d @@ -80,7 +80,7 @@ extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustN if (!f.isDtorDeclaration()) errorSupplementalInferredAttr(f, 10, false, STC.nothrow_); - e.checkOverridenDtor(null, f, dd => dd.type.toTypeFunction().isnothrow, "not nothrow"); + e.checkOverriddenDtor(null, f, dd => dd.type.toTypeFunction().isnothrow, "not nothrow"); } else if (func) { diff --git a/dmd/cli.d b/dmd/cli.d index 597b7beec3a..6bd8c17353b 100644 --- a/dmd/cli.d +++ b/dmd/cli.d @@ -429,7 +429,7 @@ dmd -cov -unittest myprog.d q"{$(P Enables "include imports" mode, where the compiler will include imported modules in the compilation, as if they were given on the command line. By default, when this option is enabled, all imported modules are included except those in - druntime/phobos. This behavior can be overriden by providing patterns via `-i=`. + druntime/phobos. This behavior can be overridden by providing patterns via `-i=`. A pattern of the form `-i=` is an "inclusive pattern", whereas a pattern of the form `-i=-` is an "exclusive pattern". Inclusive patterns will include all module's whose names match the pattern, whereas exclusive patterns will exclude them. @@ -439,14 +439,14 @@ dmd -cov -unittest myprog.d $(P The default behavior of excluding druntime/phobos is accomplished by internally adding a set of standard exclusions, namely, `-i=-std -i=-core -i=-etc -i=-object`. Note that these - can be overriden with `-i=std -i=core -i=etc -i=object`.) + can be overridden with `-i=std -i=core -i=etc -i=object`.) $(P When a module matches multiple patterns, matches are prioritized by their component length, where a match with more components takes priority (i.e. pattern `foo.bar.baz` has priority over `foo.bar`).) $(P By default modules that don't match any pattern will be included. However, if at least one inclusive pattern is given, then modules not matching any pattern will - be excluded. This behavior can be overriden by usig `-i=.` to include by default or `-i=-.` to + be excluded. This behavior can be overridden by usig `-i=.` to include by default or `-i=-.` to exclude by default.) $(P Note that multiple `-i=...` options are allowed, each one adds a pattern.)}" diff --git a/dmd/compiler.d b/dmd/compiler.d index 403712dd2ed..de326b27962 100644 --- a/dmd/compiler.d +++ b/dmd/compiler.d @@ -275,7 +275,7 @@ private struct MatcherNode * -i=-foo // include everything except modules that match "foo*" * -i=foo // only include modules that match "foo*" (exclude everything else) * --- - * Note that this default behavior can be overriden using the '.' module pattern. i.e. + * Note that this default behavior can be overridden using the '.' module pattern. i.e. * --- * -i=-foo,-. // this excludes everything * -i=foo,. // this includes everything except the default exclusions (-std,-core,-etc.-object) diff --git a/dmd/dsymbolsem.d b/dmd/dsymbolsem.d index a5cd63b1d4f..71c18568f9a 100644 --- a/dmd/dsymbolsem.d +++ b/dmd/dsymbolsem.d @@ -3963,13 +3963,13 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor hgs.fullQual = true; // https://issues.dlang.org/show_bug.cgi?id=23745 - // If the potentially overriden function contains errors, + // If the potentially overridden function contains errors, // inform the user to fix that one first if (fd.errors) { error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?", funcdecl.toChars(), fd.toPrettyChars()); - errorSupplemental(fd.loc, "Function `%s` contains errors in its declaration, therefore it cannot be correctly overriden", + errorSupplemental(fd.loc, "Function `%s` contains errors in its declaration, therefore it cannot be correctly overridden", fd.toPrettyChars()); } else @@ -3985,7 +3985,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { error(funcdecl.loc, "function `%s` does not override any function, did you mean to override %s `%s`?", funcdeclToChars, s.kind, s.toPrettyChars()); - errorSupplemental(funcdecl.loc, "Functions are the only declarations that may be overriden"); + errorSupplemental(funcdecl.loc, "Functions are the only declarations that may be overridden"); } } else diff --git a/dmd/dtoh.d b/dmd/dtoh.d index f00b8dba86c..b9bbad0a7a4 100644 --- a/dmd/dtoh.d +++ b/dmd/dtoh.d @@ -2450,7 +2450,7 @@ public: { debug (Debug_DtoH) mixin(traceVisit!e); - // Valid in most cases, others should be overriden below + // Valid in most cases, others should be overridden below // to use the appropriate operators (:: and ->) buf.writestring(e.toString()); } diff --git a/dmd/expression.d b/dmd/expression.d index 473efb8c99a..440d0a520ee 100644 --- a/dmd/expression.d +++ b/dmd/expression.d @@ -1242,7 +1242,7 @@ extern (C++) abstract class Expression : ASTNode if (!f.isDtorDeclaration()) errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.pure_); - checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().purity != PURE.impure, "impure"); + checkOverriddenDtor(sc, f, dd => dd.type.toTypeFunction().purity != PURE.impure, "impure"); return true; } return false; @@ -1261,7 +1261,7 @@ extern (C++) abstract class Expression : ASTNode * check = current check (e.g. whether it's pure) * checkName = the kind of check (e.g. `"pure"`) */ - extern (D) final void checkOverridenDtor(Scope* sc, FuncDeclaration f, + extern (D) final void checkOverriddenDtor(Scope* sc, FuncDeclaration f, scope bool function(DtorDeclaration) check, const string checkName ) { auto dd = f.isDtorDeclaration(); @@ -1314,7 +1314,7 @@ extern (C++) abstract class Expression : ASTNode field.loc.errorSupplemental(" - %s %s", field.type.toChars(), field.toChars()); if (fieldSd.dtor.isGenerated()) - checkOverridenDtor(sc, fieldSd.dtor, check, checkName); + checkOverriddenDtor(sc, fieldSd.dtor, check, checkName); else fieldSd.dtor.loc.errorSupplemental(" %.*s `%s.~this` is declared here", cast(int) checkName.length, checkName.ptr, fieldSd.toChars()); @@ -1505,7 +1505,7 @@ extern (C++) abstract class Expression : ASTNode errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.safe); .errorSupplemental(f.loc, "`%s` is declared here", prettyChars); - checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().trust > TRUST.system, "@system"); + checkOverriddenDtor(sc, f, dd => dd.type.toTypeFunction().trust > TRUST.system, "@system"); return true; } @@ -1569,7 +1569,7 @@ extern (C++) abstract class Expression : ASTNode f.errorSupplementalInferredAttr(/*max depth*/ 10, /*deprecation*/ false, STC.nogc); } - checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().isnogc, "non-@nogc"); + checkOverriddenDtor(sc, f, dd => dd.type.toTypeFunction().isnogc, "non-@nogc"); return true; } diff --git a/dmd/semantic3.d b/dmd/semantic3.d index a76496b2771..aa04f935cd3 100644 --- a/dmd/semantic3.d +++ b/dmd/semantic3.d @@ -1605,7 +1605,7 @@ private struct FuncDeclSem3 sc = s; } - /* Checks that the overriden functions (if any) have in contracts if + /* Checks that the overridden functions (if any) have in contracts if * funcdecl has an in contract. */ void checkInContractOverrides() diff --git a/tests/dmd/fail_compilation/dtor_attributes.d b/tests/dmd/fail_compilation/dtor_attributes.d index 21a12ed0253..02d95586eae 100644 --- a/tests/dmd/fail_compilation/dtor_attributes.d +++ b/tests/dmd/fail_compilation/dtor_attributes.d @@ -30,7 +30,7 @@ struct HasDtor ~this() {} } -// The user-defined dtor is overriden by a generated dtor calling both +// The user-defined dtor is overridden by a generated dtor calling both // - HasDtor.~this // - Strict.~this struct Strict diff --git a/tests/dmd/fail_compilation/fail19209.d b/tests/dmd/fail_compilation/fail19209.d index ceede5e0eed..56b85815150 100644 --- a/tests/dmd/fail_compilation/fail19209.d +++ b/tests/dmd/fail_compilation/fail19209.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/fail19209.d(16): Error: function `fail19209.Spammer.method()` does not override any function, did you mean to override variable `fail19209.Spam.method`? -fail_compilation/fail19209.d(16): Functions are the only declarations that may be overriden +fail_compilation/fail19209.d(16): Functions are the only declarations that may be overridden --- */ diff --git a/tests/dmd/fail_compilation/fail23745.d b/tests/dmd/fail_compilation/fail23745.d index eda9e1e63fa..46d92f0fa10 100644 --- a/tests/dmd/fail_compilation/fail23745.d +++ b/tests/dmd/fail_compilation/fail23745.d @@ -5,7 +5,7 @@ TEST_OUTPUT: --- fail_compilation/fail23745.d(21): Error: undefined identifier `UndefinedType` fail_compilation/fail23745.d(14): Error: function `fun` does not override any function, did you mean to override `fail23745.A.fun`? -fail_compilation/fail23745.d(21): Function `fail23745.A.fun` contains errors in its declaration, therefore it cannot be correctly overriden +fail_compilation/fail23745.d(21): Function `fail23745.A.fun` contains errors in its declaration, therefore it cannot be correctly overridden --- */ From 2e151d05fef8eb8f1c6e5e2a2103085d8b1d95b0 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Mon, 12 Jun 2023 17:07:05 +0100 Subject: [PATCH 067/176] [object.destroy] Add example for nested struct Also split up long D class and C++ class example. --- runtime/druntime/src/object.d | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/runtime/druntime/src/object.d b/runtime/druntime/src/object.d index 337eabf64db..228de32ff50 100644 --- a/runtime/druntime/src/object.d +++ b/runtime/druntime/src/object.d @@ -4195,8 +4195,11 @@ void destroy(bool initialize = true, T)(T obj) if (is(T == interface)) assert(c.s == "S"); // `c.s` is back to its inital state, `"S"` assert(c.a.dtorCount == 1); // `c.a`'s destructor was called assert(c.a.x == 10); // `c.a.x` is back to its inital state, `10` +} - // check C++ classes work too! +/// C++ classes work too +@system unittest +{ extern (C++) class CPP { struct Agg @@ -4247,6 +4250,34 @@ void destroy(bool initialize = true, T)(T obj) if (is(T == interface)) assert(i == 0); // `i` is back to its initial state `0` } +/// Nested struct type +@system unittest +{ + int dtorCount; + struct A + { + int i; + ~this() + { + dtorCount++; // capture local variable + } + } + A a = A(5); + destroy!false(a); + assert(dtorCount == 1); + assert(a.i == 5); + + destroy(a); + assert(dtorCount == 2); + assert(a.i == 0); + + // the context pointer is now null + // restore it so the dtor can run + import core.lifetime : emplace; + emplace(&a, A(0)); + // dtor also called here +} + @system unittest { extern(C++) From b947c008c480193b3c5864821addaed570d31a50 Mon Sep 17 00:00:00 2001 From: FeepingCreature <540727+FeepingCreature@users.noreply.github.com> Date: Tue, 13 Jun 2023 09:20:08 +0200 Subject: [PATCH 068/176] Fix issue 23947: If checking access after overload resolution, only check the specific overload selected, not the most public overload of the set. (dlang/dmd!15282) This deprecation also covers the deprecation for issue 21275. This is a deprecation because making it an error would force issue 21275 to be an error as well. --- dmd/expressionsem.d | 35 +++++++++---------- .../fail_compilation/imports/issue23947a.d | 8 +++++ tests/dmd/fail_compilation/issue23947.d | 11 ++++++ 3 files changed, 36 insertions(+), 18 deletions(-) create mode 100644 tests/dmd/fail_compilation/imports/issue23947a.d create mode 100644 tests/dmd/fail_compilation/issue23947.d diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index 8ac8866a85b..3121fdab54b 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -1386,15 +1386,6 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = { if (fd.errors) return ErrorExp.get(); - if (!checkSymbolAccess(sc, fd)) - { - // @@@DEPRECATED_2.105@@@ - // When turning into error, uncomment the return statement - TypeFunction tf = fd.type.isTypeFunction(); - deprecation(loc, "function `%s` of type `%s` is not accessible from module `%s`", - fd.toPrettyChars(), tf.toChars, sc._module.toChars); - //return ErrorExp.get(); - } assert(fd.type.ty == Tfunction); Expression e = new CallExp(loc, e1, e2); return e.expressionSemantic(sc); @@ -1409,14 +1400,6 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = TypeFunction tf = fd.type.isTypeFunction(); if (!e2 || tf.isref) { - if (!checkSymbolAccess(sc, fd)) - { - // @@@DEPRECATED_2.105@@@ - // When turning into error, uncomment the return statement - deprecation(loc, "function `%s` of type `%s` is not accessible from module `%s`", - fd.toPrettyChars(), tf.toChars, sc._module.toChars); - //return ErrorExp.get(); - } Expression e = new CallExp(loc, e1); if (e2) { @@ -5024,7 +5007,23 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (!exp.ignoreAttributes) checkFunctionAttributes(exp, sc, exp.f); - checkAccess(exp.loc, sc, ue.e1, exp.f); + + // Cut-down version of checkAccess() that doesn't use the "most visible" version of exp.f. + // We've already selected an overload here. + const parent = exp.f.toParent(); + if (parent && parent.isTemplateInstance()) + { + // already a deprecation + } + else if (!checkSymbolAccess(sc, exp.f)) + { + // @@@DEPRECATED_2.105@@@ + // When turning into error, uncomment the return statement + exp.deprecation("%s `%s` of type `%s` is not accessible from module `%s`", + exp.f.kind(), exp.f.toPrettyChars(), exp.f.type.toChars(), sc._module.toChars); + //return ErrorExp.get(); + } + if (!exp.f.needThis()) { exp.e1 = Expression.combine(ue.e1, new VarExp(exp.loc, exp.f, false)); diff --git a/tests/dmd/fail_compilation/imports/issue23947a.d b/tests/dmd/fail_compilation/imports/issue23947a.d new file mode 100644 index 00000000000..270bf5fd538 --- /dev/null +++ b/tests/dmd/fail_compilation/imports/issue23947a.d @@ -0,0 +1,8 @@ +module imports.issue23947a; + +struct X { } +struct Y { } +class Class { + private void handle(X x) { } + public void handle(Y y) { } +} diff --git a/tests/dmd/fail_compilation/issue23947.d b/tests/dmd/fail_compilation/issue23947.d new file mode 100644 index 00000000000..87b08aeb305 --- /dev/null +++ b/tests/dmd/fail_compilation/issue23947.d @@ -0,0 +1,11 @@ +// https://issues.dlang.org/show_bug.cgi?id=23947 +// REQUIRED_ARGS: -de +/* +TEST_OUTPUT: +--- +fail_compilation/issue23947.d(11): Deprecation: function `imports.issue23947a.Class.handle` of type `void(X x)` is not accessible from module `issue23947` +--- +*/ +import imports.issue23947a; + +void main() { Class.init.handle(X.init); } From 73a9827cf341d69fe14073f6af44f841842343fb Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Tue, 13 Jun 2023 05:04:26 -0700 Subject: [PATCH 069/176] fix Issue 23988 - Conditional Exp does not bring enums to correct common type if one leg is const (dlang/dmd!15316) --- dmd/dcast.d | 1 + tests/dmd/compilable/commontype.d | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/dmd/dcast.d b/dmd/dcast.d index 6fcc2806585..b2aa6433baf 100644 --- a/dmd/dcast.d +++ b/dmd/dcast.d @@ -2922,6 +2922,7 @@ Type typeMerge(Scope* sc, EXP op, ref Expression pe1, ref Expression pe2) ubyte mod = MODmerge(t1.mod, t2.mod); t1 = t1.castMod(mod); t2 = t2.castMod(mod); + return Lret(t1); } Lagain: diff --git a/tests/dmd/compilable/commontype.d b/tests/dmd/compilable/commontype.d index abe956c8094..a980ace2177 100644 --- a/tests/dmd/compilable/commontype.d +++ b/tests/dmd/compilable/commontype.d @@ -117,18 +117,18 @@ static assert(is( X!( Ei, Ei ) == Ei )); static assert(is( X!( Ei, const(Ei) ) == const(Ei) )); static assert(is( X!( Ei, immutable(Ei) ) == const(Ei) )); static assert(is( X!( Eb, Eb ) == Eb )); -static assert(is( X!( Eb, const(Eb) ) == int )); -static assert(is( X!( Eb, immutable(Eb) ) == int )); +static assert(is( X!( Eb, const(Eb) ) == const(Eb) )); +static assert(is( X!( Eb, immutable(Eb) ) == const(Eb) )); static assert(is( X!( Ei, Eb ) == int )); static assert(is( X!( Ei, const(Eb) ) == int )); static assert(is( X!( Ei, immutable(Eb) ) == int )); static assert(is( X!( Ec, Ec ) == Ec )); -static assert(is( X!( Ec, const(Ec) ) == const(char) )); -static assert(is( X!( Ec, immutable(Ec) ) == const(char) )); +static assert(is( X!( Ec, const(Ec) ) == const(Ec) )); +static assert(is( X!( Ec, immutable(Ec) ) == const(Ec) )); static assert(is( X!( Ew, Ew ) == Ew )); -static assert(is( X!( Ew, const(Ew) ) == const(wchar) )); -static assert(is( X!( Ew, immutable(Ew) ) == const(wchar) )); +static assert(is( X!( Ew, const(Ew) ) == const(Ew) )); +static assert(is( X!( Ew, immutable(Ew) ) == const(Ew) )); static assert(is( X!( Ew, Ec ) == dchar )); static assert(is( X!( Ew, const(Ec) ) == dchar )); static assert(is( X!( Ew, immutable(Ec) ) == dchar )); From 7927bb65e8721f1b3b3cd54cc6bfffe6e85f6dee Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Wed, 14 Jun 2023 06:42:32 +0100 Subject: [PATCH 070/176] Fix Issue 4663 - Wrong 'static' position error message (dlang/dmd!15321) Also detects `extern`, `deprecated`, `ref`, `override` and friends. --- dmd/parse.d | 9 +++++++++ tests/dmd/fail_compilation/funcpostattr.d | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 tests/dmd/fail_compilation/funcpostattr.d diff --git a/dmd/parse.d b/dmd/parse.d index b7e07911cb9..8c0a1b13c99 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -1405,6 +1405,15 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer break; } default: + Token* tk; + if (skipAttributes(&token, &tk) && tk.ptr != token.ptr || + token.value == TOK.static_ || token.value == TOK.extern_) + { + error("`%s` token is not allowed in postfix position", + Token.toChars(token.value)); + nextToken(); + continue; + } return storageClass; } storageClass = appendStorageClass(storageClass, stc); diff --git a/tests/dmd/fail_compilation/funcpostattr.d b/tests/dmd/fail_compilation/funcpostattr.d new file mode 100644 index 00000000000..b50db058e32 --- /dev/null +++ b/tests/dmd/fail_compilation/funcpostattr.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/funcpostattr.d(11): Error: `deprecated` token is not allowed in postfix position +fail_compilation/funcpostattr.d(11): Error: `extern` token is not allowed in postfix position +fail_compilation/funcpostattr.d(15): Error: `static` token is not allowed in postfix position +fail_compilation/funcpostattr.d(15): Error: `ref` token is not allowed in postfix position +fail_compilation/funcpostattr.d(20): Error: `override` token is not allowed in postfix position +--- +*/ +void foo() deprecated extern; + +void main() { + int i; + int foo() static ref => i; +} + +class C +{ + void foo() override {} +} From 18813e21a1bb32133929a1ef9fe75d9c5a96e493 Mon Sep 17 00:00:00 2001 From: Brian Callahan Date: Thu, 8 Jun 2023 17:30:44 -0400 Subject: [PATCH 071/176] Fix Issue 23980 - OpenBSD: Add getthrname(2) and setthrname(2) to unistd.d --- runtime/druntime/src/core/sys/openbsd/unistd.d | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/runtime/druntime/src/core/sys/openbsd/unistd.d b/runtime/druntime/src/core/sys/openbsd/unistd.d index 0b8580fb860..4232c036049 100644 --- a/runtime/druntime/src/core/sys/openbsd/unistd.d +++ b/runtime/druntime/src/core/sys/openbsd/unistd.d @@ -12,6 +12,10 @@ extern (C): nothrow: @nogc: +public import core.sys.posix.sys.types; + int getentropy(void*, size_t); +int getthrname(pid_t, char*, size_t); int pledge(const scope char*, const scope char*); +int setthrname(pid_t, const scope char*); int unveil(const scope char*, const scope char*); From 6b0839d6ee82743c4a50f0e6baf7405ae1f5528d Mon Sep 17 00:00:00 2001 From: Vladimir Panteleev Date: Thu, 15 Jun 2023 08:01:42 +0000 Subject: [PATCH 072/176] Add Valgrind GC integration (dlang/dmd!15304) * rt.minfo: Avoid calling realloc with size 0 This is not portable, and memcheck complains about this. * Add C Valgrind API Add the BSD-licensed C header files which provide the API for controlling Valgrind from within programs executed under it. The files are from Valgrind v3.21.0. * Add some D bindings for the Valgrind C API We will use these in the GC implementation to tell Valgrind which memory operations are OK or not. * Silence Valgrind warnings caused by GC marking Allow the conservative GC to scan memory, whether it has been initialized by the application or not. * Add test suite for Valgrind * Unify VALGRIND with MEMSTOMP The two share the same goal: mark memory which should not be accessed any more. * Mask "invalid" access to free lists The GC stores free lists in the cells of the objects on the list. We would like to allow the GC to work with these lists, but still raise a warning if application code attempts to access them. * Distinguish between writable and unwritable invalidation Freshly allocated memory should be writable but not readable. Explicitly deallocated or GC-ed memory should be neither readable or writable. * Add use-after-free test * Invalidate freshly-allocated memory * Integrate VALGRIND with SENTINEL * Fix reporting of arrays of structs with destructors * Re-invalidate reused blocks during malloc/calloc * Add Changelog entry * .pre-commit-config.yaml: Exempt vendored files * etc.valgrind.valgrind: Propagate return values of the vbits functions * etc.valgrind.valgrind: Add documentation for functions Copy/adapt the documentation in memcheck.h. * druntime/test/valgrind: Add no_use_after_gc test * ci/cirrusci.sh: Install Valgrind on Linux Run the Druntime Valgrind integration tests. libc6-dbg is needed to allow Valgrind to redirect certain functions. * etc.valgrind.valgrind: Add @nogc Although the GC is the primary user, this is not a restriction of these Valgrind API wrappers. * druntime/test/valgrind: Fix no_use_after_gc test with -release Trick the optimizer to pretend we're doing something with the result of those invalid memory accesses. --- runtime/druntime/posix.mak | 8 +- .../core/internal/gc/impl/conservative/gc.d | 121 +- runtime/druntime/src/etc/valgrind/memcheck.h | 309 + runtime/druntime/src/etc/valgrind/valgrind.c | 38 + runtime/druntime/src/etc/valgrind/valgrind.d | 85 + runtime/druntime/src/etc/valgrind/valgrind.h | 7165 +++++++++++++++++ runtime/druntime/src/rt/lifetime.d | 8 + runtime/druntime/src/rt/minfo.d | 4 +- runtime/druntime/test/valgrind/Makefile | 34 + runtime/druntime/test/valgrind/src/no_oob.d | 7 + .../test/valgrind/src/no_oob_sentinel.d | 7 + .../test/valgrind/src/no_use_after_free.d | 10 + .../test/valgrind/src/no_use_after_gc.d | 26 + .../druntime/test/valgrind/src/ok_append.d | 12 + 14 files changed, 7806 insertions(+), 28 deletions(-) create mode 100644 runtime/druntime/src/etc/valgrind/memcheck.h create mode 100644 runtime/druntime/src/etc/valgrind/valgrind.c create mode 100644 runtime/druntime/src/etc/valgrind/valgrind.d create mode 100644 runtime/druntime/src/etc/valgrind/valgrind.h create mode 100644 runtime/druntime/test/valgrind/Makefile create mode 100644 runtime/druntime/test/valgrind/src/no_oob.d create mode 100644 runtime/druntime/test/valgrind/src/no_oob_sentinel.d create mode 100644 runtime/druntime/test/valgrind/src/no_use_after_free.d create mode 100644 runtime/druntime/test/valgrind/src/no_use_after_gc.d create mode 100644 runtime/druntime/test/valgrind/src/ok_append.d diff --git a/runtime/druntime/posix.mak b/runtime/druntime/posix.mak index da0f1ddad0d..0735a976f7f 100644 --- a/runtime/druntime/posix.mak +++ b/runtime/druntime/posix.mak @@ -126,7 +126,7 @@ SRCS:=$(subst \,/,$(SRCS)) # NOTE: a pre-compiled minit.obj has been provided in dmd for Win32 and # minit.asm is not used by dmd for Linux -OBJS= $(ROOT)/errno_c.o $(ROOT)/threadasm.o +OBJS= $(ROOT)/errno_c.o $(ROOT)/threadasm.o $(ROOT)/valgrind.o # use timelimit to avoid deadlocks if available TIMELIMIT:=$(if $(shell which timelimit 2>/dev/null || true),timelimit -t 10 ,) @@ -367,6 +367,10 @@ $(ROOT)/threadasm.o : src/core/threadasm.S @mkdir -p $(dir $@) $(CC) -c $(CFLAGS) $< -o$@ +$(ROOT)/valgrind.o : src/etc/valgrind/valgrind.c src/etc/valgrind/valgrind.h src/etc/valgrind/memcheck.h + @mkdir -p `dirname $@` + $(CC) -c $(CFLAGS) $< -o$@ + ######################## Create a shared library ############################## $(DRUNTIMESO) $(DRUNTIMESOLIB) dll: DFLAGS+=-version=Shared -fPIC @@ -392,7 +396,7 @@ ifeq ($(HAS_ADDITIONAL_TESTS),1) ADDITIONAL_TESTS:=test/init_fini test/exceptions test/coverage test/profile test/cycles test/allocations test/typeinfo \ test/aa test/cpuid test/gc test/hash test/lifetime \ test/thread test/unittest test/imports test/betterc test/stdcpp test/config \ - test/traits + test/traits test/valgrind ADDITIONAL_TESTS+=$(if $(SHARED),test/shared,) endif diff --git a/runtime/druntime/src/core/internal/gc/impl/conservative/gc.d b/runtime/druntime/src/core/internal/gc/impl/conservative/gc.d index 62ce941e393..2ed1ca92c38 100644 --- a/runtime/druntime/src/core/internal/gc/impl/conservative/gc.d +++ b/runtime/druntime/src/core/internal/gc/impl/conservative/gc.d @@ -26,6 +26,7 @@ module core.internal.gc.impl.conservative.gc; //debug = INVARIANT; // enable invariants //debug = PROFILE_API; // profile API calls for config.profile > 1 //debug = GC_RECURSIVE_LOCK; // check for recursive locking on the same thread +//debug = VALGRIND; // Valgrind memcheck integration /***************************************************/ version = COLLECT_PARALLEL; // parallel scanning @@ -52,6 +53,8 @@ version (GNU) import gcc.builtins; debug (PRINTF_TO_FILE) import core.stdc.stdio : sprintf, fprintf, fopen, fflush, FILE; else import core.stdc.stdio : sprintf, printf; // needed to output profiling results +debug (VALGRIND) import etc.valgrind.valgrind; + import core.time; alias currTime = MonoTime.currTime; @@ -480,6 +483,8 @@ class ConservativeGC : GC auto p = runLocked!(mallocNoSync, mallocTime, numMallocs)(size, bits, localAllocSize, ti); + invalidate(p[0 .. localAllocSize], 0xF0, true); + if (!(bits & BlkAttr.NO_SCAN)) { memset(p + size, 0, localAllocSize - size); @@ -567,6 +572,9 @@ class ConservativeGC : GC auto p = runLocked!(mallocNoSync, mallocTime, numMallocs)(size, bits, localAllocSize, ti); + debug (VALGRIND) makeMemUndefined(p[0..size]); + invalidate((p + size)[0 .. localAllocSize - size], 0xF0, true); + memset(p, 0, size); if (!(bits & BlkAttr.NO_SCAN)) { @@ -688,7 +696,7 @@ class ConservativeGC : GC else if (newsz < psz) { // Shrink in place - debug (MEMSTOMP) memset(p + size, 0xF2, psize - size); + invalidate((p + size)[0 .. psize - size], 0xF2, false); lpool.freePages(pagenum + newsz, psz - newsz); lpool.mergeFreePageOffsets!(false, true)(pagenum + newsz, psz - newsz); lpool.bPageOffsets[pagenum] = cast(uint) newsz; @@ -704,7 +712,7 @@ class ConservativeGC : GC if (freesz < newPages) return doMalloc(); // free range too small - debug (MEMSTOMP) memset(p + psize, 0xF0, size - psize); + invalidate((p + psize)[0 .. size - psize], 0xF0, true); debug (PRINTF) printFreeInfo(pool); memset(&lpool.pagetable[pagenum + psz], Bins.B_PAGEPLUS, newPages); lpool.bPageOffsets[pagenum] = cast(uint) newsz; @@ -795,7 +803,7 @@ class ConservativeGC : GC if (freesz < minsz) return 0; size_t sz = freesz > maxsz ? maxsz : freesz; - debug (MEMSTOMP) memset(pool.baseAddr + (pagenum + psz) * PAGESIZE, 0xF0, sz * PAGESIZE); + invalidate((pool.baseAddr + (pagenum + psz) * PAGESIZE)[0 .. sz * PAGESIZE], 0xF0, true); memset(lpool.pagetable + pagenum + psz, Bins.B_PAGEPLUS, sz); lpool.bPageOffsets[pagenum] = cast(uint) (psz + sz); for (auto offset = psz; offset < psz + sz; offset++) @@ -911,7 +919,7 @@ class ConservativeGC : GC size_t npages = lpool.bPageOffsets[pagenum]; auto size = npages * PAGESIZE; ssize = sentinel_size(q, size); - debug (MEMSTOMP) memset(p, 0xF2, size); + invalidate(p[0 .. size], 0xF2, false); lpool.freePages(pagenum, npages); lpool.mergeFreePageOffsets!(true, true)(pagenum, npages); } @@ -925,13 +933,13 @@ class ConservativeGC : GC auto size = binsize[bin]; ssize = sentinel_size(q, size); - debug (MEMSTOMP) memset(p, 0xF2, size); + invalidate(p[0 .. size], 0xF2, false); // in case the page hasn't been recovered yet, don't add the object to the free list if (!gcx.recoverPool[bin] || pool.binPageChain[pagenum] == Pool.PageRecovered) { - list.next = gcx.bucket[bin]; - list.pool = pool; + undefinedWrite(list.next, gcx.bucket[bin]); + undefinedWrite(list.pool, pool); gcx.bucket[bin] = list; } pool.freebits.set(biti); @@ -1965,8 +1973,8 @@ struct Gcx assert(p !is null); L_hasBin: // Return next item from free list - bucket[bin] = (cast(List*)p).next; - auto pool = (cast(List*)p).pool; + bucket[bin] = undefinedRead((cast(List*)p).next); + auto pool = undefinedRead((cast(List*)p).pool); auto biti = (p - pool.baseAddr) >> pool.shiftBy; assert(pool.freebits.test(biti)); @@ -1976,7 +1984,7 @@ struct Gcx if (bits) pool.setBits(biti, bits); //debug(PRINTF) printf("\tmalloc => %p\n", p); - debug (MEMSTOMP) memset(p, 0xF0, alloc_size); + invalidate(p[0 .. alloc_size], 0xF0, true); if (ConservativeGC.isPrecise) { @@ -2059,7 +2067,7 @@ struct Gcx auto p = pool.baseAddr + pn * PAGESIZE; debug(PRINTF) printf("Got large alloc: %p, pt = %d, np = %d\n", p, pool.pagetable[pn], npages); - debug (MEMSTOMP) memset(p, 0xF1, size); + invalidate(p[0 .. size], 0xF1, true); alloc_size = npages * PAGESIZE; //debug(PRINTF) printf("\tp = %p\n", p); @@ -2241,6 +2249,7 @@ struct Gcx immutable ncap = _cap ? 2 * _cap : initSize / RANGE.sizeof; auto p = cast(RANGE*)os_mem_map(ncap * RANGE.sizeof); if (p is null) onOutOfMemoryErrorNoGC(); + debug (VALGRIND) makeMemUndefined(p[0..ncap]); if (_p !is null) { p[0 .. _length] = _p[0 .. _length]; @@ -2295,7 +2304,8 @@ struct Gcx for (;;) { - auto p = *cast(void**)(rng.pbot); + auto p = undefinedRead(*cast(void**)(rng.pbot)); + debug (VALGRIND) makeMemDefined((&p)[0 .. 1]); debug(MARK_PRINTF) printf("\tmark %p: %p\n", rng.pbot, p); @@ -2525,6 +2535,7 @@ struct Gcx for (auto p = cast(void**)pbot; cast(void*)p < ptop; p++) { auto ptr = *p; + debug (VALGRIND) makeMemDefined((&ptr)[0 .. 1]); if (cast(size_t)(ptr - minAddr) < memSize) toscanRoots.push(ptr); } @@ -2650,7 +2661,7 @@ struct Gcx pool.freepages += npages; numFree += npages; - debug (MEMSTOMP) memset(p, 0xF3, npages * PAGESIZE); + invalidate(p[0 .. npages * PAGESIZE], 0xF3, false); // Don't need to update searchStart here because // pn is guaranteed to be greater than last time // we updated it. @@ -2765,7 +2776,7 @@ struct Gcx debug(COLLECT_PRINTF) printf("\tcollecting %p\n", p); leakDetector.log_free(q, sentinel_size(q, size)); - debug (MEMSTOMP) memset(p, 0xF3, size); + invalidate(p[0 .. size], 0xF3, false); } } } @@ -2830,11 +2841,11 @@ struct Gcx if (!core.bitop.bt(freebitsdata, u / 16)) continue; auto elem = cast(List *)(p + u); - elem.pool = &pool.base; - *bucketTail = elem; + undefinedWrite(elem.pool, &pool.base); + undefinedWrite(*bucketTail, elem); bucketTail = &elem.next; } - *bucketTail = null; + undefinedWrite(*bucketTail, null); assert(bucket[bin] !is null); return true; } @@ -3572,6 +3583,7 @@ struct Pool //debug(PRINTF) printf("Pool::Pool(%u)\n", npages); poolsize = npages * PAGESIZE; baseAddr = cast(byte *)os_mem_map(poolsize); + version (VALGRIND) makeMemNoAccess(baseAddr[0..poolsize]); // Some of the code depends on page alignment of memory pools assert((cast(size_t)baseAddr & (PAGESIZE - 1)) == 0); @@ -4275,7 +4287,7 @@ struct LargeObjectPool for (; pn + n < npages; ++n) if (pagetable[pn + n] != Bins.B_PAGEPLUS) break; - debug (MEMSTOMP) memset(baseAddr + pn * PAGESIZE, 0xF3, n * PAGESIZE); + invalidate((baseAddr + pn * PAGESIZE)[0 .. n * PAGESIZE], 0xF3, false); freePages(pn, n); mergeFreePageOffsets!(true, true)(pn, n); } @@ -4394,7 +4406,7 @@ struct SmallObjectPool debug(COLLECT_PRINTF) printf("\tcollecting %p\n", p); //log_free(sentinel_add(p)); - debug (MEMSTOMP) memset(p, 0xF3, size); + invalidate(p[0 .. size], 0xF3, false); } if (freeBits) @@ -4431,11 +4443,11 @@ struct SmallObjectPool void* ptop = p + PAGESIZE - 2 * size + 1; for (; p < ptop; p += size) { - (cast(List *)p).next = cast(List *)(p + size); - (cast(List *)p).pool = &base; + undefinedWrite((cast(List *)p).next, cast(List *)(p + size)); + undefinedWrite((cast(List *)p).pool, &base); } - (cast(List *)p).next = null; - (cast(List *)p).pool = &base; + undefinedWrite((cast(List *)p).next, null); + undefinedWrite((cast(List *)p).pool, &base); return first; } } @@ -4823,13 +4835,22 @@ debug (SENTINEL) { assert(size <= uint.max); *sentinel_psize(p) = cast(uint)size; - *sentinel_pre(p) = SENTINEL_PRE; - *sentinel_post(p) = SENTINEL_POST; + debug (VALGRIND) + { + makeMemNoAccess(sentinel_pre(p)[0..1]); + makeMemNoAccess(sentinel_post(p)[0..1]); + } + else + { + *sentinel_pre(p) = SENTINEL_PRE; + *sentinel_post(p) = SENTINEL_POST; + } } void sentinel_Invariant(const void *p) nothrow @nogc { + debug (VALGRIND) {} else debug { assert(*sentinel_pre(p) == SENTINEL_PRE); @@ -5063,3 +5084,53 @@ unittest printf("unexpected pointers %p and %p\n", p.ptr, q.ptr); } } + +/* ============================ MEMSTOMP =============================== */ + +/// Mark the specified memory region as uninitialized - +/// reading from this region is an error. +/// If writable is false, writing to it is also an error. +pragma(inline, true) +void invalidate(void[] mem, ubyte pattern, bool writable) nothrow @nogc +{ + debug (MEMSTOMP) memset(mem.ptr, pattern, mem.length); + debug (VALGRIND) + { + if (writable) + makeMemUndefined(mem); + else + makeMemNoAccess(mem); + } +} + +/// Read memory that should otherwise be marked as unreadable +/// (e.g. free lists overlapped with unallocated heap objects). +pragma(inline, true) +T undefinedRead(T)(ref T var) nothrow +{ + debug (VALGRIND) + { + auto varArr = (&var)[0..1]; + disableAddrReportingInRange(varArr); + T result = var; + enableAddrReportingInRange(varArr); + return result; + } + else + return var; +} + +/// Write memory that should otherwise be marked as unwritable. +pragma(inline, true) +void undefinedWrite(T)(ref T var, T value) nothrow +{ + debug (VALGRIND) + { + auto varArr = (&var)[0..1]; + disableAddrReportingInRange(varArr); + var = value; + enableAddrReportingInRange(varArr); + } + else + var = value; +} diff --git a/runtime/druntime/src/etc/valgrind/memcheck.h b/runtime/druntime/src/etc/valgrind/memcheck.h new file mode 100644 index 00000000000..53700542c62 --- /dev/null +++ b/runtime/druntime/src/etc/valgrind/memcheck.h @@ -0,0 +1,309 @@ + +/* + ---------------------------------------------------------------- + + Notice that the following BSD-style license applies to this one + file (memcheck.h) only. The rest of Valgrind is licensed under the + terms of the GNU General Public License, version 2, unless + otherwise indicated. See the COPYING file in the source + distribution for details. + + ---------------------------------------------------------------- + + This file is part of MemCheck, a heavyweight Valgrind tool for + detecting memory errors. + + Copyright (C) 2000-2017 Julian Seward. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ---------------------------------------------------------------- + + Notice that the above BSD-style license applies to this one file + (memcheck.h) only. The entire rest of Valgrind is licensed under + the terms of the GNU General Public License, version 2. See the + COPYING file in the source distribution for details. + + ---------------------------------------------------------------- +*/ + + +#ifndef __MEMCHECK_H +#define __MEMCHECK_H + + +/* This file is for inclusion into client (your!) code. + + You can use these macros to manipulate and query memory permissions + inside your own programs. + + See comment near the top of valgrind.h on how to use them. +*/ + +#include "valgrind.h" + +/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! + This enum comprises an ABI exported by Valgrind to programs + which use client requests. DO NOT CHANGE THE ORDER OF THESE + ENTRIES, NOR DELETE ANY -- add new ones at the end. */ +typedef + enum { + VG_USERREQ__MAKE_MEM_NOACCESS = VG_USERREQ_TOOL_BASE('M','C'), + VG_USERREQ__MAKE_MEM_UNDEFINED, + VG_USERREQ__MAKE_MEM_DEFINED, + VG_USERREQ__DISCARD, + VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE, + VG_USERREQ__CHECK_MEM_IS_DEFINED, + VG_USERREQ__DO_LEAK_CHECK, + VG_USERREQ__COUNT_LEAKS, + + VG_USERREQ__GET_VBITS, + VG_USERREQ__SET_VBITS, + + VG_USERREQ__CREATE_BLOCK, + + VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE, + + /* Not next to VG_USERREQ__COUNT_LEAKS because it was added later. */ + VG_USERREQ__COUNT_LEAK_BLOCKS, + + VG_USERREQ__ENABLE_ADDR_ERROR_REPORTING_IN_RANGE, + VG_USERREQ__DISABLE_ADDR_ERROR_REPORTING_IN_RANGE, + + /* This is just for memcheck's internal use - don't use it */ + _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR + = VG_USERREQ_TOOL_BASE('M','C') + 256 + } Vg_MemCheckClientRequest; + + + +/* Client-code macros to manipulate the state of memory. */ + +/* Mark memory at _qzz_addr as unaddressable for _qzz_len bytes. */ +#define VALGRIND_MAKE_MEM_NOACCESS(_qzz_addr,_qzz_len) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ + VG_USERREQ__MAKE_MEM_NOACCESS, \ + (_qzz_addr), (_qzz_len), 0, 0, 0) + +/* Similarly, mark memory at _qzz_addr as addressable but undefined + for _qzz_len bytes. */ +#define VALGRIND_MAKE_MEM_UNDEFINED(_qzz_addr,_qzz_len) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ + VG_USERREQ__MAKE_MEM_UNDEFINED, \ + (_qzz_addr), (_qzz_len), 0, 0, 0) + +/* Similarly, mark memory at _qzz_addr as addressable and defined + for _qzz_len bytes. */ +#define VALGRIND_MAKE_MEM_DEFINED(_qzz_addr,_qzz_len) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ + VG_USERREQ__MAKE_MEM_DEFINED, \ + (_qzz_addr), (_qzz_len), 0, 0, 0) + +/* Similar to VALGRIND_MAKE_MEM_DEFINED except that addressability is + not altered: bytes which are addressable are marked as defined, + but those which are not addressable are left unchanged. */ +#define VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(_qzz_addr,_qzz_len) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ + VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE, \ + (_qzz_addr), (_qzz_len), 0, 0, 0) + +/* Create a block-description handle. The description is an ascii + string which is included in any messages pertaining to addresses + within the specified memory range. Has no other effect on the + properties of the memory range. */ +#define VALGRIND_CREATE_BLOCK(_qzz_addr,_qzz_len, _qzz_desc) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ + VG_USERREQ__CREATE_BLOCK, \ + (_qzz_addr), (_qzz_len), (_qzz_desc), \ + 0, 0) + +/* Discard a block-description-handle. Returns 1 for an + invalid handle, 0 for a valid handle. */ +#define VALGRIND_DISCARD(_qzz_blkindex) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ + VG_USERREQ__DISCARD, \ + 0, (_qzz_blkindex), 0, 0, 0) + + +/* Client-code macros to check the state of memory. */ + +/* Check that memory at _qzz_addr is addressable for _qzz_len bytes. + If suitable addressibility is not established, Valgrind prints an + error message and returns the address of the first offending byte. + Otherwise it returns zero. */ +#define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(_qzz_addr,_qzz_len) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ + VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE, \ + (_qzz_addr), (_qzz_len), 0, 0, 0) + +/* Check that memory at _qzz_addr is addressable and defined for + _qzz_len bytes. If suitable addressibility and definedness are not + established, Valgrind prints an error message and returns the + address of the first offending byte. Otherwise it returns zero. */ +#define VALGRIND_CHECK_MEM_IS_DEFINED(_qzz_addr,_qzz_len) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ + VG_USERREQ__CHECK_MEM_IS_DEFINED, \ + (_qzz_addr), (_qzz_len), 0, 0, 0) + +/* Use this macro to force the definedness and addressibility of an + lvalue to be checked. If suitable addressibility and definedness + are not established, Valgrind prints an error message and returns + the address of the first offending byte. Otherwise it returns + zero. */ +#define VALGRIND_CHECK_VALUE_IS_DEFINED(__lvalue) \ + VALGRIND_CHECK_MEM_IS_DEFINED( \ + (volatile unsigned char *)&(__lvalue), \ + (unsigned long)(sizeof (__lvalue))) + + +/* Do a full memory leak check (like --leak-check=full) mid-execution. */ +#define VALGRIND_DO_LEAK_CHECK \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ + 0, 0, 0, 0, 0) + +/* Same as VALGRIND_DO_LEAK_CHECK but only showing the entries for + which there was an increase in leaked bytes or leaked nr of blocks + since the previous leak search. */ +#define VALGRIND_DO_ADDED_LEAK_CHECK \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ + 0, 1, 0, 0, 0) + +/* Same as VALGRIND_DO_ADDED_LEAK_CHECK but showing entries with + increased or decreased leaked bytes/blocks since previous leak + search. */ +#define VALGRIND_DO_CHANGED_LEAK_CHECK \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ + 0, 2, 0, 0, 0) + +/* Same as VALGRIND_DO_LEAK_CHECK but only showing new entries + i.e. loss records that were not there in the previous leak + search. */ +#define VALGRIND_DO_NEW_LEAK_CHECK \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ + 0, 3, 0, 0, 0) + +/* Do a summary memory leak check (like --leak-check=summary) mid-execution. */ +#define VALGRIND_DO_QUICK_LEAK_CHECK \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DO_LEAK_CHECK, \ + 1, 0, 0, 0, 0) + +/* Return number of leaked, dubious, reachable and suppressed bytes found by + all previous leak checks. They must be lvalues. */ +#define VALGRIND_COUNT_LEAKS(leaked, dubious, reachable, suppressed) \ + /* For safety on 64-bit platforms we assign the results to private + unsigned long variables, then assign these to the lvalues the user + specified, which works no matter what type 'leaked', 'dubious', etc + are. We also initialise '_qzz_leaked', etc because + VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as + defined. */ \ + { \ + unsigned long _qzz_leaked = 0, _qzz_dubious = 0; \ + unsigned long _qzz_reachable = 0, _qzz_suppressed = 0; \ + VALGRIND_DO_CLIENT_REQUEST_STMT( \ + VG_USERREQ__COUNT_LEAKS, \ + &_qzz_leaked, &_qzz_dubious, \ + &_qzz_reachable, &_qzz_suppressed, 0); \ + leaked = _qzz_leaked; \ + dubious = _qzz_dubious; \ + reachable = _qzz_reachable; \ + suppressed = _qzz_suppressed; \ + } + +/* Return number of leaked, dubious, reachable and suppressed bytes found by + all previous leak checks. They must be lvalues. */ +#define VALGRIND_COUNT_LEAK_BLOCKS(leaked, dubious, reachable, suppressed) \ + /* For safety on 64-bit platforms we assign the results to private + unsigned long variables, then assign these to the lvalues the user + specified, which works no matter what type 'leaked', 'dubious', etc + are. We also initialise '_qzz_leaked', etc because + VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as + defined. */ \ + { \ + unsigned long _qzz_leaked = 0, _qzz_dubious = 0; \ + unsigned long _qzz_reachable = 0, _qzz_suppressed = 0; \ + VALGRIND_DO_CLIENT_REQUEST_STMT( \ + VG_USERREQ__COUNT_LEAK_BLOCKS, \ + &_qzz_leaked, &_qzz_dubious, \ + &_qzz_reachable, &_qzz_suppressed, 0); \ + leaked = _qzz_leaked; \ + dubious = _qzz_dubious; \ + reachable = _qzz_reachable; \ + suppressed = _qzz_suppressed; \ + } + + +/* Get the validity data for addresses [zza..zza+zznbytes-1] and copy it + into the provided zzvbits array. Return values: + 0 if not running on valgrind + 1 success + 2 [previously indicated unaligned arrays; these are now allowed] + 3 if any parts of zzsrc/zzvbits are not addressable. + The metadata is not copied in cases 0, 2 or 3 so it should be + impossible to segfault your system by using this call. +*/ +#define VALGRIND_GET_VBITS(zza,zzvbits,zznbytes) \ + (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ + VG_USERREQ__GET_VBITS, \ + (const char*)(zza), \ + (char*)(zzvbits), \ + (zznbytes), 0, 0) + +/* Set the validity data for addresses [zza..zza+zznbytes-1], copying it + from the provided zzvbits array. Return values: + 0 if not running on valgrind + 1 success + 2 [previously indicated unaligned arrays; these are now allowed] + 3 if any parts of zza/zzvbits are not addressable. + The metadata is not copied in cases 0, 2 or 3 so it should be + impossible to segfault your system by using this call. +*/ +#define VALGRIND_SET_VBITS(zza,zzvbits,zznbytes) \ + (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ + VG_USERREQ__SET_VBITS, \ + (const char*)(zza), \ + (const char*)(zzvbits), \ + (zznbytes), 0, 0 ) + +/* Disable and re-enable reporting of addressing errors in the + specified address range. */ +#define VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(_qzz_addr,_qzz_len) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ + VG_USERREQ__DISABLE_ADDR_ERROR_REPORTING_IN_RANGE, \ + (_qzz_addr), (_qzz_len), 0, 0, 0) + +#define VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(_qzz_addr,_qzz_len) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ + VG_USERREQ__ENABLE_ADDR_ERROR_REPORTING_IN_RANGE, \ + (_qzz_addr), (_qzz_len), 0, 0, 0) + +#endif + diff --git a/runtime/druntime/src/etc/valgrind/valgrind.c b/runtime/druntime/src/etc/valgrind/valgrind.c new file mode 100644 index 00000000000..bb225a1da1c --- /dev/null +++ b/runtime/druntime/src/etc/valgrind/valgrind.c @@ -0,0 +1,38 @@ +#include "valgrind.h" /**/ +#include "memcheck.h" /**/ +#include /* for size_t */ + +void _d_valgrind_make_mem_noaccess(const void* addr, size_t len) +{ + VALGRIND_MAKE_MEM_NOACCESS(addr, len); +} + +void _d_valgrind_make_mem_undefined(const void* addr, size_t len) +{ + VALGRIND_MAKE_MEM_UNDEFINED(addr, len); +} + +void _d_valgrind_make_mem_defined(const void* addr, size_t len) +{ + VALGRIND_MAKE_MEM_DEFINED(addr, len); +} + +unsigned _d_valgrind_get_vbits(const void* addr, char* bits, size_t len) +{ + return VALGRIND_GET_VBITS(addr, bits, len); +} + +unsigned _d_valgrind_set_vbits(const void* addr, char* bits, size_t len) +{ + return VALGRIND_SET_VBITS(addr, bits, len); +} + +void _d_valgrind_disable_addr_reporting_in_range(const void* addr, size_t len) +{ + VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(addr, len); +} + +void _d_valgrind_enable_addr_reporting_in_range(const void* addr, size_t len) +{ + VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(addr, len); +} diff --git a/runtime/druntime/src/etc/valgrind/valgrind.d b/runtime/druntime/src/etc/valgrind/valgrind.d new file mode 100644 index 00000000000..21829fc23bf --- /dev/null +++ b/runtime/druntime/src/etc/valgrind/valgrind.d @@ -0,0 +1,85 @@ +/// D wrapper for the Valgrind client API. +/// Note that you must include this file into your program's compilation +/// and compile with `-debug=VALGRIND` to access the declarations below. +module etc.valgrind.valgrind; + +version (StdDdoc) +{ + /// Mark the memory covered by `mem` as unaddressable. + void makeMemNoAccess (const(void)[] mem) nothrow @nogc; + + /// Similarly, mark memory covered by `mem` as addressable but undefined. + void makeMemUndefined(const(void)[] mem) nothrow @nogc; + + /// Similarly, mark memory covered by `mem` as addressable and defined. + void makeMemDefined (const(void)[] mem) nothrow @nogc; + + /// Get the validity data for the address range covered by `mem` and copy it + /// into the provided `bits` array. + /// Returns: + /// - 0 if not running on valgrind + /// - 1 success + /// - 2 [previously indicated unaligned arrays; these are now allowed] + /// - 3 if any parts of `mem`/`bits` are not addressable. + /// The metadata is not copied in cases 0, 2 or 3 so it should be + /// impossible to segfault your system by using this call. + uint getVBits(const(void)[] mem, ubyte[] bits) nothrow @nogc; + + /// Set the validity data for the address range covered by `mem`, copying it + /// from the provided `bits` array. + /// Returns: + /// - 0 if not running on valgrind + /// - 1 success + /// - 2 [previously indicated unaligned arrays; these are now allowed] + /// - 3 if any parts of `mem`/`bits` are not addressable. + /// The metadata is not copied in cases 0, 2 or 3 so it should be + /// impossible to segfault your system by using this call. + uint setVBits(const(void)[] mem, ubyte[] bits) nothrow @nogc; + + /// Disable and re-enable reporting of addressing errors in the + /// address range covered by `mem`. + void disableAddrReportingInRange(const(void)[] mem) nothrow @nogc; + + /// ditto + void enableAddrReportingInRange(const(void)[] mem) nothrow @nogc; +} +else: + +debug(VALGRIND): + +private extern(C) nothrow @nogc +{ + void _d_valgrind_make_mem_noaccess (const(void)* addr, size_t len); + void _d_valgrind_make_mem_undefined(const(void)* addr, size_t len); + void _d_valgrind_make_mem_defined (const(void)* addr, size_t len); + uint _d_valgrind_get_vbits(const(void)* addr, ubyte* bits, size_t len); + uint _d_valgrind_set_vbits(const(void)* addr, ubyte* bits, size_t len); + void _d_valgrind_disable_addr_reporting_in_range(const(void)* addr, size_t len); + void _d_valgrind_enable_addr_reporting_in_range (const(void)* addr, size_t len); +} + +void makeMemNoAccess (const(void)[] mem) nothrow @nogc { _d_valgrind_make_mem_noaccess (mem.ptr, mem.length); } +void makeMemUndefined(const(void)[] mem) nothrow @nogc { _d_valgrind_make_mem_undefined(mem.ptr, mem.length); } +void makeMemDefined (const(void)[] mem) nothrow @nogc { _d_valgrind_make_mem_defined (mem.ptr, mem.length); } + +uint getVBits(const(void)[] mem, ubyte[] bits) nothrow @nogc +{ + assert(mem.length == bits.length); + return _d_valgrind_get_vbits(mem.ptr, bits.ptr, mem.length); +} + +uint setVBits(const(void)[] mem, ubyte[] bits) nothrow @nogc +{ + assert(mem.length == bits.length); + return _d_valgrind_set_vbits(mem.ptr, bits.ptr, mem.length); +} + +void disableAddrReportingInRange(const(void)[] mem) nothrow @nogc +{ + _d_valgrind_disable_addr_reporting_in_range(mem.ptr, mem.length); +} + +void enableAddrReportingInRange(const(void)[] mem) nothrow @nogc +{ + _d_valgrind_enable_addr_reporting_in_range(mem.ptr, mem.length); +} diff --git a/runtime/druntime/src/etc/valgrind/valgrind.h b/runtime/druntime/src/etc/valgrind/valgrind.h new file mode 100644 index 00000000000..4acbb81e83f --- /dev/null +++ b/runtime/druntime/src/etc/valgrind/valgrind.h @@ -0,0 +1,7165 @@ +/* -*- c -*- + ---------------------------------------------------------------- + + Notice that the following BSD-style license applies to this one + file (valgrind.h) only. The rest of Valgrind is licensed under the + terms of the GNU General Public License, version 2, unless + otherwise indicated. See the COPYING file in the source + distribution for details. + + ---------------------------------------------------------------- + + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2017 Julian Seward. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ---------------------------------------------------------------- + + Notice that the above BSD-style license applies to this one file + (valgrind.h) only. The entire rest of Valgrind is licensed under + the terms of the GNU General Public License, version 2. See the + COPYING file in the source distribution for details. + + ---------------------------------------------------------------- +*/ + + +/* This file is for inclusion into client (your!) code. + + You can use these macros to manipulate and query Valgrind's + execution inside your own programs. + + The resulting executables will still run without Valgrind, just a + little bit more slowly than they otherwise would, but otherwise + unchanged. When not running on valgrind, each client request + consumes very few (eg. 7) instructions, so the resulting performance + loss is negligible unless you plan to execute client requests + millions of times per second. Nevertheless, if that is still a + problem, you can compile with the NVALGRIND symbol defined (gcc + -DNVALGRIND) so that client requests are not even compiled in. */ + +#ifndef __VALGRIND_H +#define __VALGRIND_H + + +/* ------------------------------------------------------------------ */ +/* VERSION NUMBER OF VALGRIND */ +/* ------------------------------------------------------------------ */ + +/* Specify Valgrind's version number, so that user code can + conditionally compile based on our version number. Note that these + were introduced at version 3.6 and so do not exist in version 3.5 + or earlier. The recommended way to use them to check for "version + X.Y or later" is (eg) + +#if defined(__VALGRIND_MAJOR__) && defined(__VALGRIND_MINOR__) \ + && (__VALGRIND_MAJOR__ > 3 \ + || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6)) +*/ +#define __VALGRIND_MAJOR__ 3 +#define __VALGRIND_MINOR__ 21 + + +#include + +/* Nb: this file might be included in a file compiled with -ansi. So + we can't use C++ style "//" comments nor the "asm" keyword (instead + use "__asm__"). */ + +/* Derive some tags indicating what the target platform is. Note + that in this file we're using the compiler's CPP symbols for + identifying architectures, which are different to the ones we use + within the rest of Valgrind. Note, __powerpc__ is active for both + 32 and 64-bit PPC, whereas __powerpc64__ is only active for the + latter (on Linux, that is). + + Misc note: how to find out what's predefined in gcc by default: + gcc -Wp,-dM somefile.c +*/ +#undef PLAT_x86_darwin +#undef PLAT_amd64_darwin +#undef PLAT_x86_freebsd +#undef PLAT_amd64_freebsd +#undef PLAT_x86_win32 +#undef PLAT_amd64_win64 +#undef PLAT_x86_linux +#undef PLAT_amd64_linux +#undef PLAT_ppc32_linux +#undef PLAT_ppc64be_linux +#undef PLAT_ppc64le_linux +#undef PLAT_arm_linux +#undef PLAT_arm64_linux +#undef PLAT_s390x_linux +#undef PLAT_mips32_linux +#undef PLAT_mips64_linux +#undef PLAT_nanomips_linux +#undef PLAT_x86_solaris +#undef PLAT_amd64_solaris + + +#if defined(__APPLE__) && defined(__i386__) +# define PLAT_x86_darwin 1 +#elif defined(__APPLE__) && defined(__x86_64__) +# define PLAT_amd64_darwin 1 +#elif defined(__FreeBSD__) && defined(__i386__) +# define PLAT_x86_freebsd 1 +#elif defined(__FreeBSD__) && defined(__amd64__) +# define PLAT_amd64_freebsd 1 +#elif (defined(__MINGW32__) && defined(__i386__)) \ + || defined(__CYGWIN32__) \ + || (defined(_WIN32) && defined(_M_IX86)) +# define PLAT_x86_win32 1 +#elif (defined(__MINGW32__) && defined(__x86_64__)) \ + || (defined(_WIN32) && defined(_M_X64)) +/* __MINGW32__ and _WIN32 are defined in 64 bit mode as well. */ +# define PLAT_amd64_win64 1 +#elif defined(__linux__) && defined(__i386__) +# define PLAT_x86_linux 1 +#elif defined(__linux__) && defined(__x86_64__) && !defined(__ILP32__) +# define PLAT_amd64_linux 1 +#elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__) +# define PLAT_ppc32_linux 1 +#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) && _CALL_ELF != 2 +/* Big Endian uses ELF version 1 */ +# define PLAT_ppc64be_linux 1 +#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) && _CALL_ELF == 2 +/* Little Endian uses ELF version 2 */ +# define PLAT_ppc64le_linux 1 +#elif defined(__linux__) && defined(__arm__) && !defined(__aarch64__) +# define PLAT_arm_linux 1 +#elif defined(__linux__) && defined(__aarch64__) && !defined(__arm__) +# define PLAT_arm64_linux 1 +#elif defined(__linux__) && defined(__s390__) && defined(__s390x__) +# define PLAT_s390x_linux 1 +#elif defined(__linux__) && defined(__mips__) && (__mips==64) +# define PLAT_mips64_linux 1 +#elif defined(__linux__) && defined(__mips__) && (__mips==32) +# define PLAT_mips32_linux 1 +#elif defined(__linux__) && defined(__nanomips__) +# define PLAT_nanomips_linux 1 +#elif defined(__sun) && defined(__i386__) +# define PLAT_x86_solaris 1 +#elif defined(__sun) && defined(__x86_64__) +# define PLAT_amd64_solaris 1 +#else +/* If we're not compiling for our target platform, don't generate + any inline asms. */ +# if !defined(NVALGRIND) +# define NVALGRIND 1 +# endif +#endif + + +/* ------------------------------------------------------------------ */ +/* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS. There is nothing */ +/* in here of use to end-users -- skip to the next section. */ +/* ------------------------------------------------------------------ */ + +/* + * VALGRIND_DO_CLIENT_REQUEST(): a statement that invokes a Valgrind client + * request. Accepts both pointers and integers as arguments. + * + * VALGRIND_DO_CLIENT_REQUEST_STMT(): a statement that invokes a Valgrind + * client request that does not return a value. + + * VALGRIND_DO_CLIENT_REQUEST_EXPR(): a C expression that invokes a Valgrind + * client request and whose value equals the client request result. Accepts + * both pointers and integers as arguments. Note that such calls are not + * necessarily pure functions -- they may have side effects. + */ + +#define VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, \ + _zzq_request, _zzq_arg1, _zzq_arg2, \ + _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + do { (_zzq_rlval) = VALGRIND_DO_CLIENT_REQUEST_EXPR((_zzq_default), \ + (_zzq_request), (_zzq_arg1), (_zzq_arg2), \ + (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0) + +#define VALGRIND_DO_CLIENT_REQUEST_STMT(_zzq_request, _zzq_arg1, \ + _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + do { (void) VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ + (_zzq_request), (_zzq_arg1), (_zzq_arg2), \ + (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0) + +#if defined(NVALGRIND) + +/* Define NVALGRIND to completely remove the Valgrind magic sequence + from the compiled code (analogous to NDEBUG's effects on + assert()) */ +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + (_zzq_default) + +#else /* ! NVALGRIND */ + +/* The following defines the magic code sequences which the JITter + spots and handles magically. Don't look too closely at them as + they will rot your brain. + + The assembly code sequences for all architectures is in this one + file. This is because this file must be stand-alone, and we don't + want to have multiple files. + + For VALGRIND_DO_CLIENT_REQUEST, we must ensure that the default + value gets put in the return slot, so that everything works when + this is executed not under Valgrind. Args are passed in a memory + block, and so there's no intrinsic limit to the number that could + be passed, but it's currently five. + + The macro args are: + _zzq_rlval result lvalue + _zzq_default default value (result returned when running on real CPU) + _zzq_request request code + _zzq_arg1..5 request params + + The other two macros are used to support function wrapping, and are + a lot simpler. VALGRIND_GET_NR_CONTEXT returns the value of the + guest's NRADDR pseudo-register and whatever other information is + needed to safely run the call original from the wrapper: on + ppc64-linux, the R2 value at the divert point is also needed. This + information is abstracted into a user-visible type, OrigFn. + + VALGRIND_CALL_NOREDIR_* behaves the same as the following on the + guest, but guarantees that the branch instruction will not be + redirected: x86: call *%eax, amd64: call *%rax, ppc32/ppc64: + branch-and-link-to-r11. VALGRIND_CALL_NOREDIR is just text, not a + complete inline asm, since it needs to be combined with more magic + inline asm stuff to be useful. +*/ + +/* ----------------- x86-{linux,darwin,solaris} ---------------- */ + +#if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \ + || (defined(PLAT_x86_win32) && defined(__GNUC__)) \ + || defined(PLAT_x86_solaris) || defined(PLAT_x86_freebsd) + +typedef + struct { + unsigned int nraddr; /* where's the code? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "roll $3, %%edi ; roll $13, %%edi\n\t" \ + "roll $29, %%edi ; roll $19, %%edi\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + __extension__ \ + ({volatile unsigned int _zzq_args[6]; \ + volatile unsigned int _zzq_result; \ + _zzq_args[0] = (unsigned int)(_zzq_request); \ + _zzq_args[1] = (unsigned int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned int)(_zzq_arg5); \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %EDX = client_request ( %EAX ) */ \ + "xchgl %%ebx,%%ebx" \ + : "=d" (_zzq_result) \ + : "a" (&_zzq_args[0]), "0" (_zzq_default) \ + : "cc", "memory" \ + ); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + volatile unsigned int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %EAX = guest_NRADDR */ \ + "xchgl %%ecx,%%ecx" \ + : "=a" (__addr) \ + : \ + : "cc", "memory" \ + ); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_CALL_NOREDIR_EAX \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* call-noredir *%EAX */ \ + "xchgl %%edx,%%edx\n\t" + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + "xchgl %%edi,%%edi\n\t" \ + : : : "cc", "memory" \ + ); \ + } while (0) + +#endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__) + || PLAT_x86_solaris */ + +/* ------------------------- x86-Win32 ------------------------- */ + +#if defined(PLAT_x86_win32) && !defined(__GNUC__) + +typedef + struct { + unsigned int nraddr; /* where's the code? */ + } + OrigFn; + +#if defined(_MSC_VER) + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + __asm rol edi, 3 __asm rol edi, 13 \ + __asm rol edi, 29 __asm rol edi, 19 + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + valgrind_do_client_request_expr((uintptr_t)(_zzq_default), \ + (uintptr_t)(_zzq_request), (uintptr_t)(_zzq_arg1), \ + (uintptr_t)(_zzq_arg2), (uintptr_t)(_zzq_arg3), \ + (uintptr_t)(_zzq_arg4), (uintptr_t)(_zzq_arg5)) + +static __inline uintptr_t +valgrind_do_client_request_expr(uintptr_t _zzq_default, uintptr_t _zzq_request, + uintptr_t _zzq_arg1, uintptr_t _zzq_arg2, + uintptr_t _zzq_arg3, uintptr_t _zzq_arg4, + uintptr_t _zzq_arg5) +{ + volatile uintptr_t _zzq_args[6]; + volatile unsigned int _zzq_result; + _zzq_args[0] = (uintptr_t)(_zzq_request); + _zzq_args[1] = (uintptr_t)(_zzq_arg1); + _zzq_args[2] = (uintptr_t)(_zzq_arg2); + _zzq_args[3] = (uintptr_t)(_zzq_arg3); + _zzq_args[4] = (uintptr_t)(_zzq_arg4); + _zzq_args[5] = (uintptr_t)(_zzq_arg5); + __asm { __asm lea eax, _zzq_args __asm mov edx, _zzq_default + __SPECIAL_INSTRUCTION_PREAMBLE + /* %EDX = client_request ( %EAX ) */ + __asm xchg ebx,ebx + __asm mov _zzq_result, edx + } + return _zzq_result; +} + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + volatile unsigned int __addr; \ + __asm { __SPECIAL_INSTRUCTION_PREAMBLE \ + /* %EAX = guest_NRADDR */ \ + __asm xchg ecx,ecx \ + __asm mov __addr, eax \ + } \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_CALL_NOREDIR_EAX ERROR + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm { __SPECIAL_INSTRUCTION_PREAMBLE \ + __asm xchg edi,edi \ + } \ + } while (0) + +#else +#error Unsupported compiler. +#endif + +#endif /* PLAT_x86_win32 */ + +/* ----------------- amd64-{linux,darwin,solaris} --------------- */ + +#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \ + || defined(PLAT_amd64_solaris) \ + || defined(PLAT_amd64_freebsd) \ + || (defined(PLAT_amd64_win64) && defined(__GNUC__)) + +typedef + struct { + unsigned long int nraddr; /* where's the code? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "rolq $3, %%rdi ; rolq $13, %%rdi\n\t" \ + "rolq $61, %%rdi ; rolq $51, %%rdi\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + __extension__ \ + ({ volatile unsigned long int _zzq_args[6]; \ + volatile unsigned long int _zzq_result; \ + _zzq_args[0] = (unsigned long int)(_zzq_request); \ + _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %RDX = client_request ( %RAX ) */ \ + "xchgq %%rbx,%%rbx" \ + : "=d" (_zzq_result) \ + : "a" (&_zzq_args[0]), "0" (_zzq_default) \ + : "cc", "memory" \ + ); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + volatile unsigned long int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %RAX = guest_NRADDR */ \ + "xchgq %%rcx,%%rcx" \ + : "=a" (__addr) \ + : \ + : "cc", "memory" \ + ); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_CALL_NOREDIR_RAX \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* call-noredir *%RAX */ \ + "xchgq %%rdx,%%rdx\n\t" + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + "xchgq %%rdi,%%rdi\n\t" \ + : : : "cc", "memory" \ + ); \ + } while (0) + +#endif /* PLAT_amd64_linux || PLAT_amd64_darwin || PLAT_amd64_solaris */ + +/* ------------------------- amd64-Win64 ------------------------- */ + +#if defined(PLAT_amd64_win64) && !defined(__GNUC__) + +#error Unsupported compiler. + +#endif /* PLAT_amd64_win64 */ + +/* ------------------------ ppc32-linux ------------------------ */ + +#if defined(PLAT_ppc32_linux) + +typedef + struct { + unsigned int nraddr; /* where's the code? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "rlwinm 0,0,3,0,31 ; rlwinm 0,0,13,0,31\n\t" \ + "rlwinm 0,0,29,0,31 ; rlwinm 0,0,19,0,31\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + \ + __extension__ \ + ({ unsigned int _zzq_args[6]; \ + unsigned int _zzq_result; \ + unsigned int* _zzq_ptr; \ + _zzq_args[0] = (unsigned int)(_zzq_request); \ + _zzq_args[1] = (unsigned int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned int)(_zzq_arg5); \ + _zzq_ptr = _zzq_args; \ + __asm__ volatile("mr 3,%1\n\t" /*default*/ \ + "mr 4,%2\n\t" /*ptr*/ \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = client_request ( %R4 ) */ \ + "or 1,1,1\n\t" \ + "mr %0,3" /*result*/ \ + : "=b" (_zzq_result) \ + : "b" (_zzq_default), "b" (_zzq_ptr) \ + : "cc", "memory", "r3", "r4"); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + unsigned int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR */ \ + "or 2,2,2\n\t" \ + "mr %0,3" \ + : "=b" (__addr) \ + : \ + : "cc", "memory", "r3" \ + ); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* branch-and-link-to-noredir *%R11 */ \ + "or 3,3,3\n\t" + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + "or 5,5,5\n\t" \ + ); \ + } while (0) + +#endif /* PLAT_ppc32_linux */ + +/* ------------------------ ppc64-linux ------------------------ */ + +#if defined(PLAT_ppc64be_linux) + +typedef + struct { + unsigned long int nraddr; /* where's the code? */ + unsigned long int r2; /* what tocptr do we need? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ + "rotldi 0,0,61 ; rotldi 0,0,51\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + \ + __extension__ \ + ({ unsigned long int _zzq_args[6]; \ + unsigned long int _zzq_result; \ + unsigned long int* _zzq_ptr; \ + _zzq_args[0] = (unsigned long int)(_zzq_request); \ + _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ + _zzq_ptr = _zzq_args; \ + __asm__ volatile("mr 3,%1\n\t" /*default*/ \ + "mr 4,%2\n\t" /*ptr*/ \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = client_request ( %R4 ) */ \ + "or 1,1,1\n\t" \ + "mr %0,3" /*result*/ \ + : "=b" (_zzq_result) \ + : "b" (_zzq_default), "b" (_zzq_ptr) \ + : "cc", "memory", "r3", "r4"); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + unsigned long int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR */ \ + "or 2,2,2\n\t" \ + "mr %0,3" \ + : "=b" (__addr) \ + : \ + : "cc", "memory", "r3" \ + ); \ + _zzq_orig->nraddr = __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR_GPR2 */ \ + "or 4,4,4\n\t" \ + "mr %0,3" \ + : "=b" (__addr) \ + : \ + : "cc", "memory", "r3" \ + ); \ + _zzq_orig->r2 = __addr; \ + } + +#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* branch-and-link-to-noredir *%R11 */ \ + "or 3,3,3\n\t" + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + "or 5,5,5\n\t" \ + ); \ + } while (0) + +#endif /* PLAT_ppc64be_linux */ + +#if defined(PLAT_ppc64le_linux) + +typedef + struct { + unsigned long int nraddr; /* where's the code? */ + unsigned long int r2; /* what tocptr do we need? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ + "rotldi 0,0,61 ; rotldi 0,0,51\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + \ + __extension__ \ + ({ unsigned long int _zzq_args[6]; \ + unsigned long int _zzq_result; \ + unsigned long int* _zzq_ptr; \ + _zzq_args[0] = (unsigned long int)(_zzq_request); \ + _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ + _zzq_ptr = _zzq_args; \ + __asm__ volatile("mr 3,%1\n\t" /*default*/ \ + "mr 4,%2\n\t" /*ptr*/ \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = client_request ( %R4 ) */ \ + "or 1,1,1\n\t" \ + "mr %0,3" /*result*/ \ + : "=b" (_zzq_result) \ + : "b" (_zzq_default), "b" (_zzq_ptr) \ + : "cc", "memory", "r3", "r4"); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + unsigned long int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR */ \ + "or 2,2,2\n\t" \ + "mr %0,3" \ + : "=b" (__addr) \ + : \ + : "cc", "memory", "r3" \ + ); \ + _zzq_orig->nraddr = __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR_GPR2 */ \ + "or 4,4,4\n\t" \ + "mr %0,3" \ + : "=b" (__addr) \ + : \ + : "cc", "memory", "r3" \ + ); \ + _zzq_orig->r2 = __addr; \ + } + +#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* branch-and-link-to-noredir *%R12 */ \ + "or 3,3,3\n\t" + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + "or 5,5,5\n\t" \ + ); \ + } while (0) + +#endif /* PLAT_ppc64le_linux */ + +/* ------------------------- arm-linux ------------------------- */ + +#if defined(PLAT_arm_linux) + +typedef + struct { + unsigned int nraddr; /* where's the code? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "mov r12, r12, ror #3 ; mov r12, r12, ror #13 \n\t" \ + "mov r12, r12, ror #29 ; mov r12, r12, ror #19 \n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + \ + __extension__ \ + ({volatile unsigned int _zzq_args[6]; \ + volatile unsigned int _zzq_result; \ + _zzq_args[0] = (unsigned int)(_zzq_request); \ + _zzq_args[1] = (unsigned int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned int)(_zzq_arg5); \ + __asm__ volatile("mov r3, %1\n\t" /*default*/ \ + "mov r4, %2\n\t" /*ptr*/ \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* R3 = client_request ( R4 ) */ \ + "orr r10, r10, r10\n\t" \ + "mov %0, r3" /*result*/ \ + : "=r" (_zzq_result) \ + : "r" (_zzq_default), "r" (&_zzq_args[0]) \ + : "cc","memory", "r3", "r4"); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + unsigned int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* R3 = guest_NRADDR */ \ + "orr r11, r11, r11\n\t" \ + "mov %0, r3" \ + : "=r" (__addr) \ + : \ + : "cc", "memory", "r3" \ + ); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* branch-and-link-to-noredir *%R4 */ \ + "orr r12, r12, r12\n\t" + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + "orr r9, r9, r9\n\t" \ + : : : "cc", "memory" \ + ); \ + } while (0) + +#endif /* PLAT_arm_linux */ + +/* ------------------------ arm64-linux ------------------------- */ + +#if defined(PLAT_arm64_linux) + +typedef + struct { + unsigned long int nraddr; /* where's the code? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "ror x12, x12, #3 ; ror x12, x12, #13 \n\t" \ + "ror x12, x12, #51 ; ror x12, x12, #61 \n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + \ + __extension__ \ + ({volatile unsigned long int _zzq_args[6]; \ + volatile unsigned long int _zzq_result; \ + _zzq_args[0] = (unsigned long int)(_zzq_request); \ + _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ + __asm__ volatile("mov x3, %1\n\t" /*default*/ \ + "mov x4, %2\n\t" /*ptr*/ \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* X3 = client_request ( X4 ) */ \ + "orr x10, x10, x10\n\t" \ + "mov %0, x3" /*result*/ \ + : "=r" (_zzq_result) \ + : "r" ((unsigned long int)(_zzq_default)), \ + "r" (&_zzq_args[0]) \ + : "cc","memory", "x3", "x4"); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + unsigned long int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* X3 = guest_NRADDR */ \ + "orr x11, x11, x11\n\t" \ + "mov %0, x3" \ + : "=r" (__addr) \ + : \ + : "cc", "memory", "x3" \ + ); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* branch-and-link-to-noredir X8 */ \ + "orr x12, x12, x12\n\t" + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + "orr x9, x9, x9\n\t" \ + : : : "cc", "memory" \ + ); \ + } while (0) + +#endif /* PLAT_arm64_linux */ + +/* ------------------------ s390x-linux ------------------------ */ + +#if defined(PLAT_s390x_linux) + +typedef + struct { + unsigned long int nraddr; /* where's the code? */ + } + OrigFn; + +/* __SPECIAL_INSTRUCTION_PREAMBLE will be used to identify Valgrind specific + * code. This detection is implemented in platform specific toIR.c + * (e.g. VEX/priv/guest_s390_decoder.c). + */ +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "lr 15,15\n\t" \ + "lr 1,1\n\t" \ + "lr 2,2\n\t" \ + "lr 3,3\n\t" + +#define __CLIENT_REQUEST_CODE "lr 2,2\n\t" +#define __GET_NR_CONTEXT_CODE "lr 3,3\n\t" +#define __CALL_NO_REDIR_CODE "lr 4,4\n\t" +#define __VEX_INJECT_IR_CODE "lr 5,5\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + __extension__ \ + ({volatile unsigned long int _zzq_args[6]; \ + volatile unsigned long int _zzq_result; \ + _zzq_args[0] = (unsigned long int)(_zzq_request); \ + _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ + __asm__ volatile(/* r2 = args */ \ + "lgr 2,%1\n\t" \ + /* r3 = default */ \ + "lgr 3,%2\n\t" \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + __CLIENT_REQUEST_CODE \ + /* results = r3 */ \ + "lgr %0, 3\n\t" \ + : "=d" (_zzq_result) \ + : "a" (&_zzq_args[0]), \ + "0" ((unsigned long int)_zzq_default) \ + : "cc", "2", "3", "memory" \ + ); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + volatile unsigned long int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + __GET_NR_CONTEXT_CODE \ + "lgr %0, 3\n\t" \ + : "=a" (__addr) \ + : \ + : "cc", "3", "memory" \ + ); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_CALL_NOREDIR_R1 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + __CALL_NO_REDIR_CODE + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + __VEX_INJECT_IR_CODE); \ + } while (0) + +#endif /* PLAT_s390x_linux */ + +/* ------------------------- mips32-linux ---------------- */ + +#if defined(PLAT_mips32_linux) + +typedef + struct { + unsigned int nraddr; /* where's the code? */ + } + OrigFn; + +/* .word 0x342 + * .word 0x742 + * .word 0xC2 + * .word 0x4C2*/ +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "srl $0, $0, 13\n\t" \ + "srl $0, $0, 29\n\t" \ + "srl $0, $0, 3\n\t" \ + "srl $0, $0, 19\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + __extension__ \ + ({ volatile unsigned int _zzq_args[6]; \ + volatile unsigned int _zzq_result; \ + _zzq_args[0] = (unsigned int)(_zzq_request); \ + _zzq_args[1] = (unsigned int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned int)(_zzq_arg5); \ + __asm__ volatile("move $11, %1\n\t" /*default*/ \ + "move $12, %2\n\t" /*ptr*/ \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* T3 = client_request ( T4 ) */ \ + "or $13, $13, $13\n\t" \ + "move %0, $11\n\t" /*result*/ \ + : "=r" (_zzq_result) \ + : "r" (_zzq_default), "r" (&_zzq_args[0]) \ + : "$11", "$12", "memory"); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + volatile unsigned int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %t9 = guest_NRADDR */ \ + "or $14, $14, $14\n\t" \ + "move %0, $11" /*result*/ \ + : "=r" (__addr) \ + : \ + : "$11" \ + ); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_CALL_NOREDIR_T9 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* call-noredir *%t9 */ \ + "or $15, $15, $15\n\t" + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + "or $11, $11, $11\n\t" \ + ); \ + } while (0) + + +#endif /* PLAT_mips32_linux */ + +/* ------------------------- mips64-linux ---------------- */ + +#if defined(PLAT_mips64_linux) + +typedef + struct { + unsigned long nraddr; /* where's the code? */ + } + OrigFn; + +/* dsll $0,$0, 3 + * dsll $0,$0, 13 + * dsll $0,$0, 29 + * dsll $0,$0, 19*/ +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "dsll $0,$0, 3 ; dsll $0,$0,13\n\t" \ + "dsll $0,$0,29 ; dsll $0,$0,19\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + __extension__ \ + ({ volatile unsigned long int _zzq_args[6]; \ + volatile unsigned long int _zzq_result; \ + _zzq_args[0] = (unsigned long int)(_zzq_request); \ + _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ + __asm__ volatile("move $11, %1\n\t" /*default*/ \ + "move $12, %2\n\t" /*ptr*/ \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* $11 = client_request ( $12 ) */ \ + "or $13, $13, $13\n\t" \ + "move %0, $11\n\t" /*result*/ \ + : "=r" (_zzq_result) \ + : "r" (_zzq_default), "r" (&_zzq_args[0]) \ + : "$11", "$12", "memory"); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + volatile unsigned long int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* $11 = guest_NRADDR */ \ + "or $14, $14, $14\n\t" \ + "move %0, $11" /*result*/ \ + : "=r" (__addr) \ + : \ + : "$11"); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_CALL_NOREDIR_T9 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* call-noredir $25 */ \ + "or $15, $15, $15\n\t" + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + "or $11, $11, $11\n\t" \ + ); \ + } while (0) + +#endif /* PLAT_mips64_linux */ + +#if defined(PLAT_nanomips_linux) + +typedef + struct { + unsigned int nraddr; /* where's the code? */ + } + OrigFn; +/* + 8000 c04d srl zero, zero, 13 + 8000 c05d srl zero, zero, 29 + 8000 c043 srl zero, zero, 3 + 8000 c053 srl zero, zero, 19 +*/ + +#define __SPECIAL_INSTRUCTION_PREAMBLE "srl[32] $zero, $zero, 13 \n\t" \ + "srl[32] $zero, $zero, 29 \n\t" \ + "srl[32] $zero, $zero, 3 \n\t" \ + "srl[32] $zero, $zero, 19 \n\t" + +#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + __extension__ \ + ({ volatile unsigned int _zzq_args[6]; \ + volatile unsigned int _zzq_result; \ + _zzq_args[0] = (unsigned int)(_zzq_request); \ + _zzq_args[1] = (unsigned int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned int)(_zzq_arg5); \ + __asm__ volatile("move $a7, %1\n\t" /* default */ \ + "move $t0, %2\n\t" /* ptr */ \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* $a7 = client_request( $t0 ) */ \ + "or[32] $t0, $t0, $t0\n\t" \ + "move %0, $a7\n\t" /* result */ \ + : "=r" (_zzq_result) \ + : "r" (_zzq_default), "r" (&_zzq_args[0]) \ + : "$a7", "$t0", "memory"); \ + _zzq_result; \ + }) + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + volatile unsigned long int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* $a7 = guest_NRADDR */ \ + "or[32] $t1, $t1, $t1\n\t" \ + "move %0, $a7" /*result*/ \ + : "=r" (__addr) \ + : \ + : "$a7"); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_CALL_NOREDIR_T9 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* call-noredir $25 */ \ + "or[32] $t2, $t2, $t2\n\t" + +#define VALGRIND_VEX_INJECT_IR() \ + do { \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + "or[32] $t3, $t3, $t3\n\t" \ + ); \ + } while (0) + +#endif +/* Insert assembly code for other platforms here... */ + +#endif /* NVALGRIND */ + + +/* ------------------------------------------------------------------ */ +/* PLATFORM SPECIFICS for FUNCTION WRAPPING. This is all very */ +/* ugly. It's the least-worst tradeoff I can think of. */ +/* ------------------------------------------------------------------ */ + +/* This section defines magic (a.k.a appalling-hack) macros for doing + guaranteed-no-redirection macros, so as to get from function + wrappers to the functions they are wrapping. The whole point is to + construct standard call sequences, but to do the call itself with a + special no-redirect call pseudo-instruction that the JIT + understands and handles specially. This section is long and + repetitious, and I can't see a way to make it shorter. + + The naming scheme is as follows: + + CALL_FN_{W,v}_{v,W,WW,WWW,WWWW,5W,6W,7W,etc} + + 'W' stands for "word" and 'v' for "void". Hence there are + different macros for calling arity 0, 1, 2, 3, 4, etc, functions, + and for each, the possibility of returning a word-typed result, or + no result. +*/ + +/* Use these to write the name of your wrapper. NOTE: duplicates + VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. NOTE also: inserts + the default behaviour equivalance class tag "0000" into the name. + See pub_tool_redir.h for details -- normally you don't need to + think about this, though. */ + +/* Use an extra level of macroisation so as to ensure the soname/fnname + args are fully macro-expanded before pasting them together. */ +#define VG_CONCAT4(_aa,_bb,_cc,_dd) _aa##_bb##_cc##_dd + +#define I_WRAP_SONAME_FNNAME_ZU(soname,fnname) \ + VG_CONCAT4(_vgw00000ZU_,soname,_,fnname) + +#define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \ + VG_CONCAT4(_vgw00000ZZ_,soname,_,fnname) + +/* Use this macro from within a wrapper function to collect the + context (address and possibly other info) of the original function. + Once you have that you can then use it in one of the CALL_FN_ + macros. The type of the argument _lval is OrigFn. */ +#define VALGRIND_GET_ORIG_FN(_lval) VALGRIND_GET_NR_CONTEXT(_lval) + +/* Also provide end-user facilities for function replacement, rather + than wrapping. A replacement function differs from a wrapper in + that it has no way to get hold of the original function being + called, and hence no way to call onwards to it. In a replacement + function, VALGRIND_GET_ORIG_FN always returns zero. */ + +#define I_REPLACE_SONAME_FNNAME_ZU(soname,fnname) \ + VG_CONCAT4(_vgr00000ZU_,soname,_,fnname) + +#define I_REPLACE_SONAME_FNNAME_ZZ(soname,fnname) \ + VG_CONCAT4(_vgr00000ZZ_,soname,_,fnname) + +/* Derivatives of the main macros below, for calling functions + returning void. */ + +#define CALL_FN_v_v(fnptr) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_v(_junk,fnptr); } while (0) + +#define CALL_FN_v_W(fnptr, arg1) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_W(_junk,fnptr,arg1); } while (0) + +#define CALL_FN_v_WW(fnptr, arg1,arg2) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0) + +#define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0) + +#define CALL_FN_v_WWWW(fnptr, arg1,arg2,arg3,arg4) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_WWWW(_junk,fnptr,arg1,arg2,arg3,arg4); } while (0) + +#define CALL_FN_v_5W(fnptr, arg1,arg2,arg3,arg4,arg5) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_5W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5); } while (0) + +#define CALL_FN_v_6W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_6W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6); } while (0) + +#define CALL_FN_v_7W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6,arg7) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_7W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); } while (0) + +/* ----------------- x86-{linux,darwin,solaris} ---------------- */ + +#if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \ + || defined(PLAT_x86_solaris) || defined(PLAT_x86_freebsd) + +/* These regs are trashed by the hidden call. No need to mention eax + as gcc can already see that, plus causes gcc to bomb. */ +#define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx" + +/* Macros to save and align the stack before making a function + call and restore it afterwards as gcc may not keep the stack + pointer aligned if it doesn't realise calls are being made + to other functions. */ + +#define VALGRIND_ALIGN_STACK \ + "movl %%esp,%%edi\n\t" \ + "andl $0xfffffff0,%%esp\n\t" +#define VALGRIND_RESTORE_STACK \ + "movl %%edi,%%esp\n\t" + +/* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned + long) == 4. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[1]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[2]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "subl $12, %%esp\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "subl $8, %%esp\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[4]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "subl $4, %%esp\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[5]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[6]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "subl $12, %%esp\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[7]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "subl $8, %%esp\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[8]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "subl $4, %%esp\n\t" \ + "pushl 28(%%eax)\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[9]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "pushl 32(%%eax)\n\t" \ + "pushl 28(%%eax)\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[10]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "subl $12, %%esp\n\t" \ + "pushl 36(%%eax)\n\t" \ + "pushl 32(%%eax)\n\t" \ + "pushl 28(%%eax)\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[11]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "subl $8, %%esp\n\t" \ + "pushl 40(%%eax)\n\t" \ + "pushl 36(%%eax)\n\t" \ + "pushl 32(%%eax)\n\t" \ + "pushl 28(%%eax)\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[12]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "subl $4, %%esp\n\t" \ + "pushl 44(%%eax)\n\t" \ + "pushl 40(%%eax)\n\t" \ + "pushl 36(%%eax)\n\t" \ + "pushl 32(%%eax)\n\t" \ + "pushl 28(%%eax)\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[13]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + _argvec[12] = (unsigned long)(arg12); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "pushl 48(%%eax)\n\t" \ + "pushl 44(%%eax)\n\t" \ + "pushl 40(%%eax)\n\t" \ + "pushl 36(%%eax)\n\t" \ + "pushl 32(%%eax)\n\t" \ + "pushl 28(%%eax)\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_x86_linux || PLAT_x86_darwin || PLAT_x86_solaris */ + +/* ---------------- amd64-{linux,darwin,solaris} --------------- */ + +#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \ + || defined(PLAT_amd64_solaris) || defined(PLAT_amd64_freebsd) + +/* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */ + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi", \ + "rdi", "r8", "r9", "r10", "r11" + +/* This is all pretty complex. It's so as to make stack unwinding + work reliably. See bug 243270. The basic problem is the sub and + add of 128 of %rsp in all of the following macros. If gcc believes + the CFA is in %rsp, then unwinding may fail, because what's at the + CFA is not what gcc "expected" when it constructs the CFIs for the + places where the macros are instantiated. + + But we can't just add a CFI annotation to increase the CFA offset + by 128, to match the sub of 128 from %rsp, because we don't know + whether gcc has chosen %rsp as the CFA at that point, or whether it + has chosen some other register (eg, %rbp). In the latter case, + adding a CFI annotation to change the CFA offset is simply wrong. + + So the solution is to get hold of the CFA using + __builtin_dwarf_cfa(), put it in a known register, and add a + CFI annotation to say what the register is. We choose %rbp for + this (perhaps perversely), because: + + (1) %rbp is already subject to unwinding. If a new register was + chosen then the unwinder would have to unwind it in all stack + traces, which is expensive, and + + (2) %rbp is already subject to precise exception updates in the + JIT. If a new register was chosen, we'd have to have precise + exceptions for it too, which reduces performance of the + generated code. + + However .. one extra complication. We can't just whack the result + of __builtin_dwarf_cfa() into %rbp and then add %rbp to the + list of trashed registers at the end of the inline assembly + fragments; gcc won't allow %rbp to appear in that list. Hence + instead we need to stash %rbp in %r15 for the duration of the asm, + and say that %r15 is trashed instead. gcc seems happy to go with + that. + + Oh .. and this all needs to be conditionalised so that it is + unchanged from before this commit, when compiled with older gccs + that don't support __builtin_dwarf_cfa. Furthermore, since + this header file is freestanding, it has to be independent of + config.h, and so the following conditionalisation cannot depend on + configure time checks. + + Although it's not clear from + 'defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)', + this expression excludes Darwin. + .cfi directives in Darwin assembly appear to be completely + different and I haven't investigated how they work. + + For even more entertainment value, note we have to use the + completely undocumented __builtin_dwarf_cfa(), which appears to + really compute the CFA, whereas __builtin_frame_address(0) claims + to but actually doesn't. See + https://bugs.kde.org/show_bug.cgi?id=243270#c47 +*/ +#if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM) +# define __FRAME_POINTER \ + ,"r"(__builtin_dwarf_cfa()) +# define VALGRIND_CFI_PROLOGUE \ + "movq %%rbp, %%r15\n\t" \ + "movq %2, %%rbp\n\t" \ + ".cfi_remember_state\n\t" \ + ".cfi_def_cfa rbp, 0\n\t" +# define VALGRIND_CFI_EPILOGUE \ + "movq %%r15, %%rbp\n\t" \ + ".cfi_restore_state\n\t" +#else +# define __FRAME_POINTER +# define VALGRIND_CFI_PROLOGUE +# define VALGRIND_CFI_EPILOGUE +#endif + +/* Macros to save and align the stack before making a function + call and restore it afterwards as gcc may not keep the stack + pointer aligned if it doesn't realise calls are being made + to other functions. */ + +#define VALGRIND_ALIGN_STACK \ + "movq %%rsp,%%r14\n\t" \ + "andq $0xfffffffffffffff0,%%rsp\n\t" +#define VALGRIND_RESTORE_STACK \ + "movq %%r14,%%rsp\n\t" + +/* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned + long) == 8. */ + +/* NB 9 Sept 07. There is a nasty kludge here in all these CALL_FN_ + macros. In order not to trash the stack redzone, we need to drop + %rsp by 128 before the hidden call, and restore afterwards. The + nastyness is that it is only by luck that the stack still appears + to be unwindable during the hidden call - since then the behaviour + of any routine using this macro does not match what the CFI data + says. Sigh. + + Why is this important? Imagine that a wrapper has a stack + allocated local, and passes to the hidden call, a pointer to it. + Because gcc does not know about the hidden call, it may allocate + that local in the redzone. Unfortunately the hidden call may then + trash it before it comes to use it. So we must step clear of the + redzone, for the duration of the hidden call, to make it safe. + + Probably the same problem afflicts the other redzone-style ABIs too + (ppc64-linux); but for those, the stack is + self describing (none of this CFI nonsense) so at least messing + with the stack pointer doesn't give a danger of non-unwindable + stack. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[1]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $128,%%rsp\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[2]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $128,%%rsp\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $128,%%rsp\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[4]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $128,%%rsp\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[5]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $128,%%rsp\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[6]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $128,%%rsp\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[7]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $128,%%rsp\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[8]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $136,%%rsp\n\t" \ + "pushq 56(%%rax)\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[9]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $128,%%rsp\n\t" \ + "pushq 64(%%rax)\n\t" \ + "pushq 56(%%rax)\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[10]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $136,%%rsp\n\t" \ + "pushq 72(%%rax)\n\t" \ + "pushq 64(%%rax)\n\t" \ + "pushq 56(%%rax)\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[11]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $128,%%rsp\n\t" \ + "pushq 80(%%rax)\n\t" \ + "pushq 72(%%rax)\n\t" \ + "pushq 64(%%rax)\n\t" \ + "pushq 56(%%rax)\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[12]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $136,%%rsp\n\t" \ + "pushq 88(%%rax)\n\t" \ + "pushq 80(%%rax)\n\t" \ + "pushq 72(%%rax)\n\t" \ + "pushq 64(%%rax)\n\t" \ + "pushq 56(%%rax)\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[13]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + _argvec[12] = (unsigned long)(arg12); \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + VALGRIND_ALIGN_STACK \ + "subq $128,%%rsp\n\t" \ + "pushq 96(%%rax)\n\t" \ + "pushq 88(%%rax)\n\t" \ + "pushq 80(%%rax)\n\t" \ + "pushq 72(%%rax)\n\t" \ + "pushq 64(%%rax)\n\t" \ + "pushq 56(%%rax)\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + VALGRIND_RESTORE_STACK \ + VALGRIND_CFI_EPILOGUE \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_amd64_linux || PLAT_amd64_darwin || PLAT_amd64_solaris */ + +/* ------------------------ ppc32-linux ------------------------ */ + +#if defined(PLAT_ppc32_linux) + +/* This is useful for finding out about the on-stack stuff: + + extern int f9 ( int,int,int,int,int,int,int,int,int ); + extern int f10 ( int,int,int,int,int,int,int,int,int,int ); + extern int f11 ( int,int,int,int,int,int,int,int,int,int,int ); + extern int f12 ( int,int,int,int,int,int,int,int,int,int,int,int ); + + int g9 ( void ) { + return f9(11,22,33,44,55,66,77,88,99); + } + int g10 ( void ) { + return f10(11,22,33,44,55,66,77,88,99,110); + } + int g11 ( void ) { + return f11(11,22,33,44,55,66,77,88,99,110,121); + } + int g12 ( void ) { + return f12(11,22,33,44,55,66,77,88,99,110,121,132); + } +*/ + +/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS \ + "lr", "ctr", "xer", \ + "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ + "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ + "r11", "r12", "r13" + +/* Macros to save and align the stack before making a function + call and restore it afterwards as gcc may not keep the stack + pointer aligned if it doesn't realise calls are being made + to other functions. */ + +#define VALGRIND_ALIGN_STACK \ + "mr 28,1\n\t" \ + "rlwinm 1,1,0,0,27\n\t" +#define VALGRIND_RESTORE_STACK \ + "mr 1,28\n\t" + +/* These CALL_FN_ macros assume that on ppc32-linux, + sizeof(unsigned long) == 4. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[1]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[2]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[4]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[5]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[6]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[7]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[8]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 9,28(11)\n\t" \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[9]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 9,28(11)\n\t" \ + "lwz 10,32(11)\n\t" /* arg8->r10 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[10]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + _argvec[9] = (unsigned long)arg9; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "addi 1,1,-16\n\t" \ + /* arg9 */ \ + "lwz 3,36(11)\n\t" \ + "stw 3,8(1)\n\t" \ + /* args1-8 */ \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 9,28(11)\n\t" \ + "lwz 10,32(11)\n\t" /* arg8->r10 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[11]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + _argvec[9] = (unsigned long)arg9; \ + _argvec[10] = (unsigned long)arg10; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "addi 1,1,-16\n\t" \ + /* arg10 */ \ + "lwz 3,40(11)\n\t" \ + "stw 3,12(1)\n\t" \ + /* arg9 */ \ + "lwz 3,36(11)\n\t" \ + "stw 3,8(1)\n\t" \ + /* args1-8 */ \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 9,28(11)\n\t" \ + "lwz 10,32(11)\n\t" /* arg8->r10 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[12]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + _argvec[9] = (unsigned long)arg9; \ + _argvec[10] = (unsigned long)arg10; \ + _argvec[11] = (unsigned long)arg11; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "addi 1,1,-32\n\t" \ + /* arg11 */ \ + "lwz 3,44(11)\n\t" \ + "stw 3,16(1)\n\t" \ + /* arg10 */ \ + "lwz 3,40(11)\n\t" \ + "stw 3,12(1)\n\t" \ + /* arg9 */ \ + "lwz 3,36(11)\n\t" \ + "stw 3,8(1)\n\t" \ + /* args1-8 */ \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 9,28(11)\n\t" \ + "lwz 10,32(11)\n\t" /* arg8->r10 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[13]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + _argvec[9] = (unsigned long)arg9; \ + _argvec[10] = (unsigned long)arg10; \ + _argvec[11] = (unsigned long)arg11; \ + _argvec[12] = (unsigned long)arg12; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "addi 1,1,-32\n\t" \ + /* arg12 */ \ + "lwz 3,48(11)\n\t" \ + "stw 3,20(1)\n\t" \ + /* arg11 */ \ + "lwz 3,44(11)\n\t" \ + "stw 3,16(1)\n\t" \ + /* arg10 */ \ + "lwz 3,40(11)\n\t" \ + "stw 3,12(1)\n\t" \ + /* arg9 */ \ + "lwz 3,36(11)\n\t" \ + "stw 3,8(1)\n\t" \ + /* args1-8 */ \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 9,28(11)\n\t" \ + "lwz 10,32(11)\n\t" /* arg8->r10 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + VALGRIND_RESTORE_STACK \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_ppc32_linux */ + +/* ------------------------ ppc64-linux ------------------------ */ + +#if defined(PLAT_ppc64be_linux) + +/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS \ + "lr", "ctr", "xer", \ + "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ + "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ + "r11", "r12", "r13" + +/* Macros to save and align the stack before making a function + call and restore it afterwards as gcc may not keep the stack + pointer aligned if it doesn't realise calls are being made + to other functions. */ + +#define VALGRIND_ALIGN_STACK \ + "mr 28,1\n\t" \ + "rldicr 1,1,0,59\n\t" +#define VALGRIND_RESTORE_STACK \ + "mr 1,28\n\t" + +/* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned + long) == 8. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+0]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+1]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+2]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+3]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+4]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+5]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+6]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+7]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+8]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 10, 64(11)\n\t" /* arg8->r10 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+9]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "addi 1,1,-128\n\t" /* expand stack frame */ \ + /* arg9 */ \ + "ld 3,72(11)\n\t" \ + "std 3,112(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 10, 64(11)\n\t" /* arg8->r10 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+10]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "addi 1,1,-128\n\t" /* expand stack frame */ \ + /* arg10 */ \ + "ld 3,80(11)\n\t" \ + "std 3,120(1)\n\t" \ + /* arg9 */ \ + "ld 3,72(11)\n\t" \ + "std 3,112(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 10, 64(11)\n\t" /* arg8->r10 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+11]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + _argvec[2+11] = (unsigned long)arg11; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "addi 1,1,-144\n\t" /* expand stack frame */ \ + /* arg11 */ \ + "ld 3,88(11)\n\t" \ + "std 3,128(1)\n\t" \ + /* arg10 */ \ + "ld 3,80(11)\n\t" \ + "std 3,120(1)\n\t" \ + /* arg9 */ \ + "ld 3,72(11)\n\t" \ + "std 3,112(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 10, 64(11)\n\t" /* arg8->r10 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+12]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + _argvec[2+11] = (unsigned long)arg11; \ + _argvec[2+12] = (unsigned long)arg12; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "addi 1,1,-144\n\t" /* expand stack frame */ \ + /* arg12 */ \ + "ld 3,96(11)\n\t" \ + "std 3,136(1)\n\t" \ + /* arg11 */ \ + "ld 3,88(11)\n\t" \ + "std 3,128(1)\n\t" \ + /* arg10 */ \ + "ld 3,80(11)\n\t" \ + "std 3,120(1)\n\t" \ + /* arg9 */ \ + "ld 3,72(11)\n\t" \ + "std 3,112(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 10, 64(11)\n\t" /* arg8->r10 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_ppc64be_linux */ + +/* ------------------------- ppc64le-linux ----------------------- */ +#if defined(PLAT_ppc64le_linux) + +/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS \ + "lr", "ctr", "xer", \ + "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ + "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ + "r11", "r12", "r13" + +/* Macros to save and align the stack before making a function + call and restore it afterwards as gcc may not keep the stack + pointer aligned if it doesn't realise calls are being made + to other functions. */ + +#define VALGRIND_ALIGN_STACK \ + "mr 28,1\n\t" \ + "rldicr 1,1,0,59\n\t" +#define VALGRIND_RESTORE_STACK \ + "mr 1,28\n\t" + +/* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned + long) == 8. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+0]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+1]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+2]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+3]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 5, 24(12)\n\t" /* arg3->r5 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+4]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 5, 24(12)\n\t" /* arg3->r5 */ \ + "ld 6, 32(12)\n\t" /* arg4->r6 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+5]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 5, 24(12)\n\t" /* arg3->r5 */ \ + "ld 6, 32(12)\n\t" /* arg4->r6 */ \ + "ld 7, 40(12)\n\t" /* arg5->r7 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+6]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 5, 24(12)\n\t" /* arg3->r5 */ \ + "ld 6, 32(12)\n\t" /* arg4->r6 */ \ + "ld 7, 40(12)\n\t" /* arg5->r7 */ \ + "ld 8, 48(12)\n\t" /* arg6->r8 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+7]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 5, 24(12)\n\t" /* arg3->r5 */ \ + "ld 6, 32(12)\n\t" /* arg4->r6 */ \ + "ld 7, 40(12)\n\t" /* arg5->r7 */ \ + "ld 8, 48(12)\n\t" /* arg6->r8 */ \ + "ld 9, 56(12)\n\t" /* arg7->r9 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+8]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 5, 24(12)\n\t" /* arg3->r5 */ \ + "ld 6, 32(12)\n\t" /* arg4->r6 */ \ + "ld 7, 40(12)\n\t" /* arg5->r7 */ \ + "ld 8, 48(12)\n\t" /* arg6->r8 */ \ + "ld 9, 56(12)\n\t" /* arg7->r9 */ \ + "ld 10, 64(12)\n\t" /* arg8->r10 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+9]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "addi 1,1,-128\n\t" /* expand stack frame */ \ + /* arg9 */ \ + "ld 3,72(12)\n\t" \ + "std 3,96(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 5, 24(12)\n\t" /* arg3->r5 */ \ + "ld 6, 32(12)\n\t" /* arg4->r6 */ \ + "ld 7, 40(12)\n\t" /* arg5->r7 */ \ + "ld 8, 48(12)\n\t" /* arg6->r8 */ \ + "ld 9, 56(12)\n\t" /* arg7->r9 */ \ + "ld 10, 64(12)\n\t" /* arg8->r10 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+10]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "addi 1,1,-128\n\t" /* expand stack frame */ \ + /* arg10 */ \ + "ld 3,80(12)\n\t" \ + "std 3,104(1)\n\t" \ + /* arg9 */ \ + "ld 3,72(12)\n\t" \ + "std 3,96(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 5, 24(12)\n\t" /* arg3->r5 */ \ + "ld 6, 32(12)\n\t" /* arg4->r6 */ \ + "ld 7, 40(12)\n\t" /* arg5->r7 */ \ + "ld 8, 48(12)\n\t" /* arg6->r8 */ \ + "ld 9, 56(12)\n\t" /* arg7->r9 */ \ + "ld 10, 64(12)\n\t" /* arg8->r10 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+11]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + _argvec[2+11] = (unsigned long)arg11; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "addi 1,1,-144\n\t" /* expand stack frame */ \ + /* arg11 */ \ + "ld 3,88(12)\n\t" \ + "std 3,112(1)\n\t" \ + /* arg10 */ \ + "ld 3,80(12)\n\t" \ + "std 3,104(1)\n\t" \ + /* arg9 */ \ + "ld 3,72(12)\n\t" \ + "std 3,96(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 5, 24(12)\n\t" /* arg3->r5 */ \ + "ld 6, 32(12)\n\t" /* arg4->r6 */ \ + "ld 7, 40(12)\n\t" /* arg5->r7 */ \ + "ld 8, 48(12)\n\t" /* arg6->r8 */ \ + "ld 9, 56(12)\n\t" /* arg7->r9 */ \ + "ld 10, 64(12)\n\t" /* arg8->r10 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+12]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + _argvec[2+11] = (unsigned long)arg11; \ + _argvec[2+12] = (unsigned long)arg12; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "mr 12,%1\n\t" \ + "std 2,-16(12)\n\t" /* save tocptr */ \ + "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ + "addi 1,1,-144\n\t" /* expand stack frame */ \ + /* arg12 */ \ + "ld 3,96(12)\n\t" \ + "std 3,120(1)\n\t" \ + /* arg11 */ \ + "ld 3,88(12)\n\t" \ + "std 3,112(1)\n\t" \ + /* arg10 */ \ + "ld 3,80(12)\n\t" \ + "std 3,104(1)\n\t" \ + /* arg9 */ \ + "ld 3,72(12)\n\t" \ + "std 3,96(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(12)\n\t" /* arg1->r3 */ \ + "ld 4, 16(12)\n\t" /* arg2->r4 */ \ + "ld 5, 24(12)\n\t" /* arg3->r5 */ \ + "ld 6, 32(12)\n\t" /* arg4->r6 */ \ + "ld 7, 40(12)\n\t" /* arg5->r7 */ \ + "ld 8, 48(12)\n\t" /* arg6->r8 */ \ + "ld 9, 56(12)\n\t" /* arg7->r9 */ \ + "ld 10, 64(12)\n\t" /* arg8->r10 */ \ + "ld 12, 0(12)\n\t" /* target->r12 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ + "mr 12,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(12)\n\t" /* restore tocptr */ \ + VALGRIND_RESTORE_STACK \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_ppc64le_linux */ + +/* ------------------------- arm-linux ------------------------- */ + +#if defined(PLAT_arm_linux) + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS "r0", "r1", "r2", "r3","r4", "r12", "r14" + +/* Macros to save and align the stack before making a function + call and restore it afterwards as gcc may not keep the stack + pointer aligned if it doesn't realise calls are being made + to other functions. */ + +/* This is a bit tricky. We store the original stack pointer in r10 + as it is callee-saves. gcc doesn't allow the use of r11 for some + reason. Also, we can't directly "bic" the stack pointer in thumb + mode since r13 isn't an allowed register number in that context. + So use r4 as a temporary, since that is about to get trashed + anyway, just after each use of this macro. Side effect is we need + to be very careful about any future changes, since + VALGRIND_ALIGN_STACK simply assumes r4 is usable. */ +#define VALGRIND_ALIGN_STACK \ + "mov r10, sp\n\t" \ + "mov r4, sp\n\t" \ + "bic r4, r4, #7\n\t" \ + "mov sp, r4\n\t" +#define VALGRIND_RESTORE_STACK \ + "mov sp, r10\n\t" + +/* These CALL_FN_ macros assume that on arm-linux, sizeof(unsigned + long) == 4. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[1]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[2]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[4]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[5]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[6]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "sub sp, sp, #4 \n\t" \ + "ldr r0, [%1, #20] \n\t" \ + "push {r0} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[7]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "push {r0, r1} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[8]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "sub sp, sp, #4 \n\t" \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "ldr r2, [%1, #28] \n\t" \ + "push {r0, r1, r2} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[9]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "ldr r2, [%1, #28] \n\t" \ + "ldr r3, [%1, #32] \n\t" \ + "push {r0, r1, r2, r3} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[10]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "sub sp, sp, #4 \n\t" \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "ldr r2, [%1, #28] \n\t" \ + "ldr r3, [%1, #32] \n\t" \ + "ldr r4, [%1, #36] \n\t" \ + "push {r0, r1, r2, r3, r4} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[11]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr r0, [%1, #40] \n\t" \ + "push {r0} \n\t" \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "ldr r2, [%1, #28] \n\t" \ + "ldr r3, [%1, #32] \n\t" \ + "ldr r4, [%1, #36] \n\t" \ + "push {r0, r1, r2, r3, r4} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[12]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "sub sp, sp, #4 \n\t" \ + "ldr r0, [%1, #40] \n\t" \ + "ldr r1, [%1, #44] \n\t" \ + "push {r0, r1} \n\t" \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "ldr r2, [%1, #28] \n\t" \ + "ldr r3, [%1, #32] \n\t" \ + "ldr r4, [%1, #36] \n\t" \ + "push {r0, r1, r2, r3, r4} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[13]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + _argvec[12] = (unsigned long)(arg12); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr r0, [%1, #40] \n\t" \ + "ldr r1, [%1, #44] \n\t" \ + "ldr r2, [%1, #48] \n\t" \ + "push {r0, r1, r2} \n\t" \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "ldr r2, [%1, #28] \n\t" \ + "ldr r3, [%1, #32] \n\t" \ + "ldr r4, [%1, #36] \n\t" \ + "push {r0, r1, r2, r3, r4} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + VALGRIND_RESTORE_STACK \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_arm_linux */ + +/* ------------------------ arm64-linux ------------------------ */ + +#if defined(PLAT_arm64_linux) + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS \ + "x0", "x1", "x2", "x3","x4", "x5", "x6", "x7", "x8", "x9", \ + "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", \ + "x18", "x19", "x20", "x30", \ + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", \ + "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", \ + "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", \ + "v26", "v27", "v28", "v29", "v30", "v31" + +/* x21 is callee-saved, so we can use it to save and restore SP around + the hidden call. */ +#define VALGRIND_ALIGN_STACK \ + "mov x21, sp\n\t" \ + "bic sp, x21, #15\n\t" +#define VALGRIND_RESTORE_STACK \ + "mov sp, x21\n\t" + +/* These CALL_FN_ macros assume that on arm64-linux, + sizeof(unsigned long) == 8. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[1]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[2]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[4]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x2, [%1, #24] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[5]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x2, [%1, #24] \n\t" \ + "ldr x3, [%1, #32] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[6]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x2, [%1, #24] \n\t" \ + "ldr x3, [%1, #32] \n\t" \ + "ldr x4, [%1, #40] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[7]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x2, [%1, #24] \n\t" \ + "ldr x3, [%1, #32] \n\t" \ + "ldr x4, [%1, #40] \n\t" \ + "ldr x5, [%1, #48] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[8]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x2, [%1, #24] \n\t" \ + "ldr x3, [%1, #32] \n\t" \ + "ldr x4, [%1, #40] \n\t" \ + "ldr x5, [%1, #48] \n\t" \ + "ldr x6, [%1, #56] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[9]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x2, [%1, #24] \n\t" \ + "ldr x3, [%1, #32] \n\t" \ + "ldr x4, [%1, #40] \n\t" \ + "ldr x5, [%1, #48] \n\t" \ + "ldr x6, [%1, #56] \n\t" \ + "ldr x7, [%1, #64] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[10]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "sub sp, sp, #0x20 \n\t" \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x2, [%1, #24] \n\t" \ + "ldr x3, [%1, #32] \n\t" \ + "ldr x4, [%1, #40] \n\t" \ + "ldr x5, [%1, #48] \n\t" \ + "ldr x6, [%1, #56] \n\t" \ + "ldr x7, [%1, #64] \n\t" \ + "ldr x8, [%1, #72] \n\t" \ + "str x8, [sp, #0] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[11]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "sub sp, sp, #0x20 \n\t" \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x2, [%1, #24] \n\t" \ + "ldr x3, [%1, #32] \n\t" \ + "ldr x4, [%1, #40] \n\t" \ + "ldr x5, [%1, #48] \n\t" \ + "ldr x6, [%1, #56] \n\t" \ + "ldr x7, [%1, #64] \n\t" \ + "ldr x8, [%1, #72] \n\t" \ + "str x8, [sp, #0] \n\t" \ + "ldr x8, [%1, #80] \n\t" \ + "str x8, [sp, #8] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[12]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "sub sp, sp, #0x30 \n\t" \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x2, [%1, #24] \n\t" \ + "ldr x3, [%1, #32] \n\t" \ + "ldr x4, [%1, #40] \n\t" \ + "ldr x5, [%1, #48] \n\t" \ + "ldr x6, [%1, #56] \n\t" \ + "ldr x7, [%1, #64] \n\t" \ + "ldr x8, [%1, #72] \n\t" \ + "str x8, [sp, #0] \n\t" \ + "ldr x8, [%1, #80] \n\t" \ + "str x8, [sp, #8] \n\t" \ + "ldr x8, [%1, #88] \n\t" \ + "str x8, [sp, #16] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11, \ + arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[13]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + _argvec[12] = (unsigned long)(arg12); \ + __asm__ volatile( \ + VALGRIND_ALIGN_STACK \ + "sub sp, sp, #0x30 \n\t" \ + "ldr x0, [%1, #8] \n\t" \ + "ldr x1, [%1, #16] \n\t" \ + "ldr x2, [%1, #24] \n\t" \ + "ldr x3, [%1, #32] \n\t" \ + "ldr x4, [%1, #40] \n\t" \ + "ldr x5, [%1, #48] \n\t" \ + "ldr x6, [%1, #56] \n\t" \ + "ldr x7, [%1, #64] \n\t" \ + "ldr x8, [%1, #72] \n\t" \ + "str x8, [sp, #0] \n\t" \ + "ldr x8, [%1, #80] \n\t" \ + "str x8, [sp, #8] \n\t" \ + "ldr x8, [%1, #88] \n\t" \ + "str x8, [sp, #16] \n\t" \ + "ldr x8, [%1, #96] \n\t" \ + "str x8, [sp, #24] \n\t" \ + "ldr x8, [%1] \n\t" /* target->x8 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ + VALGRIND_RESTORE_STACK \ + "mov %0, x0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_arm64_linux */ + +/* ------------------------- s390x-linux ------------------------- */ + +#if defined(PLAT_s390x_linux) + +/* Similar workaround as amd64 (see above), but we use r11 as frame + pointer and save the old r11 in r7. r11 might be used for + argvec, therefore we copy argvec in r1 since r1 is clobbered + after the call anyway. */ +#if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM) +# define __FRAME_POINTER \ + ,"d"(__builtin_dwarf_cfa()) +# define VALGRIND_CFI_PROLOGUE \ + ".cfi_remember_state\n\t" \ + "lgr 1,%1\n\t" /* copy the argvec pointer in r1 */ \ + "lgr 7,11\n\t" \ + "lgr 11,%2\n\t" \ + ".cfi_def_cfa r11, 0\n\t" +# define VALGRIND_CFI_EPILOGUE \ + "lgr 11, 7\n\t" \ + ".cfi_restore_state\n\t" +#else +# define __FRAME_POINTER +# define VALGRIND_CFI_PROLOGUE \ + "lgr 1,%1\n\t" +# define VALGRIND_CFI_EPILOGUE +#endif + +/* Nb: On s390 the stack pointer is properly aligned *at all times* + according to the s390 GCC maintainer. (The ABI specification is not + precise in this regard.) Therefore, VALGRIND_ALIGN_STACK and + VALGRIND_RESTORE_STACK are not defined here. */ + +/* These regs are trashed by the hidden call. Note that we overwrite + r14 in s390_irgen_noredir (VEX/priv/guest_s390_irgen.c) to give the + function a proper return address. All others are ABI defined call + clobbers. */ +#if defined(__VX__) || defined(__S390_VX__) +#define __CALLER_SAVED_REGS "0", "1", "2", "3", "4", "5", "14", \ + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", \ + "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", \ + "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", \ + "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" +#else +#define __CALLER_SAVED_REGS "0", "1", "2", "3", "4", "5", "14", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7" +#endif + +/* Nb: Although r11 is modified in the asm snippets below (inside + VALGRIND_CFI_PROLOGUE) it is not listed in the clobber section, for + two reasons: + (1) r11 is restored in VALGRIND_CFI_EPILOGUE, so effectively it is not + modified + (2) GCC will complain that r11 cannot appear inside a clobber section, + when compiled with -O -fno-omit-frame-pointer + */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[1]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-160\n\t" \ + "lg 1, 0(1)\n\t" /* target->r1 */ \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,160\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "d" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +/* The call abi has the arguments in r2-r6 and stack */ +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[2]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-160\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,160\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1, arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-160\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,160\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1, arg2, arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[4]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-160\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 4,24(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,160\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1, arg2, arg3, arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[5]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-160\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 4,24(1)\n\t" \ + "lg 5,32(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,160\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1, arg2, arg3, arg4, arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[6]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-160\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 4,24(1)\n\t" \ + "lg 5,32(1)\n\t" \ + "lg 6,40(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,160\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ + arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[7]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-168\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 4,24(1)\n\t" \ + "lg 5,32(1)\n\t" \ + "lg 6,40(1)\n\t" \ + "mvc 160(8,15), 48(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,168\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ + arg6, arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[8]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-176\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 4,24(1)\n\t" \ + "lg 5,32(1)\n\t" \ + "lg 6,40(1)\n\t" \ + "mvc 160(8,15), 48(1)\n\t" \ + "mvc 168(8,15), 56(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,176\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ + arg6, arg7 ,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[9]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-184\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 4,24(1)\n\t" \ + "lg 5,32(1)\n\t" \ + "lg 6,40(1)\n\t" \ + "mvc 160(8,15), 48(1)\n\t" \ + "mvc 168(8,15), 56(1)\n\t" \ + "mvc 176(8,15), 64(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,184\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ + arg6, arg7 ,arg8, arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[10]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + _argvec[9] = (unsigned long)arg9; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-192\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 4,24(1)\n\t" \ + "lg 5,32(1)\n\t" \ + "lg 6,40(1)\n\t" \ + "mvc 160(8,15), 48(1)\n\t" \ + "mvc 168(8,15), 56(1)\n\t" \ + "mvc 176(8,15), 64(1)\n\t" \ + "mvc 184(8,15), 72(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,192\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ + arg6, arg7 ,arg8, arg9, arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[11]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + _argvec[9] = (unsigned long)arg9; \ + _argvec[10] = (unsigned long)arg10; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-200\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 4,24(1)\n\t" \ + "lg 5,32(1)\n\t" \ + "lg 6,40(1)\n\t" \ + "mvc 160(8,15), 48(1)\n\t" \ + "mvc 168(8,15), 56(1)\n\t" \ + "mvc 176(8,15), 64(1)\n\t" \ + "mvc 184(8,15), 72(1)\n\t" \ + "mvc 192(8,15), 80(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,200\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ + arg6, arg7 ,arg8, arg9, arg10, arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[12]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + _argvec[9] = (unsigned long)arg9; \ + _argvec[10] = (unsigned long)arg10; \ + _argvec[11] = (unsigned long)arg11; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-208\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 4,24(1)\n\t" \ + "lg 5,32(1)\n\t" \ + "lg 6,40(1)\n\t" \ + "mvc 160(8,15), 48(1)\n\t" \ + "mvc 168(8,15), 56(1)\n\t" \ + "mvc 176(8,15), 64(1)\n\t" \ + "mvc 184(8,15), 72(1)\n\t" \ + "mvc 192(8,15), 80(1)\n\t" \ + "mvc 200(8,15), 88(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,208\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ + arg6, arg7 ,arg8, arg9, arg10, arg11, arg12)\ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[13]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + _argvec[9] = (unsigned long)arg9; \ + _argvec[10] = (unsigned long)arg10; \ + _argvec[11] = (unsigned long)arg11; \ + _argvec[12] = (unsigned long)arg12; \ + __asm__ volatile( \ + VALGRIND_CFI_PROLOGUE \ + "aghi 15,-216\n\t" \ + "lg 2, 8(1)\n\t" \ + "lg 3,16(1)\n\t" \ + "lg 4,24(1)\n\t" \ + "lg 5,32(1)\n\t" \ + "lg 6,40(1)\n\t" \ + "mvc 160(8,15), 48(1)\n\t" \ + "mvc 168(8,15), 56(1)\n\t" \ + "mvc 176(8,15), 64(1)\n\t" \ + "mvc 184(8,15), 72(1)\n\t" \ + "mvc 192(8,15), 80(1)\n\t" \ + "mvc 200(8,15), 88(1)\n\t" \ + "mvc 208(8,15), 96(1)\n\t" \ + "lg 1, 0(1)\n\t" \ + VALGRIND_CALL_NOREDIR_R1 \ + "aghi 15,216\n\t" \ + VALGRIND_CFI_EPILOGUE \ + "lgr %0, 2\n\t" \ + : /*out*/ "=d" (_res) \ + : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + + +#endif /* PLAT_s390x_linux */ + +/* ------------------------- mips32-linux ----------------------- */ + +#if defined(PLAT_mips32_linux) + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS "$2", "$3", "$4", "$5", "$6", \ +"$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", \ +"$25", "$31" + +/* These CALL_FN_ macros assume that on mips-linux, sizeof(unsigned + long) == 4. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[1]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "subu $29, $29, 16 \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 16\n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[2]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "subu $29, $29, 16 \n\t" \ + "lw $4, 4(%1) \n\t" /* arg1*/ \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 16 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "subu $29, $29, 16 \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 16 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[4]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "subu $29, $29, 16 \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $6, 12(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 16 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[5]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "subu $29, $29, 16 \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $6, 12(%1) \n\t" \ + "lw $7, 16(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 16 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[6]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "lw $4, 20(%1) \n\t" \ + "subu $29, $29, 24\n\t" \ + "sw $4, 16($29) \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $6, 12(%1) \n\t" \ + "lw $7, 16(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 24 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[7]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "lw $4, 20(%1) \n\t" \ + "subu $29, $29, 32\n\t" \ + "sw $4, 16($29) \n\t" \ + "lw $4, 24(%1) \n\t" \ + "nop\n\t" \ + "sw $4, 20($29) \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $6, 12(%1) \n\t" \ + "lw $7, 16(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 32 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[8]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "lw $4, 20(%1) \n\t" \ + "subu $29, $29, 32\n\t" \ + "sw $4, 16($29) \n\t" \ + "lw $4, 24(%1) \n\t" \ + "sw $4, 20($29) \n\t" \ + "lw $4, 28(%1) \n\t" \ + "sw $4, 24($29) \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $6, 12(%1) \n\t" \ + "lw $7, 16(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 32 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[9]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "lw $4, 20(%1) \n\t" \ + "subu $29, $29, 40\n\t" \ + "sw $4, 16($29) \n\t" \ + "lw $4, 24(%1) \n\t" \ + "sw $4, 20($29) \n\t" \ + "lw $4, 28(%1) \n\t" \ + "sw $4, 24($29) \n\t" \ + "lw $4, 32(%1) \n\t" \ + "sw $4, 28($29) \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $6, 12(%1) \n\t" \ + "lw $7, 16(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 40 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[10]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "lw $4, 20(%1) \n\t" \ + "subu $29, $29, 40\n\t" \ + "sw $4, 16($29) \n\t" \ + "lw $4, 24(%1) \n\t" \ + "sw $4, 20($29) \n\t" \ + "lw $4, 28(%1) \n\t" \ + "sw $4, 24($29) \n\t" \ + "lw $4, 32(%1) \n\t" \ + "sw $4, 28($29) \n\t" \ + "lw $4, 36(%1) \n\t" \ + "sw $4, 32($29) \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $6, 12(%1) \n\t" \ + "lw $7, 16(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 40 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[11]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "lw $4, 20(%1) \n\t" \ + "subu $29, $29, 48\n\t" \ + "sw $4, 16($29) \n\t" \ + "lw $4, 24(%1) \n\t" \ + "sw $4, 20($29) \n\t" \ + "lw $4, 28(%1) \n\t" \ + "sw $4, 24($29) \n\t" \ + "lw $4, 32(%1) \n\t" \ + "sw $4, 28($29) \n\t" \ + "lw $4, 36(%1) \n\t" \ + "sw $4, 32($29) \n\t" \ + "lw $4, 40(%1) \n\t" \ + "sw $4, 36($29) \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $6, 12(%1) \n\t" \ + "lw $7, 16(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 48 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[12]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "lw $4, 20(%1) \n\t" \ + "subu $29, $29, 48\n\t" \ + "sw $4, 16($29) \n\t" \ + "lw $4, 24(%1) \n\t" \ + "sw $4, 20($29) \n\t" \ + "lw $4, 28(%1) \n\t" \ + "sw $4, 24($29) \n\t" \ + "lw $4, 32(%1) \n\t" \ + "sw $4, 28($29) \n\t" \ + "lw $4, 36(%1) \n\t" \ + "sw $4, 32($29) \n\t" \ + "lw $4, 40(%1) \n\t" \ + "sw $4, 36($29) \n\t" \ + "lw $4, 44(%1) \n\t" \ + "sw $4, 40($29) \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $6, 12(%1) \n\t" \ + "lw $7, 16(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 48 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[13]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + _argvec[12] = (unsigned long)(arg12); \ + __asm__ volatile( \ + "subu $29, $29, 8 \n\t" \ + "sw $28, 0($29) \n\t" \ + "sw $31, 4($29) \n\t" \ + "lw $4, 20(%1) \n\t" \ + "subu $29, $29, 56\n\t" \ + "sw $4, 16($29) \n\t" \ + "lw $4, 24(%1) \n\t" \ + "sw $4, 20($29) \n\t" \ + "lw $4, 28(%1) \n\t" \ + "sw $4, 24($29) \n\t" \ + "lw $4, 32(%1) \n\t" \ + "sw $4, 28($29) \n\t" \ + "lw $4, 36(%1) \n\t" \ + "sw $4, 32($29) \n\t" \ + "lw $4, 40(%1) \n\t" \ + "sw $4, 36($29) \n\t" \ + "lw $4, 44(%1) \n\t" \ + "sw $4, 40($29) \n\t" \ + "lw $4, 48(%1) \n\t" \ + "sw $4, 44($29) \n\t" \ + "lw $4, 4(%1) \n\t" \ + "lw $5, 8(%1) \n\t" \ + "lw $6, 12(%1) \n\t" \ + "lw $7, 16(%1) \n\t" \ + "lw $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "addu $29, $29, 56 \n\t" \ + "lw $28, 0($29) \n\t" \ + "lw $31, 4($29) \n\t" \ + "addu $29, $29, 8 \n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_mips32_linux */ + +/* ------------------------- nanomips-linux -------------------- */ + +#if defined(PLAT_nanomips_linux) + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS "$t4", "$t5", "$a0", "$a1", "$a2", \ +"$a3", "$a4", "$a5", "$a6", "$a7", "$t0", "$t1", "$t2", "$t3", \ +"$t8","$t9", "$at" + +/* These CALL_FN_ macros assume that on mips-linux, sizeof(unsigned + long) == 4. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[1]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + "lw $t9, 0(%1)\n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[2]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + __asm__ volatile( \ + "lw $t9, 0(%1)\n\t" \ + "lw $a0, 4(%1)\n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + __asm__ volatile( \ + "lw $t9, 0(%1)\n\t" \ + "lw $a0, 4(%1)\n\t" \ + "lw $a1, 8(%1)\n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[4]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + __asm__ volatile( \ + "lw $t9, 0(%1)\n\t" \ + "lw $a0, 4(%1)\n\t" \ + "lw $a1, 8(%1)\n\t" \ + "lw $a2,12(%1)\n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[5]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + __asm__ volatile( \ + "lw $t9, 0(%1)\n\t" \ + "lw $a0, 4(%1)\n\t" \ + "lw $a1, 8(%1)\n\t" \ + "lw $a2,12(%1)\n\t" \ + "lw $a3,16(%1)\n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[6]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + __asm__ volatile( \ + "lw $t9, 0(%1)\n\t" \ + "lw $a0, 4(%1)\n\t" \ + "lw $a1, 8(%1)\n\t" \ + "lw $a2,12(%1)\n\t" \ + "lw $a3,16(%1)\n\t" \ + "lw $a4,20(%1)\n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[7]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + __asm__ volatile( \ + "lw $t9, 0(%1)\n\t" \ + "lw $a0, 4(%1)\n\t" \ + "lw $a1, 8(%1)\n\t" \ + "lw $a2,12(%1)\n\t" \ + "lw $a3,16(%1)\n\t" \ + "lw $a4,20(%1)\n\t" \ + "lw $a5,24(%1)\n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[8]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + __asm__ volatile( \ + "lw $t9, 0(%1)\n\t" \ + "lw $a0, 4(%1)\n\t" \ + "lw $a1, 8(%1)\n\t" \ + "lw $a2,12(%1)\n\t" \ + "lw $a3,16(%1)\n\t" \ + "lw $a4,20(%1)\n\t" \ + "lw $a5,24(%1)\n\t" \ + "lw $a6,28(%1)\n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[9]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + __asm__ volatile( \ + "lw $t9, 0(%1)\n\t" \ + "lw $a0, 4(%1)\n\t" \ + "lw $a1, 8(%1)\n\t" \ + "lw $a2,12(%1)\n\t" \ + "lw $a3,16(%1)\n\t" \ + "lw $a4,20(%1)\n\t" \ + "lw $a5,24(%1)\n\t" \ + "lw $a6,28(%1)\n\t" \ + "lw $a7,32(%1)\n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[10]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + __asm__ volatile( \ + "addiu $sp, $sp, -16 \n\t" \ + "lw $t9,36(%1) \n\t" \ + "sw $t9, 0($sp) \n\t" \ + "lw $t9, 0(%1) \n\t" \ + "lw $a0, 4(%1) \n\t" \ + "lw $a1, 8(%1) \n\t" \ + "lw $a2,12(%1) \n\t" \ + "lw $a3,16(%1) \n\t" \ + "lw $a4,20(%1) \n\t" \ + "lw $a5,24(%1) \n\t" \ + "lw $a6,28(%1) \n\t" \ + "lw $a7,32(%1) \n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0 \n\t" \ + "addiu $sp, $sp, 16 \n\t" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[11]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + __asm__ volatile( \ + "addiu $sp, $sp, -16 \n\t" \ + "lw $t9,36(%1) \n\t" \ + "sw $t9, 0($sp) \n\t" \ + "lw $t9,40(%1) \n\t" \ + "sw $t9, 4($sp) \n\t" \ + "lw $t9, 0(%1) \n\t" \ + "lw $a0, 4(%1) \n\t" \ + "lw $a1, 8(%1) \n\t" \ + "lw $a2,12(%1) \n\t" \ + "lw $a3,16(%1) \n\t" \ + "lw $a4,20(%1) \n\t" \ + "lw $a5,24(%1) \n\t" \ + "lw $a6,28(%1) \n\t" \ + "lw $a7,32(%1) \n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0 \n\t" \ + "addiu $sp, $sp, 16 \n\t" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[12]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + __asm__ volatile( \ + "addiu $sp, $sp, -16 \n\t" \ + "lw $t9,36(%1) \n\t" \ + "sw $t9, 0($sp) \n\t" \ + "lw $t9,40(%1) \n\t" \ + "sw $t9, 4($sp) \n\t" \ + "lw $t9,44(%1) \n\t" \ + "sw $t9, 8($sp) \n\t" \ + "lw $t9, 0(%1) \n\t" \ + "lw $a0, 4(%1) \n\t" \ + "lw $a1, 8(%1) \n\t" \ + "lw $a2,12(%1) \n\t" \ + "lw $a3,16(%1) \n\t" \ + "lw $a4,20(%1) \n\t" \ + "lw $a5,24(%1) \n\t" \ + "lw $a6,28(%1) \n\t" \ + "lw $a7,32(%1) \n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0 \n\t" \ + "addiu $sp, $sp, 16 \n\t" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[13]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + _argvec[12] = (unsigned long)(arg12); \ + __asm__ volatile( \ + "addiu $sp, $sp, -16 \n\t" \ + "lw $t9,36(%1) \n\t" \ + "sw $t9, 0($sp) \n\t" \ + "lw $t9,40(%1) \n\t" \ + "sw $t9, 4($sp) \n\t" \ + "lw $t9,44(%1) \n\t" \ + "sw $t9, 8($sp) \n\t" \ + "lw $t9,48(%1) \n\t" \ + "sw $t9,12($sp) \n\t" \ + "lw $t9, 0(%1) \n\t" \ + "lw $a0, 4(%1) \n\t" \ + "lw $a1, 8(%1) \n\t" \ + "lw $a2,12(%1) \n\t" \ + "lw $a3,16(%1) \n\t" \ + "lw $a4,20(%1) \n\t" \ + "lw $a5,24(%1) \n\t" \ + "lw $a6,28(%1) \n\t" \ + "lw $a7,32(%1) \n\t" \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $a0 \n\t" \ + "addiu $sp, $sp, 16 \n\t" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_nanomips_linux */ + +/* ------------------------- mips64-linux ------------------------- */ + +#if defined(PLAT_mips64_linux) + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS "$2", "$3", "$4", "$5", "$6", \ +"$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", \ +"$25", "$31" + +/* These CALL_FN_ macros assume that on mips64-linux, + sizeof(long long) == 8. */ + +#define MIPS64_LONG2REG_CAST(x) ((long long)(long)x) + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[1]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + __asm__ volatile( \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[2]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + __asm__ volatile( \ + "ld $4, 8(%1)\n\t" /* arg1*/ \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[3]; \ + volatile unsigned long long _res; \ + _argvec[0] = _orig.nraddr; \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + __asm__ volatile( \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[4]; \ + volatile unsigned long long _res; \ + _argvec[0] = _orig.nraddr; \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ + __asm__ volatile( \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $6, 24(%1)\n\t" \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[5]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ + _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ + __asm__ volatile( \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $6, 24(%1)\n\t" \ + "ld $7, 32(%1)\n\t" \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[6]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ + _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ + _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ + __asm__ volatile( \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $6, 24(%1)\n\t" \ + "ld $7, 32(%1)\n\t" \ + "ld $8, 40(%1)\n\t" \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[7]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ + _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ + _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ + _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ + __asm__ volatile( \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $6, 24(%1)\n\t" \ + "ld $7, 32(%1)\n\t" \ + "ld $8, 40(%1)\n\t" \ + "ld $9, 48(%1)\n\t" \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[8]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ + _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ + _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ + _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ + _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ + __asm__ volatile( \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $6, 24(%1)\n\t" \ + "ld $7, 32(%1)\n\t" \ + "ld $8, 40(%1)\n\t" \ + "ld $9, 48(%1)\n\t" \ + "ld $10, 56(%1)\n\t" \ + "ld $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[9]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ + _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ + _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ + _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ + _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ + _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ + __asm__ volatile( \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $6, 24(%1)\n\t" \ + "ld $7, 32(%1)\n\t" \ + "ld $8, 40(%1)\n\t" \ + "ld $9, 48(%1)\n\t" \ + "ld $10, 56(%1)\n\t" \ + "ld $11, 64(%1)\n\t" \ + "ld $25, 0(%1) \n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[10]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ + _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ + _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ + _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ + _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ + _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ + _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \ + __asm__ volatile( \ + "dsubu $29, $29, 8\n\t" \ + "ld $4, 72(%1)\n\t" \ + "sd $4, 0($29)\n\t" \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $6, 24(%1)\n\t" \ + "ld $7, 32(%1)\n\t" \ + "ld $8, 40(%1)\n\t" \ + "ld $9, 48(%1)\n\t" \ + "ld $10, 56(%1)\n\t" \ + "ld $11, 64(%1)\n\t" \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "daddu $29, $29, 8\n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[11]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ + _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ + _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ + _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ + _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ + _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ + _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \ + _argvec[10] = MIPS64_LONG2REG_CAST(arg10); \ + __asm__ volatile( \ + "dsubu $29, $29, 16\n\t" \ + "ld $4, 72(%1)\n\t" \ + "sd $4, 0($29)\n\t" \ + "ld $4, 80(%1)\n\t" \ + "sd $4, 8($29)\n\t" \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $6, 24(%1)\n\t" \ + "ld $7, 32(%1)\n\t" \ + "ld $8, 40(%1)\n\t" \ + "ld $9, 48(%1)\n\t" \ + "ld $10, 56(%1)\n\t" \ + "ld $11, 64(%1)\n\t" \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "daddu $29, $29, 16\n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[12]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ + _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ + _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ + _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ + _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ + _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ + _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \ + _argvec[10] = MIPS64_LONG2REG_CAST(arg10); \ + _argvec[11] = MIPS64_LONG2REG_CAST(arg11); \ + __asm__ volatile( \ + "dsubu $29, $29, 24\n\t" \ + "ld $4, 72(%1)\n\t" \ + "sd $4, 0($29)\n\t" \ + "ld $4, 80(%1)\n\t" \ + "sd $4, 8($29)\n\t" \ + "ld $4, 88(%1)\n\t" \ + "sd $4, 16($29)\n\t" \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $6, 24(%1)\n\t" \ + "ld $7, 32(%1)\n\t" \ + "ld $8, 40(%1)\n\t" \ + "ld $9, 48(%1)\n\t" \ + "ld $10, 56(%1)\n\t" \ + "ld $11, 64(%1)\n\t" \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "daddu $29, $29, 24\n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long long _argvec[13]; \ + volatile unsigned long long _res; \ + _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ + _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ + _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ + _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ + _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ + _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ + _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ + _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ + _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ + _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \ + _argvec[10] = MIPS64_LONG2REG_CAST(arg10); \ + _argvec[11] = MIPS64_LONG2REG_CAST(arg11); \ + _argvec[12] = MIPS64_LONG2REG_CAST(arg12); \ + __asm__ volatile( \ + "dsubu $29, $29, 32\n\t" \ + "ld $4, 72(%1)\n\t" \ + "sd $4, 0($29)\n\t" \ + "ld $4, 80(%1)\n\t" \ + "sd $4, 8($29)\n\t" \ + "ld $4, 88(%1)\n\t" \ + "sd $4, 16($29)\n\t" \ + "ld $4, 96(%1)\n\t" \ + "sd $4, 24($29)\n\t" \ + "ld $4, 8(%1)\n\t" \ + "ld $5, 16(%1)\n\t" \ + "ld $6, 24(%1)\n\t" \ + "ld $7, 32(%1)\n\t" \ + "ld $8, 40(%1)\n\t" \ + "ld $9, 48(%1)\n\t" \ + "ld $10, 56(%1)\n\t" \ + "ld $11, 64(%1)\n\t" \ + "ld $25, 0(%1)\n\t" /* target->t9 */ \ + VALGRIND_CALL_NOREDIR_T9 \ + "daddu $29, $29, 32\n\t" \ + "move %0, $2\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) (long)_res; \ + } while (0) + +#endif /* PLAT_mips64_linux */ + +/* ------------------------------------------------------------------ */ +/* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS. */ +/* */ +/* ------------------------------------------------------------------ */ + +/* Some request codes. There are many more of these, but most are not + exposed to end-user view. These are the public ones, all of the + form 0x1000 + small_number. + + Core ones are in the range 0x00000000--0x0000ffff. The non-public + ones start at 0x2000. +*/ + +/* These macros are used by tools -- they must be public, but don't + embed them into other programs. */ +#define VG_USERREQ_TOOL_BASE(a,b) \ + ((unsigned int)(((a)&0xff) << 24 | ((b)&0xff) << 16)) +#define VG_IS_TOOL_USERREQ(a, b, v) \ + (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000)) + +/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! + This enum comprises an ABI exported by Valgrind to programs + which use client requests. DO NOT CHANGE THE NUMERIC VALUES OF THESE + ENTRIES, NOR DELETE ANY -- add new ones at the end of the most + relevant group. */ +typedef + enum { VG_USERREQ__RUNNING_ON_VALGRIND = 0x1001, + VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002, + + /* These allow any function to be called from the simulated + CPU but run on the real CPU. Nb: the first arg passed to + the function is always the ThreadId of the running + thread! So CLIENT_CALL0 actually requires a 1 arg + function, etc. */ + VG_USERREQ__CLIENT_CALL0 = 0x1101, + VG_USERREQ__CLIENT_CALL1 = 0x1102, + VG_USERREQ__CLIENT_CALL2 = 0x1103, + VG_USERREQ__CLIENT_CALL3 = 0x1104, + + /* Can be useful in regression testing suites -- eg. can + send Valgrind's output to /dev/null and still count + errors. */ + VG_USERREQ__COUNT_ERRORS = 0x1201, + + /* Allows the client program and/or gdbserver to execute a monitor + command. */ + VG_USERREQ__GDB_MONITOR_COMMAND = 0x1202, + + /* Allows the client program to change a dynamic command line + option. */ + VG_USERREQ__CLO_CHANGE = 0x1203, + + /* These are useful and can be interpreted by any tool that + tracks malloc() et al, by using vg_replace_malloc.c. */ + VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301, + VG_USERREQ__RESIZEINPLACE_BLOCK = 0x130b, + VG_USERREQ__FREELIKE_BLOCK = 0x1302, + /* Memory pool support. */ + VG_USERREQ__CREATE_MEMPOOL = 0x1303, + VG_USERREQ__DESTROY_MEMPOOL = 0x1304, + VG_USERREQ__MEMPOOL_ALLOC = 0x1305, + VG_USERREQ__MEMPOOL_FREE = 0x1306, + VG_USERREQ__MEMPOOL_TRIM = 0x1307, + VG_USERREQ__MOVE_MEMPOOL = 0x1308, + VG_USERREQ__MEMPOOL_CHANGE = 0x1309, + VG_USERREQ__MEMPOOL_EXISTS = 0x130a, + + /* Allow printfs to valgrind log. */ + /* The first two pass the va_list argument by value, which + assumes it is the same size as or smaller than a UWord, + which generally isn't the case. Hence are deprecated. + The second two pass the vargs by reference and so are + immune to this problem. */ + /* both :: char* fmt, va_list vargs (DEPRECATED) */ + VG_USERREQ__PRINTF = 0x1401, + VG_USERREQ__PRINTF_BACKTRACE = 0x1402, + /* both :: char* fmt, va_list* vargs */ + VG_USERREQ__PRINTF_VALIST_BY_REF = 0x1403, + VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF = 0x1404, + + /* Stack support. */ + VG_USERREQ__STACK_REGISTER = 0x1501, + VG_USERREQ__STACK_DEREGISTER = 0x1502, + VG_USERREQ__STACK_CHANGE = 0x1503, + + /* Wine support */ + VG_USERREQ__LOAD_PDB_DEBUGINFO = 0x1601, + + /* Querying of debug info. */ + VG_USERREQ__MAP_IP_TO_SRCLOC = 0x1701, + + /* Disable/enable error reporting level. Takes a single + Word arg which is the delta to this thread's error + disablement indicator. Hence 1 disables or further + disables errors, and -1 moves back towards enablement. + Other values are not allowed. */ + VG_USERREQ__CHANGE_ERR_DISABLEMENT = 0x1801, + + /* Some requests used for Valgrind internal, such as + self-test or self-hosting. */ + /* Initialise IR injection */ + VG_USERREQ__VEX_INIT_FOR_IRI = 0x1901, + /* Used by Inner Valgrind to inform Outer Valgrind where to + find the list of inner guest threads */ + VG_USERREQ__INNER_THREADS = 0x1902 + } Vg_ClientRequest; + +#if !defined(__GNUC__) +# define __extension__ /* */ +#endif + + +/* Returns the number of Valgrinds this code is running under. That + is, 0 if running natively, 1 if running under Valgrind, 2 if + running under Valgrind which is running under another Valgrind, + etc. */ +#define RUNNING_ON_VALGRIND \ + (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* if not */, \ + VG_USERREQ__RUNNING_ON_VALGRIND, \ + 0, 0, 0, 0, 0) \ + + +/* Discard translation of code in the range [_qzz_addr .. _qzz_addr + + _qzz_len - 1]. Useful if you are debugging a JITter or some such, + since it provides a way to make sure valgrind will retranslate the + invalidated area. Returns no value. */ +#define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DISCARD_TRANSLATIONS, \ + _qzz_addr, _qzz_len, 0, 0, 0) + +#define VALGRIND_INNER_THREADS(_qzz_addr) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__INNER_THREADS, \ + _qzz_addr, 0, 0, 0, 0) + + +/* These requests are for getting Valgrind itself to print something. + Possibly with a backtrace. This is a really ugly hack. The return value + is the number of characters printed, excluding the "**** " part at the + start and the backtrace (if present). */ + +#if defined(__GNUC__) || defined(__INTEL_COMPILER) && !defined(_MSC_VER) +/* Modern GCC will optimize the static routine out if unused, + and unused attribute will shut down warnings about it. */ +static int VALGRIND_PRINTF(const char *format, ...) + __attribute__((format(__printf__, 1, 2), __unused__)); +#endif +static int +#if defined(_MSC_VER) +__inline +#endif +VALGRIND_PRINTF(const char *format, ...) +{ +#if defined(NVALGRIND) + (void)format; + return 0; +#else /* NVALGRIND */ +#if defined(_MSC_VER) || defined(__MINGW64__) + uintptr_t _qzz_res; +#else + unsigned long _qzz_res; +#endif + va_list vargs; + va_start(vargs, format); +#if defined(_MSC_VER) || defined(__MINGW64__) + _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, + VG_USERREQ__PRINTF_VALIST_BY_REF, + (uintptr_t)format, + (uintptr_t)&vargs, + 0, 0, 0); +#else + _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, + VG_USERREQ__PRINTF_VALIST_BY_REF, + (unsigned long)format, + (unsigned long)&vargs, + 0, 0, 0); +#endif + va_end(vargs); + return (int)_qzz_res; +#endif /* NVALGRIND */ +} + +#if defined(__GNUC__) || defined(__INTEL_COMPILER) && !defined(_MSC_VER) +static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...) + __attribute__((format(__printf__, 1, 2), __unused__)); +#endif +static int +#if defined(_MSC_VER) +__inline +#endif +VALGRIND_PRINTF_BACKTRACE(const char *format, ...) +{ +#if defined(NVALGRIND) + (void)format; + return 0; +#else /* NVALGRIND */ +#if defined(_MSC_VER) || defined(__MINGW64__) + uintptr_t _qzz_res; +#else + unsigned long _qzz_res; +#endif + va_list vargs; + va_start(vargs, format); +#if defined(_MSC_VER) || defined(__MINGW64__) + _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, + VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, + (uintptr_t)format, + (uintptr_t)&vargs, + 0, 0, 0); +#else + _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, + VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, + (unsigned long)format, + (unsigned long)&vargs, + 0, 0, 0); +#endif + va_end(vargs); + return (int)_qzz_res; +#endif /* NVALGRIND */ +} + + +/* These requests allow control to move from the simulated CPU to the + real CPU, calling an arbitrary function. + + Note that the current ThreadId is inserted as the first argument. + So this call: + + VALGRIND_NON_SIMD_CALL2(f, arg1, arg2) + + requires f to have this signature: + + Word f(Word tid, Word arg1, Word arg2) + + where "Word" is a word-sized type. + + Note that these client requests are not entirely reliable. For example, + if you call a function with them that subsequently calls printf(), + there's a high chance Valgrind will crash. Generally, your prospects of + these working are made higher if the called function does not refer to + any global variables, and does not refer to any libc or other functions + (printf et al). Any kind of entanglement with libc or dynamic linking is + likely to have a bad outcome, for tricky reasons which we've grappled + with a lot in the past. +*/ +#define VALGRIND_NON_SIMD_CALL0(_qyy_fn) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ + VG_USERREQ__CLIENT_CALL0, \ + _qyy_fn, \ + 0, 0, 0, 0) + +#define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ + VG_USERREQ__CLIENT_CALL1, \ + _qyy_fn, \ + _qyy_arg1, 0, 0, 0) + +#define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ + VG_USERREQ__CLIENT_CALL2, \ + _qyy_fn, \ + _qyy_arg1, _qyy_arg2, 0, 0) + +#define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ + VG_USERREQ__CLIENT_CALL3, \ + _qyy_fn, \ + _qyy_arg1, _qyy_arg2, \ + _qyy_arg3, 0) + + +/* Counts the number of errors that have been recorded by a tool. Nb: + the tool must record the errors with VG_(maybe_record_error)() or + VG_(unique_error)() for them to be counted. */ +#define VALGRIND_COUNT_ERRORS \ + (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR( \ + 0 /* default return */, \ + VG_USERREQ__COUNT_ERRORS, \ + 0, 0, 0, 0, 0) + +/* Several Valgrind tools (Memcheck, Massif, Helgrind, DRD) rely on knowing + when heap blocks are allocated in order to give accurate results. This + happens automatically for the standard allocator functions such as + malloc(), calloc(), realloc(), memalign(), new, new[], free(), delete, + delete[], etc. + + But if your program uses a custom allocator, this doesn't automatically + happen, and Valgrind will not do as well. For example, if you allocate + superblocks with mmap() and then allocates chunks of the superblocks, all + Valgrind's observations will be at the mmap() level and it won't know that + the chunks should be considered separate entities. In Memcheck's case, + that means you probably won't get heap block overrun detection (because + there won't be redzones marked as unaddressable) and you definitely won't + get any leak detection. + + The following client requests allow a custom allocator to be annotated so + that it can be handled accurately by Valgrind. + + VALGRIND_MALLOCLIKE_BLOCK marks a region of memory as having been allocated + by a malloc()-like function. For Memcheck (an illustrative case), this + does two things: + + - It records that the block has been allocated. This means any addresses + within the block mentioned in error messages will be + identified as belonging to the block. It also means that if the block + isn't freed it will be detected by the leak checker. + + - It marks the block as being addressable and undefined (if 'is_zeroed' is + not set), or addressable and defined (if 'is_zeroed' is set). This + controls how accesses to the block by the program are handled. + + 'addr' is the start of the usable block (ie. after any + redzone), 'sizeB' is its size. 'rzB' is the redzone size if the allocator + can apply redzones -- these are blocks of padding at the start and end of + each block. Adding redzones is recommended as it makes it much more likely + Valgrind will spot block overruns. `is_zeroed' indicates if the memory is + zeroed (or filled with another predictable value), as is the case for + calloc(). + + VALGRIND_MALLOCLIKE_BLOCK should be put immediately after the point where a + heap block -- that will be used by the client program -- is allocated. + It's best to put it at the outermost level of the allocator if possible; + for example, if you have a function my_alloc() which calls + internal_alloc(), and the client request is put inside internal_alloc(), + stack traces relating to the heap block will contain entries for both + my_alloc() and internal_alloc(), which is probably not what you want. + + For Memcheck users: if you use VALGRIND_MALLOCLIKE_BLOCK to carve out + custom blocks from within a heap block, B, that has been allocated with + malloc/calloc/new/etc, then block B will be *ignored* during leak-checking + -- the custom blocks will take precedence. + + VALGRIND_FREELIKE_BLOCK is the partner to VALGRIND_MALLOCLIKE_BLOCK. For + Memcheck, it does two things: + + - It records that the block has been deallocated. This assumes that the + block was annotated as having been allocated via + VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued. + + - It marks the block as being unaddressable. + + VALGRIND_FREELIKE_BLOCK should be put immediately after the point where a + heap block is deallocated. + + VALGRIND_RESIZEINPLACE_BLOCK informs a tool about reallocation. For + Memcheck, it does four things: + + - It records that the size of a block has been changed. This assumes that + the block was annotated as having been allocated via + VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued. + + - If the block shrunk, it marks the freed memory as being unaddressable. + + - If the block grew, it marks the new area as undefined and defines a red + zone past the end of the new block. + + - The V-bits of the overlap between the old and the new block are preserved. + + VALGRIND_RESIZEINPLACE_BLOCK should be put after allocation of the new block + and before deallocation of the old block. + + In many cases, these three client requests will not be enough to get your + allocator working well with Memcheck. More specifically, if your allocator + writes to freed blocks in any way then a VALGRIND_MAKE_MEM_UNDEFINED call + will be necessary to mark the memory as addressable just before the zeroing + occurs, otherwise you'll get a lot of invalid write errors. For example, + you'll need to do this if your allocator recycles freed blocks, but it + zeroes them before handing them back out (via VALGRIND_MALLOCLIKE_BLOCK). + Alternatively, if your allocator reuses freed blocks for allocator-internal + data structures, VALGRIND_MAKE_MEM_UNDEFINED calls will also be necessary. + + Really, what's happening is a blurring of the lines between the client + program and the allocator... after VALGRIND_FREELIKE_BLOCK is called, the + memory should be considered unaddressable to the client program, but the + allocator knows more than the rest of the client program and so may be able + to safely access it. Extra client requests are necessary for Valgrind to + understand the distinction between the allocator and the rest of the + program. + + Ignored if addr == 0. +*/ +#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MALLOCLIKE_BLOCK, \ + addr, sizeB, rzB, is_zeroed, 0) + +/* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details. + Ignored if addr == 0. +*/ +#define VALGRIND_RESIZEINPLACE_BLOCK(addr, oldSizeB, newSizeB, rzB) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RESIZEINPLACE_BLOCK, \ + addr, oldSizeB, newSizeB, rzB, 0) + +/* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details. + Ignored if addr == 0. +*/ +#define VALGRIND_FREELIKE_BLOCK(addr, rzB) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__FREELIKE_BLOCK, \ + addr, rzB, 0, 0, 0) + +/* Create a memory pool. */ +#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CREATE_MEMPOOL, \ + pool, rzB, is_zeroed, 0, 0) + +/* Create a memory pool with some flags specifying extended behaviour. + When flags is zero, the behaviour is identical to VALGRIND_CREATE_MEMPOOL. + + The flag VALGRIND_MEMPOOL_METAPOOL specifies that the pieces of memory + associated with the pool using VALGRIND_MEMPOOL_ALLOC will be used + by the application as superblocks to dole out MALLOC_LIKE blocks using + VALGRIND_MALLOCLIKE_BLOCK. In other words, a meta pool is a "2 levels" + pool : first level is the blocks described by VALGRIND_MEMPOOL_ALLOC. + The second level blocks are described using VALGRIND_MALLOCLIKE_BLOCK. + Note that the association between the pool and the second level blocks + is implicit : second level blocks will be located inside first level + blocks. It is necessary to use the VALGRIND_MEMPOOL_METAPOOL flag + for such 2 levels pools, as otherwise valgrind will detect overlapping + memory blocks, and will abort execution (e.g. during leak search). + + Such a meta pool can also be marked as an 'auto free' pool using the flag + VALGRIND_MEMPOOL_AUTO_FREE, which must be OR-ed together with the + VALGRIND_MEMPOOL_METAPOOL. For an 'auto free' pool, VALGRIND_MEMPOOL_FREE + will automatically free the second level blocks that are contained + inside the first level block freed with VALGRIND_MEMPOOL_FREE. + In other words, calling VALGRIND_MEMPOOL_FREE will cause implicit calls + to VALGRIND_FREELIKE_BLOCK for all the second level blocks included + in the first level block. + Note: it is an error to use the VALGRIND_MEMPOOL_AUTO_FREE flag + without the VALGRIND_MEMPOOL_METAPOOL flag. +*/ +#define VALGRIND_MEMPOOL_AUTO_FREE 1 +#define VALGRIND_MEMPOOL_METAPOOL 2 +#define VALGRIND_CREATE_MEMPOOL_EXT(pool, rzB, is_zeroed, flags) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CREATE_MEMPOOL, \ + pool, rzB, is_zeroed, flags, 0) + +/* Destroy a memory pool. */ +#define VALGRIND_DESTROY_MEMPOOL(pool) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DESTROY_MEMPOOL, \ + pool, 0, 0, 0, 0) + +/* Associate a piece of memory with a memory pool. */ +#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_ALLOC, \ + pool, addr, size, 0, 0) + +/* Disassociate a piece of memory from a memory pool. */ +#define VALGRIND_MEMPOOL_FREE(pool, addr) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_FREE, \ + pool, addr, 0, 0, 0) + +/* Disassociate any pieces outside a particular range. */ +#define VALGRIND_MEMPOOL_TRIM(pool, addr, size) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_TRIM, \ + pool, addr, size, 0, 0) + +/* Resize and/or move a piece associated with a memory pool. */ +#define VALGRIND_MOVE_MEMPOOL(poolA, poolB) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MOVE_MEMPOOL, \ + poolA, poolB, 0, 0, 0) + +/* Resize and/or move a piece associated with a memory pool. */ +#define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_CHANGE, \ + pool, addrA, addrB, size, 0) + +/* Return 1 if a mempool exists, else 0. */ +#define VALGRIND_MEMPOOL_EXISTS(pool) \ + (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ + VG_USERREQ__MEMPOOL_EXISTS, \ + pool, 0, 0, 0, 0) + +/* Mark a piece of memory as being a stack. Returns a stack id. + start is the lowest addressable stack byte, end is the highest + addressable stack byte. */ +#define VALGRIND_STACK_REGISTER(start, end) \ + (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ + VG_USERREQ__STACK_REGISTER, \ + start, end, 0, 0, 0) + +/* Unmark the piece of memory associated with a stack id as being a + stack. */ +#define VALGRIND_STACK_DEREGISTER(id) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STACK_DEREGISTER, \ + id, 0, 0, 0, 0) + +/* Change the start and end address of the stack id. + start is the new lowest addressable stack byte, end is the new highest + addressable stack byte. */ +#define VALGRIND_STACK_CHANGE(id, start, end) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STACK_CHANGE, \ + id, start, end, 0, 0) + +/* Load PDB debug info for Wine PE image_map. */ +#define VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LOAD_PDB_DEBUGINFO, \ + fd, ptr, total_size, delta, 0) + +/* Map a code address to a source file name and line number. buf64 + must point to a 64-byte buffer in the caller's address space. The + result will be dumped in there and is guaranteed to be zero + terminated. If no info is found, the first byte is set to zero. */ +#define VALGRIND_MAP_IP_TO_SRCLOC(addr, buf64) \ + (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ + VG_USERREQ__MAP_IP_TO_SRCLOC, \ + addr, buf64, 0, 0, 0) + +/* Disable error reporting for this thread. Behaves in a stack like + way, so you can safely call this multiple times provided that + VALGRIND_ENABLE_ERROR_REPORTING is called the same number of times + to re-enable reporting. The first call of this macro disables + reporting. Subsequent calls have no effect except to increase the + number of VALGRIND_ENABLE_ERROR_REPORTING calls needed to re-enable + reporting. Child threads do not inherit this setting from their + parents -- they are always created with reporting enabled. */ +#define VALGRIND_DISABLE_ERROR_REPORTING \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \ + 1, 0, 0, 0, 0) + +/* Re-enable error reporting, as per comments on + VALGRIND_DISABLE_ERROR_REPORTING. */ +#define VALGRIND_ENABLE_ERROR_REPORTING \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \ + -1, 0, 0, 0, 0) + +/* Execute a monitor command from the client program. + If a connection is opened with GDB, the output will be sent + according to the output mode set for vgdb. + If no connection is opened, output will go to the log output. + Returns 1 if command not recognised, 0 otherwise. */ +#define VALGRIND_MONITOR_COMMAND(command) \ + VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__GDB_MONITOR_COMMAND, \ + command, 0, 0, 0, 0) + + +/* Change the value of a dynamic command line option. + Note that unknown or not dynamically changeable options + will cause a warning message to be output. */ +#define VALGRIND_CLO_CHANGE(option) \ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CLO_CHANGE, \ + option, 0, 0, 0, 0) + + +#undef PLAT_x86_darwin +#undef PLAT_amd64_darwin +#undef PLAT_x86_win32 +#undef PLAT_amd64_win64 +#undef PLAT_x86_linux +#undef PLAT_amd64_linux +#undef PLAT_ppc32_linux +#undef PLAT_ppc64be_linux +#undef PLAT_ppc64le_linux +#undef PLAT_arm_linux +#undef PLAT_s390x_linux +#undef PLAT_mips32_linux +#undef PLAT_mips64_linux +#undef PLAT_nanomips_linux +#undef PLAT_x86_solaris +#undef PLAT_amd64_solaris + +#endif /* __VALGRIND_H */ diff --git a/runtime/druntime/src/rt/lifetime.d b/runtime/druntime/src/rt/lifetime.d index 40fa3e00b45..f78b4189853 100644 --- a/runtime/druntime/src/rt/lifetime.d +++ b/runtime/druntime/src/rt/lifetime.d @@ -1307,12 +1307,19 @@ int hasArrayFinalizerInSegment(void* p, size_t size, in void[] segment) nothrow return cast(size_t)(cast(void*)si.xdtor - segment.ptr) < segment.length; } +debug (VALGRIND) import etc.valgrind.valgrind; + // called by the GC void finalize_array2(void* p, size_t size) nothrow { debug(PRINTF) printf("rt_finalize_array2(p = %p)\n", p); TypeInfo_Struct si = void; + debug (VALGRIND) + { + auto block = p[0..size]; + disableAddrReportingInRange(block); + } if (size <= 256) { si = *cast(TypeInfo_Struct*)(p + size - size_t.sizeof); @@ -1329,6 +1336,7 @@ void finalize_array2(void* p, size_t size) nothrow size = *cast(size_t*)p; p += LARGEPREFIX; } + debug (VALGRIND) enableAddrReportingInRange(block); try { diff --git a/runtime/druntime/src/rt/minfo.d b/runtime/druntime/src/rt/minfo.d index 74891506364..b5c868f70bc 100644 --- a/runtime/druntime/src/rt/minfo.d +++ b/runtime/druntime/src/rt/minfo.d @@ -268,7 +268,9 @@ struct ModuleGroup } } // trim space to what is needed. - edges[i] = (cast(int*)realloc(edge, int.sizeof * nEdges))[0 .. nEdges]; + edges[i] = nEdges > 0 + ? (cast(int*)realloc(edge, int.sizeof * nEdges))[0 .. nEdges] + : null; } } diff --git a/runtime/druntime/test/valgrind/Makefile b/runtime/druntime/test/valgrind/Makefile new file mode 100644 index 00000000000..3ac82f72737 --- /dev/null +++ b/runtime/druntime/test/valgrind/Makefile @@ -0,0 +1,34 @@ +include ../common.mak + +TESTS := ok_append no_use_after_free no_oob no_oob_sentinel no_use_after_gc + +GC_SRC = \ + ../../src/core/internal/gc/impl/conservative/gc.d \ + ../../src/etc/valgrind/valgrind.d \ + ../../src/rt/lifetime.d + +.PHONY: all clean +all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) + +$(ROOT)/ok_%.done: $(ROOT)/ok_% + @echo Testing ok_$* + $(QUIET)if ! command -v valgrind >/dev/null; then \ + echo valgrind not installed, skipping; \ + else \ + $(TIMELIMIT)valgrind --quiet --tool=memcheck --error-exitcode=8 $(ROOT)/ok_$* $(RUN_ARGS); \ + fi + $(QUIET)touch $@ + +$(ROOT)/no_%.done: $(ROOT)/no_% + @echo Testing no_$* + $(QUIET)if ! command -v valgrind >/dev/null; then \ + echo valgrind not installed, skipping; \ + else \ + ( ! $(TIMELIMIT)valgrind --quiet --tool=memcheck --error-exitcode=8 $(ROOT)/no_$* $(RUN_ARGS); ) \ + fi + $(QUIET)touch $@ + +$(ROOT)/%: $(SRC)/%.d $(GC_SRC) + $(QUIET)$(DMD) -debug=VALGRIND -debug=SENTINEL $(DFLAGS) -of$@ $< $(GC_SRC) +clean: + rm -rf $(ROOT) diff --git a/runtime/druntime/test/valgrind/src/no_oob.d b/runtime/druntime/test/valgrind/src/no_oob.d new file mode 100644 index 00000000000..444ba602a5e --- /dev/null +++ b/runtime/druntime/test/valgrind/src/no_oob.d @@ -0,0 +1,7 @@ +// Out-of-bounds access (within the same block). + +void main() +{ + auto arr = new ubyte[4]; + arr.ptr[5] = 2; +} diff --git a/runtime/druntime/test/valgrind/src/no_oob_sentinel.d b/runtime/druntime/test/valgrind/src/no_oob_sentinel.d new file mode 100644 index 00000000000..36bc8980f5a --- /dev/null +++ b/runtime/druntime/test/valgrind/src/no_oob_sentinel.d @@ -0,0 +1,7 @@ +// Out-of-bounds access (SENTINEL). + +void main() +{ + auto arr = new ubyte[4]; + arr.ptr[-1] = 42; +} diff --git a/runtime/druntime/test/valgrind/src/no_use_after_free.d b/runtime/druntime/test/valgrind/src/no_use_after_free.d new file mode 100644 index 00000000000..bdfb03a4e9e --- /dev/null +++ b/runtime/druntime/test/valgrind/src/no_use_after_free.d @@ -0,0 +1,10 @@ +// Explicit use-after-free. + +import core.memory; + +int main() +{ + auto p = cast(int*)GC.malloc(int.sizeof * 3); + GC.free(p); + return *p; +} diff --git a/runtime/druntime/test/valgrind/src/no_use_after_gc.d b/runtime/druntime/test/valgrind/src/no_use_after_gc.d new file mode 100644 index 00000000000..1bb45628ff0 --- /dev/null +++ b/runtime/druntime/test/valgrind/src/no_use_after_gc.d @@ -0,0 +1,26 @@ +// Use-after-GC (escaping heap reference). + +struct S +{ + S* other; + + ~this() + { + // Dereferencing other GC-allocated values in a destructor is not allowed, + // as the deallocation/destruction order is undefined, + // and here even forms a loop. + int dummy = other.other !is &this; + result += dummy; + } +} + +__gshared int result; // Trick the optimizer + +int main() +{ + auto a = new S; + auto b = new S; + a.other = b; + b.other = a; + return result; +} diff --git a/runtime/druntime/test/valgrind/src/ok_append.d b/runtime/druntime/test/valgrind/src/ok_append.d new file mode 100644 index 00000000000..e2e8ee1a145 --- /dev/null +++ b/runtime/druntime/test/valgrind/src/ok_append.d @@ -0,0 +1,12 @@ +// Simply generate some garbage. +// This program should not trigger any Valgrind warnings. + +void main() +{ + foreach (i; 0..100) + { + string s; + foreach (j; 0..1000) + s ~= 'x'; + } +} From ddd88742647b61d1735a5df2fda0fb8f097a0c9b Mon Sep 17 00:00:00 2001 From: Dennis Date: Fri, 16 Jun 2023 13:48:47 +0200 Subject: [PATCH 073/176] Refer to bugzilla issues by hyperlink (dlang/dmd!15328) --- dmd/attrib.d | 3 ++- dmd/cparse.d | 2 +- dmd/expression.d | 2 +- dmd/expressionsem.d | 2 +- dmd/hdrgen.d | 2 +- dmd/inline.d | 4 ++-- dmd/mtype.d | 6 +++--- dmd/optimize.d | 2 +- dmd/traits.d | 2 +- runtime/druntime/src/core/atomic.d | 4 ++-- .../src/core/internal/gc/impl/conservative/gc.d | 10 +++++----- runtime/druntime/src/core/lifetime.d | 10 +++++----- runtime/druntime/src/object.d | 7 ++++--- runtime/druntime/src/rt/dwarfeh.d | 3 ++- runtime/druntime/src/rt/lifetime.d | 4 ++-- runtime/druntime/src/rt/util/typeinfo.d | 2 +- tests/dmd/compilable/b20938.d | 3 ++- tests/dmd/compilable/test16635.d | 2 +- tests/dmd/compilable/testInference.d | 6 +++--- tests/dmd/runnable/functype.d | 2 +- tests/dmd/runnable/interface2.d | 4 ++-- tests/dmd/runnable/link10425.d | 2 +- tests/dmd/runnable/template9.d | 3 ++- tests/dmd/runnable/testcontracts.d | 2 +- 24 files changed, 47 insertions(+), 42 deletions(-) diff --git a/dmd/attrib.d b/dmd/attrib.d index c08382cbd04..ff4ebe8eaf9 100644 --- a/dmd/attrib.d +++ b/dmd/attrib.d @@ -653,7 +653,8 @@ extern (C++) final class VisibilityDeclaration : AttribDeclaration { Module m = sc._module; - // While isAncestorPackageOf does an equality check, the fix for issue 17441 adds a check to see if + // https://issues.dlang.org/show_bug.cgi?id=17441 + // While isAncestorPackageOf does an equality check, the fix for the issue adds a check to see if // each package's .isModule() properites are equal. // // Properties generated from `package(foo)` i.e. visibility.pkg have .isModule() == null. diff --git a/dmd/cparse.d b/dmd/cparse.d index 33669e38c41..1b6b2bb4b1b 100644 --- a/dmd/cparse.d +++ b/dmd/cparse.d @@ -4235,7 +4235,7 @@ final class CParser(AST) : Parser!AST return false; /* https://issues.dlang.org/show_bug.cgi?id=22267 - Fix issue 22267: If the parser encounters the following + If the parser encounters the following `identifier variableName = (expression);` the initializer is not identified as such since the parentheses cause the parser to keep walking indefinitely diff --git a/dmd/expression.d b/dmd/expression.d index ae5746cf11f..35f11afdc93 100644 --- a/dmd/expression.d +++ b/dmd/expression.d @@ -4512,7 +4512,7 @@ extern (C++) abstract class BinExp : Expression Type t2 = e2.type; // T opAssign floating yields a floating. Prevent truncating conversions (float to int). - // See issue 3841. + // See https://issues.dlang.org/show_bug.cgi?id=3841. // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ? if (op == EXP.addAssign || op == EXP.minAssign || op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign || diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index 73339de3ac3..ec9c102d1a3 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -3387,7 +3387,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (ve && ve.var && exp.parens && !ve.var.isStatic() && !(sc.stc & STC.static_) && sc.func && sc.func.needThis && ve.var.isMember2()) { - // printf("apply fix for issue 9490: add `this.` to `%s`...\n", e.toChars()); + // printf("apply fix for bugzilla issue 9490: add `this.` to `%s`...\n", e.toChars()); e = new DotVarExp(exp.loc, new ThisExp(exp.loc), ve.var, false); } //printf("e = %s %s\n", Token.toChars(e.op), e.toChars()); diff --git a/dmd/hdrgen.d b/dmd/hdrgen.d index a159c2f1561..9e2a5b7c91f 100644 --- a/dmd/hdrgen.d +++ b/dmd/hdrgen.d @@ -927,7 +927,7 @@ public: } if (d.decl.length == 0 || (hgs.hdrgen && d.decl.length == 1 && (*d.decl)[0].isUnitTestDeclaration())) { - // hack for bugzilla 8081 + // hack for https://issues.dlang.org/show_bug.cgi?id=8081 if (hasSTC) buf.writeByte(' '); buf.writestring("{}"); } diff --git a/dmd/inline.d b/dmd/inline.d index 2b8ab623099..2a522216ce6 100644 --- a/dmd/inline.d +++ b/dmd/inline.d @@ -84,8 +84,8 @@ private void inlineScanDsymbol(Dsymbol s) * Perform the "inline copying" of a default argument for a function parameter. * * Todo: - * The hack for bugzilla 4820 case is still questionable. Perhaps would have to - * handle a delegate expression with 'null' context properly in front-end. + * The hack for https://issues.dlang.org/show_bug.cgi?id=4820 case is still questionable. + * Perhaps would have to handle a delegate expression with 'null' context properly in front-end. */ public Expression inlineCopy(Expression e, Scope* sc) { diff --git a/dmd/mtype.d b/dmd/mtype.d index cb3e6cddd20..103c761be5d 100644 --- a/dmd/mtype.d +++ b/dmd/mtype.d @@ -2054,7 +2054,7 @@ extern (C++) abstract class Type : ASTNode return Type.terror; auto t = fd.type.nextOf(); - if (!t) // issue 14185 + if (!t) // https://issues.dlang.org/show_bug.cgi?id=14185 return Type.terror; t = t.substWildTo(mod == 0 ? MODFlags.mutable : mod); return t; @@ -5105,7 +5105,7 @@ extern (C++) final class TypeDelegate : TypeNext * This is a shell containing a TraitsExp that can be * either resolved to a type or to a symbol. * - * The point is to allow AliasDeclarationY to use `__traits()`, see issue 7804. + * The point is to allow AliasDeclarationY to use `__traits()`, see https://issues.dlang.org/show_bug.cgi?id=7804. */ extern (C++) final class TypeTraits : Type { @@ -7271,7 +7271,7 @@ private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct, { /* Although a copy constructor may exist, no suitable match was found. * i.e: `inout` constructor creates `const` object, not mutable. - * Fallback to using the original generic error before bugzilla 22202. + * Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202. */ goto Lnocpctor; } diff --git a/dmd/optimize.d b/dmd/optimize.d index 335310de65d..f98e7c76bcc 100644 --- a/dmd/optimize.d +++ b/dmd/optimize.d @@ -189,7 +189,7 @@ private Expression fromConstInitializer(int result, Expression e1) { // If it is a comma expression involving a declaration, we mustn't // perform a copy -- we'd get two declarations of the same variable. - // See bugzilla 4465. + // See https://issues.dlang.org/show_bug.cgi?id=4465. if (e.op == EXP.comma && e.isCommaExp().e1.isDeclarationExp()) e = e1; else if (e.type != e1.type && e1.type && e1.type.ty != Tident) diff --git a/dmd/traits.d b/dmd/traits.d index 53c8fb08b50..8e1fa58a493 100644 --- a/dmd/traits.d +++ b/dmd/traits.d @@ -2116,7 +2116,7 @@ private bool isSame(RootObject o1, RootObject o2, Scope* sc) return true; } - // issue 12001, allow isSame, , + // https://issues.dlang.org/show_bug.cgi?id=12001, allow isSame, , Type t1 = isType(o1); Type t2 = isType(o2); if (t1 && t2 && t1.equals(t2)) diff --git a/runtime/druntime/src/core/atomic.d b/runtime/druntime/src/core/atomic.d index 940ed1fae66..ff7f7abf0c2 100644 --- a/runtime/druntime/src/core/atomic.d +++ b/runtime/druntime/src/core/atomic.d @@ -1203,7 +1203,7 @@ version (CoreUnittest) } } - @betterC pure nothrow @nogc @safe unittest // issue 16651 + @betterC pure nothrow @nogc @safe unittest // https://issues.dlang.org/show_bug.cgi?id=16651 { shared ulong a = 2; uint b = 1; @@ -1216,7 +1216,7 @@ version (CoreUnittest) assert(c == 1); } - pure nothrow @safe unittest // issue 16230 + pure nothrow @safe unittest // https://issues.dlang.org/show_bug.cgi?id=16230 { shared int i; static assert(is(typeof(atomicLoad(i)) == int)); diff --git a/runtime/druntime/src/core/internal/gc/impl/conservative/gc.d b/runtime/druntime/src/core/internal/gc/impl/conservative/gc.d index 2ed1ca92c38..39cd30aee16 100644 --- a/runtime/druntime/src/core/internal/gc/impl/conservative/gc.d +++ b/runtime/druntime/src/core/internal/gc/impl/conservative/gc.d @@ -93,7 +93,7 @@ private int rt_hasFinalizerInSegment(void* p, size_t size, uint attr, const scope void[] segment) nothrow; // Declared as an extern instead of importing core.exception - // to avoid inlining - see issue 13725. + // to avoid inlining - see https://issues.dlang.org/show_bug.cgi?id=13725. void onInvalidMemoryOperationError(void* pretend_sideffect = null) @trusted pure nothrow @nogc; void onOutOfMemoryErrorNoGC() @trusted nothrow @nogc; @@ -4453,7 +4453,7 @@ struct SmallObjectPool } debug(SENTINEL) {} else // no additional capacity with SENTINEL -unittest // bugzilla 14467 +unittest // https://issues.dlang.org/show_bug.cgi?id=14467 { int[] arr = new int[10]; assert(arr.capacity); @@ -4461,7 +4461,7 @@ unittest // bugzilla 14467 assert(arr.capacity); } -unittest // bugzilla 15353 +unittest // https://issues.dlang.org/show_bug.cgi?id=15353 { import core.memory : GC; @@ -4478,7 +4478,7 @@ unittest // bugzilla 15353 GC.collect(); } -unittest // bugzilla 15822 +unittest // https://issues.dlang.org/show_bug.cgi?id=15822 { import core.memory : GC; @@ -4499,7 +4499,7 @@ unittest // bugzilla 15822 GC.collect(); } -unittest // bugzilla 1180 +unittest // https://issues.dlang.org/show_bug.cgi?id=1180 { import core.exception; try diff --git a/runtime/druntime/src/core/lifetime.d b/runtime/druntime/src/core/lifetime.d index ae047cb730e..89236dbf4c1 100644 --- a/runtime/druntime/src/core/lifetime.d +++ b/runtime/druntime/src/core/lifetime.d @@ -364,7 +364,7 @@ T* emplace(T, Args...)(void[] chunk, auto ref Args args) assert(u1.a == "hello"); } -@system unittest // bugzilla 15772 +@system unittest // https://issues.dlang.org/show_bug.cgi?id=15772 { abstract class Foo {} class Bar: Foo {} @@ -2322,7 +2322,7 @@ pure nothrow @nogc @system unittest assert(val == 1); } -// issue 18913 +// https://issues.dlang.org/show_bug.cgi?id=18913 @safe unittest { static struct NoCopy @@ -2454,7 +2454,7 @@ template _d_delstructImpl(T) assert(outerDtors == 1); } -// issue 25552 +// https://issues.dlang.org/show_bug.cgi?id=25552 pure nothrow @system unittest { int i; @@ -2478,7 +2478,7 @@ pure nothrow @system unittest assert(i == 2); } -// issue 25552 +// https://issues.dlang.org/show_bug.cgi?id=25552 @safe unittest { int i; @@ -2527,7 +2527,7 @@ pure nothrow @system unittest assert(i == 6); } -// issue 25552 +// https://issues.dlang.org/show_bug.cgi?id=25552 @safe unittest { int i; diff --git a/runtime/druntime/src/object.d b/runtime/druntime/src/object.d index 228de32ff50..b0889b66386 100644 --- a/runtime/druntime/src/object.d +++ b/runtime/druntime/src/object.d @@ -289,8 +289,9 @@ if ((is(LHS : const Object) || is(LHS : const shared Object)) && // If same exact type => one call to method opEquals if (typeid(lhs) is typeid(rhs) || !__ctfe && typeid(lhs).opEquals(typeid(rhs))) - /* CTFE doesn't like typeid much. 'is' works, but opEquals doesn't - (issue 7147). But CTFE also guarantees that equal TypeInfos are + /* CTFE doesn't like typeid much. 'is' works, but opEquals doesn't: + https://issues.dlang.org/show_bug.cgi?id=7147 + But CTFE also guarantees that equal TypeInfos are always identical. So, no opEquals needed during CTFE. */ { return true; @@ -983,7 +984,7 @@ class TypeInfo_Enum : TypeInfo } -@safe unittest // issue 12233 +@safe unittest // https://issues.dlang.org/show_bug.cgi?id=12233 { static assert(is(typeof(TypeInfo.init) == TypeInfo)); assert(TypeInfo.init is null); diff --git a/runtime/druntime/src/rt/dwarfeh.d b/runtime/druntime/src/rt/dwarfeh.d index 1ce1c0b2882..05900ec3aee 100644 --- a/runtime/druntime/src/rt/dwarfeh.d +++ b/runtime/druntime/src/rt/dwarfeh.d @@ -590,7 +590,8 @@ ClassInfo getClassInfo(_Unwind_Exception* exceptionObject, const(ubyte)* current for (ExceptionHeader* ehn = eh.next; ehn; ehn = ehn.next) { // like __dmd_personality_v0, don't combine when the exceptions are from different functions - // (fixes issue 19831, exception thrown and caught while inside finally block) + // Fixes "exception thrown and caught while inside finally block" + // https://issues.dlang.org/show_bug.cgi?id=19831 if (currentLsd != ehn.languageSpecificData) { debug (EH_personality) writeln("break: %p %p", currentLsd, ehn.languageSpecificData); diff --git a/runtime/druntime/src/rt/lifetime.d b/runtime/druntime/src/rt/lifetime.d index f78b4189853..1245374ec5f 100644 --- a/runtime/druntime/src/rt/lifetime.d +++ b/runtime/druntime/src/rt/lifetime.d @@ -2381,7 +2381,7 @@ unittest unittest { - // bugzilla 13854 + // https://issues.dlang.org/show_bug.cgi?id=13854 auto arr = new ubyte[PAGESIZE]; // ensure page size auto info1 = GC.query(arr.ptr); assert(info1.base !is arr.ptr); // offset is required for page size or larger @@ -2424,7 +2424,7 @@ unittest unittest { - // bugzilla 13878 + // https://issues.dlang.org/show_bug.cgi?id=13878 auto arr = new ubyte[1]; auto info = GC.query(arr.ptr); assert(info.attr & BlkAttr.NO_SCAN); // should be NO_SCAN diff --git a/runtime/druntime/src/rt/util/typeinfo.d b/runtime/druntime/src/rt/util/typeinfo.d index 7b55693a720..730649ef481 100644 --- a/runtime/druntime/src/rt/util/typeinfo.d +++ b/runtime/druntime/src/rt/util/typeinfo.d @@ -545,7 +545,7 @@ unittest unittest { - // Original test case from issue 13073 + // Original test case from https://issues.dlang.org/show_bug.cgi?id=13073 uint x = 0x22_DF_FF_FF; uint y = 0xA2_DF_FF_FF; assert(!(x < y && y < x)); diff --git a/tests/dmd/compilable/b20938.d b/tests/dmd/compilable/b20938.d index ba3565ae8f9..b3aa46c2435 100644 --- a/tests/dmd/compilable/b20938.d +++ b/tests/dmd/compilable/b20938.d @@ -1,4 +1,5 @@ -// issue 20938 - Cannot create const arrays mixing immutable and mutable structs with indirections +// https://issues.dlang.org/show_bug.cgi?id=20938 +// Cannot create const arrays mixing immutable and mutable structs with indirections struct S { int[] a; } enum A { a } enum B { b } diff --git a/tests/dmd/compilable/test16635.d b/tests/dmd/compilable/test16635.d index 5f3d0ba9b6c..dcdd35b3bb0 100644 --- a/tests/dmd/compilable/test16635.d +++ b/tests/dmd/compilable/test16635.d @@ -39,7 +39,7 @@ void test16635_1() Vector2 b = Vector2(3, 4); // this line causes application to run infinitely - // Already fixed. It was issue 16621 + // Already fixed. It was https://issues.dlang.org/show_bug.cgi?id=16621 Vector2 c = a + b; // OK <- this line seg faults without the above line diff --git a/tests/dmd/compilable/testInference.d b/tests/dmd/compilable/testInference.d index 31b10494148..bddbaf42946 100644 --- a/tests/dmd/compilable/testInference.d +++ b/tests/dmd/compilable/testInference.d @@ -171,9 +171,9 @@ template map7017(fun...) if (fun.length >= 1) auto map7017() { struct Result { - this(int dummy){} // impure member function -> inferred to pure by fixing issue 10329 + this(int dummy){} // impure member function -> inferred to pure by fixing https://issues.dlang.org/show_bug.cgi?id=10329 } - return Result(0); // impure call -> inferred to pure by fixing issue 10329 + return Result(0); // impure call -> inferred to pure by fixing https://issues.dlang.org/show_bug.cgi?id=10329 } } @@ -588,7 +588,7 @@ auto fb10148(T)() static assert(is(typeof(&fc) == void delegate())); fa10148(); } - // [1] this is now inferred to @safe by implementing issue 7511 + // [1] this is now inferred to @safe by implementing https://issues.dlang.org/show_bug.cgi?id=7511 this(S a) {} } diff --git a/tests/dmd/runnable/functype.d b/tests/dmd/runnable/functype.d index 5dad6186fba..cdeb4182a1f 100644 --- a/tests/dmd/runnable/functype.d +++ b/tests/dmd/runnable/functype.d @@ -301,7 +301,7 @@ void test10734() void test14656() { - //void unaryFun()(auto int a) pure nothrow @safe @nogc {} // changed to invalid by fixing issue 14669 + //void unaryFun()(auto int a) pure nothrow @safe @nogc {} // changed to invalid by fixing https://issues.dlang.org/show_bug.cgi?id=14669 alias Identity(F) = F; //unaryFun!()(41); static void fun(int n) pure nothrow @safe @nogc {} diff --git a/tests/dmd/runnable/interface2.d b/tests/dmd/runnable/interface2.d index fabbbfd4bfc..603e4b25108 100644 --- a/tests/dmd/runnable/interface2.d +++ b/tests/dmd/runnable/interface2.d @@ -962,11 +962,11 @@ void test1747() assert(pia == pc + n); assert(id.mA() == 1); - assert(id.mB() == 2); // OK <- NG (bugzilla 2013 case) + assert(id.mB() == 2); // OK <- NG (https://issues.dlang.org/show_bug.cgi?id=2013 case) assert(id.mD() == 3); assert(ic.mA() == 1); - assert(ic.mB() == 2); // OK <- NG (bugzilla 2013 case) + assert(ic.mB() == 2); // OK <- NG (https://issues.dlang.org/show_bug.cgi?id=2013 case) assert(ib.mA() == 1); assert(ib.mB() == 2); // OK <- NG diff --git a/tests/dmd/runnable/link10425.d b/tests/dmd/runnable/link10425.d index d0825165765..ae135ea703a 100644 --- a/tests/dmd/runnable/link10425.d +++ b/tests/dmd/runnable/link10425.d @@ -10,7 +10,7 @@ void main() * the TypeInfo object on comdat section (done by TypeInfoDeclaration::toObjFile), * even if the associated struct belongs *non-root modules*. * - * And, from 2.062, issue 7511 is implemented. + * And, from 2.062, https://issues.dlang.org/show_bug.cgi?id=7511 is implemented. * The attribute inference for member functions in instantiated struct may modify * their actual mangled names. Then TypeInfo object compiled in this module would * use wrong symbol names, to link non-template opEquals/opCmp/toHash/toString diff --git a/tests/dmd/runnable/template9.d b/tests/dmd/runnable/template9.d index cb3de5bc6f0..dbad3f1daec 100644 --- a/tests/dmd/runnable/template9.d +++ b/tests/dmd/runnable/template9.d @@ -4689,7 +4689,8 @@ struct S14604 } alias Id14604(alias thing) = thing; alias c14604 = Id14604!(S14604.opDispatch!"go"); // ok -alias d14604 = Id14604!(S14604.go); // issue 14604, 'Error: template instance opDispatch!"go" cannot resolve forward reference' +// https://issues.dlang.org/show_bug.cgi?id=14604 +alias d14604 = Id14604!(S14604.go); // 'Error: template instance opDispatch!"go" cannot resolve forward reference' /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=14735 diff --git a/tests/dmd/runnable/testcontracts.d b/tests/dmd/runnable/testcontracts.d index e79c6a05716..439040b7b38 100644 --- a/tests/dmd/runnable/testcontracts.d +++ b/tests/dmd/runnable/testcontracts.d @@ -936,7 +936,7 @@ void test9383() /*******************************************/ // https://issues.dlang.org/show_bug.cgi?id=15524 -// Different from issue 9383 cases, closed variable size is bigger than REGSIZE. +// Different from https://issues.dlang.org/show_bug.cgi?id=9383 cases, closed variable size is bigger than REGSIZE. class A15524 { From e78b8d0668942a337fdeee94bb12d4d0f9187426 Mon Sep 17 00:00:00 2001 From: Dennis Date: Fri, 16 Jun 2023 13:49:36 +0200 Subject: [PATCH 074/176] Improve error message for declaring opaque type variable (dlang/dmd!15327) --- dmd/dsymbolsem.d | 2 ++ tests/dmd/fail_compilation/enum_init.d | 2 ++ tests/dmd/fail_compilation/failcstuff4.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/dmd/dsymbolsem.d b/dmd/dsymbolsem.d index 71c18568f9a..d97d37db81f 100644 --- a/dmd/dsymbolsem.d +++ b/dmd/dsymbolsem.d @@ -587,6 +587,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor const loc = (s ? s : dsym).loc; loc.errorSupplemental("required by type `%s`", dsym.type.toChars()); } + errorSupplemental(dsym.loc, "see https://dlang.org/spec/struct.html#opaque_struct_unions"); + errorSupplemental(dsym.loc, "perhaps declare a variable with pointer type `%s*` instead", dsym.type.toChars()); // Flag variable as error to avoid invalid error messages due to unknown size dsym.type = Type.terror; diff --git a/tests/dmd/fail_compilation/enum_init.d b/tests/dmd/fail_compilation/enum_init.d index 8344a4701c7..c968f5ee184 100644 --- a/tests/dmd/fail_compilation/enum_init.d +++ b/tests/dmd/fail_compilation/enum_init.d @@ -58,6 +58,8 @@ TEST_OUTPUT: --- fail_compilation/enum_init.d(306): Error: variable `enum_init.fooOB.ob` - no definition of struct `S` fail_compilation/enum_init.d(302): required by type `OpaqueBase` +fail_compilation/enum_init.d(306): see https://dlang.org/spec/struct.html#opaque_struct_unions +fail_compilation/enum_init.d(306): perhaps declare a variable with pointer type `OpaqueBase*` instead --- */ #line 300 diff --git a/tests/dmd/fail_compilation/failcstuff4.c b/tests/dmd/fail_compilation/failcstuff4.c index 41f9ab5556b..5964ccad00b 100644 --- a/tests/dmd/fail_compilation/failcstuff4.c +++ b/tests/dmd/fail_compilation/failcstuff4.c @@ -3,6 +3,8 @@ --- fail_compilation/failcstuff4.c(100): Error: can only `*` a pointer, not a `int` fail_compilation/failcstuff4.c(157): Error: variable `failcstuff4.T22106.f1` - no definition of struct `S22106_t` +fail_compilation/failcstuff4.c(157): see https://dlang.org/spec/struct.html#opaque_struct_unions +fail_compilation/failcstuff4.c(157): perhaps declare a variable with pointer type `S22106_t*` instead --- */ From 12dec384ff3b97cbacc119c81a787f04d36a2900 Mon Sep 17 00:00:00 2001 From: FeepingCreature <540727+FeepingCreature@users.noreply.github.com> Date: Fri, 16 Jun 2023 13:51:14 +0200 Subject: [PATCH 075/176] Make 'private function is not accessible' deprecation an error. (dlang/dmd!15319) Affects issue 21275, 23947. --- dmd/expressionsem.d | 6 ++---- tests/dmd/fail_compilation/fail21275.d | 5 ++--- tests/dmd/fail_compilation/issue23947.d | 3 +-- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index ec9c102d1a3..d382930cd3b 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -5017,11 +5017,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else if (!checkSymbolAccess(sc, exp.f)) { - // @@@DEPRECATED_2.105@@@ - // When turning into error, uncomment the return statement - exp.deprecation("%s `%s` of type `%s` is not accessible from module `%s`", + exp.error("%s `%s` of type `%s` is not accessible from module `%s`", exp.f.kind(), exp.f.toPrettyChars(), exp.f.type.toChars(), sc._module.toChars); - //return ErrorExp.get(); + return setError(); } if (!exp.f.needThis()) diff --git a/tests/dmd/fail_compilation/fail21275.d b/tests/dmd/fail_compilation/fail21275.d index 69cdf1ada9a..b7bbcfa6250 100644 --- a/tests/dmd/fail_compilation/fail21275.d +++ b/tests/dmd/fail_compilation/fail21275.d @@ -1,12 +1,11 @@ // https://issues.dlang.org/show_bug.cgi?id=21275 -// REQUIRED_ARGS: -de // EXTRA_FILES: imports/fail21275a.d /* TEST_OUTPUT: --- -fail_compilation/fail21275.d(18): Deprecation: function `imports.fail21275a.Foo.x` of type `ref int() return` is not accessible from module `fail21275` -fail_compilation/fail21275.d(21): Deprecation: function `imports.fail21275a.Bar.x` of type `int(int)` is not accessible from module `fail21275` +fail_compilation/fail21275.d(17): Error: function `imports.fail21275a.Foo.x` of type `ref int() return` is not accessible from module `fail21275` +fail_compilation/fail21275.d(20): Error: function `imports.fail21275a.Bar.x` of type `int(int)` is not accessible from module `fail21275` --- */ diff --git a/tests/dmd/fail_compilation/issue23947.d b/tests/dmd/fail_compilation/issue23947.d index 87b08aeb305..d73cd8572fa 100644 --- a/tests/dmd/fail_compilation/issue23947.d +++ b/tests/dmd/fail_compilation/issue23947.d @@ -1,9 +1,8 @@ // https://issues.dlang.org/show_bug.cgi?id=23947 -// REQUIRED_ARGS: -de /* TEST_OUTPUT: --- -fail_compilation/issue23947.d(11): Deprecation: function `imports.issue23947a.Class.handle` of type `void(X x)` is not accessible from module `issue23947` +fail_compilation/issue23947.d(10): Error: function `imports.issue23947a.Class.handle` of type `void(X x)` is not accessible from module `issue23947` --- */ import imports.issue23947a; From 713032eb38e75aa1a72ed061ca08033d5c30204a Mon Sep 17 00:00:00 2001 From: Vladimir Panteleev Date: Mon, 19 Jun 2023 12:41:29 +0000 Subject: [PATCH 076/176] core.sys.linux: Add input header translations (dlang/dmd!15323) Add bindings for the Linux input system. --- runtime/druntime/src/core/sys/linux/input.d | 236 ++++++ .../src/core/sys/linux/input_event_codes.d | 758 ++++++++++++++++++ runtime/druntime/src/core/sys/linux/uinput.d | 85 ++ 3 files changed, 1079 insertions(+) create mode 100644 runtime/druntime/src/core/sys/linux/input.d create mode 100644 runtime/druntime/src/core/sys/linux/input_event_codes.d create mode 100644 runtime/druntime/src/core/sys/linux/uinput.d diff --git a/runtime/druntime/src/core/sys/linux/input.d b/runtime/druntime/src/core/sys/linux/input.d new file mode 100644 index 00000000000..1bf356dca98 --- /dev/null +++ b/runtime/druntime/src/core/sys/linux/input.d @@ -0,0 +1,236 @@ +module core.sys.linux.input; + +version (linux): +extern(C): +nothrow: + +import core.sys.linux.sys.time; +import core.sys.posix.sys.ioctl; + +public import core.sys.linux.input_event_codes; + +struct input_event +{ + timeval time; + ushort type; + ushort code; + int value; +} + +enum EV_VERSION = 0x010001; + +struct input_id +{ + ushort bustype; + ushort vendor; + ushort product; + ushort version_; +} + +struct input_absinfo +{ + int value; + int minimum; + int maximum; + int fuzz; + int flat; + int resolution; +} + +enum INPUT_KEYMAP_BY_INDEX = (1 << 0); +struct input_keymap_entry +{ + ubyte flags; + ubyte len; + ushort index; + uint keycode; + ubyte[32] scancode; +} + +struct input_mask +{ + uint type; + uint codes_size; + ulong codes_ptr; +} + +enum EVIOCGVERSION = _IOR!int('E', 0x01); +enum EVIOCGID = _IOR!input_id('E', 0x02); +enum EVIOCGREP = _IOR!(uint[2])('E', 0x03); +enum EVIOCSREP = _IOW!(uint[2])('E', 0x03); + +enum EVIOCGKEYCODE = _IOR!(uint[2])('E', 0x04); +enum EVIOCGKEYCODE_V2 = _IOR!input_keymap_entry('E', 0x04); +enum EVIOCSKEYCODE = _IOW!(uint[2])('E', 0x04); +enum EVIOCSKEYCODE_V2 = _IOW!input_keymap_entry('E', 0x04); + +enum EVIOCGNAME(len) = _IOC(_IOC_READ, 'E', 0x06, len); +enum EVIOCGPHYS(len) = _IOC(_IOC_READ, 'E', 0x07, len); +enum EVIOCGUNIQ(len) = _IOC(_IOC_READ, 'E', 0x08, len); +enum EVIOCGPROP(len) = _IOC(_IOC_READ, 'E', 0x09, len); + +enum EVIOCGMTSLOTS(len) = _IOC(_IOC_READ, 'E', 0x0a, len); + +enum EVIOCGKEY(len) = _IOC(_IOC_READ, 'E', 0x18, len); +enum EVIOCGLED(len) = _IOC(_IOC_READ, 'E', 0x19, len); +enum EVIOCGSND(len) = _IOC(_IOC_READ, 'E', 0x1a, len); +enum EVIOCGSW(len) = _IOC(_IOC_READ, 'E', 0x1b, len); + +enum EVIOCGBIT(ev,len) = _IOC(_IOC_READ, 'E', 0x20 + (ev), len); +enum EVIOCGABS(abs) = _IOR!input_absinfo('E', 0x40 + (abs)); +enum EVIOCSABS(abs) = _IOW!input_absinfo('E', 0xc0 + (abs)); + +enum EVIOCSFF = _IOW!ff_effect('E', 0x80); +enum EVIOCRMFF = _IOW!int('E', 0x81); +enum EVIOCGEFFECTS = _IOR!int('E', 0x84); + +enum EVIOCGRAB = _IOW!int('E', 0x90); +enum EVIOCREVOKE = _IOW!int('E', 0x91); + +enum EVIOCGMASK = _IOR!input_mask('E', 0x92); + +enum EVIOCSMASK = _IOW!input_mask('E', 0x93); + +enum EVIOCSCLOCKID = _IOW!int('E', 0xa0); + +enum ID_BUS = 0; +enum ID_VENDOR = 1; +enum ID_PRODUCT = 2; +enum ID_VERSION = 3; + +enum BUS_PCI = 0x01; +enum BUS_ISAPNP = 0x02; +enum BUS_USB = 0x03; +enum BUS_HIL = 0x04; +enum BUS_BLUETOOTH = 0x05; +enum BUS_VIRTUAL = 0x06; + +enum BUS_ISA = 0x10; +enum BUS_I8042 = 0x11; +enum BUS_XTKBD = 0x12; +enum BUS_RS232 = 0x13; +enum BUS_GAMEPORT = 0x14; +enum BUS_PARPORT = 0x15; +enum BUS_AMIGA = 0x16; +enum BUS_ADB = 0x17; +enum BUS_I2C = 0x18; +enum BUS_HOST = 0x19; +enum BUS_GSC = 0x1A; +enum BUS_ATARI = 0x1B; +enum BUS_SPI = 0x1C; +enum BUS_RMI = 0x1D; +enum BUS_CEC = 0x1E; +enum BUS_INTEL_ISHTP = 0x1F; + +enum MT_TOOL_FINGER = 0; +enum MT_TOOL_PEN = 1; +enum MT_TOOL_PALM = 2; +enum MT_TOOL_MAX = 2; + +enum FF_STATUS_STOPPED = 0x00; +enum FF_STATUS_PLAYING = 0x01; +enum FF_STATUS_MAX = 0x01; + +struct ff_replay { + ushort length; + ushort delay; +}; + +struct ff_trigger { + ushort button; + ushort interval; +}; + +struct ff_envelope { + ushort attack_length; + ushort attack_level; + ushort fade_length; + ushort fade_level; +}; + +struct ff_constant_effect { + short level; + ff_envelope envelope; +}; + +struct ff_ramp_effect { + short start_level; + short end_level; + ff_envelope envelope; +}; + +struct ff_condition_effect { + ushort right_saturation; + ushort left_saturation; + + short right_coeff; + short left_coeff; + + ushort deadband; + short center; +}; + +struct ff_periodic_effect { + ushort waveform; + ushort period; + short magnitude; + short offset; + ushort phase; + + ff_envelope envelope; + + uint custom_len; + short *custom_data; +}; + +struct ff_rumble_effect { + ushort strong_magnitude; + ushort weak_magnitude; +}; + +struct ff_effect { + ushort type; + short id; + ushort direction; + ff_trigger trigger; + ff_replay replay; + + union U { + ff_constant_effect constant; + ff_ramp_effect ramp; + ff_periodic_effect periodic; + ff_condition_effect[2] condition; + ff_rumble_effect rumble; + } + U u; +}; + +enum FF_RUMBLE = 0x50; +enum FF_PERIODIC = 0x51; +enum FF_CONSTANT = 0x52; +enum FF_SPRING = 0x53; +enum FF_FRICTION = 0x54; +enum FF_DAMPER = 0x55; +enum FF_INERTIA = 0x56; +enum FF_RAMP = 0x57; + +enum FF_EFFECT_MIN = FF_RUMBLE; +enum FF_EFFECT_MAX = FF_RAMP; + +enum FF_SQUARE = 0x58; +enum FF_TRIANGLE = 0x59; +enum FF_SINE = 0x5a; +enum FF_SAW_UP = 0x5b; +enum FF_SAW_DOWN = 0x5c; +enum FF_CUSTOM = 0x5d; + +enum FF_WAVEFORM_MIN = FF_SQUARE; +enum FF_WAVEFORM_MAX = FF_CUSTOM; + +enum FF_GAIN = 0x60; +enum FF_AUTOCENTER = 0x61; + +enum FF_MAX_EFFECTS = FF_GAIN; + +enum FF_MAX = 0x7f; +enum FF_CNT = (FF_MAX+1); diff --git a/runtime/druntime/src/core/sys/linux/input_event_codes.d b/runtime/druntime/src/core/sys/linux/input_event_codes.d new file mode 100644 index 00000000000..3ebda69fd07 --- /dev/null +++ b/runtime/druntime/src/core/sys/linux/input_event_codes.d @@ -0,0 +1,758 @@ +module core.sys.linux.input_event_codes; + +version (linux): +extern(C): +nothrow: + +enum INPUT_PROP_POINTER = 0x00; +enum INPUT_PROP_DIRECT = 0x01; +enum INPUT_PROP_BUTTONPAD = 0x02; +enum INPUT_PROP_SEMI_MT = 0x03; +enum INPUT_PROP_TOPBUTTONPAD = 0x04; +enum INPUT_PROP_POINTING_STICK = 0x05; +enum INPUT_PROP_ACCELEROMETER = 0x06; + +enum INPUT_PROP_MAX = 0x1f; +enum INPUT_PROP_CNT = (INPUT_PROP_MAX + 1); + +enum EV_SYN = 0x00; +enum EV_KEY = 0x01; +enum EV_REL = 0x02; +enum EV_ABS = 0x03; +enum EV_MSC = 0x04; +enum EV_SW = 0x05; +enum EV_LED = 0x11; +enum EV_SND = 0x12; +enum EV_REP = 0x14; +enum EV_FF = 0x15; +enum EV_PWR = 0x16; +enum EV_FF_STATUS = 0x17; +enum EV_MAX = 0x1f; +enum EV_CNT = (EV_MAX+1); + +enum SYN_REPORT = 0; +enum SYN_CONFIG = 1; +enum SYN_MT_REPORT = 2; +enum SYN_DROPPED = 3; +enum SYN_MAX = 0xf; +enum SYN_CNT = (SYN_MAX+1); + +enum KEY_RESERVED = 0; +enum KEY_ESC = 1; +enum KEY_1 = 2; +enum KEY_2 = 3; +enum KEY_3 = 4; +enum KEY_4 = 5; +enum KEY_5 = 6; +enum KEY_6 = 7; +enum KEY_7 = 8; +enum KEY_8 = 9; +enum KEY_9 = 10; +enum KEY_0 = 11; +enum KEY_MINUS = 12; +enum KEY_EQUAL = 13; +enum KEY_BACKSPACE = 14; +enum KEY_TAB = 15; +enum KEY_Q = 16; +enum KEY_W = 17; +enum KEY_E = 18; +enum KEY_R = 19; +enum KEY_T = 20; +enum KEY_Y = 21; +enum KEY_U = 22; +enum KEY_I = 23; +enum KEY_O = 24; +enum KEY_P = 25; +enum KEY_LEFTBRACE = 26; +enum KEY_RIGHTBRACE = 27; +enum KEY_ENTER = 28; +enum KEY_LEFTCTRL = 29; +enum KEY_A = 30; +enum KEY_S = 31; +enum KEY_D = 32; +enum KEY_F = 33; +enum KEY_G = 34; +enum KEY_H = 35; +enum KEY_J = 36; +enum KEY_K = 37; +enum KEY_L = 38; +enum KEY_SEMICOLON = 39; +enum KEY_APOSTROPHE = 40; +enum KEY_GRAVE = 41; +enum KEY_LEFTSHIFT = 42; +enum KEY_BACKSLASH = 43; +enum KEY_Z = 44; +enum KEY_X = 45; +enum KEY_C = 46; +enum KEY_V = 47; +enum KEY_B = 48; +enum KEY_N = 49; +enum KEY_M = 50; +enum KEY_COMMA = 51; +enum KEY_DOT = 52; +enum KEY_SLASH = 53; +enum KEY_RIGHTSHIFT = 54; +enum KEY_KPASTERISK = 55; +enum KEY_LEFTALT = 56; +enum KEY_SPACE = 57; +enum KEY_CAPSLOCK = 58; +enum KEY_F1 = 59; +enum KEY_F2 = 60; +enum KEY_F3 = 61; +enum KEY_F4 = 62; +enum KEY_F5 = 63; +enum KEY_F6 = 64; +enum KEY_F7 = 65; +enum KEY_F8 = 66; +enum KEY_F9 = 67; +enum KEY_F10 = 68; +enum KEY_NUMLOCK = 69; +enum KEY_SCROLLLOCK = 70; +enum KEY_KP7 = 71; +enum KEY_KP8 = 72; +enum KEY_KP9 = 73; +enum KEY_KPMINUS = 74; +enum KEY_KP4 = 75; +enum KEY_KP5 = 76; +enum KEY_KP6 = 77; +enum KEY_KPPLUS = 78; +enum KEY_KP1 = 79; +enum KEY_KP2 = 80; +enum KEY_KP3 = 81; +enum KEY_KP0 = 82; +enum KEY_KPDOT = 83; + +enum KEY_ZENKAKUHANKAKU = 85; +enum KEY_102ND = 86; +enum KEY_F11 = 87; +enum KEY_F12 = 88; +enum KEY_RO = 89; +enum KEY_KATAKANA = 90; +enum KEY_HIRAGANA = 91; +enum KEY_HENKAN = 92; +enum KEY_KATAKANAHIRAGANA = 93; +enum KEY_MUHENKAN = 94; +enum KEY_KPJPCOMMA = 95; +enum KEY_KPENTER = 96; +enum KEY_RIGHTCTRL = 97; +enum KEY_KPSLASH = 98; +enum KEY_SYSRQ = 99; +enum KEY_RIGHTALT = 100; +enum KEY_LINEFEED = 101; +enum KEY_HOME = 102; +enum KEY_UP = 103; +enum KEY_PAGEUP = 104; +enum KEY_LEFT = 105; +enum KEY_RIGHT = 106; +enum KEY_END = 107; +enum KEY_DOWN = 108; +enum KEY_PAGEDOWN = 109; +enum KEY_INSERT = 110; +enum KEY_DELETE = 111; +enum KEY_MACRO = 112; +enum KEY_MUTE = 113; +enum KEY_VOLUMEDOWN = 114; +enum KEY_VOLUMEUP = 115; +enum KEY_POWER = 116; +enum KEY_KPEQUAL = 117; +enum KEY_KPPLUSMINUS = 118; +enum KEY_PAUSE = 119; +enum KEY_SCALE = 120; + +enum KEY_KPCOMMA = 121; +enum KEY_HANGEUL = 122; +enum KEY_HANGUEL = KEY_HANGEUL; +enum KEY_HANJA = 123; +enum KEY_YEN = 124; +enum KEY_LEFTMETA = 125; +enum KEY_RIGHTMETA = 126; +enum KEY_COMPOSE = 127; + +enum KEY_STOP = 128; +enum KEY_AGAIN = 129; +enum KEY_PROPS = 130; +enum KEY_UNDO = 131; +enum KEY_FRONT = 132; +enum KEY_COPY = 133; +enum KEY_OPEN = 134; +enum KEY_PASTE = 135; +enum KEY_FIND = 136; +enum KEY_CUT = 137; +enum KEY_HELP = 138; +enum KEY_MENU = 139; +enum KEY_CALC = 140; +enum KEY_SETUP = 141; +enum KEY_SLEEP = 142; +enum KEY_WAKEUP = 143; +enum KEY_FILE = 144; +enum KEY_SENDFILE = 145; +enum KEY_DELETEFILE = 146; +enum KEY_XFER = 147; +enum KEY_PROG1 = 148; +enum KEY_PROG2 = 149; +enum KEY_WWW = 150; +enum KEY_MSDOS = 151; +enum KEY_COFFEE = 152; +enum KEY_SCREENLOCK = KEY_COFFEE; +enum KEY_ROTATE_DISPLAY = 153; +enum KEY_DIRECTION = KEY_ROTATE_DISPLAY; +enum KEY_CYCLEWINDOWS = 154; +enum KEY_MAIL = 155; +enum KEY_BOOKMARKS = 156; +enum KEY_COMPUTER = 157; +enum KEY_BACK = 158; +enum KEY_FORWARD = 159; +enum KEY_CLOSECD = 160; +enum KEY_EJECTCD = 161; +enum KEY_EJECTCLOSECD = 162; +enum KEY_NEXTSONG = 163; +enum KEY_PLAYPAUSE = 164; +enum KEY_PREVIOUSSONG = 165; +enum KEY_STOPCD = 166; +enum KEY_RECORD = 167; +enum KEY_REWIND = 168; +enum KEY_PHONE = 169; +enum KEY_ISO = 170; +enum KEY_CONFIG = 171; +enum KEY_HOMEPAGE = 172; +enum KEY_REFRESH = 173; +enum KEY_EXIT = 174; +enum KEY_MOVE = 175; +enum KEY_EDIT = 176; +enum KEY_SCROLLUP = 177; +enum KEY_SCROLLDOWN = 178; +enum KEY_KPLEFTPAREN = 179; +enum KEY_KPRIGHTPAREN = 180; +enum KEY_NEW = 181; +enum KEY_REDO = 182; + +enum KEY_F13 = 183; +enum KEY_F14 = 184; +enum KEY_F15 = 185; +enum KEY_F16 = 186; +enum KEY_F17 = 187; +enum KEY_F18 = 188; +enum KEY_F19 = 189; +enum KEY_F20 = 190; +enum KEY_F21 = 191; +enum KEY_F22 = 192; +enum KEY_F23 = 193; +enum KEY_F24 = 194; + +enum KEY_PLAYCD = 200; +enum KEY_PAUSECD = 201; +enum KEY_PROG3 = 202; +enum KEY_PROG4 = 203; +enum KEY_DASHBOARD = 204; +enum KEY_SUSPEND = 205; +enum KEY_CLOSE = 206; +enum KEY_PLAY = 207; +enum KEY_FASTFORWARD = 208; +enum KEY_BASSBOOST = 209; +enum KEY_PRINT = 210; +enum KEY_HP = 211; +enum KEY_CAMERA = 212; +enum KEY_SOUND = 213; +enum KEY_QUESTION = 214; +enum KEY_EMAIL = 215; +enum KEY_CHAT = 216; +enum KEY_SEARCH = 217; +enum KEY_CONNECT = 218; +enum KEY_FINANCE = 219; +enum KEY_SPORT = 220; +enum KEY_SHOP = 221; +enum KEY_ALTERASE = 222; +enum KEY_CANCEL = 223; +enum KEY_BRIGHTNESSDOWN = 224; +enum KEY_BRIGHTNESSUP = 225; +enum KEY_MEDIA = 226; + +enum KEY_SWITCHVIDEOMODE = 227; +enum KEY_KBDILLUMTOGGLE = 228; +enum KEY_KBDILLUMDOWN = 229; +enum KEY_KBDILLUMUP = 230; + +enum KEY_SEND = 231; +enum KEY_REPLY = 232; +enum KEY_FORWARDMAIL = 233; +enum KEY_SAVE = 234; +enum KEY_DOCUMENTS = 235; + +enum KEY_BATTERY = 236; + +enum KEY_BLUETOOTH = 237; +enum KEY_WLAN = 238; +enum KEY_UWB = 239; + +enum KEY_UNKNOWN = 240; + +enum KEY_VIDEO_NEXT = 241; +enum KEY_VIDEO_PREV = 242; +enum KEY_BRIGHTNESS_CYCLE = 243; +enum KEY_BRIGHTNESS_AUTO = 244; +enum KEY_BRIGHTNESS_ZERO = KEY_BRIGHTNESS_AUTO; +enum KEY_DISPLAY_OFF = 245; + +enum KEY_WWAN = 246; +enum KEY_WIMAX = KEY_WWAN; +enum KEY_RFKILL = 247; + +enum KEY_MICMUTE = 248; + +enum BTN_MISC = 0x100; +enum BTN_0 = 0x100; +enum BTN_1 = 0x101; +enum BTN_2 = 0x102; +enum BTN_3 = 0x103; +enum BTN_4 = 0x104; +enum BTN_5 = 0x105; +enum BTN_6 = 0x106; +enum BTN_7 = 0x107; +enum BTN_8 = 0x108; +enum BTN_9 = 0x109; + +enum BTN_MOUSE = 0x110; +enum BTN_LEFT = 0x110; +enum BTN_RIGHT = 0x111; +enum BTN_MIDDLE = 0x112; +enum BTN_SIDE = 0x113; +enum BTN_EXTRA = 0x114; +enum BTN_FORWARD = 0x115; +enum BTN_BACK = 0x116; +enum BTN_TASK = 0x117; + +enum BTN_JOYSTICK = 0x120; +enum BTN_TRIGGER = 0x120; +enum BTN_THUMB = 0x121; +enum BTN_THUMB2 = 0x122; +enum BTN_TOP = 0x123; +enum BTN_TOP2 = 0x124; +enum BTN_PINKIE = 0x125; +enum BTN_BASE = 0x126; +enum BTN_BASE2 = 0x127; +enum BTN_BASE3 = 0x128; +enum BTN_BASE4 = 0x129; +enum BTN_BASE5 = 0x12a; +enum BTN_BASE6 = 0x12b; +enum BTN_DEAD = 0x12f; + +enum BTN_GAMEPAD = 0x130; +enum BTN_SOUTH = 0x130; +enum BTN_A = BTN_SOUTH; +enum BTN_EAST = 0x131; +enum BTN_B = BTN_EAST; +enum BTN_C = 0x132; +enum BTN_NORTH = 0x133; +enum BTN_X = BTN_NORTH; +enum BTN_WEST = 0x134; +enum BTN_Y = BTN_WEST; +enum BTN_Z = 0x135; +enum BTN_TL = 0x136; +enum BTN_TR = 0x137; +enum BTN_TL2 = 0x138; +enum BTN_TR2 = 0x139; +enum BTN_SELECT = 0x13a; +enum BTN_START = 0x13b; +enum BTN_MODE = 0x13c; +enum BTN_THUMBL = 0x13d; +enum BTN_THUMBR = 0x13e; + +enum BTN_DIGI = 0x140; +enum BTN_TOOL_PEN = 0x140; +enum BTN_TOOL_RUBBER = 0x141; +enum BTN_TOOL_BRUSH = 0x142; +enum BTN_TOOL_PENCIL = 0x143; +enum BTN_TOOL_AIRBRUSH = 0x144; +enum BTN_TOOL_FINGER = 0x145; +enum BTN_TOOL_MOUSE = 0x146; +enum BTN_TOOL_LENS = 0x147; +enum BTN_TOOL_QUINTTAP = 0x148; +enum BTN_STYLUS3 = 0x149; +enum BTN_TOUCH = 0x14a; +enum BTN_STYLUS = 0x14b; +enum BTN_STYLUS2 = 0x14c; +enum BTN_TOOL_DOUBLETAP = 0x14d; +enum BTN_TOOL_TRIPLETAP = 0x14e; +enum BTN_TOOL_QUADTAP = 0x14f; + +enum BTN_WHEEL = 0x150; +enum BTN_GEAR_DOWN = 0x150; +enum BTN_GEAR_UP = 0x151; + +enum KEY_OK = 0x160; +enum KEY_SELECT = 0x161; +enum KEY_GOTO = 0x162; +enum KEY_CLEAR = 0x163; +enum KEY_POWER2 = 0x164; +enum KEY_OPTION = 0x165; +enum KEY_INFO = 0x166; +enum KEY_TIME = 0x167; +enum KEY_VENDOR = 0x168; +enum KEY_ARCHIVE = 0x169; +enum KEY_PROGRAM = 0x16a; +enum KEY_CHANNEL = 0x16b; +enum KEY_FAVORITES = 0x16c; +enum KEY_EPG = 0x16d; +enum KEY_PVR = 0x16e; +enum KEY_MHP = 0x16f; +enum KEY_LANGUAGE = 0x170; +enum KEY_TITLE = 0x171; +enum KEY_SUBTITLE = 0x172; +enum KEY_ANGLE = 0x173; +enum KEY_ZOOM = 0x174; +enum KEY_MODE = 0x175; +enum KEY_KEYBOARD = 0x176; +enum KEY_SCREEN = 0x177; +enum KEY_PC = 0x178; +enum KEY_TV = 0x179; +enum KEY_TV2 = 0x17a; +enum KEY_VCR = 0x17b; +enum KEY_VCR2 = 0x17c; +enum KEY_SAT = 0x17d; +enum KEY_SAT2 = 0x17e; +enum KEY_CD = 0x17f; +enum KEY_TAPE = 0x180; +enum KEY_RADIO = 0x181; +enum KEY_TUNER = 0x182; +enum KEY_PLAYER = 0x183; +enum KEY_TEXT = 0x184; +enum KEY_DVD = 0x185; +enum KEY_AUX = 0x186; +enum KEY_MP3 = 0x187; +enum KEY_AUDIO = 0x188; +enum KEY_VIDEO = 0x189; +enum KEY_DIRECTORY = 0x18a; +enum KEY_LIST = 0x18b; +enum KEY_MEMO = 0x18c; +enum KEY_CALENDAR = 0x18d; +enum KEY_RED = 0x18e; +enum KEY_GREEN = 0x18f; +enum KEY_YELLOW = 0x190; +enum KEY_BLUE = 0x191; +enum KEY_CHANNELUP = 0x192; +enum KEY_CHANNELDOWN = 0x193; +enum KEY_FIRST = 0x194; +enum KEY_LAST = 0x195; +enum KEY_AB = 0x196; +enum KEY_NEXT = 0x197; +enum KEY_RESTART = 0x198; +enum KEY_SLOW = 0x199; +enum KEY_SHUFFLE = 0x19a; +enum KEY_BREAK = 0x19b; +enum KEY_PREVIOUS = 0x19c; +enum KEY_DIGITS = 0x19d; +enum KEY_TEEN = 0x19e; +enum KEY_TWEN = 0x19f; +enum KEY_VIDEOPHONE = 0x1a0; +enum KEY_GAMES = 0x1a1; +enum KEY_ZOOMIN = 0x1a2; +enum KEY_ZOOMOUT = 0x1a3; +enum KEY_ZOOMRESET = 0x1a4; +enum KEY_WORDPROCESSOR = 0x1a5; +enum KEY_EDITOR = 0x1a6; +enum KEY_SPREADSHEET = 0x1a7; +enum KEY_GRAPHICSEDITOR = 0x1a8; +enum KEY_PRESENTATION = 0x1a9; +enum KEY_DATABASE = 0x1aa; +enum KEY_NEWS = 0x1ab; +enum KEY_VOICEMAIL = 0x1ac; +enum KEY_ADDRESSBOOK = 0x1ad; +enum KEY_MESSENGER = 0x1ae; +enum KEY_DISPLAYTOGGLE = 0x1af; +enum KEY_BRIGHTNESS_TOGGLE = KEY_DISPLAYTOGGLE; +enum KEY_SPELLCHECK = 0x1b0; +enum KEY_LOGOFF = 0x1b1; + +enum KEY_DOLLAR = 0x1b2; +enum KEY_EURO = 0x1b3; + +enum KEY_FRAMEBACK = 0x1b4; +enum KEY_FRAMEFORWARD = 0x1b5; +enum KEY_CONTEXT_MENU = 0x1b6; +enum KEY_MEDIA_REPEAT = 0x1b7; +enum KEY_10CHANNELSUP = 0x1b8; +enum KEY_10CHANNELSDOWN = 0x1b9; +enum KEY_IMAGES = 0x1ba; + +enum KEY_DEL_EOL = 0x1c0; +enum KEY_DEL_EOS = 0x1c1; +enum KEY_INS_LINE = 0x1c2; +enum KEY_DEL_LINE = 0x1c3; + +enum KEY_FN = 0x1d0; +enum KEY_FN_ESC = 0x1d1; +enum KEY_FN_F1 = 0x1d2; +enum KEY_FN_F2 = 0x1d3; +enum KEY_FN_F3 = 0x1d4; +enum KEY_FN_F4 = 0x1d5; +enum KEY_FN_F5 = 0x1d6; +enum KEY_FN_F6 = 0x1d7; +enum KEY_FN_F7 = 0x1d8; +enum KEY_FN_F8 = 0x1d9; +enum KEY_FN_F9 = 0x1da; +enum KEY_FN_F10 = 0x1db; +enum KEY_FN_F11 = 0x1dc; +enum KEY_FN_F12 = 0x1dd; +enum KEY_FN_1 = 0x1de; +enum KEY_FN_2 = 0x1df; +enum KEY_FN_D = 0x1e0; +enum KEY_FN_E = 0x1e1; +enum KEY_FN_F = 0x1e2; +enum KEY_FN_S = 0x1e3; +enum KEY_FN_B = 0x1e4; + +enum KEY_BRL_DOT1 = 0x1f1; +enum KEY_BRL_DOT2 = 0x1f2; +enum KEY_BRL_DOT3 = 0x1f3; +enum KEY_BRL_DOT4 = 0x1f4; +enum KEY_BRL_DOT5 = 0x1f5; +enum KEY_BRL_DOT6 = 0x1f6; +enum KEY_BRL_DOT7 = 0x1f7; +enum KEY_BRL_DOT8 = 0x1f8; +enum KEY_BRL_DOT9 = 0x1f9; +enum KEY_BRL_DOT10 = 0x1fa; + +enum KEY_NUMERIC_0 = 0x200; +enum KEY_NUMERIC_1 = 0x201; +enum KEY_NUMERIC_2 = 0x202; +enum KEY_NUMERIC_3 = 0x203; +enum KEY_NUMERIC_4 = 0x204; +enum KEY_NUMERIC_5 = 0x205; +enum KEY_NUMERIC_6 = 0x206; +enum KEY_NUMERIC_7 = 0x207; +enum KEY_NUMERIC_8 = 0x208; +enum KEY_NUMERIC_9 = 0x209; +enum KEY_NUMERIC_STAR = 0x20a; +enum KEY_NUMERIC_POUND = 0x20b; +enum KEY_NUMERIC_A = 0x20c; +enum KEY_NUMERIC_B = 0x20d; +enum KEY_NUMERIC_C = 0x20e; +enum KEY_NUMERIC_D = 0x20f; + +enum KEY_CAMERA_FOCUS = 0x210; +enum KEY_WPS_BUTTON = 0x211; + +enum KEY_TOUCHPAD_TOGGLE = 0x212; +enum KEY_TOUCHPAD_ON = 0x213; +enum KEY_TOUCHPAD_OFF = 0x214; + +enum KEY_CAMERA_ZOOMIN = 0x215; +enum KEY_CAMERA_ZOOMOUT = 0x216; +enum KEY_CAMERA_UP = 0x217; +enum KEY_CAMERA_DOWN = 0x218; +enum KEY_CAMERA_LEFT = 0x219; +enum KEY_CAMERA_RIGHT = 0x21a; + +enum KEY_ATTENDANT_ON = 0x21b; +enum KEY_ATTENDANT_OFF = 0x21c; +enum KEY_ATTENDANT_TOGGLE = 0x21d; +enum KEY_LIGHTS_TOGGLE = 0x21e; + +enum BTN_DPAD_UP = 0x220; +enum BTN_DPAD_DOWN = 0x221; +enum BTN_DPAD_LEFT = 0x222; +enum BTN_DPAD_RIGHT = 0x223; + +enum KEY_ALS_TOGGLE = 0x230; +enum KEY_ROTATE_LOCK_TOGGLE = 0x231; + +enum KEY_BUTTONCONFIG = 0x240; +enum KEY_TASKMANAGER = 0x241; +enum KEY_JOURNAL = 0x242; +enum KEY_CONTROLPANEL = 0x243; +enum KEY_APPSELECT = 0x244; +enum KEY_SCREENSAVER = 0x245; +enum KEY_VOICECOMMAND = 0x246; +enum KEY_ASSISTANT = 0x247; + +enum KEY_BRIGHTNESS_MIN = 0x250; +enum KEY_BRIGHTNESS_MAX = 0x251; + +enum KEY_KBDINPUTASSIST_PREV = 0x260; +enum KEY_KBDINPUTASSIST_NEXT = 0x261; +enum KEY_KBDINPUTASSIST_PREVGROUP = 0x262; +enum KEY_KBDINPUTASSIST_NEXTGROUP = 0x263; +enum KEY_KBDINPUTASSIST_ACCEPT = 0x264; +enum KEY_KBDINPUTASSIST_CANCEL = 0x265; + +enum KEY_RIGHT_UP = 0x266; +enum KEY_RIGHT_DOWN = 0x267; +enum KEY_LEFT_UP = 0x268; +enum KEY_LEFT_DOWN = 0x269; + +enum KEY_ROOT_MENU = 0x26a; +enum KEY_MEDIA_TOP_MENU = 0x26b; +enum KEY_NUMERIC_11 = 0x26c; +enum KEY_NUMERIC_12 = 0x26d; +enum KEY_AUDIO_DESC = 0x26e; +enum KEY_3D_MODE = 0x26f; +enum KEY_NEXT_FAVORITE = 0x270; +enum KEY_STOP_RECORD = 0x271; +enum KEY_PAUSE_RECORD = 0x272; +enum KEY_VOD = 0x273; +enum KEY_UNMUTE = 0x274; +enum KEY_FASTREVERSE = 0x275; +enum KEY_SLOWREVERSE = 0x276; +enum KEY_DATA = 0x277; +enum KEY_ONSCREEN_KEYBOARD = 0x278; + +enum BTN_TRIGGER_HAPPY = 0x2c0; +enum BTN_TRIGGER_HAPPY1 = 0x2c0; +enum BTN_TRIGGER_HAPPY2 = 0x2c1; +enum BTN_TRIGGER_HAPPY3 = 0x2c2; +enum BTN_TRIGGER_HAPPY4 = 0x2c3; +enum BTN_TRIGGER_HAPPY5 = 0x2c4; +enum BTN_TRIGGER_HAPPY6 = 0x2c5; +enum BTN_TRIGGER_HAPPY7 = 0x2c6; +enum BTN_TRIGGER_HAPPY8 = 0x2c7; +enum BTN_TRIGGER_HAPPY9 = 0x2c8; +enum BTN_TRIGGER_HAPPY10 = 0x2c9; +enum BTN_TRIGGER_HAPPY11 = 0x2ca; +enum BTN_TRIGGER_HAPPY12 = 0x2cb; +enum BTN_TRIGGER_HAPPY13 = 0x2cc; +enum BTN_TRIGGER_HAPPY14 = 0x2cd; +enum BTN_TRIGGER_HAPPY15 = 0x2ce; +enum BTN_TRIGGER_HAPPY16 = 0x2cf; +enum BTN_TRIGGER_HAPPY17 = 0x2d0; +enum BTN_TRIGGER_HAPPY18 = 0x2d1; +enum BTN_TRIGGER_HAPPY19 = 0x2d2; +enum BTN_TRIGGER_HAPPY20 = 0x2d3; +enum BTN_TRIGGER_HAPPY21 = 0x2d4; +enum BTN_TRIGGER_HAPPY22 = 0x2d5; +enum BTN_TRIGGER_HAPPY23 = 0x2d6; +enum BTN_TRIGGER_HAPPY24 = 0x2d7; +enum BTN_TRIGGER_HAPPY25 = 0x2d8; +enum BTN_TRIGGER_HAPPY26 = 0x2d9; +enum BTN_TRIGGER_HAPPY27 = 0x2da; +enum BTN_TRIGGER_HAPPY28 = 0x2db; +enum BTN_TRIGGER_HAPPY29 = 0x2dc; +enum BTN_TRIGGER_HAPPY30 = 0x2dd; +enum BTN_TRIGGER_HAPPY31 = 0x2de; +enum BTN_TRIGGER_HAPPY32 = 0x2df; +enum BTN_TRIGGER_HAPPY33 = 0x2e0; +enum BTN_TRIGGER_HAPPY34 = 0x2e1; +enum BTN_TRIGGER_HAPPY35 = 0x2e2; +enum BTN_TRIGGER_HAPPY36 = 0x2e3; +enum BTN_TRIGGER_HAPPY37 = 0x2e4; +enum BTN_TRIGGER_HAPPY38 = 0x2e5; +enum BTN_TRIGGER_HAPPY39 = 0x2e6; +enum BTN_TRIGGER_HAPPY40 = 0x2e7; + +enum KEY_MIN_INTERESTING = KEY_MUTE; +enum KEY_MAX = 0x2ff; +enum KEY_CNT = (KEY_MAX+1); + +enum REL_X = 0x00; +enum REL_Y = 0x01; +enum REL_Z = 0x02; +enum REL_RX = 0x03; +enum REL_RY = 0x04; +enum REL_RZ = 0x05; +enum REL_HWHEEL = 0x06; +enum REL_DIAL = 0x07; +enum REL_WHEEL = 0x08; +enum REL_MISC = 0x09; +enum REL_MAX = 0x0f; +enum REL_CNT = (REL_MAX+1); + +enum ABS_X = 0x00; +enum ABS_Y = 0x01; +enum ABS_Z = 0x02; +enum ABS_RX = 0x03; +enum ABS_RY = 0x04; +enum ABS_RZ = 0x05; +enum ABS_THROTTLE = 0x06; +enum ABS_RUDDER = 0x07; +enum ABS_WHEEL = 0x08; +enum ABS_GAS = 0x09; +enum ABS_BRAKE = 0x0a; +enum ABS_HAT0X = 0x10; +enum ABS_HAT0Y = 0x11; +enum ABS_HAT1X = 0x12; +enum ABS_HAT1Y = 0x13; +enum ABS_HAT2X = 0x14; +enum ABS_HAT2Y = 0x15; +enum ABS_HAT3X = 0x16; +enum ABS_HAT3Y = 0x17; +enum ABS_PRESSURE = 0x18; +enum ABS_DISTANCE = 0x19; +enum ABS_TILT_X = 0x1a; +enum ABS_TILT_Y = 0x1b; +enum ABS_TOOL_WIDTH = 0x1c; + +enum ABS_VOLUME = 0x20; + +enum ABS_MISC = 0x28; + +enum ABS_MT_SLOT = 0x2f; +enum ABS_MT_TOUCH_MAJOR = 0x30; +enum ABS_MT_TOUCH_MINOR = 0x31; +enum ABS_MT_WIDTH_MAJOR = 0x32; +enum ABS_MT_WIDTH_MINOR = 0x33; +enum ABS_MT_ORIENTATION = 0x34; +enum ABS_MT_POSITION_X = 0x35; +enum ABS_MT_POSITION_Y = 0x36; +enum ABS_MT_TOOL_TYPE = 0x37; +enum ABS_MT_BLOB_ID = 0x38; +enum ABS_MT_TRACKING_ID = 0x39; +enum ABS_MT_PRESSURE = 0x3a; +enum ABS_MT_DISTANCE = 0x3b; +enum ABS_MT_TOOL_X = 0x3c; +enum ABS_MT_TOOL_Y = 0x3d; + +enum ABS_MAX = 0x3f; +enum ABS_CNT = (ABS_MAX+1); + +enum SW_LID = 0x00; +enum SW_TABLET_MODE = 0x01; +enum SW_HEADPHONE_INSERT = 0x02; +enum SW_RFKILL_ALL = 0x03; +enum SW_RADIO = SW_RFKILL_ALL; +enum SW_MICROPHONE_INSERT = 0x04; +enum SW_DOCK = 0x05; +enum SW_LINEOUT_INSERT = 0x06; +enum SW_JACK_PHYSICAL_INSERT = 0x07; +enum SW_VIDEOOUT_INSERT = 0x08; +enum SW_CAMERA_LENS_COVER = 0x09; +enum SW_KEYPAD_SLIDE = 0x0a; +enum SW_FRONT_PROXIMITY = 0x0b; +enum SW_ROTATE_LOCK = 0x0c; +enum SW_LINEIN_INSERT = 0x0d; +enum SW_MUTE_DEVICE = 0x0e; +enum SW_PEN_INSERTED = 0x0f; +enum SW_MAX = 0x0f; +enum SW_CNT = (SW_MAX+1); + +enum MSC_SERIAL = 0x00; +enum MSC_PULSELED = 0x01; +enum MSC_GESTURE = 0x02; +enum MSC_RAW = 0x03; +enum MSC_SCAN = 0x04; +enum MSC_TIMESTAMP = 0x05; +enum MSC_MAX = 0x07; +enum MSC_CNT = (MSC_MAX+1); + +enum LED_NUML = 0x00; +enum LED_CAPSL = 0x01; +enum LED_SCROLLL = 0x02; +enum LED_COMPOSE = 0x03; +enum LED_KANA = 0x04; +enum LED_SLEEP = 0x05; +enum LED_SUSPEND = 0x06; +enum LED_MUTE = 0x07; +enum LED_MISC = 0x08; +enum LED_MAIL = 0x09; +enum LED_CHARGING = 0x0a; +enum LED_MAX = 0x0f; +enum LED_CNT = (LED_MAX+1); + +enum REP_DELAY = 0x00; +enum REP_PERIOD = 0x01; +enum REP_MAX = 0x01; +enum REP_CNT = (REP_MAX+1); + +enum SND_CLICK = 0x00; +enum SND_BELL = 0x01; +enum SND_TONE = 0x02; +enum SND_MAX = 0x07; +enum SND_CNT = (SND_MAX+1); diff --git a/runtime/druntime/src/core/sys/linux/uinput.d b/runtime/druntime/src/core/sys/linux/uinput.d new file mode 100644 index 00000000000..abb61f919c2 --- /dev/null +++ b/runtime/druntime/src/core/sys/linux/uinput.d @@ -0,0 +1,85 @@ +module core.sys.linux.uinput; + +version (linux): +extern(C): +nothrow: + +import core.sys.posix.sys.ioctl; + +public import core.sys.linux.input; +public import core.sys.linux.input_event_codes; + +enum UINPUT_VERSION = 5; +enum UINPUT_MAX_NAME_SIZE = 80; + +struct uinput_ff_upload +{ + uint request_id; + int retval; + ff_effect effect; + ff_effect old; +} + +struct uinput_ff_erase +{ + uint request_id; + int retval; + uint effect_id; +} + +enum UINPUT_IOCTL_BASE = 'U'; +enum UI_DEV_CREATE = _IO(UINPUT_IOCTL_BASE, 1); +enum UI_DEV_DESTROY = _IO(UINPUT_IOCTL_BASE, 2); + +struct uinput_setup +{ + input_id id; + char[UINPUT_MAX_NAME_SIZE] name; + uint ff_effects_max; +} + +enum UI_DEV_SETUP = _IOW!uinput_setup(UINPUT_IOCTL_BASE, 3); + +struct uinput_abs_setup +{ + ushort code; + + input_absinfo absinfo; +} + +enum UI_ABS_SETUP = _IOW!uinput_abs_setup(UINPUT_IOCTL_BASE, 4); + +enum UI_SET_EVBIT = _IOW!int(UINPUT_IOCTL_BASE, 100); +enum UI_SET_KEYBIT = _IOW!int(UINPUT_IOCTL_BASE, 101); +enum UI_SET_RELBIT = _IOW!int(UINPUT_IOCTL_BASE, 102); +enum UI_SET_ABSBIT = _IOW!int(UINPUT_IOCTL_BASE, 103); +enum UI_SET_MSCBIT = _IOW!int(UINPUT_IOCTL_BASE, 104); +enum UI_SET_LEDBIT = _IOW!int(UINPUT_IOCTL_BASE, 105); +enum UI_SET_SNDBIT = _IOW!int(UINPUT_IOCTL_BASE, 106); +enum UI_SET_FFBIT = _IOW!int(UINPUT_IOCTL_BASE, 107); +enum UI_SET_PHYS = _IOW!(char*)(UINPUT_IOCTL_BASE, 108); +enum UI_SET_SWBIT = _IOW!int(UINPUT_IOCTL_BASE, 109); +enum UI_SET_PROPBIT = _IOW!int(UINPUT_IOCTL_BASE, 110); + +enum UI_BEGIN_FF_UPLOAD = _IOWR!uinput_ff_upload(UINPUT_IOCTL_BASE, 200); +enum UI_END_FF_UPLOAD = _IOW!uinput_ff_upload(UINPUT_IOCTL_BASE, 201); +enum UI_BEGIN_FF_ERASE = _IOWR!uinput_ff_erase(UINPUT_IOCTL_BASE, 202); +enum UI_END_FF_ERASE = _IOW!uinput_ff_erase(UINPUT_IOCTL_BASE, 203); + +enum UI_GET_SYSNAME(len) = _IOC(_IOC_READ, UINPUT_IOCTL_BASE, 44, len); + +enum UI_GET_VERSION = _IOR!uint(UINPUT_IOCTL_BASE, 45); + +enum EV_UINPUT = 0x0101; +enum UI_FF_UPLOAD = 1; +enum UI_FF_ERASE = 2; + +struct uinput_user_dev { + char[UINPUT_MAX_NAME_SIZE] name; + input_id id; + uint ff_effects_max; + int[ABS_CNT] absmax; + int[ABS_CNT] absmin; + int[ABS_CNT] absfuzz; + int[ABS_CNT] absflat; +} From cfd3f9b951b38a96e2e5b2bbffb6192b3741a5bb Mon Sep 17 00:00:00 2001 From: Razvan Nitu Date: Wed, 21 Jun 2023 10:30:23 +0300 Subject: [PATCH 077/176] Fix Issue 23968 - Deprecation not emitted with alias to template function in UFCS (dlang/dmd!15317) --- dmd/expressionsem.d | 9 +++++++++ tests/dmd/fail_compilation/test23968.d | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 tests/dmd/fail_compilation/test23968.d diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index d382930cd3b..02c2fae9a54 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -489,6 +489,15 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident) if (auto dti = ue.isDotTemplateInstanceExp()) { + // https://issues.dlang.org/show_bug.cgi?id=23968 + // Typically, deprecated alias declarations are caught + // when `TemplateInstance.findTempDecl` is called, + // however, in this case the tempdecl field is updated + // therefore `findTempDecl` will return immediately + // and not get the chance to issue the deprecation. + if (s.isAliasDeclaration()) + s.checkDeprecated(ue.loc, sc); + auto ti = new TemplateInstance(loc, s.ident, dti.ti.tiargs); if (!ti.updateTempDecl(sc, s)) return ErrorExp.get(); diff --git a/tests/dmd/fail_compilation/test23968.d b/tests/dmd/fail_compilation/test23968.d new file mode 100644 index 00000000000..4456e75c707 --- /dev/null +++ b/tests/dmd/fail_compilation/test23968.d @@ -0,0 +1,23 @@ +// https://issues.dlang.org/show_bug.cgi?id=23968 + +// REQUIRED_ARGS: -de + +/* +TEST_OUTPUT: +--- +fail_compilation/test23968.d(22): Deprecation: alias `test23968.a` is deprecated +--- +*/ + +int fun()(int) +{ + return 0; +} + +deprecated alias a = fun; + +void main() +{ + int v; + int y = v.a!(); // No deprecation? +} From c8d455a1dae9c339294acd27d01c6f0b72b6410f Mon Sep 17 00:00:00 2001 From: Razvan Nitu Date: Wed, 21 Jun 2023 14:16:55 +0300 Subject: [PATCH 078/176] Fix Issue 23971 - Provide clearer error message when trying to return a slice with C++ linkage (dlang/dmd!15336) --- dmd/semantic3.d | 2 ++ tests/dmd/fail_compilation/fail16772.d | 3 ++- tests/dmd/fail_compilation/fail21206.d | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/dmd/semantic3.d b/dmd/semantic3.d index aa04f935cd3..a8c79e7a334 100644 --- a/dmd/semantic3.d +++ b/dmd/semantic3.d @@ -1367,6 +1367,8 @@ private extern(C++) final class Semantic3Visitor : Visitor if (isCppNonMappableType(f.next.toBasetype())) { funcdecl.error("cannot return type `%s` because its linkage is `extern(C++)`", f.next.toChars()); + if (f.next.isTypeDArray()) + errorSupplemental(funcdecl.loc, "slices are specific to D and do not have a counterpart representation in C++", f.next.toChars()); funcdecl.errors = true; } foreach (i, param; f.parameterList) diff --git a/tests/dmd/fail_compilation/fail16772.d b/tests/dmd/fail_compilation/fail16772.d index e77951d3302..0bc97512c9a 100644 --- a/tests/dmd/fail_compilation/fail16772.d +++ b/tests/dmd/fail_compilation/fail16772.d @@ -1,7 +1,8 @@ // https://issues.dlang.org/show_bug.cgi?id=16772 /* TEST_OUTPUT: --- -fail_compilation/fail16772.d(7): Error: function `fail16772.ice16772` cannot return type `ubyte[]` because its linkage is `extern(C++)` +fail_compilation/fail16772.d(8): Error: function `fail16772.ice16772` cannot return type `ubyte[]` because its linkage is `extern(C++)` +fail_compilation/fail16772.d(8): slices are specific to D and do not have a counterpart representation in C++ --- */ extern(C++) ubyte[] ice16772() { return []; } diff --git a/tests/dmd/fail_compilation/fail21206.d b/tests/dmd/fail_compilation/fail21206.d index c3d648e5d75..b3b42f34296 100644 --- a/tests/dmd/fail_compilation/fail21206.d +++ b/tests/dmd/fail_compilation/fail21206.d @@ -1,7 +1,8 @@ // https://issues.dlang.org/show_bug.cgi?id=21206 /* TEST_OUTPUT: --- -fail_compilation/fail21206.d(9): Error: function `fail21206.Obj.toString` cannot return type `string` because its linkage is `extern(C++)` +fail_compilation/fail21206.d(10): Error: function `fail21206.Obj.toString` cannot return type `string` because its linkage is `extern(C++)` +fail_compilation/fail21206.d(10): slices are specific to D and do not have a counterpart representation in C++ --- */ extern(C++) struct Obj From a795ab140ce2f530a6d19d2f81695bd91c9162e3 Mon Sep 17 00:00:00 2001 From: Dennis Date: Fri, 23 Jun 2023 13:57:49 +0200 Subject: [PATCH 079/176] Remove unused imports (dlang/dmd!15341) --- dmd/access.d | 4 ---- dmd/asttypename.d | 1 - 2 files changed, 5 deletions(-) diff --git a/dmd/access.d b/dmd/access.d index f2d68d53d75..668129a5385 100644 --- a/dmd/access.d +++ b/dmd/access.d @@ -16,17 +16,13 @@ module dmd.access; import dmd.aggregate; import dmd.astenums; import dmd.dclass; -import dmd.declaration; import dmd.dmodule; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; -import dmd.errors; import dmd.expression; -import dmd.func; import dmd.globals; import dmd.location; -import dmd.mtype; import dmd.tokens; private enum LOG = false; diff --git a/dmd/asttypename.d b/dmd/asttypename.d index 53cde6ea284..d3ac6eaf9b5 100644 --- a/dmd/asttypename.d +++ b/dmd/asttypename.d @@ -35,7 +35,6 @@ import dmd.mtype; import dmd.typinf; import dmd.identifier; import dmd.init; -import dmd.doc; import dmd.root.complex; import dmd.root.rootobject; import dmd.statement; From 43594661d25f35fceb5ec6aa8290f2ec969dbe19 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Mon, 26 Jun 2023 08:07:10 +0100 Subject: [PATCH 080/176] Improve repeated integer suffix error message (dlang/dmd!15342) --- dmd/lexer.d | 2 +- tests/dmd/fail_compilation/lexer4.d | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dmd/lexer.d b/dmd/lexer.d index a878cc9523d..add1ce68468 100644 --- a/dmd/lexer.d +++ b/dmd/lexer.d @@ -2205,7 +2205,7 @@ class Lexer p++; if ((flags & f) && !err) { - error("unrecognized token"); + error("repeated integer suffix `%c`", p[-1]); err = true; } flags = cast(FLAGS)(flags | f); diff --git a/tests/dmd/fail_compilation/lexer4.d b/tests/dmd/fail_compilation/lexer4.d index c9db26434df..c4bdb4fd64c 100644 --- a/tests/dmd/fail_compilation/lexer4.d +++ b/tests/dmd/fail_compilation/lexer4.d @@ -8,7 +8,7 @@ fail_compilation/lexer4.d(26): Error: binary digit expected, not `2` fail_compilation/lexer4.d(27): Error: octal digit expected, not `8` fail_compilation/lexer4.d(27): Error: octal literals larger than 7 are no longer supported fail_compilation/lexer4.d(28): Error: decimal digit expected, not `a` -fail_compilation/lexer4.d(29): Error: unrecognized token +fail_compilation/lexer4.d(29): Error: repeated integer suffix `U` fail_compilation/lexer4.d(30): Error: exponent required for hex float fail_compilation/lexer4.d(31): Error: lower case integer suffix 'l' is not allowed. Please use 'L' instead fail_compilation/lexer4.d(32): Error: use 'i' suffix instead of 'I' From 8ae2e4dd465ba641d31b319a835665b345028494 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Mon, 26 Jun 2023 13:00:34 +0100 Subject: [PATCH 081/176] =?UTF-8?q?Fix=20Issue=2024000=20-=20show=20open?= =?UTF-8?q?=20bracket=20"{"=20location=20for=20Error:=20matching=20?= =?UTF-8?q?=E2=80=A6=20(dlang/dmd!15334)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix Issue 24000 - show open bracket "{" location for Error: matching `}` expected * Show unmatched brace after compound statement * Update tests --- dmd/parse.d | 12 +++++- tests/dmd/fail_compilation/e15876_1.d | 13 ++++--- tests/dmd/fail_compilation/e15876_2.d | 9 +++-- tests/dmd/fail_compilation/e15876_3.d | 27 ++++++------- tests/dmd/fail_compilation/e15876_4.d | 23 +++++------ tests/dmd/fail_compilation/e15876_5.d | 11 +++--- tests/dmd/fail_compilation/fail196.d | 38 ++++++++++--------- tests/dmd/fail_compilation/fail315.d | 15 ++++---- tests/dmd/fail_compilation/ice11965.d | 9 +++-- tests/dmd/fail_compilation/ice11982.d | 17 +++++---- tests/dmd/fail_compilation/ice15855.d | 21 +++++----- .../fail_compilation/misc_parser_err_cov1.d | 3 +- tests/dmd/fail_compilation/missingbrace.d | 10 +++++ tests/dmd/fail_compilation/unmatchedbrace.d | 10 +++++ 14 files changed, 130 insertions(+), 88 deletions(-) create mode 100644 tests/dmd/fail_compilation/missingbrace.d create mode 100644 tests/dmd/fail_compilation/unmatchedbrace.d diff --git a/dmd/parse.d b/dmd/parse.d index 8c0a1b13c99..eeaef8d7d8b 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -1155,6 +1155,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.leftCurly: { + const lcLoc = token.loc; const lookingForElseSave = lookingForElse; lookingForElse = Loc(); @@ -1164,6 +1165,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { /* { */ error("matching `}` expected, not `%s`", token.toChars()); + eSink.errorSupplemental(lcLoc, "unmatched `{`"); } else nextToken(); @@ -6015,6 +6017,7 @@ LagainStc: } case TOK.leftCurly: { + const lcLoc = token.loc; const lookingForElseSave = lookingForElse; lookingForElse = Loc.initial; @@ -6037,7 +6040,14 @@ LagainStc: s = new AST.CompoundStatement(loc, statements); if (flags & (ParseStatementFlags.scope_ | ParseStatementFlags.curlyScope)) s = new AST.ScopeStatement(loc, s, token.loc); - check(TOK.rightCurly, "compound statement"); + if (token.value != TOK.rightCurly) + { + error(token.loc, "matching `}` expected following compound statement, not `%s`", + token.toChars()); + eSink.errorSupplemental(lcLoc, "unmatched `{`"); + } + else + nextToken(); lookingForElse = lookingForElseSave; break; } diff --git a/tests/dmd/fail_compilation/e15876_1.d b/tests/dmd/fail_compilation/e15876_1.d index 92e07342d49..0152cdee276 100644 --- a/tests/dmd/fail_compilation/e15876_1.d +++ b/tests/dmd/fail_compilation/e15876_1.d @@ -1,12 +1,13 @@ /* TEST_OUTPUT: --- -fail_compilation/e15876_1.d(16): Error: valid scope identifiers are `exit`, `failure`, or `success`, not `x` -fail_compilation/e15876_1.d(17): Error: found `End of File` when expecting `)` -fail_compilation/e15876_1.d(17): Error: found `End of File` instead of statement -fail_compilation/e15876_1.d(17): Error: found `End of File` when expecting `}` following compound statement -fail_compilation/e15876_1.d(17): Error: found `End of File` when expecting `]` -fail_compilation/e15876_1.d(17): Error: no identifier for declarator `o[() +fail_compilation/e15876_1.d(17): Error: valid scope identifiers are `exit`, `failure`, or `success`, not `x` +fail_compilation/e15876_1.d(18): Error: found `End of File` when expecting `)` +fail_compilation/e15876_1.d(18): Error: found `End of File` instead of statement +fail_compilation/e15876_1.d(18): Error: matching `}` expected following compound statement, not `End of File` +fail_compilation/e15876_1.d(17): unmatched `{` +fail_compilation/e15876_1.d(18): Error: found `End of File` when expecting `]` +fail_compilation/e15876_1.d(18): Error: no identifier for declarator `o[() { scope(exit) __error__ } diff --git a/tests/dmd/fail_compilation/e15876_2.d b/tests/dmd/fail_compilation/e15876_2.d index 10ff7d53a98..92164a4fd8b 100644 --- a/tests/dmd/fail_compilation/e15876_2.d +++ b/tests/dmd/fail_compilation/e15876_2.d @@ -1,10 +1,11 @@ /* TEST_OUTPUT: --- -fail_compilation/e15876_2.d(15): Error: identifier expected following `template` -fail_compilation/e15876_2.d(15): Error: found `End of File` when expecting `}` following compound statement -fail_compilation/e15876_2.d(15): Error: found `End of File` when expecting `]` -fail_compilation/e15876_2.d(15): Error: no identifier for declarator `o[() +fail_compilation/e15876_2.d(16): Error: identifier expected following `template` +fail_compilation/e15876_2.d(16): Error: matching `}` expected following compound statement, not `End of File` +fail_compilation/e15876_2.d(15): unmatched `{` +fail_compilation/e15876_2.d(16): Error: found `End of File` when expecting `]` +fail_compilation/e15876_2.d(16): Error: no identifier for declarator `o[() { ; } diff --git a/tests/dmd/fail_compilation/e15876_3.d b/tests/dmd/fail_compilation/e15876_3.d index 0ac72296639..0482e87a549 100644 --- a/tests/dmd/fail_compilation/e15876_3.d +++ b/tests/dmd/fail_compilation/e15876_3.d @@ -1,18 +1,19 @@ /* TEST_OUTPUT: --- -fail_compilation/e15876_3.d(27): Error: unexpected `(` in declarator -fail_compilation/e15876_3.d(27): Error: basic type expected, not `=` -fail_compilation/e15876_3.d(28): Error: found `End of File` when expecting `(` -fail_compilation/e15876_3.d(28): Error: found `End of File` instead of statement -fail_compilation/e15876_3.d(28): Error: expression expected, not `End of File` -fail_compilation/e15876_3.d(28): Error: found `End of File` when expecting `;` following `for` condition -fail_compilation/e15876_3.d(28): Error: expression expected, not `End of File` -fail_compilation/e15876_3.d(28): Error: found `End of File` when expecting `)` -fail_compilation/e15876_3.d(28): Error: found `End of File` instead of statement -fail_compilation/e15876_3.d(28): Error: found `End of File` when expecting `}` following compound statement -fail_compilation/e15876_3.d(28): Error: found `End of File` when expecting `)` -fail_compilation/e15876_3.d(28): Error: no identifier for declarator `d(_error_ = () +fail_compilation/e15876_3.d(28): Error: unexpected `(` in declarator +fail_compilation/e15876_3.d(28): Error: basic type expected, not `=` +fail_compilation/e15876_3.d(29): Error: found `End of File` when expecting `(` +fail_compilation/e15876_3.d(29): Error: found `End of File` instead of statement +fail_compilation/e15876_3.d(29): Error: expression expected, not `End of File` +fail_compilation/e15876_3.d(29): Error: found `End of File` when expecting `;` following `for` condition +fail_compilation/e15876_3.d(29): Error: expression expected, not `End of File` +fail_compilation/e15876_3.d(29): Error: found `End of File` when expecting `)` +fail_compilation/e15876_3.d(29): Error: found `End of File` instead of statement +fail_compilation/e15876_3.d(29): Error: matching `}` expected following compound statement, not `End of File` +fail_compilation/e15876_3.d(28): unmatched `{` +fail_compilation/e15876_3.d(29): Error: found `End of File` when expecting `)` +fail_compilation/e15876_3.d(29): Error: no identifier for declarator `d(_error_ = () { for (__error__ 0; 0) @@ -21,7 +22,7 @@ __error__ } } )` -fail_compilation/e15876_3.d(28): Error: semicolon expected following function declaration, not `End of File` +fail_compilation/e15876_3.d(29): Error: semicolon expected following function declaration, not `End of File` --- */ d(={for diff --git a/tests/dmd/fail_compilation/e15876_4.d b/tests/dmd/fail_compilation/e15876_4.d index f4bd407b9c0..e5c3bbf5673 100644 --- a/tests/dmd/fail_compilation/e15876_4.d +++ b/tests/dmd/fail_compilation/e15876_4.d @@ -1,17 +1,18 @@ /* TEST_OUTPUT: --- -fail_compilation/e15876_4.d(25): Error: found `)` when expecting `(` -fail_compilation/e15876_4.d(26): Error: found `End of File` when expecting `(` -fail_compilation/e15876_4.d(26): Error: found `End of File` instead of statement -fail_compilation/e15876_4.d(26): Error: expression expected, not `End of File` -fail_compilation/e15876_4.d(26): Error: found `End of File` when expecting `;` following `for` condition -fail_compilation/e15876_4.d(26): Error: expression expected, not `End of File` -fail_compilation/e15876_4.d(26): Error: found `End of File` when expecting `)` -fail_compilation/e15876_4.d(26): Error: found `End of File` instead of statement -fail_compilation/e15876_4.d(26): Error: found `End of File` when expecting `}` following compound statement -fail_compilation/e15876_4.d(26): Error: found `End of File` when expecting `)` -fail_compilation/e15876_4.d(26): Error: no identifier for declarator `typeof(() +fail_compilation/e15876_4.d(26): Error: found `)` when expecting `(` +fail_compilation/e15876_4.d(27): Error: found `End of File` when expecting `(` +fail_compilation/e15876_4.d(27): Error: found `End of File` instead of statement +fail_compilation/e15876_4.d(27): Error: expression expected, not `End of File` +fail_compilation/e15876_4.d(27): Error: found `End of File` when expecting `;` following `for` condition +fail_compilation/e15876_4.d(27): Error: expression expected, not `End of File` +fail_compilation/e15876_4.d(27): Error: found `End of File` when expecting `)` +fail_compilation/e15876_4.d(27): Error: found `End of File` instead of statement +fail_compilation/e15876_4.d(27): Error: matching `}` expected following compound statement, not `End of File` +fail_compilation/e15876_4.d(26): unmatched `{` +fail_compilation/e15876_4.d(27): Error: found `End of File` when expecting `)` +fail_compilation/e15876_4.d(27): Error: no identifier for declarator `typeof(() { for (__error__ 0; 0) diff --git a/tests/dmd/fail_compilation/e15876_5.d b/tests/dmd/fail_compilation/e15876_5.d index 96b23e278cd..6bebc29fcb6 100644 --- a/tests/dmd/fail_compilation/e15876_5.d +++ b/tests/dmd/fail_compilation/e15876_5.d @@ -1,11 +1,12 @@ /* TEST_OUTPUT: --- -fail_compilation/e15876_5.d(16): Error: basic type expected, not `End of File` -fail_compilation/e15876_5.d(16): Error: semicolon expected to close `alias` declaration, not `End of File` -fail_compilation/e15876_5.d(16): Error: found `End of File` when expecting `}` following compound statement -fail_compilation/e15876_5.d(16): Error: found `End of File` when expecting `]` -fail_compilation/e15876_5.d(16): Error: no identifier for declarator `p[() +fail_compilation/e15876_5.d(17): Error: basic type expected, not `End of File` +fail_compilation/e15876_5.d(17): Error: semicolon expected to close `alias` declaration, not `End of File` +fail_compilation/e15876_5.d(17): Error: matching `}` expected following compound statement, not `End of File` +fail_compilation/e15876_5.d(16): unmatched `{` +fail_compilation/e15876_5.d(17): Error: found `End of File` when expecting `]` +fail_compilation/e15876_5.d(17): Error: no identifier for declarator `p[() { alias ; } diff --git a/tests/dmd/fail_compilation/fail196.d b/tests/dmd/fail_compilation/fail196.d index 53505f496c2..cdad5c491db 100644 --- a/tests/dmd/fail_compilation/fail196.d +++ b/tests/dmd/fail_compilation/fail196.d @@ -1,24 +1,26 @@ /* TEST_OUTPUT: --- -fail_compilation/fail196.d(27): Error: delimited string must end in `)"` -fail_compilation/fail196.d(27): Error: implicit string concatenation is error-prone and disallowed in D -fail_compilation/fail196.d(27): Use the explicit syntax instead (concatenating literals is `@nogc`): "foo(xxx)" ~ ";\n assert(s == " -fail_compilation/fail196.d(28): Error: semicolon needed to end declaration of `s`, instead of `foo` -fail_compilation/fail196.d(27): `s` declared here -fail_compilation/fail196.d(28): Error: found `");\n\n s = q"` when expecting `;` following statement `foo(xxx)` on line fail_compilation/fail196.d(28) -fail_compilation/fail196.d(30): Error: found `";\n assert(s == "` when expecting `;` following statement `[foo[xxx]]` on line fail_compilation/fail196.d(30) -fail_compilation/fail196.d(31): Error: found `");\n\n s = q"` when expecting `;` following statement `foo[xxx]` on line fail_compilation/fail196.d(31) -fail_compilation/fail196.d(33): Error: found `{` when expecting `;` following statement `foo` on line fail_compilation/fail196.d(33) -fail_compilation/fail196.d(33): Error: found `}` when expecting `;` following statement `xxx` on line fail_compilation/fail196.d(33) -fail_compilation/fail196.d(34): Error: found `foo` when expecting `;` following statement `";\n assert(s == "` on line fail_compilation/fail196.d(33) -fail_compilation/fail196.d(34): Error: found `}` when expecting `;` following statement `xxx` on line fail_compilation/fail196.d(34) -fail_compilation/fail196.d(36): Error: found `<` when expecting `;` following statement `");\n\n s = q" < foo` on line fail_compilation/fail196.d(34) -fail_compilation/fail196.d(37): Error: found `foo` when expecting `;` following statement `xxx >> ";\n assert(s == "` on line fail_compilation/fail196.d(36) -fail_compilation/fail196.d(37): Error: found `<` instead of statement -fail_compilation/fail196.d(43): Error: unterminated string constant starting at fail_compilation/fail196.d(43) -fail_compilation/fail196.d(45): Error: found `End of File` when expecting `}` following compound statement -fail_compilation/fail196.d(45): Error: found `End of File` when expecting `}` following compound statement +fail_compilation/fail196.d(29): Error: delimited string must end in `)"` +fail_compilation/fail196.d(29): Error: implicit string concatenation is error-prone and disallowed in D +fail_compilation/fail196.d(29): Use the explicit syntax instead (concatenating literals is `@nogc`): "foo(xxx)" ~ ";\n assert(s == " +fail_compilation/fail196.d(30): Error: semicolon needed to end declaration of `s`, instead of `foo` +fail_compilation/fail196.d(29): `s` declared here +fail_compilation/fail196.d(30): Error: found `");\n\n s = q"` when expecting `;` following statement `foo(xxx)` on line fail_compilation/fail196.d(30) +fail_compilation/fail196.d(32): Error: found `";\n assert(s == "` when expecting `;` following statement `[foo[xxx]]` on line fail_compilation/fail196.d(32) +fail_compilation/fail196.d(33): Error: found `");\n\n s = q"` when expecting `;` following statement `foo[xxx]` on line fail_compilation/fail196.d(33) +fail_compilation/fail196.d(35): Error: found `{` when expecting `;` following statement `foo` on line fail_compilation/fail196.d(35) +fail_compilation/fail196.d(35): Error: found `}` when expecting `;` following statement `xxx` on line fail_compilation/fail196.d(35) +fail_compilation/fail196.d(36): Error: found `foo` when expecting `;` following statement `";\n assert(s == "` on line fail_compilation/fail196.d(35) +fail_compilation/fail196.d(36): Error: found `}` when expecting `;` following statement `xxx` on line fail_compilation/fail196.d(36) +fail_compilation/fail196.d(38): Error: found `<` when expecting `;` following statement `");\n\n s = q" < foo` on line fail_compilation/fail196.d(36) +fail_compilation/fail196.d(39): Error: found `foo` when expecting `;` following statement `xxx >> ";\n assert(s == "` on line fail_compilation/fail196.d(38) +fail_compilation/fail196.d(39): Error: found `<` instead of statement +fail_compilation/fail196.d(45): Error: unterminated string constant starting at fail_compilation/fail196.d(45) +fail_compilation/fail196.d(47): Error: matching `}` expected following compound statement, not `End of File` +fail_compilation/fail196.d(36): unmatched `{` +fail_compilation/fail196.d(47): Error: matching `}` expected following compound statement, not `End of File` +fail_compilation/fail196.d(28): unmatched `{` --- */ diff --git a/tests/dmd/fail_compilation/fail315.d b/tests/dmd/fail_compilation/fail315.d index c7fd78f8fc1..1a7e0f35f91 100644 --- a/tests/dmd/fail_compilation/fail315.d +++ b/tests/dmd/fail_compilation/fail315.d @@ -1,13 +1,14 @@ /* TEST_OUTPUT: --- -fail_compilation/fail315.d-mixin-16(16): Error: found `;` when expecting `,` -fail_compilation/fail315.d-mixin-16(16): Error: expression expected, not `}` -fail_compilation/fail315.d-mixin-16(16): Error: found `End of File` when expecting `,` -fail_compilation/fail315.d-mixin-16(16): Error: found `End of File` when expecting `]` -fail_compilation/fail315.d-mixin-16(16): Error: found `End of File` when expecting `;` following `return` statement -fail_compilation/fail315.d-mixin-16(16): Error: found `End of File` when expecting `}` following compound statement -fail_compilation/fail315.d(21): Error: template instance `fail315.foo!()` error instantiating +fail_compilation/fail315.d-mixin-17(17): Error: found `;` when expecting `,` +fail_compilation/fail315.d-mixin-17(17): Error: expression expected, not `}` +fail_compilation/fail315.d-mixin-17(17): Error: found `End of File` when expecting `,` +fail_compilation/fail315.d-mixin-17(17): Error: found `End of File` when expecting `]` +fail_compilation/fail315.d-mixin-17(17): Error: found `End of File` when expecting `;` following `return` statement +fail_compilation/fail315.d-mixin-17(17): Error: matching `}` expected following compound statement, not `End of File` +fail_compilation/fail315.d-mixin-17(17): unmatched `{` +fail_compilation/fail315.d(22): Error: template instance `fail315.foo!()` error instantiating --- */ diff --git a/tests/dmd/fail_compilation/ice11965.d b/tests/dmd/fail_compilation/ice11965.d index c8db60fe9c9..9e6da3bbf84 100644 --- a/tests/dmd/fail_compilation/ice11965.d +++ b/tests/dmd/fail_compilation/ice11965.d @@ -1,10 +1,11 @@ /* TEST_OUTPUT: --- -fail_compilation/ice11965.d(15): Error: no identifier for declarator `b*` -fail_compilation/ice11965.d(15): Error: found `End of File` when expecting `}` following compound statement -fail_compilation/ice11965.d(15): Error: found `End of File` when expecting `]` -fail_compilation/ice11965.d(15): Error: no identifier for declarator `u[() +fail_compilation/ice11965.d(16): Error: no identifier for declarator `b*` +fail_compilation/ice11965.d(16): Error: matching `}` expected following compound statement, not `End of File` +fail_compilation/ice11965.d(15): unmatched `{` +fail_compilation/ice11965.d(16): Error: found `End of File` when expecting `]` +fail_compilation/ice11965.d(16): Error: no identifier for declarator `u[() { b* A; } diff --git a/tests/dmd/fail_compilation/ice11982.d b/tests/dmd/fail_compilation/ice11982.d index 0f2ce413c40..0886df61678 100644 --- a/tests/dmd/fail_compilation/ice11982.d +++ b/tests/dmd/fail_compilation/ice11982.d @@ -1,19 +1,20 @@ /* TEST_OUTPUT: --- -fail_compilation/ice11982.d(19): Error: basic type expected, not `scope` -fail_compilation/ice11982.d(19): Error: found `scope` when expecting `;` following statement `new _error_` on line fail_compilation/ice11982.d(19) -fail_compilation/ice11982.d(19): Error: basic type expected, not `}` -fail_compilation/ice11982.d(19): Error: missing `{ ... }` for function literal -fail_compilation/ice11982.d(19): Error: C style cast illegal, use `cast(funk)function _error_() +fail_compilation/ice11982.d(20): Error: basic type expected, not `scope` +fail_compilation/ice11982.d(20): Error: found `scope` when expecting `;` following statement `new _error_` on line fail_compilation/ice11982.d(20) +fail_compilation/ice11982.d(20): Error: basic type expected, not `}` +fail_compilation/ice11982.d(20): Error: missing `{ ... }` for function literal +fail_compilation/ice11982.d(20): Error: C style cast illegal, use `cast(funk)function _error_() { } ` -fail_compilation/ice11982.d(19): Error: found `}` when expecting `;` following statement `cast(funk)function _error_() +fail_compilation/ice11982.d(20): Error: found `}` when expecting `;` following statement `cast(funk)function _error_() { } -` on line fail_compilation/ice11982.d(19) -fail_compilation/ice11982.d(20): Error: found `End of File` when expecting `}` following compound statement +` on line fail_compilation/ice11982.d(20) +fail_compilation/ice11982.d(21): Error: matching `}` expected following compound statement, not `End of File` +fail_compilation/ice11982.d(20): unmatched `{` --- */ void main() { new scope ( funk ) function } diff --git a/tests/dmd/fail_compilation/ice15855.d b/tests/dmd/fail_compilation/ice15855.d index b26fe4cda04..f7ad3900683 100644 --- a/tests/dmd/fail_compilation/ice15855.d +++ b/tests/dmd/fail_compilation/ice15855.d @@ -2,16 +2,17 @@ /* TEST_OUTPUT: --- -fail_compilation/ice15855.d(27): Error: found `End of File` when expecting `(` -fail_compilation/ice15855.d(27): Error: found `End of File` instead of statement -fail_compilation/ice15855.d(27): Error: expression expected, not `End of File` -fail_compilation/ice15855.d(27): Error: found `End of File` when expecting `;` following `for` condition -fail_compilation/ice15855.d(27): Error: expression expected, not `End of File` -fail_compilation/ice15855.d(27): Error: found `End of File` when expecting `)` -fail_compilation/ice15855.d(27): Error: found `End of File` instead of statement -fail_compilation/ice15855.d(27): Error: found `End of File` when expecting `}` following compound statement -fail_compilation/ice15855.d(27): Error: found `End of File` when expecting `]` -fail_compilation/ice15855.d(27): Error: no identifier for declarator `a[() +fail_compilation/ice15855.d(28): Error: found `End of File` when expecting `(` +fail_compilation/ice15855.d(28): Error: found `End of File` instead of statement +fail_compilation/ice15855.d(28): Error: expression expected, not `End of File` +fail_compilation/ice15855.d(28): Error: found `End of File` when expecting `;` following `for` condition +fail_compilation/ice15855.d(28): Error: expression expected, not `End of File` +fail_compilation/ice15855.d(28): Error: found `End of File` when expecting `)` +fail_compilation/ice15855.d(28): Error: found `End of File` instead of statement +fail_compilation/ice15855.d(28): Error: matching `}` expected following compound statement, not `End of File` +fail_compilation/ice15855.d(27): unmatched `{` +fail_compilation/ice15855.d(28): Error: found `End of File` when expecting `]` +fail_compilation/ice15855.d(28): Error: no identifier for declarator `a[() { for (__error__ 0; 0) diff --git a/tests/dmd/fail_compilation/misc_parser_err_cov1.d b/tests/dmd/fail_compilation/misc_parser_err_cov1.d index d1361440920..a719b123a6a 100644 --- a/tests/dmd/fail_compilation/misc_parser_err_cov1.d +++ b/tests/dmd/fail_compilation/misc_parser_err_cov1.d @@ -24,7 +24,8 @@ fail_compilation/misc_parser_err_cov1.d(40): Error: identifier or `new` expected fail_compilation/misc_parser_err_cov1.d(41): Error: identifier or new keyword expected following `(...)`. fail_compilation/misc_parser_err_cov1.d(41): Error: expression expected, not `;` fail_compilation/misc_parser_err_cov1.d(42): Error: found `}` when expecting `;` following statement `(__error) + 0` on line fail_compilation/misc_parser_err_cov1.d(41) -fail_compilation/misc_parser_err_cov1.d(43): Error: found `End of File` when expecting `}` following compound statement +fail_compilation/misc_parser_err_cov1.d(43): Error: matching `}` expected following compound statement, not `End of File` +fail_compilation/misc_parser_err_cov1.d(33): unmatched `{` --- */ module misc_parser_err_cov1; diff --git a/tests/dmd/fail_compilation/missingbrace.d b/tests/dmd/fail_compilation/missingbrace.d new file mode 100644 index 00000000000..5c8166eaa6e --- /dev/null +++ b/tests/dmd/fail_compilation/missingbrace.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/missingbrace.d(11): Error: matching `}` expected following compound statement, not `End of File` +fail_compilation/missingbrace.d(9): unmatched `{` +--- +*/ +void main() +{ + int a; diff --git a/tests/dmd/fail_compilation/unmatchedbrace.d b/tests/dmd/fail_compilation/unmatchedbrace.d new file mode 100644 index 00000000000..30dc3b5d90e --- /dev/null +++ b/tests/dmd/fail_compilation/unmatchedbrace.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/unmatchedbrace.d(11): Error: matching `}` expected, not `End of File` +fail_compilation/unmatchedbrace.d(8): unmatched `{` +--- +*/ +@safe { + // + struct S {} From 7a9414419dd8ba4a76b944627932bc67df8913d4 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Mon, 26 Jun 2023 13:00:56 +0100 Subject: [PATCH 082/176] [dmd/cli.d] Fix some typos (dlang/dmd!15348) --- dmd/cli.d | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dmd/cli.d b/dmd/cli.d index 6bd8c17353b..d72d003322c 100644 --- a/dmd/cli.d +++ b/dmd/cli.d @@ -214,7 +214,7 @@ struct Usage $(LI $(B in): in contracts) $(LI $(B invariant): class/struct invariants) $(LI $(B out): out contracts) - $(LI $(B switch): finalswitch failure checking) + $(LI $(B switch): $(D final switch) failure checking) ) $(UL $(LI $(B on) or not specified: specified check is enabled.) @@ -226,8 +226,8 @@ struct Usage ), Option("checkaction=[D|C|halt|context]", "behavior on assert/boundscheck/finalswitch failure", - `Sets behavior when an assert fails, and array boundscheck fails, - or a final switch errors. + `Sets behavior when an assert or an array bounds check fails, + or a $(D final switch) errors. $(UL $(LI $(B D): Default behavior, which throws an unrecoverable $(D AssertError).) $(LI $(B C): Calls the C runtime library assert failure function.) @@ -394,7 +394,7 @@ dmd -cov -unittest myprog.d ), Option("Hd=", "write 'header' file to directory", - `Write D interface file to $(I dir) directory. $(SWLINK -op) + `Write D interface file to $(I directory). $(SWLINK -op) can be used if the original package hierarchy should be retained.`, ), @@ -1021,8 +1021,8 @@ struct CLIUsage /// Options supported by -HC enum hcUsage = "Available header generation modes: =[h|help|?] List information on all available choices - =silent Silently ignore non-exern(C[++]) declarations - =verbose Add a comment for ignored non-exern(C[++]) declarations + =silent Silently ignore non-extern(C[++]) declarations + =verbose Add a comment for ignored non-extern(C[++]) declarations "; /// Options supported by -gdwarf From b68b90a0e7d5703af7151684a586ede15084210f Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Mon, 26 Jun 2023 15:46:06 +0200 Subject: [PATCH 083/176] Upstream vendor-specific errors relating to missing object.d Each downstream compiler has subtle differences in its set-up, and so it doesn't work to just emit the same set of errors for all. DMD: 1. Is installed as a standalone D compiler (has its own releases). 2. Has a dmd.conf configuration file. 3. Has a command-line option to get to installation instructions. LDC: 1. Is installed as a standalone D compiler (has its own releases). 2. Has an ldc2.conf configuration file. 3. Has a fixed wiki page with installation instructions. GDC: 1. Is installed as part of a toolchain with other languages, assembler, linker, ... 2. Has no configuration file. 3. Has documentation, but the root URL path is a configure option --with-documentation-root-url and not available to the D front-end. --- dmd/dmodule.d | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/dmd/dmodule.d b/dmd/dmodule.d index 149a5b1aeb5..f00dec7a4e3 100644 --- a/dmd/dmodule.d +++ b/dmd/dmodule.d @@ -53,6 +53,10 @@ import dmd.target; import dmd.utils; import dmd.visitor; +version (IN_GCC) {} +else version (IN_LLVM) {} +else version = MARS; + // function used to call semantic3 on a module's dependencies void semantic3OnDependencies(Module m) { @@ -615,9 +619,18 @@ extern (C++) final class Module : Package if (FileName.equals(srcfile.toString(), "object.d")) { .error(loc, "cannot find source code for runtime library file 'object.d'"); - errorSupplemental(loc, "dmd might not be correctly installed. Run 'dmd -man' for installation instructions."); - const dmdConfFile = global.inifilename.length ? FileName.canonicalName(global.inifilename) : "not found"; - errorSupplemental(loc, "config file: %.*s", cast(int)dmdConfFile.length, dmdConfFile.ptr); + version (IN_LLVM) + { + errorSupplemental(loc, "ldc2 might not be correctly installed."); + errorSupplemental(loc, "Please check your ldc2.conf configuration file."); + errorSupplemental(loc, "Installation instructions can be found at http://wiki.dlang.org/LDC."); + } + version (MARS) + { + errorSupplemental(loc, "dmd might not be correctly installed. Run 'dmd -man' for installation instructions."); + const dmdConfFile = global.inifilename.length ? FileName.canonicalName(global.inifilename) : "not found"; + errorSupplemental(loc, "config file: %.*s", cast(int)dmdConfFile.length, dmdConfFile.ptr); + } } else if (FileName.ext(this.arg) || !loc.isValid()) { From d7f437e28f17ad148d5b160b18aa44351d99ad30 Mon Sep 17 00:00:00 2001 From: Dennis Date: Tue, 27 Jun 2023 08:45:00 +0200 Subject: [PATCH 084/176] Fix 20008 - __traits(allMembers) of packages is complete nonsense (dlang/dmd!15335) --- dmd/traits.d | 4 +++- tests/dmd/compilable/imports/pkg20008/package.d | 9 +++++++++ tests/dmd/compilable/imports/pkg20008/submod.d | 2 ++ tests/dmd/compilable/imports/pkg20008/subpkg/package.d | 7 +++++++ tests/dmd/compilable/imports/pkg20008/subpkg/subsubmod.d | 9 +++++++++ tests/dmd/compilable/imports/test9692b.d | 2 +- tests/dmd/compilable/test20008.d | 6 ++++++ tests/dmd/compilable/test9692.d | 4 ++-- 8 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 tests/dmd/compilable/imports/pkg20008/package.d create mode 100644 tests/dmd/compilable/imports/pkg20008/submod.d create mode 100644 tests/dmd/compilable/imports/pkg20008/subpkg/package.d create mode 100644 tests/dmd/compilable/imports/pkg20008/subpkg/subsubmod.d create mode 100644 tests/dmd/compilable/test20008.d diff --git a/dmd/traits.d b/dmd/traits.d index 8e1fa58a493..caebf1cee25 100644 --- a/dmd/traits.d +++ b/dmd/traits.d @@ -1556,7 +1556,9 @@ Expression semanticTraits(TraitsExp e, Scope* sc) if (auto imp = s.isImport()) { // https://issues.dlang.org/show_bug.cgi?id=9692 - s = imp.mod; + // https://issues.dlang.org/show_bug.cgi?id=20008 + if (imp.pkg) + s = imp.pkg; } // https://issues.dlang.org/show_bug.cgi?id=16044 diff --git a/tests/dmd/compilable/imports/pkg20008/package.d b/tests/dmd/compilable/imports/pkg20008/package.d new file mode 100644 index 00000000000..ecd1568ad34 --- /dev/null +++ b/tests/dmd/compilable/imports/pkg20008/package.d @@ -0,0 +1,9 @@ +module pkg20008; + +import pkg20008.submod; + +enum T2 { y } +enum T3 { z } + +static assert([__traits(allMembers, pkg20008)] == ["object", "pkg20008", "T2", "T3"]); +static assert([__traits(allMembers, pkg20008.submod)] == ["object", "T1"]); diff --git a/tests/dmd/compilable/imports/pkg20008/submod.d b/tests/dmd/compilable/imports/pkg20008/submod.d new file mode 100644 index 00000000000..a38a5e88cfb --- /dev/null +++ b/tests/dmd/compilable/imports/pkg20008/submod.d @@ -0,0 +1,2 @@ +module pkg20008.submod; +enum T1 { x } diff --git a/tests/dmd/compilable/imports/pkg20008/subpkg/package.d b/tests/dmd/compilable/imports/pkg20008/subpkg/package.d new file mode 100644 index 00000000000..cf3e4dfb422 --- /dev/null +++ b/tests/dmd/compilable/imports/pkg20008/subpkg/package.d @@ -0,0 +1,7 @@ +module pkg20008.subpkg; + +import pkg20008.subpkg.subsubmod; + +enum T9 { x } + +static assert([__traits(allMembers, pkg20008.subpkg)] == ["object", "pkg20008", "T9"]); diff --git a/tests/dmd/compilable/imports/pkg20008/subpkg/subsubmod.d b/tests/dmd/compilable/imports/pkg20008/subpkg/subsubmod.d new file mode 100644 index 00000000000..69a416a021d --- /dev/null +++ b/tests/dmd/compilable/imports/pkg20008/subpkg/subsubmod.d @@ -0,0 +1,9 @@ +module pkg20008.subpkg.subsubmod; + +import pkg20008.subpkg; +import pkg20008.subpkg.subsubmod; + +enum T8 { x } + +static assert([__traits(allMembers, pkg20008.subpkg)] == ["object", "pkg20008", "T9"]); +static assert([__traits(allMembers, pkg20008.subpkg.subsubmod)] == ["object", "pkg20008", "T8"]); diff --git a/tests/dmd/compilable/imports/test9692b.d b/tests/dmd/compilable/imports/test9692b.d index 25be84b3413..dab7a986aaf 100644 --- a/tests/dmd/compilable/imports/test9692b.d +++ b/tests/dmd/compilable/imports/test9692b.d @@ -1,2 +1,2 @@ module imports.test9692b; -int j; +int k; diff --git a/tests/dmd/compilable/test20008.d b/tests/dmd/compilable/test20008.d new file mode 100644 index 00000000000..3f27ad97943 --- /dev/null +++ b/tests/dmd/compilable/test20008.d @@ -0,0 +1,6 @@ +/* +REQUIRED_ARGS: -Icompilable/imports -c -o- +EXTRA_FILES: imports/pkg20008/package.d imports/pkg20008/submod.d +*/ +import pkg20008; +import pkg20008.subpkg; diff --git a/tests/dmd/compilable/test9692.d b/tests/dmd/compilable/test9692.d index 57131b8080c..cb5da6a3422 100644 --- a/tests/dmd/compilable/test9692.d +++ b/tests/dmd/compilable/test9692.d @@ -4,5 +4,5 @@ module test9692; import test9692a; import imports.test9692b; -enum x = [__traits(allMembers, imports.test9692b)]; // ok -enum y = [__traits(allMembers, test9692a)]; // ng: should work +static assert([__traits(allMembers, imports.test9692b)] == ["object", "k"]); // ok +static assert([__traits(allMembers, test9692a)] == ["object", "j"]); // ng: should work From c06280b28b5581209719b471ca120a372d1c7d9d Mon Sep 17 00:00:00 2001 From: FeepingCreature <540727+FeepingCreature@users.noreply.github.com> Date: Tue, 27 Jun 2023 14:51:07 +0200 Subject: [PATCH 085/176] Fix issue 24018: set length manually via runtime function. (dlang/dmd!15354) * Fix issue 24018: make `array.length = n` `@system` if default construction is disabled on the array type. This is needed as there is otherwise no good way to resize an array of non-constructable elements in user code at all. * Fix issue 24018: instead of calling `array.length =`, call the runtime function that implements `array.length =` instead. This skips the check for the element type being constructable, which is correct because concatenation doesn't expose unconstructed memory anyway. --- .../src/core/internal/array/concatenation.d | 17 ++++++++++++++++- tests/dmd/compilable/issue24018.d | 10 ++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tests/dmd/compilable/issue24018.d diff --git a/runtime/druntime/src/core/internal/array/concatenation.d b/runtime/druntime/src/core/internal/array/concatenation.d index ff777a6b3ab..4a05b50fcff 100644 --- a/runtime/druntime/src/core/internal/array/concatenation.d +++ b/runtime/druntime/src/core/internal/array/concatenation.d @@ -19,6 +19,7 @@ module core.internal.array.concatenation; */ Tret _d_arraycatnTX(Tret, Tarr...)(auto ref Tarr froms) @trusted { + import core.internal.array.capacity : _d_arraysetlengthTImpl; import core.internal.traits : hasElaborateCopyConstructor, Unqual; import core.lifetime : copyEmplace; import core.stdc.string : memcpy; @@ -38,7 +39,21 @@ Tret _d_arraycatnTX(Tret, Tarr...)(auto ref Tarr froms) @trusted if (totalLen == 0) return res; - res.length = totalLen; + + // We cannot use this, because it refuses to work if the array type has disabled default construction. + // res.length = totalLen; + // Call the runtime function directly instead. + // TODO: once `__arrayAlloc` is templated, call that instead. + version (D_ProfileGC) + { + // TODO: forward file, line, name from _d_arraycatnTXTrace + _d_arraysetlengthTImpl!(typeof(res))._d_arraysetlengthTTrace( + __FILE__, __LINE__, "_d_arraycatnTX", res, totalLen); + } + else + { + _d_arraysetlengthTImpl!(typeof(res))._d_arraysetlengthT(res, totalLen); + } /* Currently, if both a postblit and a cpctor are defined, the postblit is * used. If this changes, the condition below will have to be adapted. diff --git a/tests/dmd/compilable/issue24018.d b/tests/dmd/compilable/issue24018.d new file mode 100644 index 00000000000..559710c27df --- /dev/null +++ b/tests/dmd/compilable/issue24018.d @@ -0,0 +1,10 @@ +struct S +{ + @disable this(); +} + +void main() +{ + S[] s; + s = s ~ s; +} From 3016455483d65b3e8cd4eecdc0dedc4119a344aa Mon Sep 17 00:00:00 2001 From: Razvan Nitu Date: Tue, 27 Jun 2023 16:35:30 +0300 Subject: [PATCH 086/176] Remove ballast code from compiler/src/dmd/expressionsem.d (dlang/dmd!15356) --- dmd/expressionsem.d | 33 +-------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index 02c2fae9a54..8b0cf360f5b 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -386,34 +386,6 @@ Expression checkNoreturnVarAccess(Expression exp) return result; } -/****************************** - * Check the tail CallExp is really property function call. - * Bugs: - * This doesn't appear to do anything. - */ -private bool checkPropertyCall(Expression e) -{ - e = lastComma(e); - - if (auto ce = e.isCallExp()) - { - if (ce.f) - { - auto tf = ce.f.type.isTypeFunction(); - /* If a forward reference to ce.f, try to resolve it - */ - if (!tf.deco && ce.f.semanticRun < PASS.semanticdone) - { - ce.f.dsymbolSemantic(null); - tf = ce.f.type.isTypeFunction(); - } - } - else if (!ce.e1.type.isFunction_Delegate_PtrToFunction()) - assert(0); - } - return false; -} - /****************************** * Find symbol in accordance with the UFCS name look up rule */ @@ -726,7 +698,6 @@ private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2 } else if (ex && !e) { - checkPropertyCall(ex); ex = new AssignExp(loc, ex, e2); return ex.expressionSemantic(sc); } @@ -735,7 +706,6 @@ private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2 // strict setter prints errors if fails e = e.expressionSemantic(sc); } - checkPropertyCall(e); return e; } else @@ -746,8 +716,7 @@ private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2 (*arguments)[0] = eleft; e = new CallExp(loc, e, arguments); e = e.expressionSemantic(sc); - checkPropertyCall(e); - return e.expressionSemantic(sc); + return e; } } From cda305ef749959f80e152f7e6b77a311974b2ab4 Mon Sep 17 00:00:00 2001 From: Razvan Nitu Date: Tue, 27 Jun 2023 18:24:29 +0300 Subject: [PATCH 087/176] =?UTF-8?q?Fix=20Issue=2024017=20-=20Bypassing=20n?= =?UTF-8?q?othrow=20=20with=20debug=20=20doesn=E2=80=99t=20work=20(dlang/d?= =?UTF-8?q?md!15355)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix Issue 24017 - Bypassing with doesn’t work * Update compiler/src/dmd/expressionsem.d Co-authored-by: Dennis --------- Co-authored-by: Dennis --- dmd/expressionsem.d | 5 +++++ tests/dmd/compilable/test24017.d | 11 +++++++++++ 2 files changed, 16 insertions(+) create mode 100644 tests/dmd/compilable/test24017.d diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index 8b0cf360f5b..dc190234be5 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -715,6 +715,11 @@ private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2 auto arguments = new Expressions(1); (*arguments)[0] = eleft; e = new CallExp(loc, e, arguments); + + // https://issues.dlang.org/show_bug.cgi?id=24017 + if (sc.flags & SCOPE.debug_) + e.isCallExp().inDebugStatement = true; + e = e.expressionSemantic(sc); return e; } diff --git a/tests/dmd/compilable/test24017.d b/tests/dmd/compilable/test24017.d new file mode 100644 index 00000000000..0d039781201 --- /dev/null +++ b/tests/dmd/compilable/test24017.d @@ -0,0 +1,11 @@ +// https://issues.dlang.org/show_bug.cgi?id=24017 + +// REQUIRED_ARGS: -debug + +void writeln(string) {} + +void main() nothrow +{ + debug writeln("Hello"); + debug "Hello".writeln; +} From 72768d21cbf1e4ff694d8b522f0a25a745487e81 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Tue, 27 Jun 2023 17:41:03 +0200 Subject: [PATCH 088/176] Use params.useExceptions instead of betterC to gate generation of try/catch in ctors --- dmd/semantic3.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmd/semantic3.d b/dmd/semantic3.d index a8c79e7a334..e4ca22a98b5 100644 --- a/dmd/semantic3.d +++ b/dmd/semantic3.d @@ -1422,7 +1422,7 @@ private extern(C++) final class Semantic3Visitor : Visitor * https://issues.dlang.org/show_bug.cgi?id=14246 */ AggregateDeclaration ad = ctor.isMemberDecl(); - if (!ctor.fbody || !ad || !ad.fieldDtor || !global.params.dtorFields || global.params.betterC || ctor.type.toTypeFunction.isnothrow) + if (!ctor.fbody || !ad || !ad.fieldDtor || !global.params.dtorFields || !global.params.useExceptions || ctor.type.toTypeFunction.isnothrow) return visit(cast(FuncDeclaration)ctor); /* Generate: From 5aedaba65a5daad2ddd6dd359a70b092e011cd5e Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Tue, 27 Jun 2023 17:48:02 +0200 Subject: [PATCH 089/176] Only predefine D_ModuleInfo, D_Exceptions, D_TypeInfo if feature is enabled --- dmd/target.d | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dmd/target.d b/dmd/target.d index d5a8edec2ab..7d930f2c564 100644 --- a/dmd/target.d +++ b/dmd/target.d @@ -135,9 +135,12 @@ void addDefaultVersionIdentifiers(const ref Param params, const ref Target tgt) } else { - VersionCondition.addPredefinedGlobalIdent("D_ModuleInfo"); - VersionCondition.addPredefinedGlobalIdent("D_Exceptions"); - VersionCondition.addPredefinedGlobalIdent("D_TypeInfo"); + if (params.useModuleInfo) + VersionCondition.addPredefinedGlobalIdent("D_ModuleInfo"); + if (params.useExceptions) + VersionCondition.addPredefinedGlobalIdent("D_Exceptions"); + if (params.useTypeInfo) + VersionCondition.addPredefinedGlobalIdent("D_TypeInfo"); } VersionCondition.addPredefinedGlobalIdent("D_HardFloat"); From c17969f2846626468f2598ba2538b3f580769811 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Wed, 28 Jun 2023 09:17:30 +0200 Subject: [PATCH 090/176] Remove nothrow from doGNUABITagSemantic predicate function (dlang/dmd!15360) --- dmd/root/array.d | 2 +- dmd/semantic2.d | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/dmd/root/array.d b/dmd/root/array.d index 541a12d9e1d..d1c61be7344 100644 --- a/dmd/root/array.d +++ b/dmd/root/array.d @@ -574,7 +574,7 @@ unittest private template arraySortWrapper(T, alias fn) { pragma(mangle, "arraySortWrapper_" ~ T.mangleof ~ "_" ~ fn.mangleof) - extern(C) int arraySortWrapper(scope const void* e1, scope const void* e2) nothrow + extern(C) int arraySortWrapper(scope const void* e1, scope const void* e2) { return fn(cast(const(T*))e1, cast(const(T*))e2); } diff --git a/dmd/semantic2.d b/dmd/semantic2.d index b0b993ca25a..c40e72c0862 100644 --- a/dmd/semantic2.d +++ b/dmd/semantic2.d @@ -805,9 +805,8 @@ private void doGNUABITagSemantic(ref Expression e, ref Expression* lastTag) // but it's a concession to practicality. // Casts are unfortunately necessary as `implicitConvTo` is not // `const` (and nor is `StringExp`, by extension). - static int predicate(const scope Expression* e1, const scope Expression* e2) nothrow + static int predicate(const scope Expression* e1, const scope Expression* e2) { - scope(failure) assert(0, "An exception was thrown"); return (cast(Expression*)e1).toStringExp().compare((cast(Expression*)e2).toStringExp()); } ale.elements.sort!predicate; From bc58524a63233be7533817e0fa11fe777fa4bd1d Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Wed, 28 Jun 2023 08:20:40 +0100 Subject: [PATCH 091/176] Fix Issue 11612 - Inconsistent error on negative new array size (dlang/dmd!15359) * Fix Issue 11612 - Inconsistent error on negative new array size * Extend new array tests --- dmd/expressionsem.d | 5 +++-- tests/dmd/fail_compilation/issue20422.d | 9 ++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index dc190234be5..93f0a103dd2 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -4058,9 +4058,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (arg.op == EXP.error) return setError(); arg = arg.optimize(WANTvalue); - if (arg.op == EXP.int64 && cast(sinteger_t)arg.toInteger() < 0) + if (arg.op == EXP.int64 && (target.is64bit ? + cast(sinteger_t)arg.toInteger() : cast(int)arg.toInteger()) < 0) { - exp.error("negative array index `%s`", arg.toChars()); + exp.error("negative array dimension `%s`", (*exp.arguments)[i].toChars()); return setError(); } (*exp.arguments)[i] = arg; diff --git a/tests/dmd/fail_compilation/issue20422.d b/tests/dmd/fail_compilation/issue20422.d index 1964f8ac888..9dcab004d2c 100644 --- a/tests/dmd/fail_compilation/issue20422.d +++ b/tests/dmd/fail_compilation/issue20422.d @@ -1,12 +1,19 @@ // https://issues.dlang.org/show_bug.cgi?id=20422 /* +REQUIRED_ARGS: -m32 TEST_OUTPUT: --- -fail_compilation/issue20422.d(11): Error: missing length argument for array +fail_compilation/issue20422.d(15): Error: missing length argument for array +fail_compilation/issue20422.d(16): Error: negative array dimension `-1` +fail_compilation/issue20422.d(17): Error: negative array dimension `-2147483648` +fail_compilation/issue20422.d(18): Error: too many arguments for array --- */ void main() { new int[]; + new int[-1]; + new int[](int.min); + new int[](1, 2); } From 233697b32f7869f0d87144b308375664e91d82e3 Mon Sep 17 00:00:00 2001 From: Dennis Date: Wed, 28 Jun 2023 16:26:31 +0200 Subject: [PATCH 092/176] Move eh.d to backend (dlang/dmd!15364) * Make `dmd/eh.d` independent from frontend * Move eh.d to backend * Replace eh.d function prototypes with imports --- dmd/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/dmd/README.md b/dmd/README.md index 79215b7a0ea..4fd7831866a 100644 --- a/dmd/README.md +++ b/dmd/README.md @@ -174,7 +174,6 @@ Note that these groups have no strict meaning, the category assignments are a bi | [cond.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cond.d) | Evaluate `static if`, `version` `debug ` | | [staticcond.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/staticcond.d) | Lazily evaluate static conditions for `static if`, `static assert` and template constraints | | [delegatize.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/delegatize.d) | Converts expression to delegates for `lazy` parameters | -| [eh.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/eh.d) | Generate tables for exception handling | | [nspace.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/nspace.d) | Namespace for `extern (C++, Module)` | | [intrange.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/intrange.d) | [Value range propagation](https://digitalmars.com/articles/b62.html) | | [dimport.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dimport.d) | Renamed imports (`import aliasSymbol = pkg1.pkg2.symbol`) | From 9b55f656fa5e19c8f1a9bf2877247bc19299fa13 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Thu, 29 Jun 2023 01:26:48 -0700 Subject: [PATCH 093/176] fix tabs in transitivevisitor.d (dlang/dmd!15367) --- dmd/transitivevisitor.d | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dmd/transitivevisitor.d b/dmd/transitivevisitor.d index a82a268eb66..376c12fa808 100644 --- a/dmd/transitivevisitor.d +++ b/dmd/transitivevisitor.d @@ -162,14 +162,14 @@ package mixin template ParseVisitMethods(AST) } override void visit(AST.StaticForeachStatement s) - { + { // printf("Visiting StaticForeachStatement\n"); - if (s.sfe.aggrfe) + if (s.sfe.aggrfe) s.sfe.aggrfe.accept(this); - if (s.sfe.rangefe) + if (s.sfe.rangefe) s.sfe.rangefe.accept(this); - } + } override void visit(AST.IfStatement s) { From 340bdd67514a4782b6908cb2d17e34d1085bdaa9 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Fri, 30 Jun 2023 09:00:43 +0100 Subject: [PATCH 094/176] Fix Issue 23931 - Error: reference to local variable `this` calling non-scope member function `this.this()` (dlang/dmd!15368) --- dmd/escape.d | 5 +++-- tests/dmd/fail_compilation/retscope.d | 2 +- tests/dmd/fail_compilation/test20245.d | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/dmd/escape.d b/dmd/escape.d index f6e03821ab1..2bf2354c10d 100644 --- a/dmd/escape.d +++ b/dmd/escape.d @@ -365,8 +365,9 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId, (!fdc && parId) ? (desc ~ " `%s` assigned to non-scope parameter `%s`") : (desc ~ " `%s` assigned to non-scope anonymous parameter"); - auto param = isThis ? v : (parId ? parId : fdc); - if (sc.setUnsafeDIP1000(gag, arg.loc, msg, v, param, fdc)) + if (isThis ? + sc.setUnsafeDIP1000(gag, arg.loc, msg, arg, fdc.toParent2(), fdc) : + sc.setUnsafeDIP1000(gag, arg.loc, msg, v, parId ? parId : fdc, fdc)) { result = true; printScopeFailure(previewSupplementalFunc(sc.isDeprecated(), global.params.useDIP1000), vPar, 10); diff --git a/tests/dmd/fail_compilation/retscope.d b/tests/dmd/fail_compilation/retscope.d index 50cfdd3ef9c..c08747fa7e3 100644 --- a/tests/dmd/fail_compilation/retscope.d +++ b/tests/dmd/fail_compilation/retscope.d @@ -403,7 +403,7 @@ class Foo13 /* TEST_OUTPUT: --- -fail_compilation/retscope.d(1205): Error: scope variable `f14` calling non-scope member function `f14.foo()` +fail_compilation/retscope.d(1205): Error: scope variable `f14` calling non-scope member function `Foo14.foo()` --- */ diff --git a/tests/dmd/fail_compilation/test20245.d b/tests/dmd/fail_compilation/test20245.d index 3c43c5cfe4b..a6bbba29128 100644 --- a/tests/dmd/fail_compilation/test20245.d +++ b/tests/dmd/fail_compilation/test20245.d @@ -9,7 +9,7 @@ fail_compilation/test20245.d(27): Error: cannot take address of `scope` variable fail_compilation/test20245.d(33): Error: reference to local variable `x` assigned to non-scope parameter `ptr` calling `escape` fail_compilation/test20245.d(34): Error: copying `&x` into allocated memory escapes a reference to parameter `x` fail_compilation/test20245.d(50): Error: reference to local variable `price` assigned to non-scope `this.minPrice` -fail_compilation/test20245.d(69): Error: reference to local variable `this` calling non-scope member function `this.this()` +fail_compilation/test20245.d(69): Error: reference to local variable `this.content[]` calling non-scope member function `Exception.this()` fail_compilation/test20245.d(89): Error: reference to local variable `this` assigned to non-scope parameter `content` calling `listUp` fail_compilation/test20245.d(82): which is not `scope` because of `charPtr = content` --- From b0d8ad46ef846de14b19dae068442a7ef67778a0 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Fri, 30 Jun 2023 09:02:00 +0100 Subject: [PATCH 095/176] Fix Issue 15436 - Compiler still refers to AliasSeq-s as "tuple"-s (dlang/dmd!15363) * Fix Issue 15436 - Compiler still refers to AliasSeq-s as "tuple"-s Replace "tuple type" with "type sequence". Replace "tuple" with "sequence". Pretty print `AliasSeq!(args)`, not `tuple(args)`. Leave json as "tuple" for now. Also mention std.typecons.Tuple when trying to return a sequence. Note: This does not rename any internal compiler symbols. * Update runnable tests * Update stringof tests * Update remaining tests * retrigger tests --- dmd/declaration.d | 2 +- dmd/dinterpret.d | 2 +- dmd/dmangle.d | 2 +- dmd/dsymbolsem.d | 6 +- dmd/expressionsem.d | 6 +- dmd/hdrgen.d | 6 +- dmd/mtype.d | 6 +- dmd/opover.d | 2 +- dmd/statementsem.d | 2 +- dmd/typesem.d | 12 +- tests/dmd/compilable/extra-files/header1.di | 4 +- tests/dmd/compilable/extra-files/header1i.di | 2 +- tests/dmd/compilable/extra-files/vcg-ast.d.cg | 4 +- tests/dmd/compilable/stc_traits.d | 106 +++++++++--------- tests/dmd/compilable/test13668.d | 2 +- tests/dmd/compilable/test17143.d | 2 +- tests/dmd/compilable/test17373.d | 4 +- tests/dmd/compilable/test17545.d | 2 +- tests/dmd/compilable/test19728.d | 14 +-- tests/dmd/compilable/test21282.d | 2 +- tests/dmd/compilable/test21330.d | 4 +- tests/dmd/fail_compilation/casttuple.d | 6 +- tests/dmd/fail_compilation/cppmangle.d | 2 +- tests/dmd/fail_compilation/dassert.d | 2 +- tests/dmd/fail_compilation/diag13884.d | 2 +- tests/dmd/fail_compilation/diag14876.d | 2 +- tests/dmd/fail_compilation/fail12436.d | 2 +- tests/dmd/fail_compilation/fail15755.d | 2 +- tests/dmd/fail_compilation/fail222.d | 4 +- tests/dmd/fail_compilation/ice12574.d | 2 +- tests/dmd/fail_compilation/ice14424.d | 2 +- tests/dmd/fail_compilation/typeerrors.d | 2 +- tests/dmd/runnable/uda.d | 42 +++---- tests/dmd/runnable/xtest46.d | 10 +- tests/dmd/runnable/xtest46_gc.d | 10 +- 35 files changed, 141 insertions(+), 141 deletions(-) diff --git a/dmd/declaration.d b/dmd/declaration.d index cfa6988a861..5559b93eb20 100644 --- a/dmd/declaration.d +++ b/dmd/declaration.d @@ -599,7 +599,7 @@ extern (C++) final class TupleDeclaration : Declaration override const(char)* kind() const { - return "tuple"; + return "sequence"; } override Type getType() diff --git a/dmd/dinterpret.d b/dmd/dinterpret.d index ce7323f8d43..cb74a079cd4 100644 --- a/dmd/dinterpret.d +++ b/dmd/dinterpret.d @@ -2412,7 +2412,7 @@ public: continue; if (ex.op == EXP.voidExpression) { - e.error("CTFE internal error: void element `%s` in tuple", exp.toChars()); + e.error("CTFE internal error: void element `%s` in sequence", exp.toChars()); assert(0); } diff --git a/dmd/dmangle.d b/dmd/dmangle.d index 72a44765787..ad1e8165668 100644 --- a/dmd/dmangle.d +++ b/dmd/dmangle.d @@ -888,7 +888,7 @@ public: buf.writeByte('V'); if (ea.op == EXP.tuple) { - ea.error("tuple is not a valid template value argument"); + ea.error("sequence is not a valid template value argument"); continue; } // Now that we know it is not an alias, we MUST obtain a value diff --git a/dmd/dsymbolsem.d b/dmd/dsymbolsem.d index d97d37db81f..ae86ae06c2f 100644 --- a/dmd/dsymbolsem.d +++ b/dmd/dsymbolsem.d @@ -695,7 +695,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor size_t tedim = te.exps.length; if (tedim != nelems) { - error(dsym.loc, "tuple of %d elements cannot be assigned to tuple of %d elements", cast(int)tedim, cast(int)nelems); + error(dsym.loc, "sequence of %d elements cannot be assigned to sequence of %d elements", cast(int)tedim, cast(int)nelems); for (size_t u = tedim; u < nelems; u++) // fill dummy expression te.exps.push(ErrorExp.get()); } @@ -2044,7 +2044,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { } else - ns.exp.error("compile time string constant (or tuple) expected, not `%s`", + ns.exp.error("compile time string constant (or sequence) expected, not `%s`", ns.exp.toChars()); attribSemantic(ns); } @@ -2714,7 +2714,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } if (i + 1 != tempdecl.parameters.length && tp.isTemplateTupleParameter()) { - tempdecl.error("template tuple parameter must be last one"); + tempdecl.error("template sequence parameter must be the last one"); tempdecl.errors = true; } } diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index 93f0a103dd2..27bd9396070 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -7809,7 +7809,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (exp.to.ty == Ttuple) { - exp.error("cannot cast `%s` of type `%s` to tuple type `%s`", exp.e1.toChars(), exp.e1.type.toChars(), exp.to.toChars()); + exp.error("cannot cast `%s` of type `%s` to type sequence `%s`", exp.e1.toChars(), exp.e1.type.toChars(), exp.to.toChars()); return setError(); } @@ -8155,7 +8155,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } if (!exp.lwr || !exp.upr) { - exp.error("need upper and lower bound to slice tuple"); + exp.error("need upper and lower bound to slice a sequence"); return setError(); } } @@ -9200,7 +9200,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Expression e = null; if (dim != tup2.exps.length) { - exp.error("mismatched tuple lengths, %d and %d", cast(int)dim, cast(int)tup2.exps.length); + exp.error("mismatched sequence lengths, %d and %d", cast(int)dim, cast(int)tup2.exps.length); return setError(); } if (dim == 0) diff --git a/dmd/hdrgen.d b/dmd/hdrgen.d index 9e2a5b7c91f..62e0d49fdd5 100644 --- a/dmd/hdrgen.d +++ b/dmd/hdrgen.d @@ -2217,13 +2217,13 @@ private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hg { buf.writeByte('('); e.e0.expressionPrettyPrint(buf, hgs); - buf.writestring(", tuple("); + buf.writestring(", AliasSeq!("); argsToBuffer(e.exps, buf, hgs); buf.writestring("))"); } else { - buf.writestring("tuple("); + buf.writestring("AliasSeq!("); argsToBuffer(e.exps, buf, hgs); buf.writeByte(')'); } @@ -4141,7 +4141,7 @@ string EXPtoString(EXP op) EXP.delegatePointer : "delegateptr", EXP.delegateFunctionPointer : "delegatefuncptr", EXP.remove : "remove", - EXP.tuple : "tuple", + EXP.tuple : "sequence", EXP.traits : "__traits", EXP.overloadSet : "__overloadset", EXP.void_ : "void", diff --git a/dmd/mtype.d b/dmd/mtype.d index 103c761be5d..30ab9d06f85 100644 --- a/dmd/mtype.d +++ b/dmd/mtype.d @@ -4940,7 +4940,7 @@ extern (C++) final class TypeFunction : TypeNext } if (tb.ty == Ttuple) { - error(loc, "functions cannot return a tuple"); + error(loc, "functions cannot return a sequence (use `std.typecons.Tuple`)"); next = Type.terror; } if (!isref && (tb.ty == Tstruct || tb.ty == Tsarray)) @@ -6218,7 +6218,7 @@ extern (C++) final class TypeTuple : Type { Expression e = (*exps)[i]; if (e.type.ty == Ttuple) - e.error("cannot form tuple of tuples"); + e.error("cannot form sequence of sequences"); auto arg = new Parameter(STC.undefined_, e.type, null, null, null); (*arguments)[i] = arg; } @@ -6273,7 +6273,7 @@ extern (C++) final class TypeTuple : Type override const(char)* kind() const { - return "tuple"; + return "sequence"; } override TypeTuple syntaxCopy() diff --git a/dmd/opover.d b/dmd/opover.d index ea7915df78b..8b42a91f0af 100644 --- a/dmd/opover.d +++ b/dmd/opover.d @@ -1045,7 +1045,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) size_t dim = tup1.exps.length; if (dim != tup2.exps.length) { - e.error("mismatched tuple lengths, `%d` and `%d`", + e.error("mismatched sequence lengths, `%d` and `%d`", cast(int)dim, cast(int)tup2.exps.length); return ErrorExp.get(); } diff --git a/dmd/statementsem.d b/dmd/statementsem.d index f0454163224..71ad8bb2d59 100644 --- a/dmd/statementsem.d +++ b/dmd/statementsem.d @@ -4298,7 +4298,7 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState const bool skipCheck = isStatic && needExpansion; if (!skipCheck && (dim < 1 || dim > 2)) { - fs.error("only one (value) or two (key,value) arguments for tuple `foreach`"); + fs.error("only one (value) or two (key,value) arguments allowed for sequence `foreach`"); return returnEarly(); } diff --git a/dmd/typesem.d b/dmd/typesem.d index 09eef83ba08..d0923953663 100644 --- a/dmd/typesem.d +++ b/dmd/typesem.d @@ -121,7 +121,7 @@ private void resolveTupleIndex(const ref Loc loc, Scope* sc, Dsymbol s, out Expr const(uinteger_t) d = eindex.toUInteger(); if (d >= tup.objects.length) { - .error(loc, "tuple index `%llu` out of bounds `[0 .. %llu]`", d, cast(ulong)tup.objects.length); + .error(loc, "sequence index `%llu` out of bounds `[0 .. %llu]`", d, cast(ulong)tup.objects.length); pt = Type.terror; return; } @@ -525,7 +525,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) uinteger_t d = mtype.dim.toUInteger(); if (d >= tup.objects.length) { - .error(loc, "tuple index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d, cast(ulong)tup.objects.length); + .error(loc, "sequence index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d, cast(ulong)tup.objects.length); return error(); } @@ -621,7 +621,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) uinteger_t d = mtype.dim.toUInteger(); if (d >= tt.arguments.length) { - .error(loc, "tuple index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d, cast(ulong)tt.arguments.length); + .error(loc, "sequence index `%llu` out of bounds `[0 .. %llu]`", cast(ulong)d, cast(ulong)tt.arguments.length); return error(); } Type telem = (*tt.arguments)[cast(size_t)d].type; @@ -1684,7 +1684,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) Type tbn = tn.toBasetype(); if (tbn.ty != Ttuple) { - .error(loc, "can only slice tuple types, not `%s`", tbn.toChars()); + .error(loc, "can only slice type sequences, not `%s`", tbn.toChars()); return error(); } TypeTuple tt = cast(TypeTuple)tbn; @@ -2436,7 +2436,7 @@ Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier iden } else { - error(loc, "no property `%s` for tuple `%s`", ident.toChars(), mt.toChars()); + error(loc, "no property `%s` for sequence `%s`", ident.toChars(), mt.toChars()); e = ErrorExp.get(); } return e; @@ -2563,7 +2563,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type const d = mt.dim.toUInteger(); if (d >= tup.objects.length) { - error(loc, "tuple index `%llu` out of bounds `[0 .. %llu]`", d, cast(ulong) tup.objects.length); + error(loc, "sequence index `%llu` out of bounds `[0 .. %llu]`", d, cast(ulong) tup.objects.length); return returnError(); } diff --git a/tests/dmd/compilable/extra-files/header1.di b/tests/dmd/compilable/extra-files/header1.di index ef298a3878a..11186409ddf 100644 --- a/tests/dmd/compilable/extra-files/header1.di +++ b/tests/dmd/compilable/extra-files/header1.di @@ -522,7 +522,7 @@ struct SafeS int* p; } } -void test13x(@(10) int a, @(20) int, @(tuple(30), tuple(40)) int[] arr...); +void test13x(@(10) int a, @(20) int, @(AliasSeq!(30), AliasSeq!(40)) int[] arr...); enum Test14UDA1; struct Test14UDA2 { @@ -559,4 +559,4 @@ interface I12344 assert(result > 0); } ; -} \ No newline at end of file +} diff --git a/tests/dmd/compilable/extra-files/header1i.di b/tests/dmd/compilable/extra-files/header1i.di index 61125ef5c95..1be656fa88f 100644 --- a/tests/dmd/compilable/extra-files/header1i.di +++ b/tests/dmd/compilable/extra-files/header1i.di @@ -665,7 +665,7 @@ struct SafeS int* p; } } -void test13x(@(10) int a, @(20) int, @(tuple(30), tuple(40)) int[] arr...) +void test13x(@(10) int a, @(20) int, @(AliasSeq!(30), AliasSeq!(40)) int[] arr...) { } enum Test14UDA1; diff --git a/tests/dmd/compilable/extra-files/vcg-ast.d.cg b/tests/dmd/compilable/extra-files/vcg-ast.d.cg index 688eb9f080d..640cba43ed6 100644 --- a/tests/dmd/compilable/extra-files/vcg-ast.d.cg +++ b/tests/dmd/compilable/extra-files/vcg-ast.d.cg @@ -7,7 +7,7 @@ template Seq(A...) { alias Seq = A; } -(int, int, int) a = tuple(1, 2, 3); +(int, int, int) a = AliasSeq!(1, 2, 3); template R(T) { struct _R @@ -16,7 +16,7 @@ template R(T) } } int x; -static foreach (enum i; tuple(0, 1, 2)) +static foreach (enum i; AliasSeq!(0, 1, 2)) { mixin("int a" ~ i.stringof ~ " = 1;"); } diff --git a/tests/dmd/compilable/stc_traits.d b/tests/dmd/compilable/stc_traits.d index c5c4e5f0ac0..71d17315510 100644 --- a/tests/dmd/compilable/stc_traits.d +++ b/tests/dmd/compilable/stc_traits.d @@ -2,59 +2,59 @@ /* TEST_OUTPUT: --- -100 tuple() -101 tuple("return", "ref") -102 tuple("ref") -103 tuple() -104 tuple("ref") -105 tuple() -106 tuple() -107 tuple("ref") -108 tuple("ref") -109 tuple("ref") -110 tuple("ref") -111 tuple() -112 tuple("ref") -113 tuple("ref") -114 tuple("ref") -115 tuple("ref") -116 tuple() -117 tuple("ref") -118 tuple("ref") -119 tuple() -120 tuple("ref") -121 tuple() -122 tuple("ref") -123 tuple("in") -124 tuple("in") -m tuple("ref") -m-mixin tuple("ref") -m tuple("ref") -m-mixin tuple("ref") -m tuple("ref") -m-mixin tuple("ref") -m tuple("return", "ref") -m-mixin tuple("return", "ref") -m tuple("ref") -m-mixin tuple("ref") -m tuple("ref") -m-mixin tuple("ref") -m tuple() -m-mixin tuple() -m tuple("ref") -m-mixin tuple("ref") -m tuple("ref") -m-mixin tuple("ref") -m tuple("ref") -m-mixin tuple("ref") -m tuple("ref") -m-mixin tuple("ref") -m tuple("ref") -m-mixin tuple("ref") -m tuple("ref") -m-mixin tuple("ref") -m tuple("in") -m-mixin tuple("in") +100 AliasSeq!() +101 AliasSeq!("return", "ref") +102 AliasSeq!("ref") +103 AliasSeq!() +104 AliasSeq!("ref") +105 AliasSeq!() +106 AliasSeq!() +107 AliasSeq!("ref") +108 AliasSeq!("ref") +109 AliasSeq!("ref") +110 AliasSeq!("ref") +111 AliasSeq!() +112 AliasSeq!("ref") +113 AliasSeq!("ref") +114 AliasSeq!("ref") +115 AliasSeq!("ref") +116 AliasSeq!() +117 AliasSeq!("ref") +118 AliasSeq!("ref") +119 AliasSeq!() +120 AliasSeq!("ref") +121 AliasSeq!() +122 AliasSeq!("ref") +123 AliasSeq!("in") +124 AliasSeq!("in") +m AliasSeq!("ref") +m-mixin AliasSeq!("ref") +m AliasSeq!("ref") +m-mixin AliasSeq!("ref") +m AliasSeq!("ref") +m-mixin AliasSeq!("ref") +m AliasSeq!("return", "ref") +m-mixin AliasSeq!("return", "ref") +m AliasSeq!("ref") +m-mixin AliasSeq!("ref") +m AliasSeq!("ref") +m-mixin AliasSeq!("ref") +m AliasSeq!() +m-mixin AliasSeq!() +m AliasSeq!("ref") +m-mixin AliasSeq!("ref") +m AliasSeq!("ref") +m-mixin AliasSeq!("ref") +m AliasSeq!("ref") +m-mixin AliasSeq!("ref") +m AliasSeq!("ref") +m-mixin AliasSeq!("ref") +m AliasSeq!("ref") +m-mixin AliasSeq!("ref") +m AliasSeq!("ref") +m-mixin AliasSeq!("ref") +m AliasSeq!("in") +m-mixin AliasSeq!("in") --- */ diff --git a/tests/dmd/compilable/test13668.d b/tests/dmd/compilable/test13668.d index d69c764b91c..2cf758cc98b 100644 --- a/tests/dmd/compilable/test13668.d +++ b/tests/dmd/compilable/test13668.d @@ -3,7 +3,7 @@ /* TEST_OUTPUT: --- -tuple("id", "toString", "toHash", "opCmp", "opEquals", "Monitor", "factory") +AliasSeq!("id", "toString", "toHash", "opCmp", "opEquals", "Monitor", "factory") genProps --- */ diff --git a/tests/dmd/compilable/test17143.d b/tests/dmd/compilable/test17143.d index 4ec029572f4..272d65934b8 100644 --- a/tests/dmd/compilable/test17143.d +++ b/tests/dmd/compilable/test17143.d @@ -13,4 +13,4 @@ Tuple!T tuple(T...)(T args) enum foo = tuple(1, 2).expand; static assert(typeof(foo).stringof == "(int, int)"); -static assert(foo.stringof == "tuple(1, 2)"); +static assert(foo.stringof == "AliasSeq!(1, 2)"); diff --git a/tests/dmd/compilable/test17373.d b/tests/dmd/compilable/test17373.d index 9a5ee6431a2..1f83f51685d 100644 --- a/tests/dmd/compilable/test17373.d +++ b/tests/dmd/compilable/test17373.d @@ -28,5 +28,5 @@ interface ConnectionStream : Stream void close(); } -static assert(__traits(getOverloads, ConnectionStream, "connected").stringof == "tuple(connected)"); -static assert(__traits(getOverloads, ConnectionStream, "close").stringof == "tuple(close)"); +static assert(__traits(getOverloads, ConnectionStream, "connected").stringof == "AliasSeq!(connected)"); +static assert(__traits(getOverloads, ConnectionStream, "close").stringof == "AliasSeq!(close)"); diff --git a/tests/dmd/compilable/test17545.d b/tests/dmd/compilable/test17545.d index 6285418b806..d1ba7cddea1 100644 --- a/tests/dmd/compilable/test17545.d +++ b/tests/dmd/compilable/test17545.d @@ -1,6 +1,6 @@ /* TEST_OUTPUT: --- -tuple((Attrib)) +AliasSeq!((Attrib)) --- */ diff --git a/tests/dmd/compilable/test19728.d b/tests/dmd/compilable/test19728.d index 551ac0f6a89..73ed9c4a3d8 100644 --- a/tests/dmd/compilable/test19728.d +++ b/tests/dmd/compilable/test19728.d @@ -1,13 +1,13 @@ /* TEST_OUTPUT: --- -tuple((A), (B)) -tuple((A), (B), 0) -tuple((A), (B), (A)) -tuple((A), (B), (A), (B)) -tuple((A), (B), (A), (B)) -tuple((A), (B), (A), (B), (A), (B), (A), (B)) -tuple((Attr)) +AliasSeq!((A), (B)) +AliasSeq!((A), (B), 0) +AliasSeq!((A), (B), (A)) +AliasSeq!((A), (B), (A), (B)) +AliasSeq!((A), (B), (A), (B)) +AliasSeq!((A), (B), (A), (B), (A), (B), (A), (B)) +AliasSeq!((Attr)) --- */ diff --git a/tests/dmd/compilable/test21282.d b/tests/dmd/compilable/test21282.d index 761a6a60dd7..276591f6b07 100644 --- a/tests/dmd/compilable/test21282.d +++ b/tests/dmd/compilable/test21282.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -tuple(func) +AliasSeq!(func) --- */ // https://issues.dlang.org/show_bug.cgi?id=21282 diff --git a/tests/dmd/compilable/test21330.d b/tests/dmd/compilable/test21330.d index 4abf36717b5..66f9e29a63a 100644 --- a/tests/dmd/compilable/test21330.d +++ b/tests/dmd/compilable/test21330.d @@ -2,8 +2,8 @@ REQUIRED_ARGS: -unittest TEST_OUTPUT: --- -tuple(__unittest_L14_C5_1, __unittest_L14_C5_2) -tuple(__unittest_L14_C5_2) +AliasSeq!(__unittest_L14_C5_1, __unittest_L14_C5_2) +AliasSeq!(__unittest_L14_C5_2) --- */ // https://issues.dlang.org/show_bug.cgi?id=21330 diff --git a/tests/dmd/fail_compilation/casttuple.d b/tests/dmd/fail_compilation/casttuple.d index d08de08b553..89e5f3de7ee 100644 --- a/tests/dmd/fail_compilation/casttuple.d +++ b/tests/dmd/fail_compilation/casttuple.d @@ -1,9 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/casttuple.d(104): Error: cannot cast `__tup1_field_0` of type `int` to tuple type `(string)` -fail_compilation/casttuple.d(107): Error: cannot cast `tuple(__tup2_field_0, __tup2_field_1)` of type `(int, int)` to tuple type `(string, string)` -fail_compilation/casttuple.d(111): Error: cannot cast `tuple(foo, 123)` of type `(int, int)` to tuple type `(string, string)` +fail_compilation/casttuple.d(104): Error: cannot cast `__tup1_field_0` of type `int` to type sequence `(string)` +fail_compilation/casttuple.d(107): Error: cannot cast `AliasSeq!(__tup2_field_0, __tup2_field_1)` of type `(int, int)` to type sequence `(string, string)` +fail_compilation/casttuple.d(111): Error: cannot cast `AliasSeq!(foo, 123)` of type `(int, int)` to type sequence `(string, string)` --- */ diff --git a/tests/dmd/fail_compilation/cppmangle.d b/tests/dmd/fail_compilation/cppmangle.d index 8134afb18d2..b3c89b46d2a 100644 --- a/tests/dmd/fail_compilation/cppmangle.d +++ b/tests/dmd/fail_compilation/cppmangle.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/cppmangle.d(11): Error: expected valid identifier for C++ namespace but got `` fail_compilation/cppmangle.d(15): Error: expected valid identifier for C++ namespace but got `0num` -fail_compilation/cppmangle.d(19): Error: compile time string constant (or tuple) expected, not `2` +fail_compilation/cppmangle.d(19): Error: compile time string constant (or sequence) expected, not `2` fail_compilation/cppmangle.d(23): Error: expected valid identifier for C++ namespace but got `invalid@namespace` --- */ diff --git a/tests/dmd/fail_compilation/dassert.d b/tests/dmd/fail_compilation/dassert.d index 8a813177c35..c18a28d2ffb 100644 --- a/tests/dmd/fail_compilation/dassert.d +++ b/tests/dmd/fail_compilation/dassert.d @@ -2,7 +2,7 @@ REQUIRED_ARGS: -checkaction=context TEST_OUTPUT: --- -fail_compilation/dassert.d(14): Error: expression `tuple(0, 0)` of type `(int, int)` does not have a boolean value +fail_compilation/dassert.d(14): Error: expression `AliasSeq!(0, 0)` of type `(int, int)` does not have a boolean value fail_compilation/dassert.d(21): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/dassert.d(29): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/dassert.d(40): Error: expression `issue()` of type `void` does not have a boolean value diff --git a/tests/dmd/fail_compilation/diag13884.d b/tests/dmd/fail_compilation/diag13884.d index fe47c838dd9..14af2c884a9 100644 --- a/tests/dmd/fail_compilation/diag13884.d +++ b/tests/dmd/fail_compilation/diag13884.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/diag13884.d(14): Error: functions cannot return a tuple +fail_compilation/diag13884.d(14): Error: functions cannot return a sequence (use `std.typecons.Tuple`) fail_compilation/diag13884.d(21): instantiated from here: `MapResult!((t) => t.tupleof, Foo[])` fail_compilation/diag13884.d(14): instantiated from here: `map!(Foo[])` --- diff --git a/tests/dmd/fail_compilation/diag14876.d b/tests/dmd/fail_compilation/diag14876.d index 0ca03602f97..4beea959001 100644 --- a/tests/dmd/fail_compilation/diag14876.d +++ b/tests/dmd/fail_compilation/diag14876.d @@ -8,7 +8,7 @@ fail_compilation/diag14876.d(20): Deprecation: class `diag14876.Dep` is deprecat fail_compilation/diag14876.d(21): Deprecation: class `diag14876.Dep` is deprecated fail_compilation/diag14876.d(22): Deprecation: class `diag14876.Dep` is deprecated fail_compilation/diag14876.d(23): Deprecation: class `diag14876.Dep` is deprecated -fail_compilation/diag14876.d(23): Error: can only slice tuple types, not `diag14876.Dep` +fail_compilation/diag14876.d(23): Error: can only slice type sequences, not `diag14876.Dep` --- */ diff --git a/tests/dmd/fail_compilation/fail12436.d b/tests/dmd/fail_compilation/fail12436.d index 5bdf0d5a891..415e362bf29 100644 --- a/tests/dmd/fail_compilation/fail12436.d +++ b/tests/dmd/fail_compilation/fail12436.d @@ -12,7 +12,7 @@ alias Tuple!(int, int) TupleType; TEST_OUTPUT: --- fail_compilation/fail12436.d(18): Error: functions cannot return a function -fail_compilation/fail12436.d(19): Error: functions cannot return a tuple +fail_compilation/fail12436.d(19): Error: functions cannot return a sequence (use `std.typecons.Tuple`) --- */ FuncType test1(); diff --git a/tests/dmd/fail_compilation/fail15755.d b/tests/dmd/fail_compilation/fail15755.d index 8fd2b51b60a..502eedcd6e3 100644 --- a/tests/dmd/fail_compilation/fail15755.d +++ b/tests/dmd/fail_compilation/fail15755.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail15755.d(28): Error: `tuple(123)` has no effect +fail_compilation/fail15755.d(28): Error: `AliasSeq!(123)` has no effect --- */ diff --git a/tests/dmd/fail_compilation/fail222.d b/tests/dmd/fail_compilation/fail222.d index 30eb0144d99..e196b253065 100644 --- a/tests/dmd/fail_compilation/fail222.d +++ b/tests/dmd/fail_compilation/fail222.d @@ -1,10 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/fail222.d(11): Error: template `fail222.getMixin(TArg..., int i = 0)()` template tuple parameter must be last one +fail_compilation/fail222.d(11): Error: template `fail222.getMixin(TArg..., int i = 0)()` template sequence parameter must be the last one fail_compilation/fail222.d(18): Error: template instance `getMixin!()` does not match template declaration `getMixin(TArg..., int i = 0)()` fail_compilation/fail222.d(21): Error: template instance `fail222.Thing!()` error instantiating -fail_compilation/fail222.d(23): Error: template `fail222.fooBar(A..., B...)()` template tuple parameter must be last one +fail_compilation/fail222.d(23): Error: template `fail222.fooBar(A..., B...)()` template sequence parameter must be the last one --- */ diff --git a/tests/dmd/fail_compilation/ice12574.d b/tests/dmd/fail_compilation/ice12574.d index 93e5f1d8cc0..ecb0fd69a05 100644 --- a/tests/dmd/fail_compilation/ice12574.d +++ b/tests/dmd/fail_compilation/ice12574.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ice12574.d(40): Error: tuple index `2` out of bounds `[0 .. 2]` +fail_compilation/ice12574.d(40): Error: sequence index `2` out of bounds `[0 .. 2]` fail_compilation/ice12574.d(53): Error: template instance `ice12574.reduce!("a", "a").reduce!(Tuple!(int, int, int))` error instantiating --- */ diff --git a/tests/dmd/fail_compilation/ice14424.d b/tests/dmd/fail_compilation/ice14424.d index c99522dceb6..b0e0cd6407f 100644 --- a/tests/dmd/fail_compilation/ice14424.d +++ b/tests/dmd/fail_compilation/ice14424.d @@ -3,7 +3,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ice14424.d(13): Error: `tuple(__unittest_L3_C1)` has no effect +fail_compilation/ice14424.d(13): Error: `AliasSeq!(__unittest_L3_C1)` has no effect --- */ diff --git a/tests/dmd/fail_compilation/typeerrors.d b/tests/dmd/fail_compilation/typeerrors.d index 9d527b75d71..404a4c0e3fe 100644 --- a/tests/dmd/fail_compilation/typeerrors.d +++ b/tests/dmd/fail_compilation/typeerrors.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/typeerrors.d(32): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. -fail_compilation/typeerrors.d(37): Error: tuple index `4` out of bounds `[0 .. 4]` +fail_compilation/typeerrors.d(37): Error: sequence index `4` out of bounds `[0 .. 4]` fail_compilation/typeerrors.d(39): Error: variable `x` cannot be read at compile time fail_compilation/typeerrors.d(40): Error: cannot have array of `void()` fail_compilation/typeerrors.d(41): Error: cannot have array of scope `typeerrors.C` diff --git a/tests/dmd/runnable/uda.d b/tests/dmd/runnable/uda.d index 1d010989646..d4e4c2ae95e 100644 --- a/tests/dmd/runnable/uda.d +++ b/tests/dmd/runnable/uda.d @@ -2,30 +2,30 @@ EXTRA_FILES: imports/a9741.d TEST_OUTPUT: --- -tuple(3, 4, 7, (SSS)) -tuple(3, 4, 7, (SSS)) +AliasSeq!(3, 4, 7, (SSS)) +AliasSeq!(3, 4, 7, (SSS)) 7 SSS -tuple("hello") -tuple('c') -tuple((FFF)) -tuple(10) -tuple(20) -tuple(30) -tuple((Test6)) -tuple(Test7(3, "foo")) -tuple((Test8!"foo")) -tuple((Test9!"foo")) -tuple(Test10(3)) -tuple(Test11(3)) -tuple(10) -tuple(20) -tuple() -tuple(40) +AliasSeq!("hello") +AliasSeq!('c') +AliasSeq!((FFF)) +AliasSeq!(10) +AliasSeq!(20) +AliasSeq!(30) +AliasSeq!((Test6)) +AliasSeq!(Test7(3, "foo")) +AliasSeq!((Test8!"foo")) +AliasSeq!((Test9!"foo")) +AliasSeq!(Test10(3)) +AliasSeq!(Test11(3)) +AliasSeq!(10) +AliasSeq!(20) +AliasSeq!() +AliasSeq!(40) B9741 -tuple((A9741)) -tuple(1) -tuple(2) +AliasSeq!((A9741)) +AliasSeq!(1) +AliasSeq!(2) --- RUN_OUTPUT: diff --git a/tests/dmd/runnable/xtest46.d b/tests/dmd/runnable/xtest46.d index 5017a767693..972de900203 100644 --- a/tests/dmd/runnable/xtest46.d +++ b/tests/dmd/runnable/xtest46.d @@ -13,17 +13,17 @@ runnable/xtest46.d(2964): Deprecation: alias this for classes/interfaces is depr int(int i, long j = 7L) long C10390(C10390(C10390())) -tuple(height) -tuple(get, get) -tuple(clear) -tuple(draw, draw) +AliasSeq!(height) +AliasSeq!(get, get) +AliasSeq!(clear) +AliasSeq!(draw, draw) const(int) string[] double[] double[] {} runnable/xtest46.d(4670): Deprecation: alias this for classes/interfaces is deprecated -tuple("m") +AliasSeq!("m") true TFunction1: extern (C) void function() --- diff --git a/tests/dmd/runnable/xtest46_gc.d b/tests/dmd/runnable/xtest46_gc.d index 224625c65ec..aab6227230a 100644 --- a/tests/dmd/runnable/xtest46_gc.d +++ b/tests/dmd/runnable/xtest46_gc.d @@ -14,17 +14,17 @@ runnable/xtest46_gc.d-mixin-33(2996): Deprecation: alias this for classes/interf int(int i, long j = 7L) long C10390(C10390()) -tuple(height) -tuple(get, get) -tuple(clear) -tuple(draw, draw) +AliasSeq!(height) +AliasSeq!(get, get) +AliasSeq!(clear) +AliasSeq!(draw, draw) const(int) string[] double[] double[] {} runnable/xtest46_gc.d-mixin-33(4702): Deprecation: alias this for classes/interfaces is deprecated -tuple("m") +AliasSeq!("m") true TFunction1: extern (C) void function() --- From a92a88b406bae6f2cd4c1c7602442ab06e0a0ed8 Mon Sep 17 00:00:00 2001 From: Boris Carvajal Date: Fri, 30 Jun 2023 06:41:30 -0400 Subject: [PATCH 096/176] root/array.d: Add `insert` overload for multiple copies (dlang/dmd!15369) --- dmd/frontend.h | 1 + dmd/root/array.d | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/dmd/frontend.h b/dmd/frontend.h index 5903e3a89e5..7ba443441ae 100644 --- a/dmd/frontend.h +++ b/dmd/frontend.h @@ -663,6 +663,7 @@ struct Array final void remove(size_t i); void insert(size_t index, Array* a); void insert(size_t index, T ptr); + void insert(size_t index, size_t count, T value); void setDim(size_t newdim); size_t find(T ptr) const; bool contains(T ptr) const; diff --git a/dmd/root/array.d b/dmd/root/array.d index d1c61be7344..f36ddb4f29e 100644 --- a/dmd/root/array.d +++ b/dmd/root/array.d @@ -251,6 +251,18 @@ public: length++; } + /// Insert 'count' copies of 'value' at 'index' position + void insert(size_t index, size_t count, T value) pure nothrow + { + if (count == 0) + return; + reserve(count); + if (length != index) + memmove(data.ptr + index + count, data.ptr + index, (length - index) * T.sizeof); + data[index .. index + count] = value; + length += count; + } + void setDim(size_t newdim) pure nothrow { if (length < newdim) @@ -458,6 +470,12 @@ unittest arrayA.insert(0, [7, 8]); arrayA.insert(arrayA.length, [0, 9]); assert(arrayA[] == [7, 8, 5, 1, 2, 6, 0, 9]); + arrayA.insert(4, 3, 8); + assert(arrayA[] == [7, 8, 5, 1, 8, 8, 8, 2, 6, 0, 9]); + arrayA.insert(0, 3, 8); + assert(arrayA[] == [8, 8, 8, 7, 8, 5, 1, 8, 8, 8, 2, 6, 0, 9]); + arrayA.insert(arrayA.length, 3, 8); + assert(arrayA[] == [8, 8, 8, 7, 8, 5, 1, 8, 8, 8, 2, 6, 0, 9, 8, 8, 8]); } /** From 10d539a7d3861559cb3d51d6816125f18a100523 Mon Sep 17 00:00:00 2001 From: Boris Carvajal Date: Fri, 30 Jun 2023 11:35:02 -0400 Subject: [PATCH 097/176] Fix Issue 24010 - Destructor called before end of scope for tuples (dlang/dmd!15351) Co-authored-by: Walter Bright --- dmd/statementsem.d | 18 ++++++++++++++++++ tests/dmd/runnable/sdtor.d | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/dmd/statementsem.d b/dmd/statementsem.d index 71ad8bb2d59..5a10241c21d 100644 --- a/dmd/statementsem.d +++ b/dmd/statementsem.d @@ -279,6 +279,24 @@ Statement statementSemanticVisit(Statement s, Scope* sc) ++i; continue; // look for errors in rest of statements } + + // expand tuple variables in order to attach destruction/exception logic + if (auto es = s.isExpStatement()) + { + if (es.exp && es.exp.isDeclarationExp()) + { + auto de = es.exp.isDeclarationExp(); + auto vd = de.declaration.isVarDeclaration(); + if (vd && vd.aliasTuple && vd.aliasTuple.objects.length) + { + auto j = i; + cs.statements.insert(i, vd.aliasTuple.objects.length - 1, null); + vd.aliasTuple.foreachVar((v) { (*cs.statements)[j++] = toStatement(v); }); + s = (*cs.statements)[i]; + } + } + } + Statement sentry; Statement sexception; Statement sfinally; diff --git a/tests/dmd/runnable/sdtor.d b/tests/dmd/runnable/sdtor.d index e6b3238149e..be15cb244a1 100644 --- a/tests/dmd/runnable/sdtor.d +++ b/tests/dmd/runnable/sdtor.d @@ -4813,6 +4813,41 @@ void testPR12012() } } +/**********************************/ +// https://issues.dlang.org/show_bug.cgi?id=24010 + +alias AliasSeq(TList...) = TList; + +__gshared int x24010 = 7; + +struct A24010 { + int x; + ~this() { + printf("A.~this\n"); + x24010 += 1; + } +} + +struct B24010 { + ~this() { + printf("B.~this\n"); + x24010 *= 10; + } +} + +void test24010() +{ + { + AliasSeq!(A24010, B24010) params; + printf("statement\n"); + params[0].x = 3; + printf(".x = %d\n", params[0].x); + assert(params[0].x == 3); + assert(x24010 == 7); + } + assert(x24010 == 71); +} + /**********************************/ int main() @@ -4954,6 +4989,7 @@ int main() test67(); test68(); testPR12012(); + test24010(); printf("Success\n"); return 0; From 52108a97a00a09f97523d6efea38c1b6ee53e073 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Fri, 30 Jun 2023 16:36:30 +0100 Subject: [PATCH 098/176] Fix Issue 24023 - Unnecessary module prefix in error message types (dlang/dmd!15370) --- dmd/mtype.d | 7 +++---- tests/dmd/fail_compilation/callconst.d | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 tests/dmd/fail_compilation/callconst.d diff --git a/dmd/mtype.d b/dmd/mtype.d index 30ab9d06f85..7ecd4023ee1 100644 --- a/dmd/mtype.d +++ b/dmd/mtype.d @@ -4597,10 +4597,9 @@ extern (C++) final class TypeFunction : TypeNext // show qualification when toChars() is the same but types are different // https://issues.dlang.org/show_bug.cgi?id=19948 // when comparing the type with strcmp, we need to drop the qualifier - auto at = arg.type.mutableOf().toChars(); - bool qual = !arg.type.equals(par.type) && strcmp(at, par.type.mutableOf().toChars()) == 0; - if (qual) - at = arg.type.toPrettyChars(true); + bool qual = !arg.type.mutableOf().equals(par.type.mutableOf()) && + strcmp(arg.type.mutableOf().toChars(), par.type.mutableOf().toChars()) == 0; + auto at = qual ? arg.type.toPrettyChars(true) : arg.type.toChars(); OutBuffer buf; // only mention rvalue if it's relevant const rv = !arg.isLvalue() && par.isReference(); diff --git a/tests/dmd/fail_compilation/callconst.d b/tests/dmd/fail_compilation/callconst.d new file mode 100644 index 00000000000..74c1902b2d4 --- /dev/null +++ b/tests/dmd/fail_compilation/callconst.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/callconst.d(13): Error: function `callconst.func(ref X)` is not callable using argument types `(const(X))` +fail_compilation/callconst.d(13): cannot pass argument `x` of type `const(X)` to parameter `ref X` +--- +*/ +struct X {} + +void main() +{ + auto x = const X(); + func(x); +} + +void func(ref X); From 89cda9442cbcc5a42a982a4410582d34525e46db Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Sat, 1 Jul 2023 06:10:53 -0700 Subject: [PATCH 099/176] refactor flatten() (dlang/dmd!15372) --- dmd/statementsem.d | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/dmd/statementsem.d b/dmd/statementsem.d index 5a10241c21d..2def2539597 100644 --- a/dmd/statementsem.d +++ b/dmd/statementsem.d @@ -257,8 +257,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) continue; } - Statements* flt = s.flatten(sc); - if (flt) + if (auto flt = s.flatten(sc)) { cs.statements.remove(i); cs.statements.insert(i, flt); @@ -402,12 +401,11 @@ Statement statementSemanticVisit(Statement s, Scope* sc) /* Flatten them in place */ - void flatten(Statements* statements) + void flattenStatements(ref Statements statements) { for (size_t i = 0; i < statements.length;) { - Statement s = (*statements)[i]; - if (s) + if (auto s = statements[i]) { if (auto flt = s.flatten(sc)) { @@ -424,7 +422,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) * 'semantic' may return another CompoundStatement * (eg. CaseRangeStatement), so flatten it here. */ - flatten(cs.statements); + flattenStatements(*cs.statements); foreach (s; *cs.statements) { From 22587e3dbb3510c1de88eea82110c48edba0378a Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Sun, 2 Jul 2023 12:57:28 +0200 Subject: [PATCH 100/176] Update TEST_OUTPUT messages of tests merged from stable --- tests/dmd/fail_compilation/test21025.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/dmd/fail_compilation/test21025.d b/tests/dmd/fail_compilation/test21025.d index 40b3a96823d..85641998751 100644 --- a/tests/dmd/fail_compilation/test21025.d +++ b/tests/dmd/fail_compilation/test21025.d @@ -6,7 +6,7 @@ TEST_OUTPUT: --- fail_compilation/test21025.d(15): Error: variable `r` cannot be read at compile time fail_compilation/test21025.d(15): called from here: `binaryFun(r, r)` -fail_compilation/test21025.d(24): Error: none of the overloads of template `test21025.uniq` are callable using argument types `!()(void[])` +fail_compilation/test21025.d(24): Error: template `test21025.uniq` is not callable using argument types `!()(void[])` fail_compilation/test21025.d(14): Candidate is: `uniq()(int[] r)` --- */ From 8279873449554334c443f4d7aa86c4bc37cd3f04 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Mon, 3 Jul 2023 01:32:23 -0700 Subject: [PATCH 101/176] fix Issue 18528 - dmd should deduplicate identical errors (dlang/dmd!15312) --- dmd/dsymbolsem.d | 5 ++++- tests/dmd/fail_compilation/fail15896.d | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/dmd/dsymbolsem.d b/dmd/dsymbolsem.d index 622e28691a6..5b19b7540b9 100644 --- a/dmd/dsymbolsem.d +++ b/dmd/dsymbolsem.d @@ -1459,9 +1459,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (sym) { import dmd.access : symbolIsVisible; - if (!symbolIsVisible(sc, sym)) + if (!symbolIsVisible(sc, sym) && !sym.errors) + { imp.mod.error(imp.loc, "member `%s` is not visible from module `%s`", imp.names[i].toChars(), sc._module.toChars()); + sym.errors = true; + } ad.dsymbolSemantic(sc); // If the import declaration is in non-root module, // analysis of the aliased symbol is deferred. diff --git a/tests/dmd/fail_compilation/fail15896.d b/tests/dmd/fail_compilation/fail15896.d index e52503d0975..3fdbf4e9f98 100644 --- a/tests/dmd/fail_compilation/fail15896.d +++ b/tests/dmd/fail_compilation/fail15896.d @@ -14,5 +14,6 @@ int func() { thebar +=1; packagebar += 1; + thebar +=1; return 0; } From 7f983d476a0936465f80100eb6781e1f34839f55 Mon Sep 17 00:00:00 2001 From: Jacob Carlborg Date: Mon, 3 Jul 2023 17:26:30 +0200 Subject: [PATCH 102/176] Add predefined version identifier for visionOS (dlang/dmd!15371) This is Apple's new operating system for their VR/AR device Vision Pro. --- dmd/cond.d | 1 + tests/dmd/fail_compilation/reserved_version.d | 2 ++ 2 files changed, 3 insertions(+) diff --git a/dmd/cond.d b/dmd/cond.d index fcb50e0a648..467f9f1a990 100644 --- a/dmd/cond.d +++ b/dmd/cond.d @@ -733,6 +733,7 @@ extern (C++) final class VersionCondition : DVCondition case "SysV4": case "TVOS": case "unittest": + case "VisionOS": case "WASI": case "WatchOS": case "WebAssembly": diff --git a/tests/dmd/fail_compilation/reserved_version.d b/tests/dmd/fail_compilation/reserved_version.d index 29f96ece787..f7a554ce729 100644 --- a/tests/dmd/fail_compilation/reserved_version.d +++ b/tests/dmd/fail_compilation/reserved_version.d @@ -118,6 +118,7 @@ fail_compilation/reserved_version.d(219): Error: version identifier `D_PostCondi fail_compilation/reserved_version.d(220): Error: version identifier `D_ProfileGC` is reserved and cannot be set fail_compilation/reserved_version.d(221): Error: version identifier `D_Invariants` is reserved and cannot be set fail_compilation/reserved_version.d(222): Error: version identifier `D_Optimized` is reserved and cannot be set +fail_compilation/reserved_version.d(223): Error: version identifier `VisionOS` is reserved and cannot be set --- */ @@ -242,6 +243,7 @@ version = D_PostConditions; version = D_ProfileGC; version = D_Invariants; version = D_Optimized; +version = VisionOS; // This should work though debug = DigitalMars; From e3d1800488762205de8af3a1c2cfba066d3cdfa5 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Tue, 4 Jul 2023 01:15:48 -0700 Subject: [PATCH 103/176] fix Issue 24029 - ImportC: symbol name clash on statement expressions (dlang/dmd!15378) --- dmd/dsymbolsem.d | 3 +++ tests/dmd/runnable/test24029.c | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/dmd/runnable/test24029.c diff --git a/dmd/dsymbolsem.d b/dmd/dsymbolsem.d index 5b19b7540b9..c2f5dff543a 100644 --- a/dmd/dsymbolsem.d +++ b/dmd/dsymbolsem.d @@ -3179,6 +3179,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor funcdecl.skipCodegen = true; funcdecl._linkage = sc.linkage; + if (sc.flags & SCOPE.Cfile && funcdecl.isFuncLiteralDeclaration()) + funcdecl._linkage = LINK.d; // so they are uniquely mangled + if (auto fld = funcdecl.isFuncLiteralDeclaration()) { if (fld.treq) diff --git a/tests/dmd/runnable/test24029.c b/tests/dmd/runnable/test24029.c new file mode 100644 index 00000000000..145f2c28725 --- /dev/null +++ b/tests/dmd/runnable/test24029.c @@ -0,0 +1,23 @@ +// https://issues.dlang.org/show_bug.cgi?id=24029 + +int x = 0; +int y = 0; + +void a() +{ + (__extension__ ({ x += 2; })); // test.a.__dgliteral1 +} + +void b() +{ + (__extension__ ({ y += 1; })); // test.b.__dgliteral1 +} + +int main(void) +{ + a(); + b(); + __check(x == 2); + __check(y == 1); + return 0; +} From 4beeb35af5eac44265a971b1e3e57187fc006733 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Tue, 4 Jul 2023 09:49:11 +0100 Subject: [PATCH 104/176] Fix Issue 24025 - Expressions contained in parentheses should not be assumed to be C casts (dlang/dmd!15377) Allow `(identifier)` and `(BasicType)` when followed by a left parenthesis. These can be a function call or an implicit conversion - the latter may produce a semantic error (not a parse error). --- dmd/parse.d | 6 ++++++ tests/dmd/fail_compilation/ccast.d | 21 ++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/dmd/parse.d b/dmd/parse.d index eeaef8d7d8b..9ae2082f381 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -8823,6 +8823,12 @@ LagainStc: te.parens = true; e = parsePostExp(te); } + else if (token.value == TOK.leftParenthesis) + { + auto te = new AST.TypeExp(loc, t); + te.parens = true; + e = parsePostExp(te); + } else { e = parseUnaryExp(); diff --git a/tests/dmd/fail_compilation/ccast.d b/tests/dmd/fail_compilation/ccast.d index dab29844158..f1ca6c0fada 100644 --- a/tests/dmd/fail_compilation/ccast.d +++ b/tests/dmd/fail_compilation/ccast.d @@ -1,9 +1,28 @@ /* TEST_OUTPUT: --- -fail_compilation/ccast.d(9): Error: C style cast illegal, use `cast(byte)i` +fail_compilation/ccast.d(11): Error: C style cast illegal, use `cast(byte)i` +fail_compilation/ccast.d(24): Error: C style cast illegal, use `cast(foo)5` +fail_compilation/ccast.d(26): Error: C style cast illegal, use `cast(void*)5` --- */ int i; byte b = (byte)i; + +void bar(int x); + +void main() +{ + (&bar)(5); // ok + auto foo = &bar; + (foo = foo)(5); // ok + (*foo)(5); // ok + + (foo)(5); // ok + (bar)(5); // ok + (foo)5; + + (void*)5; + (void*)(5); // semantic implicit cast error +} From eab62363827580ec195686a958a0b57c078498f0 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Wed, 5 Jul 2023 19:09:18 -0700 Subject: [PATCH 105/176] revert deprecation of body (dlang/dmd!15379) --- dmd/parse.d | 64 ++++++++++++++++++------------ tests/dmd/runnable/testcontracts.d | 16 -------- 2 files changed, 38 insertions(+), 42 deletions(-) diff --git a/dmd/parse.d b/dmd/parse.d index 9ae2082f381..05a5549d188 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -718,13 +718,16 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer tk.value == TOK.out_ || tk.value == TOK.do_ || tk.value == TOK.goesTo || tk.value == TOK.identifier && tk.ident == Id._body)) { - // @@@DEPRECATED_2.117@@@ - // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md - // Deprecated in 2.097 - Can be removed from 2.117 - // The deprecation period is longer than usual as `body` - // was quite widely used. - if (tk.value == TOK.identifier && tk.ident == Id._body) - deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); + version (none) + { + // @@@DEPRECATED_2.117@@@ + // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md + // Deprecated in 2.097 - Can be removed from 2.117 + // The deprecation period is longer than usual as `body` + // was quite widely used. + if (tk.value == TOK.identifier && tk.ident == Id._body) + deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); + } a = parseDeclarations(true, pAttrs, pAttrs.comment); if (a && a.length) @@ -4450,13 +4453,16 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer (tk.value == TOK.leftParenthesis || tk.value == TOK.leftCurly || tk.value == TOK.in_ || tk.value == TOK.out_ || tk.value == TOK.goesTo || tk.value == TOK.do_ || tk.value == TOK.identifier && tk.ident == Id._body)) { - // @@@DEPRECATED_2.117@@@ - // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md - // Deprecated in 2.097 - Can be removed from 2.117 - // The deprecation period is longer than usual as `body` - // was quite widely used. - if (tk.value == TOK.identifier && tk.ident == Id._body) - deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); + version (none) + { + // @@@DEPRECATED_2.117@@@ + // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md + // Deprecated in 2.097 - Can be removed from 2.117 + // The deprecation period is longer than usual as `body` + // was quite widely used. + if (tk.value == TOK.identifier && tk.ident == Id._body) + deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); + } ts = null; } @@ -5193,12 +5199,15 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.identifier: if (token.ident == Id._body) { - // @@@DEPRECATED_2.117@@@ - // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md - // Deprecated in 2.097 - Can be removed from 2.117 - // The deprecation period is longer than usual as `body` - // was quite widely used. - deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); + version (none) + { + // @@@DEPRECATED_2.117@@@ + // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md + // Deprecated in 2.097 - Can be removed from 2.117 + // The deprecation period is longer than usual as `body` + // was quite widely used. + deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); + } goto case TOK.do_; } goto default; @@ -7572,12 +7581,15 @@ LagainStc: case TOK.identifier: if (t.ident == Id._body) { - // @@@DEPRECATED_2.117@@@ - // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md - // Deprecated in 2.097 - Can be removed from 2.117 - // The deprecation period is longer than usual as `body` - // was quite widely used. - deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); + version (none) + { + // @@@DEPRECATED_2.117@@@ + // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md + // Deprecated in 2.097 - Can be removed from 2.117 + // The deprecation period is longer than usual as `body` + // was quite widely used. + deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); + } goto case TOK.do_; } goto default; diff --git a/tests/dmd/runnable/testcontracts.d b/tests/dmd/runnable/testcontracts.d index 439040b7b38..63d18fcc627 100644 --- a/tests/dmd/runnable/testcontracts.d +++ b/tests/dmd/runnable/testcontracts.d @@ -1,20 +1,4 @@ /* PERMUTE_ARGS: -inline -g -O -TEST_OUTPUT: ---- -runnable/testcontracts.d(323): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(324): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(325): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(326): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(328): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(329): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(330): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(331): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(502): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(503): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(504): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(505): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(505): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. ---- */ extern(C) int printf(const char*, ...); From fe26df6a1b0f259a52e9d8ac75214d8119e7224e Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Thu, 6 Jul 2023 00:36:58 -0700 Subject: [PATCH 106/176] fix Issue 24024 - cannot pass class this to ref class (dlang/dmd!15389) --- dmd/expression.d | 24 +++++++++++++++--------- tests/dmd/compilable/deprecate14283.d | 8 ++++---- tests/dmd/fail_compilation/diag4596.d | 4 ++-- tests/dmd/fail_compilation/fail13116.d | 2 +- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/dmd/expression.d b/dmd/expression.d index 35f11afdc93..7adc051dd48 100644 --- a/dmd/expression.d +++ b/dmd/expression.d @@ -2468,19 +2468,13 @@ extern (C++) class ThisExp : Expression return typeof(return)(true); } - override final bool isLvalue() + override bool isLvalue() { - // Class `this` should be an rvalue; struct `this` should be an lvalue. - return type.toBasetype().ty != Tclass; + return true; } - override final Expression toLvalue(Scope* sc, Expression e) + override Expression toLvalue(Scope* sc, Expression e) { - if (type.toBasetype().ty == Tclass) - { - // Class `this` is an rvalue; struct `this` is an lvalue. - return Expression.toLvalue(sc, e); - } return this; } @@ -2500,6 +2494,18 @@ extern (C++) final class SuperExp : ThisExp super(loc, EXP.super_); } + override final bool isLvalue() + { + // Class `super` should be an rvalue + return false; + } + + override final Expression toLvalue(Scope* sc, Expression e) + { + // Class `super` is an rvalue + return Expression.toLvalue(sc, e); + } + override void accept(Visitor v) { v.visit(this); diff --git a/tests/dmd/compilable/deprecate14283.d b/tests/dmd/compilable/deprecate14283.d index e91db649cee..fc51cf3f0b6 100644 --- a/tests/dmd/compilable/deprecate14283.d +++ b/tests/dmd/compilable/deprecate14283.d @@ -1,12 +1,12 @@ -// REQUIRED_ARGS: -dw +// REQUIRED_ARGS: // PERMUTE_ARGS: class C { void bug() { - autoref(this); // 'auto ref' becomes non-ref parameter - autoref(super); // 'auto ref' becomes non-ref parameter + autoref!(true, C)(this); // 'auto ref' becomes ref parameter + autoref!(false, Object)(super); // 'auto ref' becomes non-ref parameter } } -void autoref(T)(auto ref T t) { static assert(__traits(isRef, t) == false); } +void autoref(bool result, T)(auto ref T t) { static assert(__traits(isRef, t) == result); } diff --git a/tests/dmd/fail_compilation/diag4596.d b/tests/dmd/fail_compilation/diag4596.d index f6b49d6bd13..517b328e8d6 100644 --- a/tests/dmd/fail_compilation/diag4596.d +++ b/tests/dmd/fail_compilation/diag4596.d @@ -1,13 +1,13 @@ /* TEST_OUTPUT: --- -fail_compilation/diag4596.d(15): Error: `this` is not an lvalue and cannot be modified -fail_compilation/diag4596.d(16): Error: conditional expression `1 ? this : this` is not a modifiable lvalue fail_compilation/diag4596.d(18): Error: `super` is not an lvalue and cannot be modified fail_compilation/diag4596.d(19): Error: conditional expression `1 ? super : super` is not a modifiable lvalue --- */ + + class NoGo4596 { void fun() diff --git a/tests/dmd/fail_compilation/fail13116.d b/tests/dmd/fail_compilation/fail13116.d index ac520d79997..077fa75ac77 100644 --- a/tests/dmd/fail_compilation/fail13116.d +++ b/tests/dmd/fail_compilation/fail13116.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail13116.d(14): Error: `this` is not an lvalue and cannot be modified +fail_compilation/fail13116.d(14): Error: returning `this` escapes a reference to parameter `this` fail_compilation/fail13116.d(23): Error: `super` is not an lvalue and cannot be modified --- */ From 27057411cfa44b8c26361d73d5d292c736e9e970 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Thu, 6 Jul 2023 03:58:38 -0700 Subject: [PATCH 107/176] parse.d: add usageOfBodyKeyword() (dlang/dmd!15388) --- dmd/parse.d | 63 +++++++++++++++++++---------------------------------- 1 file changed, 22 insertions(+), 41 deletions(-) diff --git a/dmd/parse.d b/dmd/parse.d index 05a5549d188..70ce7fe8d3c 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -718,16 +718,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer tk.value == TOK.out_ || tk.value == TOK.do_ || tk.value == TOK.goesTo || tk.value == TOK.identifier && tk.ident == Id._body)) { - version (none) - { - // @@@DEPRECATED_2.117@@@ - // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md - // Deprecated in 2.097 - Can be removed from 2.117 - // The deprecation period is longer than usual as `body` - // was quite widely used. - if (tk.value == TOK.identifier && tk.ident == Id._body) - deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); - } + if (tk.value == TOK.identifier && tk.ident == Id._body) + usageOfBodyKeyword(); a = parseDeclarations(true, pAttrs, pAttrs.comment); if (a && a.length) @@ -1166,7 +1158,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer a = parseDeclDefs(0, pLastDecl); if (token.value != TOK.rightCurly) { - /* { */ + /* left curly brace */ error("matching `}` expected, not `%s`", token.toChars()); eSink.errorSupplemental(lcLoc, "unmatched `{`"); } @@ -1508,7 +1500,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value != TOK.leftCurly) { - error("`{` expected after template parameter list, not `%s`", token.toChars()); + error("`{` expected after template parameter list, not `%s`", token.toChars()); /* } */ goto Lerr; } decldefs = parseBlock(null); @@ -2727,7 +2719,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); - const(char)* begPtr = token.ptr + 1; // skip '{' + const(char)* begPtr = token.ptr + 1; // skip left curly brace const(char)* endPtr = null; AST.Statement sbody = parseStatement(ParseStatementFlags.curly, &endPtr); @@ -4453,16 +4445,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer (tk.value == TOK.leftParenthesis || tk.value == TOK.leftCurly || tk.value == TOK.in_ || tk.value == TOK.out_ || tk.value == TOK.goesTo || tk.value == TOK.do_ || tk.value == TOK.identifier && tk.ident == Id._body)) { - version (none) - { - // @@@DEPRECATED_2.117@@@ - // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md - // Deprecated in 2.097 - Can be removed from 2.117 - // The deprecation period is longer than usual as `body` - // was quite widely used. - if (tk.value == TOK.identifier && tk.ident == Id._body) - deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); - } + if (tk.value == TOK.identifier && tk.ident == Id._body) + usageOfBodyKeyword(); ts = null; } @@ -5199,15 +5183,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.identifier: if (token.ident == Id._body) { - version (none) - { - // @@@DEPRECATED_2.117@@@ - // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md - // Deprecated in 2.097 - Can be removed from 2.117 - // The deprecation period is longer than usual as `body` - // was quite widely used. - deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); - } + usageOfBodyKeyword(); goto case TOK.do_; } goto default; @@ -7581,15 +7557,7 @@ LagainStc: case TOK.identifier: if (t.ident == Id._body) { - version (none) - { - // @@@DEPRECATED_2.117@@@ - // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md - // Deprecated in 2.097 - Can be removed from 2.117 - // The deprecation period is longer than usual as `body` - // was quite widely used. - deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); - } + usageOfBodyKeyword(); goto case TOK.do_; } goto default; @@ -9544,6 +9512,19 @@ LagainStc: STC.live | /*STC.future |*/ // probably should be included STC.disable; + + void usageOfBodyKeyword() + { + version (none) + { + // @@@DEPRECATED_2.117@@@ + // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md + // Deprecated in 2.097 - Can be removed from 2.117 + // The deprecation period is longer than usual as `body` + // was quite widely used. + deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); + } + } } enum PREC : int From 0d6bfeb55bb22429dfbe549247272fcd0d634917 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Thu, 6 Jul 2023 18:59:46 -0700 Subject: [PATCH 108/176] add -wo switch about use of obsolete features (dlang/dmd!15381) --- dmd/cli.d | 5 +++++ dmd/frontend.h | 5 ++++- dmd/globals.d | 1 + dmd/globals.h | 1 + dmd/mars.d | 2 ++ 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/dmd/cli.d b/dmd/cli.d index d72d003322c..11df29548ea 100644 --- a/dmd/cli.d +++ b/dmd/cli.d @@ -820,6 +820,11 @@ dmd -cov -unittest myprog.d `Enable $(LINK2 $(ROOT_DIR)articles/warnings.html, informational warnings (i.e. compilation still proceeds normally))`, ), + Option("wo", + "warnings about use of obsolete features (compilation will continue)", + `Enable warnings about use of obsolete features that may be problematic (compilation + still proceeds normally)`, + ), Option("X", "generate JSON file" ), diff --git a/dmd/frontend.h b/dmd/frontend.h index 7ba443441ae..0e13bd9e90e 100644 --- a/dmd/frontend.h +++ b/dmd/frontend.h @@ -3079,6 +3079,7 @@ struct Param final bool release; bool preservePaths; DiagnosticReporting warnings; + bool obsolete; bool color; bool cov; uint8_t covPercent; @@ -3184,6 +3185,7 @@ struct Param final release(), preservePaths(), warnings((DiagnosticReporting)2u), + obsolete(), color(), cov(), covPercent(), @@ -3263,7 +3265,7 @@ struct Param final mapfile() { } - Param(bool obj, bool multiobj = false, bool trace = false, bool tracegc = false, bool verbose = false, bool vcg_ast = false, bool showColumns = false, bool vtls = false, bool vtemplates = false, bool vtemplatesListInstances = false, bool vgc = false, bool vfield = false, bool vcomplex = true, bool vin = false, DiagnosticReporting useDeprecated = (DiagnosticReporting)1u, bool useUnitTests = false, bool useInline = false, bool release = false, bool preservePaths = false, DiagnosticReporting warnings = (DiagnosticReporting)2u, bool color = false, bool cov = false, uint8_t covPercent = 0u, bool ctfe_cov = false, bool ignoreUnsupportedPragmas = false, bool useModuleInfo = true, bool useTypeInfo = true, bool useExceptions = true, bool betterC = false, bool addMain = false, bool allInst = false, bool bitfields = false, CppStdRevision cplusplus = (CppStdRevision)201103u, bool showGaggedErrors = false, bool printErrorContext = false, bool manual = false, bool usage = false, bool mcpuUsage = false, bool transitionUsage = false, bool checkUsage = false, bool checkActionUsage = false, bool revertUsage = false, bool previewUsage = false, bool externStdUsage = false, bool hcUsage = false, bool logo = false, FeatureState useDIP25 = (FeatureState)1, FeatureState useDIP1000 = (FeatureState)-1, bool ehnogc = false, bool useDIP1021 = false, FeatureState fieldwise = (FeatureState)-1, bool fixAliasThis = false, FeatureState rvalueRefParam = (FeatureState)-1, FeatureState noSharedAccess = (FeatureState)-1, bool previewIn = false, bool inclusiveInContracts = false, bool shortenedMethods = true, bool fixImmutableConv = false, bool fix16997 = true, FeatureState dtorFields = (FeatureState)-1, FeatureState systemVariables = (FeatureState)-1, CHECKENABLE useInvariants = (CHECKENABLE)0u, CHECKENABLE useIn = (CHECKENABLE)0u, CHECKENABLE useOut = (CHECKENABLE)0u, CHECKENABLE useArrayBounds = (CHECKENABLE)0u, CHECKENABLE useAssert = (CHECKENABLE)0u, CHECKENABLE useSwitchError = (CHECKENABLE)0u, CHECKENABLE boundscheck = (CHECKENABLE)0u, CHECKACTION checkAction = (CHECKACTION)0u, uint32_t errorLimit = 20u, uint32_t errorSupplementLimit = 6u, _d_dynamicArray< const char > argv0 = {}, Array modFileAliasStrings = Array(), Array* imppath = nullptr, Array* fileImppath = nullptr, _d_dynamicArray< const char > objdir = {}, _d_dynamicArray< const char > objname = {}, _d_dynamicArray< const char > libname = {}, Output ddoc = Output(), Output dihdr = Output(), Output cxxhdr = Output(), Output json = Output(), JsonFieldFlags jsonFieldFlags = (JsonFieldFlags)0u, Output makeDeps = Output(), Output mixinOut = Output(), Output moduleDeps = Output(), uint32_t debuglevel = 0u, Array* debugids = nullptr, uint32_t versionlevel = 0u, Array* versionids = nullptr, MessageStyle messageStyle = (MessageStyle)0u, bool run = false, Array runargs = Array(), Array cppswitches = Array(), const char* cpp = nullptr, Array objfiles = Array(), Array linkswitches = Array(), Array linkswitchIsForCC = Array(), Array libfiles = Array(), Array dllfiles = Array(), _d_dynamicArray< const char > deffile = {}, _d_dynamicArray< const char > resfile = {}, _d_dynamicArray< const char > exefile = {}, _d_dynamicArray< const char > mapfile = {}) : + Param(bool obj, bool multiobj = false, bool trace = false, bool tracegc = false, bool verbose = false, bool vcg_ast = false, bool showColumns = false, bool vtls = false, bool vtemplates = false, bool vtemplatesListInstances = false, bool vgc = false, bool vfield = false, bool vcomplex = true, bool vin = false, DiagnosticReporting useDeprecated = (DiagnosticReporting)1u, bool useUnitTests = false, bool useInline = false, bool release = false, bool preservePaths = false, DiagnosticReporting warnings = (DiagnosticReporting)2u, bool obsolete = false, bool color = false, bool cov = false, uint8_t covPercent = 0u, bool ctfe_cov = false, bool ignoreUnsupportedPragmas = false, bool useModuleInfo = true, bool useTypeInfo = true, bool useExceptions = true, bool betterC = false, bool addMain = false, bool allInst = false, bool bitfields = false, CppStdRevision cplusplus = (CppStdRevision)201103u, bool showGaggedErrors = false, bool printErrorContext = false, bool manual = false, bool usage = false, bool mcpuUsage = false, bool transitionUsage = false, bool checkUsage = false, bool checkActionUsage = false, bool revertUsage = false, bool previewUsage = false, bool externStdUsage = false, bool hcUsage = false, bool logo = false, FeatureState useDIP25 = (FeatureState)1, FeatureState useDIP1000 = (FeatureState)-1, bool ehnogc = false, bool useDIP1021 = false, FeatureState fieldwise = (FeatureState)-1, bool fixAliasThis = false, FeatureState rvalueRefParam = (FeatureState)-1, FeatureState noSharedAccess = (FeatureState)-1, bool previewIn = false, bool inclusiveInContracts = false, bool shortenedMethods = true, bool fixImmutableConv = false, bool fix16997 = true, FeatureState dtorFields = (FeatureState)-1, FeatureState systemVariables = (FeatureState)-1, CHECKENABLE useInvariants = (CHECKENABLE)0u, CHECKENABLE useIn = (CHECKENABLE)0u, CHECKENABLE useOut = (CHECKENABLE)0u, CHECKENABLE useArrayBounds = (CHECKENABLE)0u, CHECKENABLE useAssert = (CHECKENABLE)0u, CHECKENABLE useSwitchError = (CHECKENABLE)0u, CHECKENABLE boundscheck = (CHECKENABLE)0u, CHECKACTION checkAction = (CHECKACTION)0u, uint32_t errorLimit = 20u, uint32_t errorSupplementLimit = 6u, _d_dynamicArray< const char > argv0 = {}, Array modFileAliasStrings = Array(), Array* imppath = nullptr, Array* fileImppath = nullptr, _d_dynamicArray< const char > objdir = {}, _d_dynamicArray< const char > objname = {}, _d_dynamicArray< const char > libname = {}, Output ddoc = Output(), Output dihdr = Output(), Output cxxhdr = Output(), Output json = Output(), JsonFieldFlags jsonFieldFlags = (JsonFieldFlags)0u, Output makeDeps = Output(), Output mixinOut = Output(), Output moduleDeps = Output(), uint32_t debuglevel = 0u, Array* debugids = nullptr, uint32_t versionlevel = 0u, Array* versionids = nullptr, MessageStyle messageStyle = (MessageStyle)0u, bool run = false, Array runargs = Array(), Array cppswitches = Array(), const char* cpp = nullptr, Array objfiles = Array(), Array linkswitches = Array(), Array linkswitchIsForCC = Array(), Array libfiles = Array(), Array dllfiles = Array(), _d_dynamicArray< const char > deffile = {}, _d_dynamicArray< const char > resfile = {}, _d_dynamicArray< const char > exefile = {}, _d_dynamicArray< const char > mapfile = {}) : obj(obj), multiobj(multiobj), trace(trace), @@ -3284,6 +3286,7 @@ struct Param final release(release), preservePaths(preservePaths), warnings(warnings), + obsolete(obsolete), color(color), cov(cov), covPercent(covPercent), diff --git a/dmd/globals.d b/dmd/globals.d index 0ac60420ef7..bdd12ccad83 100644 --- a/dmd/globals.d +++ b/dmd/globals.d @@ -124,6 +124,7 @@ extern (C++) struct Param bool release; // build release version bool preservePaths; // true means don't strip path from source file DiagnosticReporting warnings = DiagnosticReporting.off; // how compiler warnings are handled + bool obsolete; // enable warnings about use of obsolete messages bool color; // use ANSI colors in console output bool cov; // generate code coverage data ubyte covPercent; // 0..100 code coverage percentage required diff --git a/dmd/globals.h b/dmd/globals.h index 66345acc88b..bf23b86d80e 100644 --- a/dmd/globals.h +++ b/dmd/globals.h @@ -119,6 +119,7 @@ struct Param d_bool release; // build release version d_bool preservePaths; // true means don't strip path from source file Diagnostic warnings; + d_bool obsolete; // warn about use of obsolete features d_bool color; // use ANSI colors in console output d_bool cov; // generate code coverage data unsigned char covPercent; // 0..100 code coverage percentage required diff --git a/dmd/mars.d b/dmd/mars.d index 539f712c0c3..56d8d9db7ea 100644 --- a/dmd/mars.d +++ b/dmd/mars.d @@ -1942,6 +1942,8 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param params.warnings = DiagnosticReporting.error; else if (arg == "-wi") // https://dlang.org/dmd.html#switch-wi params.warnings = DiagnosticReporting.inform; + else if (arg == "-wo") // https://dlang.org/dmd.html#switch-wo + params.obsolete = true; else if (arg == "-O") // https://dlang.org/dmd.html#switch-O driverParams.optimize = true; else if (arg == "-o-") // https://dlang.org/dmd.html#switch-o- From d42f54b0a784e7f78630f11831511a793f32afa5 Mon Sep 17 00:00:00 2001 From: Razvan Nitu Date: Mon, 10 Jul 2023 16:11:54 +0300 Subject: [PATCH 109/176] Update C++ headers (dlang/dmd!15396) --- dmd/expression.h | 6 ++++-- dmd/frontend.h | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/dmd/expression.h b/dmd/expression.h index 770c3e7ae3d..8c6393fb6e1 100644 --- a/dmd/expression.h +++ b/dmd/expression.h @@ -348,8 +348,8 @@ class ThisExp : public Expression ThisExp *syntaxCopy() override; Optional toBool() override; - bool isLvalue() override final; - Expression *toLvalue(Scope *sc, Expression *e) override final; + bool isLvalue() override; + Expression *toLvalue(Scope *sc, Expression *e) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -357,6 +357,8 @@ class ThisExp : public Expression class SuperExp final : public ThisExp { public: + bool isLvalue() override; + Expression* toLvalue(Scope* sc, Expression* e) final override; void accept(Visitor *v) override { v->visit(this); } }; diff --git a/dmd/frontend.h b/dmd/frontend.h index 0e13bd9e90e..34de0740d13 100644 --- a/dmd/frontend.h +++ b/dmd/frontend.h @@ -7150,14 +7150,16 @@ class ThisExp : public Expression ThisExp(const Loc& loc, const EXP tok); ThisExp* syntaxCopy() override; Optional toBool() override; - bool isLvalue() final override; - Expression* toLvalue(Scope* sc, Expression* e) final override; + bool isLvalue() override; + Expression* toLvalue(Scope* sc, Expression* e) override; void accept(Visitor* v) override; }; class SuperExp final : public ThisExp { public: + bool isLvalue() override; + Expression* toLvalue(Scope* sc, Expression* e) override; void accept(Visitor* v) override; }; From 60c4f6e034ad0d239bc7762bd90ab6cfd87e7ef0 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Mon, 10 Jul 2023 06:16:55 -0700 Subject: [PATCH 110/176] dstyle recommends these changes (dlang/dmd!15395) --- dmd/expression.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dmd/expression.d b/dmd/expression.d index 7adc051dd48..9477867e929 100644 --- a/dmd/expression.d +++ b/dmd/expression.d @@ -2494,13 +2494,13 @@ extern (C++) final class SuperExp : ThisExp super(loc, EXP.super_); } - override final bool isLvalue() + override bool isLvalue() { // Class `super` should be an rvalue return false; } - override final Expression toLvalue(Scope* sc, Expression e) + override Expression toLvalue(Scope* sc, Expression e) { // Class `super` is an rvalue return Expression.toLvalue(sc, e); From 4eeb4fece1ef36b41f41e7fe9a5bbbbe7cb1ae91 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Mon, 10 Jul 2023 22:40:29 +0200 Subject: [PATCH 111/176] Fix regression introduced by dlang/dmd!15359 (dlang/dmd!15399) --- dmd/expressionsem.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index f6bfae99914..be597dfa90f 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -4065,7 +4065,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (arg.op == EXP.error) return setError(); arg = arg.optimize(WANTvalue); - if (arg.op == EXP.int64 && (target.is64bit ? + if (arg.op == EXP.int64 && (target.isLP64 ? cast(sinteger_t)arg.toInteger() : cast(int)arg.toInteger()) < 0) { exp.error("negative array dimension `%s`", (*exp.arguments)[i].toChars()); From 7ef10f5b1d5a06c720aa582f302ebede38c23993 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Mon, 10 Jul 2023 21:52:37 +0100 Subject: [PATCH 112/176] [core.int128] Make I, U private, document Cent type (dlang/dmd!15390) --- runtime/druntime/src/core/int128.d | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/runtime/druntime/src/core/int128.d b/runtime/druntime/src/core/int128.d index 20fa7dea170..4c88f15abfb 100644 --- a/runtime/druntime/src/core/int128.d +++ b/runtime/druntime/src/core/int128.d @@ -14,8 +14,8 @@ nothrow: @safe: @nogc: -alias I = long; -alias U = ulong; +private alias I = long; +private alias U = ulong; enum Ubits = uint(U.sizeof * 8); version (DigitalMars) @@ -36,6 +36,10 @@ else else private enum Cent_alignment = (size_t.sizeof * 2); } +/** + * 128 bit integer type. + * See_also: $(REF Int128, std,int128). + */ align(Cent_alignment) struct Cent { version (LittleEndian) From 82b24137a7f56aba93aa8b9607c3b3f795d2dede Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Mon, 10 Jul 2023 16:22:25 -0700 Subject: [PATCH 113/176] make use of body as keyword a legacy feature (dlang/dmd!15394) --- dmd/frontend.h | 9 ++++++--- dmd/globals.h | 1 + dmd/lexer.d | 1 + dmd/mars.d | 8 ++++++-- dmd/parse.d | 11 +++-------- tests/dmd/fail_compilation/body.d | 11 +++++++++++ 6 files changed, 28 insertions(+), 13 deletions(-) create mode 100644 tests/dmd/fail_compilation/body.d diff --git a/dmd/frontend.h b/dmd/frontend.h index 34de0740d13..f71ae503186 100644 --- a/dmd/frontend.h +++ b/dmd/frontend.h @@ -3384,6 +3384,7 @@ struct CompileEnv final bool previewIn; bool ddocOutput; bool shortenedMethods; + bool obsolete; CompileEnv() : versionNumber(), date(), @@ -3392,10 +3393,11 @@ struct CompileEnv final timestamp(), previewIn(), ddocOutput(), - shortenedMethods(true) + shortenedMethods(true), + obsolete() { } - CompileEnv(uint32_t versionNumber, _d_dynamicArray< const char > date = {}, _d_dynamicArray< const char > time = {}, _d_dynamicArray< const char > vendor = {}, _d_dynamicArray< const char > timestamp = {}, bool previewIn = false, bool ddocOutput = false, bool shortenedMethods = true) : + CompileEnv(uint32_t versionNumber, _d_dynamicArray< const char > date = {}, _d_dynamicArray< const char > time = {}, _d_dynamicArray< const char > vendor = {}, _d_dynamicArray< const char > timestamp = {}, bool previewIn = false, bool ddocOutput = false, bool shortenedMethods = true, bool obsolete = false) : versionNumber(versionNumber), date(date), time(time), @@ -3403,7 +3405,8 @@ struct CompileEnv final timestamp(timestamp), previewIn(previewIn), ddocOutput(ddocOutput), - shortenedMethods(shortenedMethods) + shortenedMethods(shortenedMethods), + obsolete(obsolete) {} }; diff --git a/dmd/globals.h b/dmd/globals.h index bf23b86d80e..93dc4db96df 100644 --- a/dmd/globals.h +++ b/dmd/globals.h @@ -264,6 +264,7 @@ struct CompileEnv bool previewIn; bool ddocOutput; bool shortenedMethods; + bool obsolete; }; struct Global diff --git a/dmd/lexer.d b/dmd/lexer.d index add1ce68468..9cce7c56723 100644 --- a/dmd/lexer.d +++ b/dmd/lexer.d @@ -51,6 +51,7 @@ struct CompileEnv bool previewIn; /// `in` means `[ref] scope const`, accepts rvalues bool ddocOutput; /// collect embedded documentation comments bool shortenedMethods = true; /// allow => in normal function declarations + bool obsolete; /// warn on use of legacy code } /*********************************************************** diff --git a/dmd/mars.d b/dmd/mars.d index 56d8d9db7ea..73c986ba967 100644 --- a/dmd/mars.d +++ b/dmd/mars.d @@ -153,9 +153,10 @@ private int tryMain(size_t argc, const(char)** argv, ref Param params) if (parseCommandlineAndConfig(argc, argv, params, files)) return EXIT_FAILURE; - global.compileEnv.previewIn = global.params.previewIn; - global.compileEnv.ddocOutput = global.params.ddoc.doOutput; + global.compileEnv.previewIn = global.params.previewIn; + global.compileEnv.ddocOutput = global.params.ddoc.doOutput; global.compileEnv.shortenedMethods = global.params.shortenedMethods; + global.compileEnv.obsolete = global.params.obsolete; if (params.usage) { @@ -1943,7 +1944,10 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param else if (arg == "-wi") // https://dlang.org/dmd.html#switch-wi params.warnings = DiagnosticReporting.inform; else if (arg == "-wo") // https://dlang.org/dmd.html#switch-wo + { + params.warnings = DiagnosticReporting.inform; params.obsolete = true; + } else if (arg == "-O") // https://dlang.org/dmd.html#switch-O driverParams.optimize = true; else if (arg == "-o-") // https://dlang.org/dmd.html#switch-o- diff --git a/dmd/parse.d b/dmd/parse.d index 70ce7fe8d3c..a0818fde423 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -9515,14 +9515,9 @@ LagainStc: void usageOfBodyKeyword() { - version (none) - { - // @@@DEPRECATED_2.117@@@ - // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md - // Deprecated in 2.097 - Can be removed from 2.117 - // The deprecation period is longer than usual as `body` - // was quite widely used. - deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); + if (compileEnv.obsolete) + { + eSink.warning(token.loc, "usage of identifer `body` as a keyword is obsolete. Use `do` instead."); } } } diff --git a/tests/dmd/fail_compilation/body.d b/tests/dmd/fail_compilation/body.d new file mode 100644 index 00000000000..7b718c25060 --- /dev/null +++ b/tests/dmd/fail_compilation/body.d @@ -0,0 +1,11 @@ +/* REQUIRED_ARGS: -wo -w +TEST_OUTPUT: +--- +fail_compilation/body.d(11): Warning: usage of identifer `body` as a keyword is obsolete. Use `do` instead. +Error: warnings are treated as errors + Use -wi if you wish to treat warnings only as informational. +--- +*/ + +void test() +in { } body { } From a02cabc80ff5ebfa558bd18d77a22a3dae689293 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Tue, 11 Jul 2023 01:22:36 -0700 Subject: [PATCH 114/176] add ENDBR32 and ENDBR64 to inline assembler (dlang/dmd!15401) --- tests/dmd/runnable/iasm64.d | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/dmd/runnable/iasm64.d b/tests/dmd/runnable/iasm64.d index 1883c873873..4fd78797440 100644 --- a/tests/dmd/runnable/iasm64.d +++ b/tests/dmd/runnable/iasm64.d @@ -3718,6 +3718,8 @@ void test50() 0x9B, // wait 0x91, // xchg EAX,ECX 0xD7, // xlat + 0xF3, 0x0F, 0x1E, 0xFB, // endbr32 + 0xF3, 0x0F, 0x1E, 0xFA, // endbr64 0x48, 0x8D, 0x1D, 0x02, 0x00, 0x00, 0x00, // lea RBX,L1; 0x89, 0xC0, // mov EAX,EAX ]; @@ -3844,6 +3846,8 @@ L10: nop; nop; // put instructions above this or L10 changes wait ; xchg EAX,ECX ; xlat ; + endbr32 ; + endbr64 ; lea RBX,L1 ; mov EAX,EAX ; @@ -3853,6 +3857,7 @@ L1: ; } for (i = 0; i < data.length; i++) { + //printf("[%d] %02x %02x\n", i, p[i], data[i]); assert(p[i] == data[i]); } } From 9dbb4053b8ff8798566b571bb79c69bc9c62e1c9 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Tue, 11 Jul 2023 10:29:25 +0200 Subject: [PATCH 115/176] target: Rename is64bit to isX86_64 (dlang/dmd!15398) --- dmd/frontend.h | 8 ++--- dmd/mars.d | 20 +++++------ dmd/target.d | 56 +++++++++++++++--------------- dmd/target.h | 2 +- tests/dmd/dub_package/avg.d | 2 +- tests/dmd/dub_package/impvisitor.d | 2 +- tests/dmd/unit/triple.d | 8 ++--- 7 files changed, 49 insertions(+), 49 deletions(-) diff --git a/dmd/frontend.h b/dmd/frontend.h index f71ae503186..7273739898d 100644 --- a/dmd/frontend.h +++ b/dmd/frontend.h @@ -8192,7 +8192,7 @@ struct Target final TargetObjC objc; _d_dynamicArray< const char > architectureName; CPU cpu; - bool is64bit; + bool isX86_64; bool isLP64; _d_dynamicArray< const char > obj_ext; _d_dynamicArray< const char > lib_ext; @@ -8265,7 +8265,7 @@ struct Target final objc(), architectureName(), cpu((CPU)11u), - is64bit(true), + isX86_64(true), isLP64(), obj_ext(), lib_ext(), @@ -8279,7 +8279,7 @@ struct Target final params() { } - Target(OS os, uint8_t osMajor = 0u, uint8_t ptrsize = 0u, uint8_t realsize = 0u, uint8_t realpad = 0u, uint8_t realalignsize = 0u, uint8_t classinfosize = 0u, uint64_t maxStaticDataSize = 0LLU, TargetC c = TargetC(), TargetCPP cpp = TargetCPP(), TargetObjC objc = TargetObjC(), _d_dynamicArray< const char > architectureName = {}, CPU cpu = (CPU)11u, bool is64bit = true, bool isLP64 = false, _d_dynamicArray< const char > obj_ext = {}, _d_dynamicArray< const char > lib_ext = {}, _d_dynamicArray< const char > dll_ext = {}, bool run_noext = false, bool omfobj = false, FPTypeProperties FloatProperties = FPTypeProperties(), FPTypeProperties DoubleProperties = FPTypeProperties(), FPTypeProperties<_d_real > RealProperties = FPTypeProperties<_d_real >(), Type* tvalist = nullptr, const Param* params = nullptr) : + Target(OS os, uint8_t osMajor = 0u, uint8_t ptrsize = 0u, uint8_t realsize = 0u, uint8_t realpad = 0u, uint8_t realalignsize = 0u, uint8_t classinfosize = 0u, uint64_t maxStaticDataSize = 0LLU, TargetC c = TargetC(), TargetCPP cpp = TargetCPP(), TargetObjC objc = TargetObjC(), _d_dynamicArray< const char > architectureName = {}, CPU cpu = (CPU)11u, bool isX86_64 = true, bool isLP64 = false, _d_dynamicArray< const char > obj_ext = {}, _d_dynamicArray< const char > lib_ext = {}, _d_dynamicArray< const char > dll_ext = {}, bool run_noext = false, bool omfobj = false, FPTypeProperties FloatProperties = FPTypeProperties(), FPTypeProperties DoubleProperties = FPTypeProperties(), FPTypeProperties<_d_real > RealProperties = FPTypeProperties<_d_real >(), Type* tvalist = nullptr, const Param* params = nullptr) : os(os), osMajor(osMajor), ptrsize(ptrsize), @@ -8293,7 +8293,7 @@ struct Target final objc(objc), architectureName(architectureName), cpu(cpu), - is64bit(is64bit), + isX86_64(isX86_64), isLP64(isLP64), obj_ext(obj_ext), lib_ext(lib_ext), diff --git a/dmd/mars.d b/dmd/mars.d index 73c986ba967..8478194b824 100644 --- a/dmd/mars.d +++ b/dmd/mars.d @@ -698,7 +698,7 @@ bool parseCommandlineAndConfig(size_t argc, const(char)** argv, ref Param params sections.push("Environment"); parseConfFile(environment, global.inifilename, inifilepath, inifileBuffer, §ions); - const(char)[] arch = target.is64bit ? "64" : "32"; // use default + const(char)[] arch = target.isX86_64 ? "64" : "32"; // use default arch = parse_arch_arg(&arguments, arch); // parse architecture from DFLAGS read from [Environment] section @@ -709,7 +709,7 @@ bool parseCommandlineAndConfig(size_t argc, const(char)** argv, ref Param params arch = parse_arch_arg(&dflags, arch); } - bool is64bit = arch[0] == '6'; + bool isX86_64 = arch[0] == '6'; version(Windows) // delete LIB entry in [Environment] (necessary for optlink) to allow inheriting environment for MS-COFF if (arch != "32omf") @@ -732,7 +732,7 @@ bool parseCommandlineAndConfig(size_t argc, const(char)** argv, ref Param params return true; } - if (target.is64bit != is64bit) + if (target.isX86_64 != isX86_64) error(Loc.initial, "the architecture must not be changed in the %s section of %.*s", envsection.ptr, cast(int)global.inifilename.length, global.inifilename.ptr); @@ -1128,7 +1128,7 @@ private void setDefaultLibrary(ref Param params, const ref Target target) { if (target.os == Target.OS.Windows) { - if (target.is64bit) + if (target.isX86_64) driverParams.defaultlibname = "phobos64"; else if (!target.omfobj) driverParams.defaultlibname = "phobos32mscoff"; @@ -1621,22 +1621,22 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param } else if (arg == "-m32") // https://dlang.org/dmd.html#switch-m32 { - target.is64bit = false; + target.isX86_64 = false; target.omfobj = false; } else if (arg == "-m64") // https://dlang.org/dmd.html#switch-m64 { - target.is64bit = true; + target.isX86_64 = true; target.omfobj = false; } else if (arg == "-m32mscoff") // https://dlang.org/dmd.html#switch-m32mscoff { - target.is64bit = false; + target.isX86_64 = false; target.omfobj = false; } else if (arg == "-m32omf") // https://dlang.org/dmd.html#switch-m32omfobj { - target.is64bit = false; + target.isX86_64 = false; target.omfobj = true; } else if (startsWith(p + 1, "mscrtlib=")) @@ -2439,7 +2439,7 @@ private void reconcileCommands(ref Param params, ref Target target) } else if (target.os == Target.OS.DragonFlyBSD) { - if (!target.is64bit) + if (!target.isX86_64) error(Loc.initial, "`-m32` is not supported on DragonFlyBSD, it is 64-bit only"); } @@ -2554,7 +2554,7 @@ private void reconcileLinkRunLib(ref Param params, size_t numSrcFiles, const cha { VSOptions vsopt; vsopt.initialize(); - driverParams.mscrtlib = vsopt.defaultRuntimeLibrary(target.is64bit).toDString; + driverParams.mscrtlib = vsopt.defaultRuntimeLibrary(target.isX86_64).toDString; } else { diff --git a/dmd/target.d b/dmd/target.d index 7d930f2c564..e7c3dbc9d68 100644 --- a/dmd/target.d +++ b/dmd/target.d @@ -186,7 +186,7 @@ void addPredefinedGlobalIdentifiers(const ref Target tgt) case OS.Windows: { predef("Windows"); - VersionCondition.addPredefinedGlobalIdent(tgt.is64bit ? "Win64" : "Win32"); + VersionCondition.addPredefinedGlobalIdent(tgt.isX86_64 ? "Win64" : "Win32"); break; } case OS.OSX: @@ -216,7 +216,7 @@ void addPredefinedGlobalIdentifiers(const ref Target tgt) addCRuntimePredefinedGlobalIdent(tgt.c); addCppRuntimePredefinedGlobalIdent(tgt.cpp); - if (tgt.is64bit) + if (tgt.isX86_64) { VersionCondition.addPredefinedGlobalIdent("D_InlineAsm_X86_64"); VersionCondition.addPredefinedGlobalIdent("X86_64"); @@ -229,7 +229,7 @@ void addPredefinedGlobalIdentifiers(const ref Target tgt) } if (tgt.isLP64) VersionCondition.addPredefinedGlobalIdent("D_LP64"); - else if (tgt.is64bit) + else if (tgt.isX86_64) VersionCondition.addPredefinedGlobalIdent("X32"); } @@ -345,7 +345,7 @@ extern (C++) struct Target /// Architecture name const(char)[] architectureName; CPU cpu = CPU.baseline; // CPU instruction set to target - bool is64bit = (size_t.sizeof == 8); // generate 64 bit code for x86_64; true by default for 64 bit dmd + bool isX86_64 = (size_t.sizeof == 8); // generate 64 bit code for x86_64; true by default for 64 bit dmd bool isLP64; // pointers are 64 bits // Environmental @@ -401,7 +401,7 @@ extern (C++) struct Target */ extern (C++) void _init(ref const Param params) { - // is64bit, omfobj and cpu are initialized in parseCommandLine + // isX86_64, omfobj and cpu are initialized in parseCommandLine this.params = ¶ms; @@ -409,7 +409,7 @@ extern (C++) struct Target DoubleProperties.initialize(); RealProperties.initialize(); - isLP64 = is64bit; + isLP64 = isX86_64; // These have default values for 32 bit code, they get // adjusted for 64 bit code. @@ -456,7 +456,7 @@ extern (C++) struct Target } else assert(0); - if (is64bit) + if (isX86_64) { if (os & (Target.OS.linux | Target.OS.FreeBSD | Target.OS.OpenBSD | Target.OS.DragonFlyBSD | Target.OS.Solaris)) { @@ -470,7 +470,7 @@ extern (C++) struct Target cpp.initialize(params, this); objc.initialize(params, this); - if (is64bit) + if (isX86_64) architectureName = "X86_64"; else architectureName = "X86"; @@ -577,7 +577,7 @@ extern (C++) struct Target case TY.Timaginary64: case TY.Tcomplex64: if (os & Target.OS.Posix) - return is64bit ? 8 : 4; + return isX86_64 ? 8 : 4; break; default: break; @@ -596,7 +596,7 @@ extern (C++) struct Target { const size = type.alignsize(); - if ((is64bit || os == Target.OS.OSX) && (size == 16 || size == 32)) + if ((isX86_64 || os == Target.OS.OSX) && (size == 16 || size == 32)) return size; return (8 < size) ? 8 : size; @@ -621,7 +621,7 @@ extern (C++) struct Target } else if (os & Target.OS.Posix) { - if (is64bit) + if (isX86_64) { import dmd.identifier : Identifier; import dmd.mtype : TypeIdentifier; @@ -949,7 +949,7 @@ extern (C++) struct Target { import dmd.argtypes_x86 : toArgTypes_x86; import dmd.argtypes_sysv_x64 : toArgTypes_sysv_x64; - if (is64bit) + if (isX86_64) { // no argTypes for Win64 yet return isPOSIX ? toArgTypes_sysv_x64(t) : null; @@ -996,7 +996,7 @@ extern (C++) struct Target const sz = tn.size(); Type tns = tn; - if (os == Target.OS.Windows && is64bit) + if (os == Target.OS.Windows && isX86_64) { // https://msdn.microsoft.com/en-us/library/7572ztz4%28v=vs.100%29.aspx if (tns.ty == TY.Tcomplex32) @@ -1028,7 +1028,7 @@ extern (C++) struct Target return true; } } - else if (is64bit && isPOSIX) + else if (isX86_64 && isPOSIX) { TypeTuple tt = toArgTypes_sysv_x64(tn); if (!tt) @@ -1044,7 +1044,7 @@ extern (C++) struct Target if (tns.ty != TY.Tstruct) { L2: - if (os == Target.OS.linux && tf.linkage != LINK.d && !is64bit) + if (os == Target.OS.linux && tf.linkage != LINK.d && !isX86_64) { // 32 bit C/C++ structs always on stack } @@ -1071,12 +1071,12 @@ extern (C++) struct Target if (auto ts = tns.isTypeStruct()) { auto sd = ts.sym; - if (os == Target.OS.linux && tf.linkage != LINK.d && !is64bit) + if (os == Target.OS.linux && tf.linkage != LINK.d && !isX86_64) { //printf(" 2 true\n"); return true; // 32 bit C/C++ structs always on stack } - if (os == Target.OS.Windows && tf.linkage == LINK.cpp && !is64bit && + if (os == Target.OS.Windows && tf.linkage == LINK.cpp && !isX86_64 && sd.isPOD() && sd.ctor) { // win32 returns otherwise POD structs with ctors via memory @@ -1089,7 +1089,7 @@ extern (C++) struct Target goto L2; goto Lagain; } - else if (is64bit && sd.numArgTypes() == 0) + else if (isX86_64 && sd.numArgTypes() == 0) return true; else if (sd.isPOD()) { @@ -1103,7 +1103,7 @@ extern (C++) struct Target return false; // return small structs in regs // (not 3 byte structs!) case 16: - if (os & Target.OS.Posix && is64bit) + if (os & Target.OS.Posix && isX86_64) return false; break; @@ -1124,7 +1124,7 @@ extern (C++) struct Target return true; } else if (os == Target.OS.Windows && - !is64bit && + !isX86_64 && tf.linkage == LINK.cpp && tf.isfloating()) { @@ -1152,7 +1152,7 @@ extern (C++) struct Target extern (C++) bool preferPassByRef(Type t) { const size = t.size(); - if (is64bit) + if (isX86_64) { if (os == Target.OS.Windows) { @@ -1279,7 +1279,7 @@ extern (C++) struct Target */ extern (C++) bool libraryObjectMonitors(FuncDeclaration fd, Statement fbody) { - if (!is64bit && os == Target.OS.Windows && !fd.isStatic() && !fbody.usesEH() && !params.trace) + if (!isX86_64 && os == Target.OS.Windows && !fd.isStatic() && !fbody.usesEH() && !params.trace) { /* The back end uses the "jmonitor" hack for syncing; * no need to do the sync in the library. @@ -1310,7 +1310,7 @@ extern (C++) struct Target */ extern (D) bool isXmmSupported() { - return is64bit || os == Target.OS.OSX; + return isX86_64 || os == Target.OS.OSX; } /** @@ -1330,7 +1330,7 @@ extern (C++) struct Target */ extern (D) uint stackAlign() { - return isXmmSupported() ? 16 : (is64bit ? 8 : 4); + return isXmmSupported() ? 16 : (isX86_64 ? 8 : 4); } } @@ -1388,14 +1388,14 @@ struct TargetC longsize = 4; else assert(0); - if (target.is64bit) + if (target.isX86_64) { if (os & (Target.OS.linux | Target.OS.FreeBSD | Target.OS.OpenBSD | Target.OS.DragonFlyBSD | Target.OS.Solaris)) longsize = 8; else if (os == Target.OS.OSX) longsize = 8; } - if (target.is64bit && os == Target.OS.Windows) + if (target.isX86_64 && os == Target.OS.Windows) long_doublesize = 8; else long_doublesize = target.realsize; @@ -1486,7 +1486,7 @@ struct TargetCPP else assert(0); // C++ and D ABI incompatible on all (?) x86 32-bit platforms - wrapDtorInExternD = !target.is64bit; + wrapDtorInExternD = !target.isX86_64; } /** @@ -1620,7 +1620,7 @@ struct TargetObjC extern (D) void initialize(ref const Param params, ref const Target target) { - if (target.os == Target.OS.OSX && target.is64bit) + if (target.os == Target.OS.OSX && target.isX86_64) supported = true; } } diff --git a/dmd/target.h b/dmd/target.h index 561afa18d42..ca0e09c88e0 100644 --- a/dmd/target.h +++ b/dmd/target.h @@ -156,7 +156,7 @@ struct Target DString architectureName; // name of the platform architecture (e.g. X86_64) CPU cpu; // CPU instruction set to target - d_bool is64bit; // generate 64 bit code for x86_64; true by default for 64 bit dmd + d_bool isX86_64; // generate 64 bit code for x86_64; true by default for 64 bit dmd d_bool isLP64; // pointers are 64 bits // Environmental diff --git a/tests/dmd/dub_package/avg.d b/tests/dmd/dub_package/avg.d index b6f9f1e8898..9be5a0a3910 100755 --- a/tests/dmd/dub_package/avg.d +++ b/tests/dmd/dub_package/avg.d @@ -53,7 +53,7 @@ void main() Id.initialize(); global._init(); target.os = Target.OS.linux; - target.is64bit = (size_t.sizeof == 8); + target.isX86_64 = (size_t.sizeof == 8); global.params.useUnitTests = true; ASTBase.Type._init(); diff --git a/tests/dmd/dub_package/impvisitor.d b/tests/dmd/dub_package/impvisitor.d index c27a71abea0..8619748f947 100755 --- a/tests/dmd/dub_package/impvisitor.d +++ b/tests/dmd/dub_package/impvisitor.d @@ -100,7 +100,7 @@ void main() Id.initialize(); global._init(); target.os = Target.OS.linux; - target.is64bit = (size_t.sizeof == 8); + target.isX86_64 = (size_t.sizeof == 8); global.params.useUnitTests = true; ASTBase.Type._init(); diff --git a/tests/dmd/unit/triple.d b/tests/dmd/unit/triple.d index bbfe027dc6c..a95145bff88 100644 --- a/tests/dmd/unit/triple.d +++ b/tests/dmd/unit/triple.d @@ -16,7 +16,7 @@ unittest { auto triple = Triple("x86-unknown-windows-msvc"); assert(triple.os == Target.OS.Windows); - assert(triple.is64bit == false); + assert(triple.isX86_64 == false); assert(triple.cenv == TargetC.Runtime.Microsoft); } @@ -25,7 +25,7 @@ unittest { auto triple = Triple("x64-apple-darwin20.3.0"); assert(triple.os == Target.OS.OSX); - assert(triple.is64bit == true); + assert(triple.isX86_64 == true); } @("-target=x86_64+avx2-apple-darwin20.3.0") @@ -33,7 +33,7 @@ unittest { auto triple = Triple("x86_64+avx2-apple-darwin20.3.0"); assert(triple.os == Target.OS.OSX); - assert(triple.is64bit == true); + assert(triple.isX86_64 == true); assert(triple.cpu == CPU.avx2); } @@ -41,7 +41,7 @@ unittest unittest { auto triple = Triple("x86_64-unknown-linux-musl-clang"); - assert(triple.is64bit == true); + assert(triple.isX86_64 == true); assert(triple.os == Target.OS.linux); assert(triple.cenv == TargetC.Runtime.Musl); assert(triple.cppenv == TargetCPP.Runtime.Clang); From 41a3ee4b7c8fdcc66dc38db3889135465c8ece3c Mon Sep 17 00:00:00 2001 From: Dennis Date: Tue, 11 Jul 2023 14:27:45 +0200 Subject: [PATCH 116/176] Remove dead code in FuncDeclaration dsymbolsem (dlang/dmd!15402) --- dmd/dsymbolsem.d | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/dmd/dsymbolsem.d b/dmd/dsymbolsem.d index c2f5dff543a..9f5856d5bcb 100644 --- a/dmd/dsymbolsem.d +++ b/dmd/dsymbolsem.d @@ -3466,23 +3466,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (funcdecl.isAbstract() && funcdecl.isFinalFunc()) funcdecl.error("cannot be both `final` and `abstract`"); - version (none) - { - if (funcdecl.isAbstract() && funcdecl.fbody) - funcdecl.error("`abstract` functions cannot have bodies"); - } - - version (none) - { - if (funcdecl.isStaticConstructor() || funcdecl.isStaticDestructor()) - { - if (!funcdecl.isStatic() || funcdecl.type.nextOf().ty != Tvoid) - funcdecl.error("static constructors / destructors must be `static void`"); - if (f.arguments && f.arguments.length) - funcdecl.error("static constructors / destructors must have empty parameter list"); - // BUG: check for invalid storage classes - } - } if (funcdecl.printf || funcdecl.scanf) { From dd6d10c8078e686d62906ae6923322c25eb5b81f Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Wed, 12 Jul 2023 10:37:42 -0700 Subject: [PATCH 117/176] revert deprecation of scope class (dlang/dmd!15380) --- dmd/dsymbolsem.d | 56 ++++++++++++++---------- tests/dmd/compilable/test7172.d | 6 +-- tests/dmd/fail_compilation/fail22780.d | 2 +- tests/dmd/fail_compilation/scope_class.d | 2 +- tests/dmd/fail_compilation/scope_type.d | 16 ------- tests/dmd/fail_compilation/typeerrors.d | 2 +- tests/dmd/runnable/sctor2.d | 5 --- 7 files changed, 38 insertions(+), 51 deletions(-) delete mode 100644 tests/dmd/fail_compilation/scope_type.d diff --git a/dmd/dsymbolsem.d b/dmd/dsymbolsem.d index 9f5856d5bcb..11c4028bc8d 100644 --- a/dmd/dsymbolsem.d +++ b/dmd/dsymbolsem.d @@ -2234,11 +2234,14 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (!(sc.flags & SCOPE.Cfile)) // C enum remains incomplete until members are done ed.semanticRun = PASS.semanticdone; - // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint - // Deprecated in 2.100 - // Make an error in 2.110 - if (sc.stc & STC.scope_) - deprecation(ed.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); + version (none) + { + // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint + // Deprecated in 2.100 + // Make an error in 2.110 + if (sc.stc & STC.scope_) + deprecation(ed.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); + } Scope* sce; if (ed.isAnonymous()) @@ -4858,11 +4861,14 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sd.deferred.semantic3(sc); } - // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint - // Deprecated in 2.100 - // Make an error in 2.110 - if (sd.storage_class & STC.scope_) - deprecation(sd.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); + version (none) + { + // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint + // Deprecated in 2.100 + // Make an error in 2.110 + if (sd.storage_class & STC.scope_) + deprecation(sd.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); + } //printf("-StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok); } @@ -5527,12 +5533,15 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } //printf("-ClassDeclaration.dsymbolSemantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); - // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint - // Deprecated in 2.100 - // Make an error in 2.110 - // Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036 - if (cldec.storage_class & STC.scope_) - deprecation(cldec.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); + version (none) + { + // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint + // Deprecated in 2.100 + // Make an error in 2.110 + // Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036 + if (cldec.storage_class & STC.scope_) + deprecation(cldec.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); + } } override void visit(InterfaceDeclaration idec) @@ -5833,12 +5842,15 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } assert(idec.type.ty != Tclass || (cast(TypeClass)idec.type).sym == idec); - // @@@DEPRECATED_2.120@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint - // Deprecated in 2.087 - // Made an error in 2.100, but removal depends on `scope class` being removed too - // Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036 - if (idec.storage_class & STC.scope_) - error(idec.loc, "`scope` as a type constraint is obsolete. Use `scope` at the usage site."); + version (none) + { + // @@@DEPRECATED_2.120@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint + // Deprecated in 2.087 + // Made an error in 2.100, but removal depends on `scope class` being removed too + // Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036 + if (idec.storage_class & STC.scope_) + error(idec.loc, "`scope` as a type constraint is obsolete. Use `scope` at the usage site."); + } } } diff --git a/tests/dmd/compilable/test7172.d b/tests/dmd/compilable/test7172.d index 013630bd483..49142d78988 100644 --- a/tests/dmd/compilable/test7172.d +++ b/tests/dmd/compilable/test7172.d @@ -1,8 +1,4 @@ -/* TEST_OUTPUT: ---- -compilable/test7172.d(14): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. ---- -*/ + void main() { abstract class AbstractC{} diff --git a/tests/dmd/fail_compilation/fail22780.d b/tests/dmd/fail_compilation/fail22780.d index e22be9fe047..8d4c8a891f0 100644 --- a/tests/dmd/fail_compilation/fail22780.d +++ b/tests/dmd/fail_compilation/fail22780.d @@ -1,10 +1,10 @@ // https://issues.dlang.org/show_bug.cgi?id=22780 /* TEST_OUTPUT: --- -fail_compilation/fail22780.d(8): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. fail_compilation/fail22780.d(12): Error: variable `fail22780.test10717.c` reference to `scope class` must be `scope` --- */ + scope class C10717 { } void test10717() diff --git a/tests/dmd/fail_compilation/scope_class.d b/tests/dmd/fail_compilation/scope_class.d index bba14908833..b5e1a54d71b 100644 --- a/tests/dmd/fail_compilation/scope_class.d +++ b/tests/dmd/fail_compilation/scope_class.d @@ -1,12 +1,12 @@ /* TEST_OUTPUT: --- -fail_compilation/scope_class.d(10): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. fail_compilation/scope_class.d(12): Error: functions cannot return `scope scope_class.C` --- */ + scope class C { int i; } // Notice the use of `scope` here C increment(C c) diff --git a/tests/dmd/fail_compilation/scope_type.d b/tests/dmd/fail_compilation/scope_type.d deleted file mode 100644 index e0550138b7e..00000000000 --- a/tests/dmd/fail_compilation/scope_type.d +++ /dev/null @@ -1,16 +0,0 @@ -/* -REQUIRED_ARGS: -de -TEST_OUTPUT: ---- -fail_compilation/scope_type.d(13): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. -fail_compilation/scope_type.d(14): Error: `scope` as a type constraint is obsolete. Use `scope` at the usage site. -fail_compilation/scope_type.d(15): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. -fail_compilation/scope_type.d(16): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. ---- -*/ - - -scope class C { } -scope interface I { } -scope struct S { } -scope enum E { e } diff --git a/tests/dmd/fail_compilation/typeerrors.d b/tests/dmd/fail_compilation/typeerrors.d index 404a4c0e3fe..4c8576c88d9 100644 --- a/tests/dmd/fail_compilation/typeerrors.d +++ b/tests/dmd/fail_compilation/typeerrors.d @@ -1,7 +1,6 @@ /* TEST_OUTPUT: --- -fail_compilation/typeerrors.d(32): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. fail_compilation/typeerrors.d(37): Error: sequence index `4` out of bounds `[0 .. 4]` fail_compilation/typeerrors.d(39): Error: variable `x` cannot be read at compile time fail_compilation/typeerrors.d(40): Error: cannot have array of `void()` @@ -25,6 +24,7 @@ fail_compilation/typeerrors.d(57): Error: slice `[2..1]` is out of range of [0.. + template tuple(T...) { alias T tuple; } void bar(); diff --git a/tests/dmd/runnable/sctor2.d b/tests/dmd/runnable/sctor2.d index bd820e498f4..a574c3e55f5 100644 --- a/tests/dmd/runnable/sctor2.d +++ b/tests/dmd/runnable/sctor2.d @@ -1,10 +1,5 @@ // REQUIRED_ARGS: -w -dw // PERMUTE_ARGS: -/* TEST_OUTPUT: ---- -runnable/sctor2.d(12): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site. ---- -*/ /***************************************************/ // 15665 From 1726fa69b4c229e3cca454318c4853ca6df3de1e Mon Sep 17 00:00:00 2001 From: Dennis Date: Thu, 13 Jul 2023 09:52:12 +0200 Subject: [PATCH 118/176] Fix 24044 - Support float opCmp(...) with array (dlang/dmd!15407) --- .../src/core/internal/array/comparison.d | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/runtime/druntime/src/core/internal/array/comparison.d b/runtime/druntime/src/core/internal/array/comparison.d index 821f96e25c0..94fa2433da8 100644 --- a/runtime/druntime/src/core/internal/array/comparison.d +++ b/runtime/druntime/src/core/internal/array/comparison.d @@ -83,7 +83,7 @@ int __cmp(T)(scope const T[] lhs, scope const T[] rhs) @trusted // This function is called by the compiler when dealing with array // comparisons in the semantic analysis phase of CmpExp. The ordering // comparison is lowered to a call to this template. -int __cmp(T1, T2)(T1[] s1, T2[] s2) +auto __cmp(T1, T2)(T1[] s1, T2[] s2) if (!__traits(isScalar, T1) && !__traits(isScalar, T2)) { import core.internal.traits : Unqual; @@ -237,3 +237,26 @@ if (!__traits(isScalar, T1) && !__traits(isScalar, T2)) auto vb = [cast(void[])b[0], b[1]]; assert(less2(va, vb)); } + +// custom aggregate types +@safe unittest +{ + // https://issues.dlang.org/show_bug.cgi?id=24044 + // Support float opCmp(...) with array + static struct F + { + float f; + float opCmp(F other) const { return this.f - other.f; } + } + + F[2] a = [F(1.0f), F(float.nan)]; + F[2] b = [F(1.0f), F(1.0f)]; + F[1] c = [F(1.0f)]; + + bool isNan(float f) { return f != f; } + + assert(isNan(__cmp(a, b))); + assert(isNan(__cmp(a, a))); + assert(__cmp(b, b) == 0); + assert(__cmp(a, c) > 0); +} From ea93d17e6f938599d1f4fc421a3e276c4093dcd2 Mon Sep 17 00:00:00 2001 From: Dennis Date: Thu, 13 Jul 2023 12:31:17 +0200 Subject: [PATCH 119/176] Improve pragma(printf) signature error message (dlang/dmd!15403) * Extract printf signature check into its own function * Improve pragma(printf) signature error message --- dmd/dsymbolsem.d | 113 +++++++++++++++------------- tests/dmd/fail_compilation/format.d | 21 ++++-- 2 files changed, 75 insertions(+), 59 deletions(-) diff --git a/dmd/dsymbolsem.d b/dmd/dsymbolsem.d index 11c4028bc8d..7a800bddd02 100644 --- a/dmd/dsymbolsem.d +++ b/dmd/dsymbolsem.d @@ -3472,57 +3472,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (funcdecl.printf || funcdecl.scanf) { - /* printf/scanf-like functions must be of the form: - * extern (C/C++) T printf([parameters...], const(char)* format, ...); - * or: - * extern (C/C++) T vprintf([parameters...], const(char)* format, va_list); - */ - - static bool isPointerToChar(Parameter p) - { - if (auto tptr = p.type.isTypePointer()) - { - return tptr.next.ty == Tchar; - } - return false; - } - - bool isVa_list(Parameter p) - { - return p.type.equals(target.va_listType(funcdecl.loc, sc)); - } - - const nparams = f.parameterList.length; - if ((f.linkage == LINK.c || f.linkage == LINK.cpp) && - - (f.parameterList.varargs == VarArg.variadic && - nparams >= 1 && - isPointerToChar(f.parameterList[nparams - 1]) || - - f.parameterList.varargs == VarArg.none && - nparams >= 2 && - isPointerToChar(f.parameterList[nparams - 2]) && - isVa_list(f.parameterList[nparams - 1]) - ) - ) - { - // the signature is valid for printf/scanf, no error - } - else - { - const p = (funcdecl.printf ? Id.printf : Id.scanf).toChars(); - if (f.parameterList.varargs == VarArg.variadic) - { - funcdecl.error("`pragma(%s)` functions must be `extern(C) %s %s([parameters...], const(char)*, ...)`" - ~ " not `%s`", - p, f.next.toChars(), funcdecl.toChars(), funcdecl.type.toChars()); - } - else - { - funcdecl.error("`pragma(%s)` functions must be `extern(C) %s %s([parameters...], const(char)*, va_list)`", - p, f.next.toChars(), funcdecl.toChars()); - } - } + checkPrintfScanfSignature(funcdecl, f, sc); } if (auto id = parent.isInterfaceDeclaration()) @@ -7387,3 +7337,64 @@ private void writeMixin(const(char)[] s, ref const Loc loc, ref int lines, ref O buf.writenl(); ++lines; } + +/** + * Check signature of `pragma(printf)` function, print error if invalid. + * + * printf/scanf-like functions must be of the form: + * extern (C/C++) T printf([parameters...], const(char)* format, ...); + * or: + * extern (C/C++) T vprintf([parameters...], const(char)* format, va_list); + * + * Params: + * funcdecl = function to check + * f = function type + * sc = scope + */ +void checkPrintfScanfSignature(FuncDeclaration funcdecl, TypeFunction f, Scope* sc) +{ + static bool isPointerToChar(Parameter p) + { + if (auto tptr = p.type.isTypePointer()) + { + return tptr.next.ty == Tchar; + } + return false; + } + + bool isVa_list(Parameter p) + { + return p.type.equals(target.va_listType(funcdecl.loc, sc)); + } + + const nparams = f.parameterList.length; + const p = (funcdecl.printf ? Id.printf : Id.scanf).toChars(); + if (!(f.linkage == LINK.c || f.linkage == LINK.cpp)) + { + .error(funcdecl.loc, "`pragma(%s)` function `%s` must have `extern(C)` or `extern(C++)` linkage," + ~" not `extern(%s)`", + p, funcdecl.toChars(), f.linkage.linkageToChars()); + } + if (f.parameterList.varargs == VarArg.variadic) + { + if (!(nparams >= 1 && isPointerToChar(f.parameterList[nparams - 1]))) + { + .error(funcdecl.loc, "`pragma(%s)` function `%s` must have" + ~ " signature `%s %s([parameters...], const(char)*, ...)` not `%s`", + p, funcdecl.toChars(), f.next.toChars(), funcdecl.toChars(), funcdecl.type.toChars()); + } + } + else if (f.parameterList.varargs == VarArg.none) + { + if(!(nparams >= 2 && isPointerToChar(f.parameterList[nparams - 2]) && + isVa_list(f.parameterList[nparams - 1]))) + .error(funcdecl.loc, "`pragma(%s)` function `%s` must have"~ + " signature `%s %s([parameters...], const(char)*, va_list)`", + p, funcdecl.toChars(), f.next.toChars(), funcdecl.toChars()); + } + else + { + .error(funcdecl.loc, "`pragma(%s)` function `%s` must have C-style variadic `...` or `va_list` parameter", + p, funcdecl.toChars()); + } +} diff --git a/tests/dmd/fail_compilation/format.d b/tests/dmd/fail_compilation/format.d index bc40d9a527a..cfd30bfc82e 100644 --- a/tests/dmd/fail_compilation/format.d +++ b/tests/dmd/fail_compilation/format.d @@ -1,10 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/format.d(101): Error: function `format.printf1` `pragma(printf)` functions must be `extern(C) void printf1([parameters...], const(char)*, ...)` not `void(const(char)*, ...)` -fail_compilation/format.d(102): Error: function `format.printf2` `pragma(printf)` functions must be `extern(C) int printf2([parameters...], const(char)*, ...)` not `extern (C) int(const(int)*, ...)` -fail_compilation/format.d(103): Error: function `format.printf3` `pragma(printf)` functions must be `extern(C) int printf3([parameters...], const(char)*, va_list)` -fail_compilation/format.d(104): Error: function `format.printf4` `pragma(printf)` functions must be `extern(C) int printf4([parameters...], const(char)*, ...)` not `extern (C) int(const(char)*, int, ...)` +fail_compilation/format.d(101): Error: `pragma(printf)` function `printf1` must have `extern(C)` or `extern(C++)` linkage, not `extern(D)` +fail_compilation/format.d(102): Error: `pragma(printf)` function `printf2` must have signature `int printf2([parameters...], const(char)*, ...)` not `extern (C) int(const(int)*, ...)` +fail_compilation/format.d(103): Error: `pragma(printf)` function `printf3` must have signature `int printf3([parameters...], const(char)*, va_list)` +fail_compilation/format.d(104): Error: `pragma(printf)` function `printf4` must have signature `int printf4([parameters...], const(char)*, ...)` not `extern (C) int(const(char)*, int, ...)` --- */ @@ -22,10 +22,13 @@ pragma(printf) extern (C) int printf7(char*, ...); /* TEST_OUTPUT: --- -fail_compilation/format.d(203): Error: function `format.vprintf1` `pragma(printf)` functions must be `extern(C) void vprintf1([parameters...], const(char)*, va_list)` -fail_compilation/format.d(204): Error: function `format.vprintf2` `pragma(printf)` functions must be `extern(C) int vprintf2([parameters...], const(char)*, va_list)` -fail_compilation/format.d(205): Error: function `format.vprintf3` `pragma(printf)` functions must be `extern(C) int vprintf3([parameters...], const(char)*, va_list)` -fail_compilation/format.d(206): Error: function `format.vprintf4` `pragma(printf)` functions must be `extern(C) int vprintf4([parameters...], const(char)*, va_list)` +fail_compilation/format.d(203): Error: `pragma(printf)` function `vprintf1` must have `extern(C)` or `extern(C++)` linkage, not `extern(D)` +fail_compilation/format.d(204): Error: `pragma(printf)` function `vprintf2` must have signature `int vprintf2([parameters...], const(char)*, va_list)` +fail_compilation/format.d(205): Error: `pragma(printf)` function `vprintf3` must have signature `int vprintf3([parameters...], const(char)*, va_list)` +fail_compilation/format.d(206): Error: `pragma(printf)` function `vprintf4` must have signature `int vprintf4([parameters...], const(char)*, va_list)` +fail_compilation/format.d(207): Error: `pragma(printf)` function `vprintf5` must have C-style variadic `...` or `va_list` parameter +fail_compilation/format.d(208): Error: `pragma(scanf)` function `vscanf1` must have `extern(C)` or `extern(C++)` linkage, not `extern(Windows)` +fail_compilation/format.d(208): Error: `pragma(scanf)` function `vscanf1` must have signature `int vscanf1([parameters...], const(char)*, va_list)` --- */ @@ -37,6 +40,8 @@ pragma(printf) void vprintf1(const(char)*, va_list); pragma(printf) extern (C) int vprintf2(const(int )*, va_list); pragma(printf) extern (C) int vprintf3(const(char)*); pragma(printf) extern (C) int vprintf4(const(char)*, int, va_list); +pragma(printf) extern (C) int vprintf5(char*, int[] a...); +pragma(scanf) extern (Windows) int vscanf1(); pragma(printf) extern (C) int vprintf5(const(char)*, va_list); pragma(printf) extern (C) int vprintf6(immutable(char)*, va_list); From d185c9a7b0822b87e4dea60b7af70c96ab3b3ea4 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Thu, 13 Jul 2023 11:31:51 +0100 Subject: [PATCH 120/176] Fix several errors parsing enum members (dlang/dmd!15392) * Fix unexpected token after identifier error for named enum * Fix Issue 24041 - Anon enum member ignores repeated type or identifier Also adds test for missing initializer when type is specified and tweaks that error. --- dmd/parse.d | 28 ++++++++++++++++++++++--- tests/dmd/fail_compilation/biterrors3.d | 2 +- tests/dmd/fail_compilation/fail10285.d | 12 +++++++++-- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/dmd/parse.d b/dmd/parse.d index a0818fde423..b4419359993 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -3036,6 +3036,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } e = new AST.EnumDeclaration(loc, id, memtype); + // opaque type if (token.value == TOK.semicolon && id) nextToken(); else if (token.value == TOK.leftCurly) @@ -3068,7 +3069,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer && token.value != TOK.comma && token.value != TOK.assign) { - switch(token.value) + switch (token.value) { case TOK.at: if (StorageClass _stc = parseAttribute(udas)) @@ -3104,12 +3105,23 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } else { - goto default; + if (isAnonymousEnum) + goto default; // maybe `Type identifier` + + prevTOK = token.value; + nextToken(); + error("expected `,` or `=` after identifier, not `%s`", token.toChars()); } break; default: if (isAnonymousEnum) { + if (type) + { + error("expected identifier after type, not `%s`", token.toChars()); + type = null; + break; + } type = parseType(&ident, null); if (type == AST.Type.terror) { @@ -3120,6 +3132,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer else { prevTOK = TOK.identifier; + const tv = token.value; + if (ident && tv != TOK.assign && tv != TOK.comma && tv != TOK.rightCurly) + { + error("expected `,` or `=` after identifier, not `%s`", token.toChars()); + } } } else @@ -3161,7 +3178,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { value = null; if (type && type != AST.Type.terror && isAnonymousEnum) - error("if type, there must be an initializer"); + error("initializer required after `%s` when type is specified", ident.toChars()); } AST.DeprecatedDeclaration dd; @@ -3466,6 +3483,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer return decldefs; } + /* Parse a type and optional identifier + * Params: + * pident = set to Identifier if there is one, null if not + * ptpl = if !null, then set to TemplateParameterList + */ AST.Type parseType(Identifier* pident = null, AST.TemplateParameters** ptpl = null) { /* Take care of the storage class prefixes that diff --git a/tests/dmd/fail_compilation/biterrors3.d b/tests/dmd/fail_compilation/biterrors3.d index f9e1df2b7b2..c5031a4db10 100644 --- a/tests/dmd/fail_compilation/biterrors3.d +++ b/tests/dmd/fail_compilation/biterrors3.d @@ -2,7 +2,7 @@ * TEST_OUTPUT: --- fail_compilation/biterrors3.d(103): Error: storage class not allowed for bit-field declaration -fail_compilation/biterrors3.d(106): Error: `d` is not a valid attribute for enum members +fail_compilation/biterrors3.d(106): Error: expected `,` or `=` after identifier, not `:` fail_compilation/biterrors3.d(106): Error: `:` is not a valid attribute for enum members fail_compilation/biterrors3.d(106): Error: `3` is not a valid attribute for enum members --- diff --git a/tests/dmd/fail_compilation/fail10285.d b/tests/dmd/fail_compilation/fail10285.d index 3277b19e2aa..c88e30688f7 100644 --- a/tests/dmd/fail_compilation/fail10285.d +++ b/tests/dmd/fail_compilation/fail10285.d @@ -1,10 +1,18 @@ /* TEST_OUTPUT: --- -fail_compilation/fail10285.d(9): Error: no identifier for declarator `int` +fail_compilation/fail10285.d(13): Error: no identifier for declarator `int` +fail_compilation/fail10285.d(14): Error: expected `,` or `=` after identifier, not `y` +fail_compilation/fail10285.d(15): Error: expected identifier after type, not `bool` +fail_compilation/fail10285.d(16): Error: expected identifier after type, not `int` +fail_compilation/fail10285.d(18): Error: initializer required after `z` when type is specified --- */ enum { - int = 5 + int = 5, + int x y, + int bool i = 3, + j int k = 3, + int z } From 4b55e33f74d0f44aa160bc65487063ca8294c7ef Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Thu, 13 Jul 2023 08:46:57 -0700 Subject: [PATCH 121/176] resurrect empty statement (dlang/dmd!15409) --- dmd/parse.d | 2 +- tests/dmd/compilable/emptystatement.d | 19 +++++++++++++++++++ tests/dmd/fail_compilation/fail4559.d | 22 ---------------------- 3 files changed, 20 insertions(+), 23 deletions(-) create mode 100644 tests/dmd/compilable/emptystatement.d delete mode 100644 tests/dmd/fail_compilation/fail4559.d diff --git a/dmd/parse.d b/dmd/parse.d index b4419359993..d5838825bf9 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -6034,7 +6034,7 @@ LagainStc: auto statements = new AST.Statements(); while (token.value != TOK.rightCurly && token.value != TOK.endOfFile) { - statements.push(parseStatement(ParseStatementFlags.curlyScope)); + statements.push(parseStatement(ParseStatementFlags.curlyScope | ParseStatementFlags.semiOk)); } if (endPtr) *endPtr = token.ptr; diff --git a/tests/dmd/compilable/emptystatement.d b/tests/dmd/compilable/emptystatement.d new file mode 100644 index 00000000000..e6bfc27caa4 --- /dev/null +++ b/tests/dmd/compilable/emptystatement.d @@ -0,0 +1,19 @@ +/* +REQUIRED_ARGS: +TEST_OUTPUT: +--- +--- +*/ + +void foo() +{ + int x;; + enum A + { + a, + b, + c + }; + + void bar() {}; +} diff --git a/tests/dmd/fail_compilation/fail4559.d b/tests/dmd/fail_compilation/fail4559.d deleted file mode 100644 index 657c184d787..00000000000 --- a/tests/dmd/fail_compilation/fail4559.d +++ /dev/null @@ -1,22 +0,0 @@ -/* -REQUIRED_ARGS: -TEST_OUTPUT: ---- -fail_compilation/fail4559.d(13): Error: use `{ }` for an empty statement, not `;` -fail_compilation/fail4559.d(19): Error: use `{ }` for an empty statement, not `;` -fail_compilation/fail4559.d(21): Error: use `{ }` for an empty statement, not `;` ---- -*/ - -void foo() -{ - int x;; - enum A - { - a, - b, - c - }; - - void bar() {}; -} From 578b4cc89c50eb8a2b59d67bc4a719e15fdc08ae Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Fri, 14 Jul 2023 10:48:21 +0100 Subject: [PATCH 122/176] Fix Issue 7184 - parse error on *(x)++ (dlang/dmd!15410) --- dmd/parse.d | 7 ++++++- tests/dmd/compilable/parens_inc.d | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 tests/dmd/compilable/parens_inc.d diff --git a/dmd/parse.d b/dmd/parse.d index d5838825bf9..a54602766c3 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -8808,6 +8808,7 @@ LagainStc: { // (type) una_exp nextToken(); + // Note: `t` may be an expression that looks like a type auto t = parseType(); check(TOK.rightParenthesis); @@ -8825,8 +8826,12 @@ LagainStc: te.parens = true; e = parsePostExp(te); } - else if (token.value == TOK.leftParenthesis) + else if (token.value == TOK.leftParenthesis || + token.value == TOK.plusPlus || token.value == TOK.minusMinus) { + // (type)(expr) + // (callable)(args) + // (expr)++ auto te = new AST.TypeExp(loc, t); te.parens = true; e = parsePostExp(te); diff --git a/tests/dmd/compilable/parens_inc.d b/tests/dmd/compilable/parens_inc.d new file mode 100644 index 00000000000..b9d11eb9b8e --- /dev/null +++ b/tests/dmd/compilable/parens_inc.d @@ -0,0 +1,23 @@ +// Test UnaryExp (expr)++ parsing + +void main(){ + int[2] y; + int *x = y.ptr; + *(x)++=0; + (*(x)--)=0; + (*x++)=0; // ok + int*[] z; + *(z[0])++=0; //ok + (y[0])--; + *x++=0; +} + +void f() +{ + int b; + (b)++; + int[] a; + b = (a)[0]++; //ok + (a[0])--; + b = (int).init; //ok +} From d9608797fbbbab58c47d46013c9389eb4819dd18 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Fri, 14 Jul 2023 12:39:56 +0100 Subject: [PATCH 123/176] Fix Issue 13063 - `enum` is allowed as storage class for functions (dlang/dmd!15405) * Fix Issue 13063 - `enum` is allowed as storage class for functions * Remove enum from unrelated test * Add changelog --- dmd/parse.d | 3 +++ tests/dmd/fail_compilation/enum_function.d | 13 +++++++++++++ tests/dmd/fail_compilation/fail22729.d | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/dmd/fail_compilation/enum_function.d diff --git a/dmd/parse.d b/dmd/parse.d index a54602766c3..d15e448150f 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -4581,6 +4581,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } else if (t.ty == Tfunction) { + if (storage_class & STC.manifest) + error("function cannot have enum storage class"); + AST.Expression constraint = null; //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t.toChars(), storage_class); auto f = new AST.FuncDeclaration(loc, Loc.initial, ident, storage_class | (disable ? STC.disable : 0), t); diff --git a/tests/dmd/fail_compilation/enum_function.d b/tests/dmd/fail_compilation/enum_function.d new file mode 100644 index 00000000000..b22f2ceccef --- /dev/null +++ b/tests/dmd/fail_compilation/enum_function.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/enum_function.d(10): Error: function cannot have enum storage class +fail_compilation/enum_function.d(11): Error: function cannot have enum storage class +fail_compilation/enum_function.d(12): Error: function cannot have enum storage class +fail_compilation/enum_function.d(13): Error: function cannot have enum storage class +--- +*/ +enum void f1() { return; } +enum f2() { return 5; } +enum f3() => 5; +enum int f4()() => 5; diff --git a/tests/dmd/fail_compilation/fail22729.d b/tests/dmd/fail_compilation/fail22729.d index 38bbfeeed2b..d0c8aa9c2f3 100644 --- a/tests/dmd/fail_compilation/fail22729.d +++ b/tests/dmd/fail_compilation/fail22729.d @@ -22,7 +22,7 @@ class Form : WidgetI template Tuple(Specs) { - enum areCompatibleTuples(Tup2)(Tuple tup1, Tup2 tup2) + auto areCompatibleTuples(Tup2)(Tuple tup1, Tup2 tup2) { tup1.field == tup2; } From 190b228a62fb422d211d66eab155a45ce37429b7 Mon Sep 17 00:00:00 2001 From: Razvan Nitu Date: Fri, 14 Jul 2023 19:02:15 +0300 Subject: [PATCH 124/176] Fix Issue 22427 - betterC: casting an array causes linker error in string comparison (dlang/dmd!15404) * Fix Issue 22427 - betterC: casting an array causes linker error in string comparison * Fix Issue 22427 - betterC: casting an array causes linker error in string comparison --- dmd/mars.d | 3 +++ tests/dmd/runnable/betterc.d | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/dmd/mars.d b/dmd/mars.d index 8478194b824..f58be00862b 100644 --- a/dmd/mars.d +++ b/dmd/mars.d @@ -2159,7 +2159,10 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param else if (arg == "-release") // https://dlang.org/dmd.html#switch-release params.release = true; else if (arg == "-betterC") // https://dlang.org/dmd.html#switch-betterC + { params.betterC = true; + params.allInst = true; + } else if (arg == "-noboundscheck") // https://dlang.org/dmd.html#switch-noboundscheck { params.boundscheck = CHECKENABLE.off; diff --git a/tests/dmd/runnable/betterc.d b/tests/dmd/runnable/betterc.d index 3d8f7da0fcc..0fc32c75a1f 100644 --- a/tests/dmd/runnable/betterc.d +++ b/tests/dmd/runnable/betterc.d @@ -210,3 +210,14 @@ int test20737() tlsVar = 123; return 0; } + +/*******************************************/ +// https://issues.dlang.org/show_bug.cgi?id=22427 +void test22427() +{ + if("a" == "a") + return; + + char[] p; + auto a = cast(int[])p; +} From 838e632cbd898ad10e872aa9622cb0b16592190e Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Sat, 15 Jul 2023 14:21:45 +0000 Subject: [PATCH 125/176] Fix broken tests caused by merge conflicts --- runtime/druntime/test/profile/Makefile | 4 +++- runtime/druntime/test/profile/bothgc.log.exp | 1 - runtime/druntime/test/profile/myprofilegc.log.freebsd.64.exp | 2 -- runtime/druntime/test/profile/myprofilegc.log.linux.64.exp | 2 -- runtime/druntime/test/profile/myprofilegc.log.osx.64.exp | 2 -- 5 files changed, 3 insertions(+), 8 deletions(-) diff --git a/runtime/druntime/test/profile/Makefile b/runtime/druntime/test/profile/Makefile index fefa05f9a8c..ac381914f4a 100644 --- a/runtime/druntime/test/profile/Makefile +++ b/runtime/druntime/test/profile/Makefile @@ -52,7 +52,9 @@ $(ROOT)/both.done: $(ROOT)/%.done: $(ROOT)/% $(QUIET) cat $(ROOT)/both.def $(QUIET) sort $(ROOT)/both.def -o $(ROOT)/both.def $(QUIET)(sort bothnew.def.exp | $(DIFF) - $(ROOT)/both.def) - $(QUIET)$(DIFF) bothgc.log.exp $(ROOT)/bothgc.log + $(QUIET)$(DIFF) \ + <($(GREP) -vF 'core.' bothgc.log.exp) \ + <($(GREP) -vF 'core.' $(ROOT)/bothgc.log) @touch $@ $(ROOT)/%: $(SRC)/%.d diff --git a/runtime/druntime/test/profile/bothgc.log.exp b/runtime/druntime/test/profile/bothgc.log.exp index 3cb975fc0d7..1fd78956b1b 100644 --- a/runtime/druntime/test/profile/bothgc.log.exp +++ b/runtime/druntime/test/profile/bothgc.log.exp @@ -1,3 +1,2 @@ bytes allocated, allocations, type, function, file:line 16000 1000 Num both.foo src/both.d:15 - 16000 1000 void[] core.lifetime._d_newitemT!(Num)._d_newitemT ../../src/core/lifetime.d:2829 diff --git a/runtime/druntime/test/profile/myprofilegc.log.freebsd.64.exp b/runtime/druntime/test/profile/myprofilegc.log.freebsd.64.exp index 20f4cba5fb4..73c4147f238 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.freebsd.64.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.freebsd.64.exp @@ -16,6 +16,4 @@ bytes allocated, allocations, type, function, file:line 16 1 int[] D main src/profilegc.d:14 16 1 int[] D main src/profilegc.d:22 16 1 int[] D main src/profilegc.d:37 - 16 1 void[] core.lifetime._d_newitemT!float._d_newitemT ../../src/core/lifetime.d:2829 - 16 1 void[] core.lifetime._d_newitemT!int._d_newitemT ../../src/core/lifetime.d:2829 16 1 wchar[] D main src/profilegc.d:35 diff --git a/runtime/druntime/test/profile/myprofilegc.log.linux.64.exp b/runtime/druntime/test/profile/myprofilegc.log.linux.64.exp index 20f4cba5fb4..73c4147f238 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.linux.64.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.linux.64.exp @@ -16,6 +16,4 @@ bytes allocated, allocations, type, function, file:line 16 1 int[] D main src/profilegc.d:14 16 1 int[] D main src/profilegc.d:22 16 1 int[] D main src/profilegc.d:37 - 16 1 void[] core.lifetime._d_newitemT!float._d_newitemT ../../src/core/lifetime.d:2829 - 16 1 void[] core.lifetime._d_newitemT!int._d_newitemT ../../src/core/lifetime.d:2829 16 1 wchar[] D main src/profilegc.d:35 diff --git a/runtime/druntime/test/profile/myprofilegc.log.osx.64.exp b/runtime/druntime/test/profile/myprofilegc.log.osx.64.exp index 20f4cba5fb4..73c4147f238 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.osx.64.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.osx.64.exp @@ -16,6 +16,4 @@ bytes allocated, allocations, type, function, file:line 16 1 int[] D main src/profilegc.d:14 16 1 int[] D main src/profilegc.d:22 16 1 int[] D main src/profilegc.d:37 - 16 1 void[] core.lifetime._d_newitemT!float._d_newitemT ../../src/core/lifetime.d:2829 - 16 1 void[] core.lifetime._d_newitemT!int._d_newitemT ../../src/core/lifetime.d:2829 16 1 wchar[] D main src/profilegc.d:35 From 588619f03a2f68ed4109965a17d755cf4a6f9592 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sun, 16 Jul 2023 20:36:37 +0200 Subject: [PATCH 126/176] druntime: Restrict some `pragma(inline, false)` kludges to DMD only They appear related to DMD's inlining at the AST level; LDC at least doesn't need them, so let the optimizer decide for non-DMD backends. --- runtime/druntime/src/core/demangle.d | 12 ++++++------ runtime/druntime/src/core/internal/array/appending.d | 4 ++-- runtime/druntime/src/core/internal/array/capacity.d | 2 +- .../druntime/src/core/internal/array/construction.d | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/runtime/druntime/src/core/demangle.d b/runtime/druntime/src/core/demangle.d index f08e1f86444..f11315914d3 100644 --- a/runtime/druntime/src/core/demangle.d +++ b/runtime/druntime/src/core/demangle.d @@ -127,7 +127,7 @@ pure @safe: void putComma(size_t n) { - pragma(inline, false); + version (DigitalMars) pragma(inline, false); if (n) put(", "); } @@ -2861,7 +2861,7 @@ private class OverflowException : Exception /// Ditto private noreturn error(string msg = "Invalid symbol") @trusted pure { - pragma(inline, false); // tame dmd inliner + version (DigitalMars) pragma(inline, false); // tame dmd inliner //throw new ParseException( msg ); debug(info) printf( "error: %.*s\n", cast(int) msg.length, msg.ptr ); @@ -2872,7 +2872,7 @@ private noreturn error(string msg = "Invalid symbol") @trusted pure /// Ditto private noreturn overflow(string msg = "Buffer overflow") @trusted pure { - pragma(inline, false); // tame dmd inliner + version (DigitalMars) pragma(inline, false); // tame dmd inliner //throw new OverflowException( msg ); debug(info) printf( "overflow: %.*s\n", cast(int) msg.length, msg.ptr ); @@ -2927,7 +2927,7 @@ private struct Buffer // move val to the end of the dst buffer char[] shift(scope const(char)[] val) return scope { - pragma(inline, false); // tame dmd inliner + version (DigitalMars) pragma(inline, false); // tame dmd inliner if (val.length) { @@ -2949,7 +2949,7 @@ private struct Buffer // remove val from dst buffer void remove(scope const(char)[] val) scope { - pragma(inline, false); // tame dmd inliner + version (DigitalMars) pragma(inline, false); // tame dmd inliner if ( val.length ) { @@ -2965,7 +2965,7 @@ private struct Buffer char[] append(scope const(char)[] val) return scope { - pragma(inline, false); // tame dmd inliner + version (DigitalMars) pragma(inline, false); // tame dmd inliner if (val.length) { diff --git a/runtime/druntime/src/core/internal/array/appending.d b/runtime/druntime/src/core/internal/array/appending.d index b609167eefe..bb24813ae9e 100644 --- a/runtime/druntime/src/core/internal/array/appending.d +++ b/runtime/druntime/src/core/internal/array/appending.d @@ -35,7 +35,7 @@ template _d_arrayappendcTXImpl(Tarr : T[], T) ref Tarr _d_arrayappendcTX(return ref scope Tarr px, size_t n) @trusted pure nothrow { // needed for CTFE: https://github.com/dlang/druntime/pull/3870#issuecomment-1178800718 - pragma(inline, false); + version (DigitalMars) pragma(inline, false); version (D_TypeInfo) { auto ti = typeid(Tarr); @@ -70,7 +70,7 @@ template _d_arrayappendcTXImpl(Tarr : T[], T) /// Implementation of `_d_arrayappendT` ref Tarr _d_arrayappendT(Tarr : T[], T)(return ref scope Tarr x, scope Tarr y) @trusted { - pragma(inline, false); + version (DigitalMars) pragma(inline, false); import core.stdc.string : memcpy; import core.internal.traits : hasElaborateCopyConstructor, Unqual; diff --git a/runtime/druntime/src/core/internal/array/capacity.d b/runtime/druntime/src/core/internal/array/capacity.d index 254e9501f63..10ce2c65c95 100644 --- a/runtime/druntime/src/core/internal/array/capacity.d +++ b/runtime/druntime/src/core/internal/array/capacity.d @@ -36,7 +36,7 @@ template _d_arraysetlengthTImpl(Tarr : T[], T) */ size_t _d_arraysetlengthT(return scope ref Tarr arr, size_t newlength) @trusted pure nothrow { - pragma(inline, false); + version (DigitalMars) pragma(inline, false); version (D_TypeInfo) { auto ti = typeid(Tarr); diff --git a/runtime/druntime/src/core/internal/array/construction.d b/runtime/druntime/src/core/internal/array/construction.d index ae71f513129..25083597761 100644 --- a/runtime/druntime/src/core/internal/array/construction.d +++ b/runtime/druntime/src/core/internal/array/construction.d @@ -36,7 +36,7 @@ import core.internal.traits : Unqual; */ Tarr _d_arrayctor(Tarr : T[], T)(return scope Tarr to, scope Tarr from, char* makeWeaklyPure = null) @trusted { - pragma(inline, false); + version (DigitalMars) pragma(inline, false); import core.internal.traits : hasElaborateCopyConstructor; import core.lifetime : copyEmplace; import core.stdc.string : memcpy; @@ -200,7 +200,7 @@ Tarr _d_arrayctor(Tarr : T[], T)(return scope Tarr to, scope Tarr from, char* ma */ void _d_arraysetctor(Tarr : T[], T)(scope Tarr p, scope ref T value) @trusted { - pragma(inline, false); + version (DigitalMars) pragma(inline, false); import core.lifetime : copyEmplace; size_t i; From 41def0be622bf149a9ec5ee6cfcdf34f4d09c68f Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sun, 16 Jul 2023 20:32:52 +0200 Subject: [PATCH 127/176] Fix little C++ header regression --- dmd/expression.h | 1 + 1 file changed, 1 insertion(+) diff --git a/dmd/expression.h b/dmd/expression.h index 8c6393fb6e1..1f04c6cb1db 100644 --- a/dmd/expression.h +++ b/dmd/expression.h @@ -955,6 +955,7 @@ class SliceExp final : public UnaExp private: uint8_t bitFields; +public: SliceExp *syntaxCopy() override; bool isLvalue() override; Expression *toLvalue(Scope *sc, Expression *e) override; From d678adf7d5cbb5af4f472d02a7df7f4b32839945 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sun, 16 Jul 2023 20:33:26 +0200 Subject: [PATCH 128/176] Expose VarArg.KRvariadic to C++ headers --- dmd/mtype.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dmd/mtype.h b/dmd/mtype.h index fbfd766fa94..457b91f1cee 100644 --- a/dmd/mtype.h +++ b/dmd/mtype.h @@ -123,8 +123,9 @@ enum VarArgValues { VARARGnone = 0, /// fixed number of arguments VARARGvariadic = 1, /// T t, ...) can be C-style (core.stdc.stdarg) or D-style (core.vararg) - VARARGtypesafe = 2 /// T t ...) typesafe https://dlang.org/spec/function.html#typesafe_variadic_functions + VARARGtypesafe = 2, /// T t ...) typesafe https://dlang.org/spec/function.html#typesafe_variadic_functions /// or https://dlang.org/spec/function.html#typesafe_variadic_functions + VARARGKRvariadic = 3 /// K+R C style variadics (no function prototype) }; typedef unsigned char VarArg; From 9103316e1f2b879d49e7b5e0a2e973393fce28bf Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Mon, 17 Jul 2023 08:52:31 -0700 Subject: [PATCH 129/176] Revert "Deprecate alias this for classes v2 (dlang/dmd!14812)" (dlang/dmd!15326) This reverts commit 03b39c5d35d929255cfc645b96f5616bb68c4fec. --- dmd/dsymbolsem.d | 5 - dmd/dtoh.d | 1 - runtime/druntime/src/object.d | 94 +++++++++++++++ tests/dmd/compilable/test21073.d | 16 +++ tests/dmd/compilable/test21543.d | 116 +++++++++++++++++++ tests/dmd/compilable/test5973.d | 41 +++++++ tests/dmd/compilable/test6777.d | 11 ++ tests/dmd/fail_compilation/fail5851.d | 16 +++ tests/dmd/runnable/aliasthis.d | 10 -- tests/dmd/runnable/interpret.d | 1 - tests/dmd/runnable/test17684.d | 10 -- tests/dmd/runnable/test19782.d | 8 -- tests/dmd/runnable/test21039.d | 7 -- tests/dmd/runnable/test23234.d | 7 -- tests/dmd/runnable/testaliascast.d | 8 -- tests/dmd/runnable/testassign.d | 2 - tests/dmd/runnable/traits_getPointerBitmap.d | 29 +++++ tests/dmd/runnable/xtest46.d | 4 - tests/dmd/runnable/xtest46_gc.d | 4 - 19 files changed, 323 insertions(+), 67 deletions(-) create mode 100644 tests/dmd/compilable/test21073.d create mode 100644 tests/dmd/compilable/test21543.d create mode 100644 tests/dmd/compilable/test5973.d create mode 100644 tests/dmd/compilable/test6777.d create mode 100644 tests/dmd/fail_compilation/fail5851.d diff --git a/dmd/dsymbolsem.d b/dmd/dsymbolsem.d index 7a800bddd02..f5ac70ec5fb 100644 --- a/dmd/dsymbolsem.d +++ b/dmd/dsymbolsem.d @@ -320,11 +320,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor return; } - // @@@DEPRECATED_2.121@@@ - // Deprecated in 2.101 - Can be removed in 2.121 - if (ad.isClassDeclaration() || ad.isInterfaceDeclaration()) - deprecation(dsym.loc, "alias this for classes/interfaces is deprecated"); - assert(ad.members); Dsymbol s = ad.search(dsym.loc, dsym.ident); if (!s) diff --git a/dmd/dtoh.d b/dmd/dtoh.d index b9bbad0a7a4..17e019b5bc4 100644 --- a/dmd/dtoh.d +++ b/dmd/dtoh.d @@ -304,7 +304,6 @@ public: } return result; } - mixin(generateMembers()); this(OutBuffer* fwdbuf, OutBuffer* donebuf, OutBuffer* buf) scope diff --git a/runtime/druntime/src/object.d b/runtime/druntime/src/object.d index b0889b66386..3b08213c9ad 100644 --- a/runtime/druntime/src/object.d +++ b/runtime/druntime/src/object.d @@ -2929,6 +2929,25 @@ void clear(Value, Key)(Value[Key]* aa) assert("k1" !in aa); } +// Issue 20559 +@system unittest +{ + static class Foo + { + int[string] aa; + alias aa this; + } + + auto v = new Foo(); + v["Hello World"] = 42; + v.clear; + assert("Hello World" !in v); + + // Test for T* + static assert(!__traits(compiles, (&v).clear)); + static assert( __traits(compiles, (*(&v)).clear)); +} + /*********************************** * Reorganizes the associative array in place so that lookups are more * efficient. @@ -4292,6 +4311,44 @@ void destroy(bool initialize = true, T)(T obj) if (is(T == interface)) destroy!true(new C()); } +@system unittest +{ + // class with an `alias this` + class A + { + static int dtorCount; + ~this() + { + dtorCount++; + } + } + + class B + { + A a; + alias a this; + this() + { + a = new A; + } + static int dtorCount; + ~this() + { + dtorCount++; + } + } + auto b = new B; + assert(A.dtorCount == 0); + assert(B.dtorCount == 0); + destroy(b); + assert(A.dtorCount == 0); + assert(B.dtorCount == 1); + + auto a = new A; + destroy(a); + assert(A.dtorCount == 1); +} + @system unittest { interface I { } @@ -4505,6 +4562,43 @@ if (__traits(isStaticArray, T)) } } +// https://issues.dlang.org/show_bug.cgi?id=19218 +@system unittest +{ + static struct S + { + static dtorCount = 0; + ~this() { ++dtorCount; } + } + + static interface I + { + ref S[3] getArray(); + alias getArray this; + } + + static class C : I + { + static dtorCount = 0; + ~this() { ++dtorCount; } + + S[3] a; + alias a this; + + ref S[3] getArray() { return a; } + } + + C c = new C(); + destroy(c); + assert(S.dtorCount == 3); + assert(C.dtorCount == 1); + + I i = new C(); + destroy(i); + assert(S.dtorCount == 6); + assert(C.dtorCount == 2); +} + /// ditto void destroy(bool initialize = true, T)(ref T obj) if (!is(T == struct) && !is(T == interface) && !is(T == class) && !__traits(isStaticArray, T)) diff --git a/tests/dmd/compilable/test21073.d b/tests/dmd/compilable/test21073.d new file mode 100644 index 00000000000..47d788128b3 --- /dev/null +++ b/tests/dmd/compilable/test21073.d @@ -0,0 +1,16 @@ +// https://issues.dlang.org/show_bug.cgi?id=21073 + +class C +{ + auto internal() const + { + return 5; + } + alias internal this; +} + +void main() pure +{ + const c = new C; + auto r = cast(C)c; +} diff --git a/tests/dmd/compilable/test21543.d b/tests/dmd/compilable/test21543.d new file mode 100644 index 00000000000..4914264aaf9 --- /dev/null +++ b/tests/dmd/compilable/test21543.d @@ -0,0 +1,116 @@ +// https://issues.dlang.org/show_bug.cgi?id=21543 + +class B +{ + Nullable!B data; + alias data this; +} + +void test1() +{ + B b; + Nullable!B n; +} + +struct Nullable(T) +{ + T payload; + + void opAssign()(T) + { + move(payload); + } + + inout(T) get_() inout + { + return payload; + } + + alias get_ this; +} + +// another version with chain of 3 alias this + +struct C +{ + Nullable2 data; + alias data this; +} + +void test2() +{ + C c; + Nullable2 n2 = &c; + Nullable3 n3 = &c; + + // these are to check a sane -vcg-ast output + fn1(c); + fn1(n2); + fn1(n3); + fn2(c); + fn2(n2); + fn2(n3); + fn3(c); + fn3(n2); + fn3(n3); +} + +void fn1(C x) {} + +void fn2(Nullable2 x) {} + +void fn3(Nullable3 x) {} + +struct Nullable2 +{ + Nullable3 payload; + + this(C* c) + { + payload = Nullable3(c); + } + + void opAssign()(Nullable3) + { + move(payload); + } + + inout(Nullable3) get_() inout + { + return payload; + } + + alias get_ this; +} + +struct Nullable3 +{ + C* payload; + + this(C* c) + { + payload = c; + } + + void opAssign()(C) + { + move(payload); + } + + inout(C) get_() inout + { + return *payload; + } + + alias get_ this; +} + +T move(T)(ref T source) +{ + return source; +} + +T move(T)(T source) +{ + return source; +} diff --git a/tests/dmd/compilable/test5973.d b/tests/dmd/compilable/test5973.d new file mode 100644 index 00000000000..a54b0ae173a --- /dev/null +++ b/tests/dmd/compilable/test5973.d @@ -0,0 +1,41 @@ +// https://issues.dlang.org/show_bug.cgi?id=5973 + +class A { int a = 1; } +class B { int b = 2; } +class C : A +{ + B obj; + alias obj this; + this(){ obj = new B(); } +} +class X : C {} + +class D +{ + int i; +} + +class E +{ + D x; + alias x this; +} + +class F : E +{ + void test() + { + i = 5; + } +} + +void main() +{ + auto c = new C(); + assert(c.a == 1); // lookup C -> A, OK + assert(c.b == 2); // lookup C => B, OK + + auto x = new X(); + assert(x.a == 1); // lookup X -> C -> A, OK + assert(x.b == 2); // lookup X -> C => B, NG (Line 17) +} diff --git a/tests/dmd/compilable/test6777.d b/tests/dmd/compilable/test6777.d new file mode 100644 index 00000000000..161a94a179d --- /dev/null +++ b/tests/dmd/compilable/test6777.d @@ -0,0 +1,11 @@ +struct S {} + +class C { + S s; + alias s this; +} + +void main() { + auto c = new C; + auto p = cast(void*) c; +} diff --git a/tests/dmd/fail_compilation/fail5851.d b/tests/dmd/fail_compilation/fail5851.d new file mode 100644 index 00000000000..236a956de92 --- /dev/null +++ b/tests/dmd/fail_compilation/fail5851.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail5851.d(11): Error: alias this is not reachable as `Foo` already converts to `object.Object` +--- +*/ + +class Foo +{ + Object o; + alias o this; +} + +void main() +{ +} diff --git a/tests/dmd/runnable/aliasthis.d b/tests/dmd/runnable/aliasthis.d index 50e5c4db64b..db5913c8389 100644 --- a/tests/dmd/runnable/aliasthis.d +++ b/tests/dmd/runnable/aliasthis.d @@ -1,16 +1,7 @@ /* TEST_OUTPUT: --- -runnable/aliasthis.d(103): Deprecation: alias this for classes/interfaces is deprecated -runnable/aliasthis.d(291): Deprecation: alias this for classes/interfaces is deprecated -runnable/aliasthis.d(292): Deprecation: alias this for classes/interfaces is deprecated -runnable/aliasthis.d(294): Deprecation: alias this for classes/interfaces is deprecated -runnable/aliasthis.d(465): Deprecation: alias this for classes/interfaces is deprecated -runnable/aliasthis.d(466): Deprecation: alias this for classes/interfaces is deprecated -runnable/aliasthis.d(477): Deprecation: alias this for classes/interfaces is deprecated -runnable/aliasthis.d(1013): Deprecation: alias this for classes/interfaces is deprecated false -runnable/aliasthis.d(2100): Deprecation: alias this for classes/interfaces is deprecated [] = int [] = string [0] = int @@ -19,7 +10,6 @@ runnable/aliasthis.d(2100): Deprecation: alias this for classes/interfaces is de [] = int [1] = string [0] = int -runnable/aliasthis.d(741): Deprecation: alias this for classes/interfaces is deprecated --- RUN_OUTPUT: diff --git a/tests/dmd/runnable/interpret.d b/tests/dmd/runnable/interpret.d index f9972f235e2..16d4c5570a4 100644 --- a/tests/dmd/runnable/interpret.d +++ b/tests/dmd/runnable/interpret.d @@ -4,7 +4,6 @@ TEST_OUTPUT: true g &Test109S(&Test109S()) -runnable/interpret.d(3742): Deprecation: alias this for classes/interfaces is deprecated tfoo tfoo Crash! diff --git a/tests/dmd/runnable/test17684.d b/tests/dmd/runnable/test17684.d index e10265558e8..efdce0847ba 100644 --- a/tests/dmd/runnable/test17684.d +++ b/tests/dmd/runnable/test17684.d @@ -1,13 +1,3 @@ -/* -TEST_OUTPUT: ---- -runnable/test17684.d(37): Deprecation: alias this for classes/interfaces is deprecated -runnable/test17684.d(54): Deprecation: alias this for classes/interfaces is deprecated -runnable/test17684.d(54): Deprecation: alias this for classes/interfaces is deprecated -runnable/test17684.d(37): Deprecation: alias this for classes/interfaces is deprecated ---- -*/ - struct StructField(T) { static T Field; diff --git a/tests/dmd/runnable/test19782.d b/tests/dmd/runnable/test19782.d index 61a168bf918..a24d84173ec 100644 --- a/tests/dmd/runnable/test19782.d +++ b/tests/dmd/runnable/test19782.d @@ -1,12 +1,4 @@ // https://issues.dlang.org/show_bug.cgi?id=19782 - -/* -TEST_OUTPUT: ---- -runnable/test19782.d(17): Deprecation: alias this for classes/interfaces is deprecated ---- -*/ - class Inner { int a; diff --git a/tests/dmd/runnable/test21039.d b/tests/dmd/runnable/test21039.d index f32267ab59e..c58600f8da0 100644 --- a/tests/dmd/runnable/test21039.d +++ b/tests/dmd/runnable/test21039.d @@ -1,12 +1,5 @@ // https://issues.dlang.org/show_bug.cgi?id=21039 -/* -TEST_OUTPUT: ---- -runnable/test21039.d(14): Deprecation: alias this for classes/interfaces is deprecated ---- -*/ - class Inner {} class Outer { diff --git a/tests/dmd/runnable/test23234.d b/tests/dmd/runnable/test23234.d index f97486404b3..7872aa76dfe 100644 --- a/tests/dmd/runnable/test23234.d +++ b/tests/dmd/runnable/test23234.d @@ -1,12 +1,5 @@ // https://issues.dlang.org/show_bug.cgi?id=23234 -/* -TEST_OUTPUT: ---- -runnable/test23234.d(17): Deprecation: alias this for classes/interfaces is deprecated ---- -*/ - class Bar { } diff --git a/tests/dmd/runnable/testaliascast.d b/tests/dmd/runnable/testaliascast.d index ed5091dff01..c55f8203499 100644 --- a/tests/dmd/runnable/testaliascast.d +++ b/tests/dmd/runnable/testaliascast.d @@ -1,13 +1,5 @@ // https://issues.dlang.org/show_bug.cgi?id=11294 -/* -TEST_OUTPUT: ---- -runnable/testaliascast.d(29): Deprecation: alias this for classes/interfaces is deprecated -runnable/testaliascast.d(58): Deprecation: alias this for classes/interfaces is deprecated ---- -*/ - string result; extern(C) void rt_finalize(void *ptr, bool det=true); diff --git a/tests/dmd/runnable/testassign.d b/tests/dmd/runnable/testassign.d index 79a4c57cf3b..586aea80cce 100644 --- a/tests/dmd/runnable/testassign.d +++ b/tests/dmd/runnable/testassign.d @@ -2,8 +2,6 @@ REQUIRED_ARGS: -preview=rvaluerefparam TEST_OUTPUT: --- -runnable/testassign.d(802): Deprecation: alias this for classes/interfaces is deprecated -runnable/testassign.d(808): Deprecation: alias this for classes/interfaces is deprecated \ S1 S2a S2b S3a S3b S4a S4b - true true true true true true true Xa true true true true true true true diff --git a/tests/dmd/runnable/traits_getPointerBitmap.d b/tests/dmd/runnable/traits_getPointerBitmap.d index ffa0b803ade..8996c9ebb8f 100644 --- a/tests/dmd/runnable/traits_getPointerBitmap.d +++ b/tests/dmd/runnable/traits_getPointerBitmap.d @@ -1,3 +1,4 @@ + module traits_getPointerBitmap; import core.stdc.stdio; @@ -75,6 +76,19 @@ template pOff(T) enum pOff = T.p.offsetof / bytesPerPtr; } +class C(T, aliasTo = void) +{ + static if(!is(aliasTo == void)) + { + aliasTo a; + alias a this; + } + + size_t x; + T t = void; + void* p; +} + /////////////////////////////////////// void _testType(T)(size_t[] expected) @@ -104,6 +118,21 @@ void testType(T)(size_t[] expected) // prepend string sexp[0] = (expected[0] << tOff!(S!(T, string))) | (1 << pOff!(S!(T, string))) | 2; // arr ptr _testType!(S!(T, string))(sexp); + + // generate bit pattern for C!T + C!T ct = null; + size_t mutexBit = (RTInfoMark__Monitor ? 2 : 0); + size_t ctpOff = ct.p.offsetof / bytesPerPtr; + size_t cttOff = ct.t.offsetof / bytesPerPtr; + sexp[0] = (expected[0] << cttOff) | (1 << ctpOff) | mutexBit; + _testType!(C!(T))(sexp); + + C!(T, string) cts = null; + size_t ctspOff = cts.p.offsetof / bytesPerPtr; + size_t ctstOff = cts.t.offsetof / bytesPerPtr; + // generate bit pattern for C!T + sexp[0] = (expected[0] << ctstOff) | (1 << ctspOff) | mutexBit | 0b1000; // arr ptr + _testType!(C!(T, string))(sexp); } /////////////////////////////////////// diff --git a/tests/dmd/runnable/xtest46.d b/tests/dmd/runnable/xtest46.d index 972de900203..aeb2aab8336 100644 --- a/tests/dmd/runnable/xtest46.d +++ b/tests/dmd/runnable/xtest46.d @@ -2,14 +2,11 @@ // /* TEST_OUTPUT: --- -runnable/xtest46.d(165): Deprecation: alias this for classes/interfaces is deprecated Boo!double Boo!int true int !! immutable(int)[] -runnable/xtest46.d(2932): Deprecation: alias this for classes/interfaces is deprecated -runnable/xtest46.d(2964): Deprecation: alias this for classes/interfaces is deprecated int(int i, long j = 7L) long C10390(C10390(C10390())) @@ -22,7 +19,6 @@ string[] double[] double[] {} -runnable/xtest46.d(4670): Deprecation: alias this for classes/interfaces is deprecated AliasSeq!("m") true TFunction1: extern (C) void function() diff --git a/tests/dmd/runnable/xtest46_gc.d b/tests/dmd/runnable/xtest46_gc.d index aab6227230a..38c136d531c 100644 --- a/tests/dmd/runnable/xtest46_gc.d +++ b/tests/dmd/runnable/xtest46_gc.d @@ -3,14 +3,11 @@ REQUIRED_ARGS: -lowmem -Jrunnable -preview=rvaluerefparam EXTRA_FILES: xtest46.d TEST_OUTPUT: --- -runnable/xtest46_gc.d-mixin-33(197): Deprecation: alias this for classes/interfaces is deprecated Boo!double Boo!int true int !! immutable(int)[] -runnable/xtest46_gc.d-mixin-33(2964): Deprecation: alias this for classes/interfaces is deprecated -runnable/xtest46_gc.d-mixin-33(2996): Deprecation: alias this for classes/interfaces is deprecated int(int i, long j = 7L) long C10390(C10390()) @@ -23,7 +20,6 @@ string[] double[] double[] {} -runnable/xtest46_gc.d-mixin-33(4702): Deprecation: alias this for classes/interfaces is deprecated AliasSeq!("m") true TFunction1: extern (C) void function() From c8084a7f3d15b51fbb07a76376bc2052eb1f6bce Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Mon, 17 Jul 2023 11:08:27 +0100 Subject: [PATCH 130/176] Add changelog for catch qualifier deprecation & update release no --- dmd/statementsem.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dmd/statementsem.d b/dmd/statementsem.d index 2def2539597..7f9b3b1af85 100644 --- a/dmd/statementsem.d +++ b/dmd/statementsem.d @@ -4068,8 +4068,8 @@ void catchSemantic(Catch c, Scope* sc) } else if (!c.type.isNaked() && !c.type.isConst()) { - // @@@DEPRECATED_2.113@@@ - // Deprecated in 2.103, change into an error & uncomment in 2.113 + // @@@DEPRECATED_2.115@@@ + // Deprecated in 2.105, change into an error & uncomment assign in 2.115 deprecation(c.loc, "can only catch mutable or const qualified types, not `%s`", c.type.toChars()); //c.errors = true; } From 9c46d9cb88fde02ca87f94cf26c1892229895721 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Sun, 23 Jul 2023 09:45:42 -0700 Subject: [PATCH 131/176] fix Issue 23857 - backend inliner takes too long on recursive function call (dlang/dmd!15447) --- tests/dmd/compilable/test23857.d | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/dmd/compilable/test23857.d diff --git a/tests/dmd/compilable/test23857.d b/tests/dmd/compilable/test23857.d new file mode 100644 index 00000000000..d1f6c033440 --- /dev/null +++ b/tests/dmd/compilable/test23857.d @@ -0,0 +1,15 @@ +/* REQUIRED_ARGS: -O -inline -release + */ + +// https://issues.dlang.org/show_bug.cgi?id=23857 + +int mars(int[] a, int u) +{ + return (a.ptr[u] < 0) ? u : (a.ptr[u] = mars(a, a.ptr[u])); +} + +void venus() +{ + mars([], 0); + mars([], 0); +} From 5014298db511f5387a62f77dda8f5ee533e5691c Mon Sep 17 00:00:00 2001 From: Razvan Nitu Date: Thu, 3 Aug 2023 15:14:56 +0300 Subject: [PATCH 132/176] Fix Issue 24065 - __traits(getTargetInfo) causes a segfault when passed a non value (dlang/dmd!15494) --- dmd/traits.d | 2 +- tests/dmd/fail_compilation/test24065.d | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 tests/dmd/fail_compilation/test24065.d diff --git a/dmd/traits.d b/dmd/traits.d index 0d9c95ff173..2bde9f2aee9 100644 --- a/dmd/traits.d +++ b/dmd/traits.d @@ -1920,7 +1920,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) StringExp se = ex ? ex.ctfeInterpret().toStringExp() : null; if (!ex || !se || se.len == 0) { - e.error("string expected as argument of __traits `%s` instead of `%s`", e.ident.toChars(), ex.toChars()); + e.error("string expected as argument of __traits `%s` instead of `%s`", e.ident.toChars(), (*e.args)[0].toChars()); return ErrorExp.get(); } se = se.toUTF8(sc); diff --git a/tests/dmd/fail_compilation/test24065.d b/tests/dmd/fail_compilation/test24065.d new file mode 100644 index 00000000000..9e4ebbf4d16 --- /dev/null +++ b/tests/dmd/fail_compilation/test24065.d @@ -0,0 +1,18 @@ +// https://issues.dlang.org/show_bug.cgi?id=24065 + +/* +TEST_OUTPUT: +--- +fail_compilation/test24065.d(12): Error: string expected as argument of __traits `getTargetInfo` instead of `int` +fail_compilation/test24065.d(15): Error: string expected as argument of __traits `getTargetInfo` instead of `foo` +fail_compilation/test24065.d(18): Error: string expected as argument of __traits `getTargetInfo` instead of `e` +--- +*/ + +auto s1 = __traits(getTargetInfo, int); + +void foo() {} +auto s2 = __traits(getTargetInfo, foo); + +enum e; +auto s3 = __traits(getTargetInfo, e); From 94394fe8737d5ea605288efdb6b49873508e32f5 Mon Sep 17 00:00:00 2001 From: Razvan Nitu Date: Thu, 3 Aug 2023 17:04:38 +0300 Subject: [PATCH 133/176] Fix Issue 24066 - __traits(isAbstractClass) causes a segfault when passed an opaque class (dlang/dmd!15495) * Fix Issue 24066 - __traits(isAbstractClass) causes a segfault when passed an opaque class * Update comment Co-authored-by: Dennis --------- Co-authored-by: Dennis --- dmd/dclass.d | 4 ++++ tests/dmd/compilable/test24066.d | 11 +++++++++++ 2 files changed, 15 insertions(+) create mode 100644 tests/dmd/compilable/test24066.d diff --git a/dmd/dclass.d b/dmd/dclass.d index 1b8e8ef1880..2174ba579aa 100644 --- a/dmd/dclass.d +++ b/dmd/dclass.d @@ -879,6 +879,10 @@ extern (C++) class ClassDeclaration : AggregateDeclaration return 0; } + // opaque class is not abstract if it is not declared abstract + if (!members) + return no(); + for (size_t i = 0; i < members.length; i++) { auto s = (*members)[i]; diff --git a/tests/dmd/compilable/test24066.d b/tests/dmd/compilable/test24066.d new file mode 100644 index 00000000000..4b8a0b345bc --- /dev/null +++ b/tests/dmd/compilable/test24066.d @@ -0,0 +1,11 @@ +// https://issues.dlang.org/show_bug.cgi?id=24066 + +/* +TEST_OUTPUT: +--- +false +--- +*/ + +class C; +pragma(msg, __traits(isAbstractClass, C)); From aaad7d3a908dc782abc7557518a16b67b7ee99b5 Mon Sep 17 00:00:00 2001 From: Nathan Sashihara <21227491+n8sh@users.noreply.github.com> Date: Tue, 8 Aug 2023 15:55:42 -0400 Subject: [PATCH 134/176] Fix Issue 24079 - core.sys.windows.winnt.IMAGE_FIRST_SECTION returns bad pointer (dlang/dmd!15519) --- runtime/druntime/src/core/sys/windows/winnt.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/druntime/src/core/sys/windows/winnt.d b/runtime/druntime/src/core/sys/windows/winnt.d index 3bd9966e33e..ca4a903fb6a 100644 --- a/runtime/druntime/src/core/sys/windows/winnt.d +++ b/runtime/druntime/src/core/sys/windows/winnt.d @@ -1199,7 +1199,7 @@ enum size_t PIMAGE_SECTION_HEADER IMAGE_FIRST_SECTION(PIMAGE_NT_HEADERS h) { return cast(PIMAGE_SECTION_HEADER) - (&h.OptionalHeader + h.FileHeader.SizeOfOptionalHeader); + (cast(ubyte*) &h.OptionalHeader + h.FileHeader.SizeOfOptionalHeader); } // ImageDirectoryEntryToDataEx() From c79663e148f786e253c9c1f7cde837fab7329640 Mon Sep 17 00:00:00 2001 From: Dennis Korpel Date: Tue, 8 Aug 2023 13:33:43 +0200 Subject: [PATCH 135/176] Fix 24070 - Opaque struct with nested definition when taking pointer segfaults --- dmd/expressionsem.d | 2 +- tests/dmd/compilable/testcstuff2.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index be597dfa90f..8e42a8bf901 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -7259,7 +7259,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor else if (!exp.e1.type.deco) { // try to resolve the type - exp.e1.type = exp.e1.type.typeSemantic(exp.e1.loc, null); + exp.e1.type = exp.e1.type.typeSemantic(exp.e1.loc, sc); if (!exp.e1.type.deco) // still couldn't resolve it { if (auto ve = exp.e1.isVarExp()) diff --git a/tests/dmd/compilable/testcstuff2.c b/tests/dmd/compilable/testcstuff2.c index e80f6a53244..c8cacd87021 100644 --- a/tests/dmd/compilable/testcstuff2.c +++ b/tests/dmd/compilable/testcstuff2.c @@ -733,3 +733,19 @@ void test23725() { __fnldcw(1, 2); } + +/************************************************************/ +// https://issues.dlang.org/show_bug.cgi?id=24070 + +typedef struct Typ Typ; +typedef struct Field Field; + +struct Typ { + struct Field { + } (*fields)[1]; +}; + +static void parse() { + Typ* ty; + void* fields = &ty->fields; +} From 403718db779ba9fe97718988d5abfadb0c43d185 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Sat, 12 Aug 2023 17:16:18 +0100 Subject: [PATCH 136/176] [stable] Make enum function a deprecation, not an error (dlang/dmd!15533) [stable] Make enum function a deprecation, not an error Signed-off-by: Dennis Signed-off-by: Vladimir Panteleev Signed-off-by: Petar Kirov Merged-on-behalf-of: Vladimir Panteleev --- dmd/parse.d | 4 +++- tests/dmd/fail_compilation/enum_function.d | 9 +++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/dmd/parse.d b/dmd/parse.d index d15e448150f..a42cc14664b 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -4581,8 +4581,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } else if (t.ty == Tfunction) { + /* @@@DEPRECATED_2.115@@@ + * change to error, deprecated in 2.105.1 */ if (storage_class & STC.manifest) - error("function cannot have enum storage class"); + deprecation("function cannot have enum storage class"); AST.Expression constraint = null; //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t.toChars(), storage_class); diff --git a/tests/dmd/fail_compilation/enum_function.d b/tests/dmd/fail_compilation/enum_function.d index b22f2ceccef..52b71d12f5d 100644 --- a/tests/dmd/fail_compilation/enum_function.d +++ b/tests/dmd/fail_compilation/enum_function.d @@ -1,10 +1,11 @@ /* +REQUIRED_ARGS: -de TEST_OUTPUT: --- -fail_compilation/enum_function.d(10): Error: function cannot have enum storage class -fail_compilation/enum_function.d(11): Error: function cannot have enum storage class -fail_compilation/enum_function.d(12): Error: function cannot have enum storage class -fail_compilation/enum_function.d(13): Error: function cannot have enum storage class +fail_compilation/enum_function.d(11): Deprecation: function cannot have enum storage class +fail_compilation/enum_function.d(12): Deprecation: function cannot have enum storage class +fail_compilation/enum_function.d(13): Deprecation: function cannot have enum storage class +fail_compilation/enum_function.d(14): Deprecation: function cannot have enum storage class --- */ enum void f1() { return; } From 4f1cd77494900e89d39742f209048712099f6175 Mon Sep 17 00:00:00 2001 From: mhh Date: Wed, 16 Aug 2023 23:40:50 +0100 Subject: [PATCH 137/176] Fix Issue 24088 - Nested functions using the shortened syntax were not recognized correctly as declarations. The fix was simply to amend `isDeclarator` to look for TOK.goesTo (i.e. `=>`) --- dmd/parse.d | 19 ++++++++++++++++++- tests/dmd/compilable/shortened_methods.d | 5 +++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/dmd/parse.d b/dmd/parse.d index a42cc14664b..02c18bd120d 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -7562,7 +7562,7 @@ LagainStc: } continue; - // Valid tokens that follow a declaration + // Valid tokens that follow the start of a declaration case TOK.rightParenthesis: case TOK.rightBracket: case TOK.assign: @@ -7581,6 +7581,23 @@ LagainStc: } return false; + // To recognize the shortened function declaration syntax + case TOK.goesTo: + /* + 1. https://issues.dlang.org/show_bug.cgi?id=24088 + + 2. We need to make sure the would-be + declarator has an identifier otherwise function literals + are handled incorrectly. Some special treatment is required + here, it turns out that a lot of code in the compiler relies + on this mess (in the parser), i.e. having isDeclarator be more + precise the parsing of other things go kaboom, so we do it in a + separate case. + */ + if (*haveId) + goto case TOK.do_; + goto default; + case TOK.identifier: if (t.ident == Id._body) { diff --git a/tests/dmd/compilable/shortened_methods.d b/tests/dmd/compilable/shortened_methods.d index 71350af8739..785cb8e5cd0 100644 --- a/tests/dmd/compilable/shortened_methods.d +++ b/tests/dmd/compilable/shortened_methods.d @@ -27,7 +27,12 @@ string test() => "hello"; // works at any scope static assert(test() == "hello"); // works normally static assert(is(typeof(&test) == string function())); // same normal type +struct S(T) {} + void func() { int a; int nested() => a; // and at nested scopes too + + // Issue 24088 - https://issues.dlang.org/show_bug.cgi?id=24088 + S!int f() => S!int(); } From a5a0f9133f524f022810e33d52e83ae9e4c17085 Mon Sep 17 00:00:00 2001 From: Teodor Dutu Date: Sat, 19 Aug 2023 08:24:13 +0800 Subject: [PATCH 138/176] Fix Issue 24078 - Fold constants on array concatenation only for strings Without this limitation, the code could incorrectly concatenate `["c"] ~ "a" ~ "b"` as `["c"] ~ "ab"`, which was incorrect. Signed-off-by: Teodor Dutu --- dmd/optimize.d | 28 +++++++++++++++++----------- tests/dmd/runnable/test24078.d | 6 ++++++ 2 files changed, 23 insertions(+), 11 deletions(-) create mode 100644 tests/dmd/runnable/test24078.d diff --git a/dmd/optimize.d b/dmd/optimize.d index f98e7c76bcc..37563826a2d 100644 --- a/dmd/optimize.d +++ b/dmd/optimize.d @@ -1280,19 +1280,25 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) //printf("CatExp::optimize(%d) %s\n", result, e.toChars()); if (binOptimize(e, result)) return; - if (auto ce1 = e.e1.isCatExp()) - { - // https://issues.dlang.org/show_bug.cgi?id=12798 - // optimize ((expr ~ str1) ~ str2) - scope CatExp cex = new CatExp(e.loc, ce1.e2, e.e2); - cex.type = e.type; - Expression ex = Expression_optimize(cex, result, false); - if (ex != cex) + + if (e.type == Type.tstring) + if (auto ce1 = e.e1.isCatExp()) { - e.e1 = ce1.e1; - e.e2 = ex; + // https://issues.dlang.org/show_bug.cgi?id=12798 + // optimize ((expr ~ str1) ~ str2) + // https://issues.dlang.org/show_bug.cgi?id=24078 + // This optimization is only valid if `expr` is a string. + // Otherwise it leads to: + // `["c"] ~ "a" ~ "b"` becoming `["c"] ~ "ab"` + scope CatExp cex = new CatExp(e.loc, ce1.e2, e.e2); + cex.type = e.type; + Expression ex = Expression_optimize(cex, result, false); + if (ex != cex) + { + e.e1 = ce1.e1; + e.e2 = ex; + } } - } // optimize "str"[] -> "str" if (auto se1 = e.e1.isSliceExp()) { diff --git a/tests/dmd/runnable/test24078.d b/tests/dmd/runnable/test24078.d new file mode 100644 index 00000000000..99d74400cf8 --- /dev/null +++ b/tests/dmd/runnable/test24078.d @@ -0,0 +1,6 @@ +//https://issues.dlang.org/show_bug.cgi?id=24078 + +void main() +{ + assert(["c"] ~ "a" ~ "b" == ["c", "a", "b"]); +} From 3b9f7259cc6dea2b3d5d1f58ef8c5d367751c840 Mon Sep 17 00:00:00 2001 From: Nathan Sashihara <21227491+n8sh@users.noreply.github.com> Date: Thu, 24 Aug 2023 00:53:14 -0400 Subject: [PATCH 139/176] Fix Issue 24106 - core.stdc.math provides an implementation of modfl for uClibc that only works when real and double are the same size --- runtime/druntime/src/core/stdc/math.d | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/runtime/druntime/src/core/stdc/math.d b/runtime/druntime/src/core/stdc/math.d index 2666c952992..76b32b44de1 100644 --- a/runtime/druntime/src/core/stdc/math.d +++ b/runtime/druntime/src/core/stdc/math.d @@ -4129,7 +4129,18 @@ else version (CRuntime_UClibc) /// pure float modff(float value, float* iptr); /// - extern(D) pure real modfl(real value, real *iptr) { return modf(cast(double) value, cast(double*) iptr); } + extern(D) pure real modfl(real value, real *iptr) + { + static if (double.sizeof == real.sizeof) + return modf(cast(double) value, cast(double*) iptr); + else + { + double i; + double r = modf(cast(double) value, &i); + *iptr = i; + return r; + } + } /// double scalbn(double x, int n); From 6270015eba1975c97eab032f50bae0424ddb577f Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 26 Aug 2023 15:40:26 +0200 Subject: [PATCH 140/176] Bump LDC version / frontend version / Phobos submodule --- CMakeLists.txt | 6 +++--- runtime/phobos | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e4fd4fb507..4866d43a54a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,10 +117,10 @@ include(GetLinuxDistribution) # # Version information -set(LDC_VERSION "1.34.0") # May be overridden by git hash tag +set(LDC_VERSION "1.35.0") # May be overridden by git hash tag set(DMDFE_MAJOR_VERSION 2) -set(DMDFE_MINOR_VERSION 104) -set(DMDFE_PATCH_VERSION 2) +set(DMDFE_MINOR_VERSION 105) +set(DMDFE_PATCH_VERSION 1) set(DMD_VERSION ${DMDFE_MAJOR_VERSION}.${DMDFE_MINOR_VERSION}.${DMDFE_PATCH_VERSION}) diff --git a/runtime/phobos b/runtime/phobos index f9112228cac..d7f31b03664 160000 --- a/runtime/phobos +++ b/runtime/phobos @@ -1 +1 @@ -Subproject commit f9112228cac41b64a42b4720cc821ba6189ee88b +Subproject commit d7f31b036640670fc9f8364ad9a21d8be302f132 From ae52da1bfa3c419551ad9c2f6bb4a2a662c926e4 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 26 Aug 2023 15:46:19 +0200 Subject: [PATCH 141/176] Adapt to Loc::linnum and Loc::charnum now being functions --- driver/timetrace.d | 4 ++-- gen/arrays.cpp | 2 +- gen/coverage.cpp | 4 ++-- gen/dibuilder.cpp | 38 +++++++++++++++++++------------------- gen/llvmhelpers.cpp | 4 ++-- gen/mangling.cpp | 2 +- gen/statements.cpp | 2 +- 7 files changed, 28 insertions(+), 28 deletions(-) diff --git a/driver/timetrace.d b/driver/timetrace.d index 8b40964db27..e90ab9f22aa 100644 --- a/driver/timetrace.d +++ b/driver/timetrace.d @@ -336,10 +336,10 @@ struct TimeTraceProfiler if (loc.filename) { writeEscapeJSONString(buf, loc.filename.toDString()); - if (loc.linnum) + if (loc.linnum()) { buf.writeByte(':'); - buf.print(loc.linnum); + buf.print(loc.linnum()); } } else diff --git a/gen/arrays.cpp b/gen/arrays.cpp index da319d5e3a7..96058ea3ef1 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -1194,7 +1194,7 @@ static void emitRangeErrorImpl(IRState *irs, const Loc &loc, LLSmallVector args; args.reserve(2 + extraArgs.size()); args.push_back(DtoModuleFileName(module, loc)); - args.push_back(DtoConstUint(loc.linnum)); + args.push_back(DtoConstUint(loc.linnum())); args.insert(args.end(), extraArgs.begin(), extraArgs.end()); irs->CreateCallOrInvoke(fn, args); irs->ir->CreateUnreachable(); diff --git a/gen/coverage.cpp b/gen/coverage.cpp index 89db3f1758b..dd779987ee8 100644 --- a/gen/coverage.cpp +++ b/gen/coverage.cpp @@ -20,12 +20,12 @@ void emitCoverageLinecountInc(const Loc &loc) { // Only emit coverage increment for locations in the source of the current // module // (for example, 'inlined' methods from other source files should be skipped). - if (!global.params.cov || !loc.linnum || !loc.filename || !m->d_cover_data || + if (!global.params.cov || !loc.linnum() || !loc.filename || !m->d_cover_data || strcmp(m->srcfile.toChars(), loc.filename) != 0) { return; } - const unsigned line = loc.linnum - 1; // convert to 0-based line# index + const unsigned line = loc.linnum() - 1; // convert to 0-based line# index assert(line < m->numlines); IF_LOG Logger::println("Coverage: increment _d_cover_data[%d]", line); diff --git a/gen/dibuilder.cpp b/gen/dibuilder.cpp index 72e8b949950..12ef10abf8f 100644 --- a/gen/dibuilder.cpp +++ b/gen/dibuilder.cpp @@ -116,7 +116,7 @@ DIBuilder::DIBuilder(IRState *const IR) emitColumnInfo(opts::getFlagOrDefault(::emitColumnInfo, !emitCodeView)) {} unsigned DIBuilder::getColumn(const Loc &loc) const { - return (loc.linnum && emitColumnInfo) ? loc.charnum : 0; + return (loc.linnum() && emitColumnInfo) ? loc.charnum() : 0; } // Returns the DI scope of a symbol. @@ -202,7 +202,7 @@ llvm::StringRef DIBuilder::GetNameAndScope(Dsymbol *sym, DIScope &scope) { // Sets the memory address for a debuginfo variable. void DIBuilder::Declare(const Loc &loc, llvm::Value *storage, DILocalVariable divar, DIExpression diexpr) { - auto debugLoc = llvm::DILocation::get(IR->context(), loc.linnum, + auto debugLoc = llvm::DILocation::get(IR->context(), loc.linnum(), getColumn(loc), GetCurrentScope()); DBuilder.insertDeclare(storage, divar, diexpr, debugLoc, IR->scopebb()); } @@ -210,7 +210,7 @@ void DIBuilder::Declare(const Loc &loc, llvm::Value *storage, // Sets the (current) value for a debuginfo variable. void DIBuilder::SetValue(const Loc &loc, llvm::Value *value, DILocalVariable divar, DIExpression diexpr) { - auto debugLoc = llvm::DILocation::get(IR->context(), loc.linnum, + auto debugLoc = llvm::DILocation::get(IR->context(), loc.linnum(), getColumn(loc), GetCurrentScope()); DBuilder.insertDbgValueIntrinsic(value, divar, diexpr, debugLoc, IR->scopebb()); @@ -346,7 +346,7 @@ DIType DIBuilder::CreateEnumType(TypeEnum *type) { DIScope scope = nullptr; const auto name = GetNameAndScope(ed, scope); - const auto lineNumber = ed->loc.linnum; + const auto lineNumber = ed->loc.linnum(); const auto file = CreateFile(ed); // just emit a typedef for non-integral base types @@ -490,7 +490,7 @@ void DIBuilder::AddFields(AggregateDeclaration *ad, DIFile file, if (vd->type->toBasetype()->isTypeNoreturn()) continue; - elems.push_back(CreateMemberType(vd->loc.linnum, vd->type, file, + elems.push_back(CreateMemberType(vd->loc.linnum(), vd->type, file, vd->toChars(), vd->offset, vd->visibility.kind)); } @@ -532,8 +532,8 @@ void DIBuilder::AddStaticMembers(AggregateDeclaration *ad, DIFile file, } } else if (!vd->type->toBasetype()->isTypeNoreturn()) { llvm::MDNode *elem = - CreateMemberType(vd->loc.linnum, vd->type, file, vd->toChars(), - 0, vd->visibility.kind, + CreateMemberType(vd->loc.linnum(), vd->type, file, + vd->toChars(), 0, vd->visibility.kind, /*isStatic = */ true, scope); elems.push_back(elem); StaticDataMemberCache[vd].reset(elem); @@ -586,7 +586,7 @@ DIType DIBuilder::CreateCompositeType(Type *t) { // defaults const auto file = CreateFile(ad); - const auto lineNum = ad->loc.linnum; + const auto lineNum = ad->loc.linnum(); const auto sizeInBits = T->isSized() ? getTypeAllocSize(T) * 8 : 0; const auto alignmentInBits = T->isSized() ? getABITypeAlign(T) * 8 : 0; const auto classOffsetInBits = 0; @@ -908,9 +908,9 @@ void DIBuilder::EmitImport(Import *im) { auto diModule = EmitModule(im->mod); DBuilder.createImportedModule(GetCurrentScope(), - diModule, // imported module - CreateFile(im), // file - im->loc.linnum // line num + diModule, // imported module + CreateFile(im), // file + im->loc.linnum() // line num ); } @@ -945,7 +945,7 @@ DISubprogram DIBuilder::EmitSubProgram(FuncDeclaration *fd) { const auto linkageName = irFunc->getLLVMFuncName(); const auto file = CreateFile(fd); - const auto lineNo = fd->loc.linnum; + const auto lineNo = fd->loc.linnum(); const auto isLocalToUnit = fd->visibility.kind == Visibility::private_; const auto isDefinition = true; const auto scopeLine = lineNo; // FIXME @@ -1011,7 +1011,7 @@ DISubprogram DIBuilder::EmitThunk(llvm::Function *Thunk, FuncDeclaration *fd) { const auto name = (llvm::Twine(fd->toChars()) + ".__thunk").str(); const auto linkageName = Thunk->getName(); const auto file = CreateFile(fd); - const auto lineNo = fd->loc.linnum; + const auto lineNo = fd->loc.linnum(); const bool isLocalToUnit = fd->visibility.kind == Visibility::private_; const bool isDefinition = true; const bool isOptimized = isOptimizationEnabled(); @@ -1080,7 +1080,7 @@ void DIBuilder::EmitBlockStart(const Loc &loc) { LOG_SCOPE; DILexicalBlock block = DBuilder.createLexicalBlock( - GetCurrentScope(), CreateFile(loc), loc.linnum, getColumn(loc)); + GetCurrentScope(), CreateFile(loc), loc.linnum(), getColumn(loc)); IR->func()->diLexicalBlocks.push(block); EmitStopPoint(loc); } @@ -1104,14 +1104,14 @@ void DIBuilder::EmitStopPoint(const Loc &loc) { // If we already have a location set and the current loc is invalid // (line 0), then we can just ignore it (see GitHub issue #998 for why we // cannot do this in all cases). - if (!loc.linnum && IR->ir->getCurrentDebugLocation()) + if (!loc.linnum() && IR->ir->getCurrentDebugLocation()) return; - unsigned linnum = loc.linnum; + unsigned linnum = loc.linnum(); // without proper loc use the line of the enclosing symbol that has line // number debug info for (Dsymbol *sym = IR->func()->decl; sym && !linnum; sym = sym->parent) - linnum = sym->loc.linnum; + linnum = sym->loc.linnum(); if (!linnum) linnum = 1; @@ -1216,7 +1216,7 @@ void DIBuilder::EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd, const auto scope = GetCurrentScope(); const auto name = vd->toChars(); const auto file = CreateFile(vd); - const auto lineNum = vd->loc.linnum; + const auto lineNum = vd->loc.linnum(); const auto preserve = true; auto flags = !isThisPtr ? DIFlags::FlagZero @@ -1288,7 +1288,7 @@ void DIBuilder::EmitGlobalVariable(llvm::GlobalVariable *llVar, vd->toChars(), // name mangleBuf.peekChars(), // linkage name CreateFile(vd), // file - vd->loc.linnum, // line num + vd->loc.linnum(), // line num CreateTypeDescription(vd->type), // type vd->visibility.kind == Visibility::private_, // is local to unit !(vd->storage_class & STCextern), // bool isDefined diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 6e517591702..5347b6d6a93 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -279,7 +279,7 @@ void DtoAssert(Module *M, const Loc &loc, DValue *msg) { args.push_back(DtoModuleFileName(M, loc)); // line param - args.push_back(DtoConstUint(loc.linnum)); + args.push_back(DtoConstUint(loc.linnum())); // call gIR->CreateCallOrInvoke(fn, args); @@ -292,7 +292,7 @@ void DtoCAssert(Module *M, const Loc &loc, LLValue *msg) { const auto &triple = *global.params.targetTriple; const auto file = DtoConstCString(loc.filename ? loc.filename : M->srcfile.toChars()); - const auto line = DtoConstUint(loc.linnum); + const auto line = DtoConstUint(loc.linnum()); const auto fn = getCAssertFunction(loc, gIR->module); llvm::SmallVector args; diff --git a/gen/mangling.cpp b/gen/mangling.cpp index b384a97ff03..884fa374e8d 100644 --- a/gen/mangling.cpp +++ b/gen/mangling.cpp @@ -70,7 +70,7 @@ std::string hashSymbolName(llvm::StringRef name, Dsymbol *symb) { } // source line number - auto lineNo = ldc::to_string(symb->loc.linnum); + auto lineNo = ldc::to_string(symb->loc.linnum()); ret += ldc::to_string(lineNo.size()+1); ret += 'L'; ret += lineNo; diff --git a/gen/statements.cpp b/gen/statements.cpp index e80d6173fdb..e7d5fe1c2a9 100644 --- a/gen/statements.cpp +++ b/gen/statements.cpp @@ -309,7 +309,7 @@ class ToIRVisitor : public Visitor { // Hack: the frontend generates 'return 0;' as last statement of // 'void main()'. But the debug location is missing. Use the end // of function as debug location. - if (isAnyMainFunction(fd) && !stmt->loc.linnum) { + if (isAnyMainFunction(fd) && !stmt->loc.linnum()) { irs->DBuilder.EmitStopPoint(fd->endloc); } From 8fc096e4c60bfc7b8ac22a5b90eae40d18cfef71 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 26 Aug 2023 15:53:01 +0200 Subject: [PATCH 142/176] Adapt to Loc::filename now being a function --- driver/cl_options_sanitizers.cpp | 2 +- driver/timetrace.d | 24 ++---------------------- gen/coverage.cpp | 4 ++-- gen/dibuilder.cpp | 4 ++-- gen/functions.cpp | 4 ++-- gen/llvmhelpers.cpp | 4 ++-- 6 files changed, 11 insertions(+), 31 deletions(-) diff --git a/driver/cl_options_sanitizers.cpp b/driver/cl_options_sanitizers.cpp index 4994e8b162a..385464287bc 100644 --- a/driver/cl_options_sanitizers.cpp +++ b/driver/cl_options_sanitizers.cpp @@ -233,7 +233,7 @@ bool functionIsInSanitizerBlacklist(FuncDeclaration *funcDecl) { return false; auto funcName = mangleExact(funcDecl); - auto fileName = funcDecl->loc.filename; + auto fileName = funcDecl->loc.filename(); // TODO: LLVM supports sections (e.g. "[address]") in the blacklist file to // only blacklist a function for a particular sanitizer. We could make use of diff --git a/driver/timetrace.d b/driver/timetrace.d index e90ab9f22aa..a19c9a91b1d 100644 --- a/driver/timetrace.d +++ b/driver/timetrace.d @@ -118,10 +118,6 @@ void timeTraceProfilerBegin(const(char)* name_ptr, const(char)* detail_ptr, Loc assert(timeTraceProfiler); - // `loc` contains a pointer to a string, so we need to duplicate that string too. - if (loc.filename) - loc.filename = strdup(loc.filename); - timeTraceProfiler.beginScope(xarraydup(name_ptr.toDString()), xarraydup(detail_ptr.toDString()), loc); } @@ -333,9 +329,9 @@ struct TimeTraceProfiler void writeLocation(Loc loc) { - if (loc.filename) + if (loc.filename()) { - writeEscapeJSONString(buf, loc.filename.toDString()); + writeEscapeJSONString(buf, loc.filename().toDString()); if (loc.linnum()) { buf.writeByte(':'); @@ -387,10 +383,6 @@ struct TimeTraceScope if (timeTraceProfilerEnabled()) { assert(timeTraceProfiler); - // `loc` contains a pointer to a string, so we need to duplicate that too. - import core.stdc.string : strdup; - if (loc.filename) - loc.filename = strdup(loc.filename); timeTraceProfiler.beginScope(name.dup, "", loc); } } @@ -399,10 +391,6 @@ struct TimeTraceScope if (timeTraceProfilerEnabled()) { assert(timeTraceProfiler); - // `loc` contains a pointer to a string, so we need to duplicate that too. - import core.stdc.string : strdup; - if (loc.filename) - loc.filename = strdup(loc.filename); timeTraceProfiler.beginScope(name.dup, detail.dup, loc); } } @@ -412,10 +400,6 @@ struct TimeTraceScope if (timeTraceProfilerEnabled()) { assert(timeTraceProfiler); - // `loc` contains a pointer to a string, so we need to duplicate that too. - import core.stdc.string : strdup; - if (loc.filename) - loc.filename = strdup(loc.filename); timeTraceProfiler.beginScope(name.dup, detail(), loc); } } @@ -446,10 +430,6 @@ struct TimeTraceScopeDelayedDetail if (timeTraceProfilerEnabled()) { assert(timeTraceProfiler); - // `loc` contains a pointer to a string, so we need to duplicate that too. - import core.stdc.string : strdup; - if (loc.filename) - loc.filename = strdup(loc.filename); details_dlg = detail; timeTraceProfiler.beginScope(name.dup, "", loc); } diff --git a/gen/coverage.cpp b/gen/coverage.cpp index dd779987ee8..d6b807b2c75 100644 --- a/gen/coverage.cpp +++ b/gen/coverage.cpp @@ -20,8 +20,8 @@ void emitCoverageLinecountInc(const Loc &loc) { // Only emit coverage increment for locations in the source of the current // module // (for example, 'inlined' methods from other source files should be skipped). - if (!global.params.cov || !loc.linnum() || !loc.filename || !m->d_cover_data || - strcmp(m->srcfile.toChars(), loc.filename) != 0) { + if (!global.params.cov || !loc.linnum() || !loc.filename() || + !m->d_cover_data || strcmp(m->srcfile.toChars(), loc.filename()) != 0) { return; } diff --git a/gen/dibuilder.cpp b/gen/dibuilder.cpp index 12ef10abf8f..63f1bf82784 100644 --- a/gen/dibuilder.cpp +++ b/gen/dibuilder.cpp @@ -240,13 +240,13 @@ DIFile DIBuilder::CreateFile(const char *filename) { } DIFile DIBuilder::CreateFile(const Loc &loc) { - return CreateFile(loc.filename); + return CreateFile(loc.filename()); } DIFile DIBuilder::CreateFile(Dsymbol *decl) { const char *filename = nullptr; for (Dsymbol *sym = decl; sym && !filename; sym = sym->parent) - filename = sym->loc.filename; + filename = sym->loc.filename(); return CreateFile(filename); } diff --git a/gen/functions.cpp b/gen/functions.cpp index adbdf4c5b7c..92d51ff7ca5 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -527,9 +527,9 @@ void onlyOneMainCheck(FuncDeclaration *fd) { (isOSWindows && (fd->isWinMain() || fd->isDllMain()))) { // global - across all modules compiled in this compiler invocation static Loc mainLoc; - if (!mainLoc.filename) { + if (!mainLoc.filename()) { mainLoc = fd->loc; - assert(mainLoc.filename); + assert(mainLoc.filename()); } else { const char *otherMainNames = isOSWindows ? ", `WinMain`, or `DllMain`" : ""; diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 5347b6d6a93..22dd807d1b7 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -291,7 +291,7 @@ void DtoAssert(Module *M, const Loc &loc, DValue *msg) { void DtoCAssert(Module *M, const Loc &loc, LLValue *msg) { const auto &triple = *global.params.targetTriple; const auto file = - DtoConstCString(loc.filename ? loc.filename : M->srcfile.toChars()); + DtoConstCString(loc.filename() ? loc.filename() : M->srcfile.toChars()); const auto line = DtoConstUint(loc.linnum()); const auto fn = getCAssertFunction(loc, gIR->module); @@ -356,7 +356,7 @@ void DtoThrow(const Loc &loc, DValue *e) { ******************************************************************************/ LLConstant *DtoModuleFileName(Module *M, const Loc &loc) { - return DtoConstString(loc.filename ? loc.filename : M->srcfile.toChars()); + return DtoConstString(loc.filename() ? loc.filename() : M->srcfile.toChars()); } /****************************************************************************** From 761ef2f5437dc30a9df9490f4516ff0756920820 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 26 Aug 2023 15:55:48 +0200 Subject: [PATCH 143/176] Adapt to removed Target::is64bit --- gen/target.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/gen/target.cpp b/gen/target.cpp index 8b81afe12e8..bdbd4e789e9 100644 --- a/gen/target.cpp +++ b/gen/target.cpp @@ -128,7 +128,6 @@ void Target::_init(const Param ¶ms) { const llvm::StringRef archName = triple.getArchName(); architectureName = {archName.size(), archName.data()}; - is64bit = triple.isArch64Bit(); isLP64 = gDataLayout->getPointerSizeInBits() == 64; run_noext = !triple.isOSWindows(); omfobj = false; From 3ab72d8e5212ce3ccab221238e4a8770afd7e310 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 26 Aug 2023 16:27:02 +0200 Subject: [PATCH 144/176] druntime: Convert LDC-specific `@safe` inline asm to `@trusted` As `@safe` inline asm is deprecated now. --- runtime/druntime/src/core/math.d | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/runtime/druntime/src/core/math.d b/runtime/druntime/src/core/math.d index 9a309f3ab80..8ec16576f6d 100644 --- a/runtime/druntime/src/core/math.d +++ b/runtime/druntime/src/core/math.d @@ -334,7 +334,7 @@ version (LDC) real ldexp(real n, int exp) { real r = void; - asm @safe pure nothrow @nogc + asm @trusted pure nothrow @nogc { `fildl %1 # push exp fxch %%st(1) # swap ST(0) and ST(1) @@ -448,7 +448,7 @@ version (LDC) real yl2x(real x, real y) { real r = void; - asm @safe pure nothrow @nogc { "fyl2x" : "=st" (r) : "st(1)" (y), "st" (x) : "st(1)", "flags"; } + asm @trusted pure nothrow @nogc { "fyl2x" : "=st" (r) : "st(1)" (y), "st" (x) : "st(1)", "flags"; } return r; } @@ -456,7 +456,7 @@ version (LDC) real yl2xp1(real x, real y) { real r = void; - asm @safe pure nothrow @nogc { "fyl2xp1" : "=st" (r) : "st(1)" (y), "st" (x) : "st(1)", "flags"; } + asm @trusted pure nothrow @nogc { "fyl2xp1" : "=st" (r) : "st(1)" (y), "st" (x) : "st(1)", "flags"; } return r; } } From c5704c764dedf9738e00d7f7e9f27a065a35fbb4 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 26 Aug 2023 16:48:04 +0200 Subject: [PATCH 145/176] Adapt to new _d_newitemT template lowering for heap-allocations of structs --- gen/llvmhelpers.cpp | 9 --------- gen/llvmhelpers.h | 1 - gen/runtime.cpp | 8 +------- gen/toir.cpp | 5 +++-- 4 files changed, 4 insertions(+), 19 deletions(-) diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 22dd807d1b7..3426ef99e71 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -91,15 +91,6 @@ LLValue *DtoNew(const Loc &loc, Type *newtype) { return DtoBitCast(mem, DtoPtrToType(newtype), ".gc_mem"); } -LLValue *DtoNewStruct(const Loc &loc, TypeStruct *newtype) { - llvm::Function *fn = getRuntimeFunction( - loc, gIR->module, - newtype->isZeroInit(newtype->sym->loc) ? "_d_newitemT" : "_d_newitemiT"); - LLConstant *ti = DtoTypeInfoOf(loc, newtype); - LLValue *mem = gIR->CreateCallOrInvoke(fn, ti, ".gc_struct"); - return DtoBitCast(mem, DtoPtrToType(newtype), ".gc_struct"); -} - void DtoDeleteMemory(const Loc &loc, DValue *ptr) { llvm::Function *fn = getRuntimeFunction(loc, gIR->module, "_d_delmemory"); LLValue *lval = (ptr->isLVal() ? DtoLVal(ptr) : makeLValue(loc, ptr)); diff --git a/gen/llvmhelpers.h b/gen/llvmhelpers.h index 7dbacbefda6..6720309942d 100644 --- a/gen/llvmhelpers.h +++ b/gen/llvmhelpers.h @@ -30,7 +30,6 @@ llvm::LLVMContext& getGlobalContext(); // dynamic memory helpers LLValue *DtoNew(const Loc &loc, Type *newtype); -LLValue *DtoNewStruct(const Loc &loc, TypeStruct *newtype); void DtoDeleteMemory(const Loc &loc, DValue *ptr); void DtoDeleteStruct(const Loc &loc, DValue *ptr); void DtoDeleteClass(const Loc &loc, DValue *inst); diff --git a/gen/runtime.cpp b/gen/runtime.cpp index 706acac292b..4fc39fdff2b 100644 --- a/gen/runtime.cpp +++ b/gen/runtime.cpp @@ -89,8 +89,7 @@ static void checkForImplicitGCCall(const Loc &loc, const char *name) { "_d_newarrayU", "_d_newclass", "_d_allocclass", - "_d_newitemT", - "_d_newitemiT", + // TODO: _d_newitemT instantiations }; if (binary_search(&GCNAMES[0], @@ -618,11 +617,6 @@ static void buildRuntimeModule() { createFwdDecl(LINK::c, throwableTy, {"_d_newThrowable"}, {classInfoTy}, {STCconst}); - // void* _d_newitemT (TypeInfo ti) - // void* _d_newitemiT(TypeInfo ti) - createFwdDecl(LINK::c, voidPtrTy, {"_d_newitemT", "_d_newitemiT"}, - {typeInfoTy}, {0}); - // void _d_delarray_t(void[]* p, const TypeInfo_Struct ti) createFwdDecl(LINK::c, voidTy, {"_d_delarray_t"}, {voidArrayPtrTy, structTypeInfoTy}, {0, STCconst}); diff --git a/gen/toir.cpp b/gen/toir.cpp index 6ea93a69823..1fa7a7f5bd8 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1549,8 +1549,9 @@ class ToElemVisitor : public Visitor { TypeStruct *ts = static_cast(ntype); - // allocate - LLValue *mem = DtoNewStruct(e->loc, ts); + // allocate (via _d_newitemT template lowering) + assert(e->lowering); + LLValue *mem = DtoRVal(e->lowering); if (!e->member && e->arguments) { IF_LOG Logger::println("Constructing using literal"); From fda89c1c637d7813e59ecc030b1fd58a65450ca1 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 26 Aug 2023 17:08:10 +0200 Subject: [PATCH 146/176] druntime: Exclude valgrind.c on Windows --- runtime/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 5766d6211fa..e3a0d9e41a5 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -205,6 +205,10 @@ endif() # druntime C parts file(GLOB_RECURSE DRUNTIME_C ${RUNTIME_DIR}/src/*.c) list(REMOVE_ITEM DRUNTIME_C ${RUNTIME_DIR}/src/rt/dylib_fixes.c) +# remove unsupported valgrind.c on Windows +if("${TARGET_SYSTEM}" MATCHES "Windows") + list(REMOVE_ITEM DRUNTIME_C ${RUNTIME_DIR}/src/etc/valgrind/valgrind.c) +endif() # druntime ASM parts set(DRUNTIME_ASM) From 12286284cd99015df421845a6cdf05ef35d24ce2 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 26 Aug 2023 22:34:59 +0200 Subject: [PATCH 147/176] Allow member function address as constant initializer This is allowed since D v2.105. Fixes dmd-testsuite's runnable/test20687.d. Kindly got a heads-up early: https://github.com/dlang/dmd/pull/10958#issuecomment-1471147790 --- gen/llvmhelpers.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 3426ef99e71..4f4c4f67a0b 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1609,14 +1609,6 @@ DValue *DtoSymbolAddress(const Loc &loc, Type *type, Declaration *decl) { } llvm::Constant *DtoConstSymbolAddress(const Loc &loc, Declaration *decl) { - // Make sure 'this' isn't needed. - // TODO: This check really does not belong here, should be moved to - // semantic analysis in the frontend. - if (decl->needThis()) { - error(loc, "need `this` to access `%s`", decl->toChars()); - fatal(); - } - // global variable if (VarDeclaration *vd = decl->isVarDeclaration()) { if (!vd->isDataseg()) { From 1f8f5e94db5468d8998d81751553331bb3849ee6 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 26 Aug 2023 22:48:16 +0200 Subject: [PATCH 148/176] ImportC: Fix `alloca` availability Fixes dmd-testsuite's runnable/test23889.c. DMD has an alloca implementation in druntime; we use an intrinsic. --- runtime/druntime/src/__builtins.di | 2 ++ runtime/druntime/src/importc.h | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/runtime/druntime/src/__builtins.di b/runtime/druntime/src/__builtins.di index fd1f0675a28..6a112e0b8c1 100644 --- a/runtime/druntime/src/__builtins.di +++ b/runtime/druntime/src/__builtins.di @@ -156,4 +156,6 @@ else version (LDC) void __builtin_assume(T)(lazy T arg) { } alias __uint128_t = imported!"core.int128".Cent; + + alias __builtin_alloca = imported!"core.stdc.stdlib".alloca; } diff --git a/runtime/druntime/src/importc.h b/runtime/druntime/src/importc.h index 68443ba1252..23ac190b365 100644 --- a/runtime/druntime/src/importc.h +++ b/runtime/druntime/src/importc.h @@ -79,7 +79,8 @@ #define __builtin_isnan(x) isnan(x) #define __builtin_isfinite(x) finite(x) -#define __builtin_alloca(x) alloca(x) +// IN_LLVM: replaced by symbol in __builtins.di +//#define __builtin_alloca(x) alloca(x) /******************************** * __has_extension is a clang thing: From 9c265436fee1e40a97413e375a212420e547a1bd Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 26 Aug 2023 23:16:38 +0200 Subject: [PATCH 149/176] Adopt DMD's -wo command-line option to enable warnings about obsolete features Fixes dmd-testsuite's fail_compilation/body.d. --- driver/cl_options.cpp | 4 ++++ driver/ldmd.cpp | 8 +++++++- driver/main.cpp | 6 ++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/driver/cl_options.cpp b/driver/cl_options.cpp index 1a0ac4933aa..b12f9967050 100644 --- a/driver/cl_options.cpp +++ b/driver/cl_options.cpp @@ -178,6 +178,10 @@ static cl::opt warnings( "Enable warnings as messages (compilation will continue)")), cl::init(DIAGNOSTICoff)); +static cl::opt warningsObsolete( + "wo", cl::ZeroOrMore, cl::location(global.params.obsolete), + cl::desc("Enable warnings about use of obsolete features")); + static cl::opt ignoreUnsupportedPragmas( "ignore", cl::desc("Ignore unsupported pragmas"), cl::ZeroOrMore, cl::location(global.params.ignoreUnsupportedPragmas)); diff --git a/driver/ldmd.cpp b/driver/ldmd.cpp index c25938a1c51..47a0d035bbc 100644 --- a/driver/ldmd.cpp +++ b/driver/ldmd.cpp @@ -275,6 +275,7 @@ Where:\n\ -vtls list all variables going into thread local storage\n\ -w warnings as errors (compilation will halt)\n\ -wi warnings as messages (compilation will continue)\n\ + -wo warnings about use of obsolete features (compilation will continue)\n\ -X generate JSON file\n\ -Xf= write JSON file to filename\n\ -Xcc= pass driverflag to linker driver (cc)\n", @@ -593,7 +594,12 @@ void translateArgs(const llvm::SmallVectorImpl &ldmdArgs, * -revert * -w * -wi - * -O + */ + else if (strcmp(p + 1, "wo") == 0) { + ldcArgs.push_back("-wo"); + ldcArgs.push_back("-wi"); // DMD overrides a previous `-w` to `-wi`; LDC doesn't + } + /* -O * -o- * -od * -of diff --git a/driver/main.cpp b/driver/main.cpp index 07751983478..a7fbcf0e7ae 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -444,6 +444,11 @@ void parseCommandLine(Strings &sourceFiles) { deprecation(Loc(), "`-dip25` no longer has any effect"); } + // -wo implies at least -wi (print the warnings) + if (global.params.obsolete && global.params.warnings == DIAGNOSTICoff) { + global.params.warnings = DIAGNOSTICinform; + } + global.params.output_o = (opts::output_o == cl::BOU_UNSET && !(opts::output_bc || opts::output_ll || opts::output_s || @@ -1117,6 +1122,7 @@ int cppmain() { global.compileEnv.previewIn = global.params.previewIn; global.compileEnv.ddocOutput = global.params.ddoc.doOutput; global.compileEnv.shortenedMethods = global.params.shortenedMethods; + global.compileEnv.obsolete = global.params.obsolete; if (opts::fTimeTrace) { initializeTimeTrace(opts::fTimeTraceGranularity, 0, opts::allArguments[0]); From fc008faf92296c5b369bc4761c98f43bcbd5ec6b Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 26 Aug 2023 23:24:14 +0200 Subject: [PATCH 150/176] druntime: Disable new valgrind integration tests on Windows --- runtime/DRuntimeIntegrationTests.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/runtime/DRuntimeIntegrationTests.cmake b/runtime/DRuntimeIntegrationTests.cmake index 61d2d662058..a70a0051131 100644 --- a/runtime/DRuntimeIntegrationTests.cmake +++ b/runtime/DRuntimeIntegrationTests.cmake @@ -53,6 +53,9 @@ elseif(${BUILD_SHARED_LIBS} STREQUAL "ON") list(REMOVE_ITEM testnames cycles gc) endif() list(REMOVE_ITEM testnames uuid) # MSVC only, custom Makefile (win64.mak) +if("${TARGET_SYSTEM}" MATCHES "Windows") + list(REMOVE_ITEM testnames valgrind) +endif() foreach(name ${testnames}) foreach(build debug release) From 798fde387d510588c0c62a26ce4add7e4e7c3517 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 26 Aug 2023 23:45:32 +0200 Subject: [PATCH 151/176] Follow DMD and make -betterC imply -allinst --- driver/main.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/driver/main.cpp b/driver/main.cpp index a7fbcf0e7ae..da570b96ade 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -444,6 +444,11 @@ void parseCommandLine(Strings &sourceFiles) { deprecation(Loc(), "`-dip25` no longer has any effect"); } + // -betterC implies -allinst (since D v2.105) + if (global.params.betterC) { + global.params.allInst = true; + } + // -wo implies at least -wi (print the warnings) if (global.params.obsolete && global.params.warnings == DIAGNOSTICoff) { global.params.warnings = DIAGNOSTICinform; From 4e1f6d004492df77e298c0d5a830fe8d84bbaa9d Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 26 Aug 2023 23:52:08 +0200 Subject: [PATCH 152/176] Remove some Target fields unused by LDC To make sure they aren't accidentally used (not initialized properly). --- dmd/target.d | 6 ++++++ dmd/target.h | 4 ++++ gen/target.cpp | 1 - 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/dmd/target.d b/dmd/target.d index cf1dbcb851a..854bf53114a 100644 --- a/dmd/target.d +++ b/dmd/target.d @@ -359,8 +359,11 @@ version (IN_LLVM) /// Architecture name const(char)[] architectureName; +version (IN_LLVM) {} else +{ CPU cpu = CPU.baseline; // CPU instruction set to target bool isX86_64 = (size_t.sizeof == 8); // generate 64 bit code for x86_64; true by default for 64 bit dmd +} bool isLP64; // pointers are 64 bits // Environmental @@ -368,7 +371,10 @@ version (IN_LLVM) const(char)[] lib_ext; /// extension for static library files const(char)[] dll_ext; /// extension for dynamic library files bool run_noext; /// allow -run sources without extensions +version (IN_LLVM) {} else +{ bool omfobj = false; // for Win32: write OMF object files instead of MsCoff +} /** * Values representing all properties for floating point types */ diff --git a/dmd/target.h b/dmd/target.h index e006fd72cb2..2a8d8e35fde 100644 --- a/dmd/target.h +++ b/dmd/target.h @@ -166,8 +166,10 @@ struct Target TargetObjC objc; DString architectureName; // name of the platform architecture (e.g. X86_64) +#if !IN_LLVM CPU cpu; // CPU instruction set to target d_bool isX86_64; // generate 64 bit code for x86_64; true by default for 64 bit dmd +#endif d_bool isLP64; // pointers are 64 bits // Environmental @@ -175,7 +177,9 @@ struct Target DString lib_ext; /// extension for static library files DString dll_ext; /// extension for dynamic library files d_bool run_noext; /// allow -run sources without extensions +#if !IN_LLVM d_bool omfobj; /// for Win32: write OMF object files instead of COFF +#endif template struct FPTypeProperties diff --git a/gen/target.cpp b/gen/target.cpp index bdbd4e789e9..6e2499bb1e6 100644 --- a/gen/target.cpp +++ b/gen/target.cpp @@ -130,7 +130,6 @@ void Target::_init(const Param ¶ms) { isLP64 = gDataLayout->getPointerSizeInBits() == 64; run_noext = !triple.isOSWindows(); - omfobj = false; if (isMSVC) { obj_ext = {3, "obj"}; From 9b50726ae29904daa89409f66e52ff49341b74d0 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Wed, 30 Aug 2023 16:08:13 +0200 Subject: [PATCH 153/176] Fix multiple va_start calls in a single extern(D) function This is supposed to work (verified via clang), and we need to properly va_copy the implicit _argptr, so that each resulting `ap` is independent. Fixes a new subtest in dmd-testsuite's runnable/variadic.d on Posix x86_64. --- gen/tocall.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gen/tocall.cpp b/gen/tocall.cpp index 615aa7ba3ea..205a4a1d3db 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -295,7 +295,9 @@ bool DtoLowerMagicIntrinsic(IRState *p, FuncDeclaration *fndecl, CallExp *e, assert(ap); // variadic extern(D) function with implicit _argptr? if (LLValue *argptrMem = p->func()->_argptr) { - DtoMemCpy(DtoType(ap->type), DtoLVal(ap), argptrMem); // ap = _argptr + // then va_copy the _argptr + DLValue argptr(ap->type, argptrMem); + gABI->vaCopy(ap, &argptr); } else { LLValue *llAp = gABI->prepareVaStart(ap); p->ir->CreateCall(GET_INTRINSIC_DECL(vastart), llAp, ""); From ac8c61e2911d8b7a7271925797727bff6d08157e Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Thu, 31 Aug 2023 11:44:40 +0200 Subject: [PATCH 154/176] druntime: Fix malloc-leaks in ModuleGroup.sortCtors() (dlang/dmd!15559) I guess the recent removal of module constructors in druntime has brought these to light, for a little LDC ASan smoke test, which newly complains with D v2.105, e.g.: > Direct leak of 78624 byte(s) in 126 object(s) allocated from: > #0 0x55606978c40d in malloc /local/mnt/workspace/tmp/final/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:145:3 > #1 0x5560698050b1 in _D2rt5minfo11ModuleGroup9sortCtorsMFNbAyaZv --- runtime/druntime/src/rt/minfo.d | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/runtime/druntime/src/rt/minfo.d b/runtime/druntime/src/rt/minfo.d index b5c868f70bc..9bc10558981 100644 --- a/runtime/druntime/src/rt/minfo.d +++ b/runtime/druntime/src/rt/minfo.d @@ -267,10 +267,16 @@ struct ModuleGroup edge[nEdges++] = *impidx; } } - // trim space to what is needed. - edges[i] = nEdges > 0 - ? (cast(int*)realloc(edge, int.sizeof * nEdges))[0 .. nEdges] - : null; + if (nEdges > 0) + { + // trim space to what is needed + edges[i] = (cast(int*)realloc(edge, int.sizeof * nEdges))[0 .. nEdges]; + } + else + { + edges[i] = null; + .free(edge); + } } } From 798f73bd37308abc7aaef21e411f1615c4422022 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Fri, 1 Sep 2023 15:12:02 +0200 Subject: [PATCH 155/176] ImportC: Make gcc builtins available (#4483) Co-authored-by: Martin Kinkelin --- runtime/druntime/src/__builtins.di | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/runtime/druntime/src/__builtins.di b/runtime/druntime/src/__builtins.di index 81c004da7a5..4b0880a8a33 100644 --- a/runtime/druntime/src/__builtins.di +++ b/runtime/druntime/src/__builtins.di @@ -157,4 +157,23 @@ else version (LDC) void __builtin_assume(T)(lazy T arg) { } alias __uint128_t = imported!"core.int128".Cent; + + // gcc builtins: + + version (ARM) public import ldc.gccbuiltins_arm; + version (AArch64) public import ldc.gccbuiltins_aarch64; + + version (MIPS32) public import ldc.gccbuiltins_mips; + version (MIPS64) public import ldc.gccbuiltins_mips; + + version (PPC) public import ldc.gccbuiltins_ppc; + version (PPC64) public import ldc.gccbuiltins_ppc; + + version (RISCV32) public import ldc.gccbuiltins_riscv; + version (RISCV64) public import ldc.gccbuiltins_riscv; + + version (SystemZ) public import ldc.gccbuiltins_s390; + + version (X86) public import ldc.gccbuiltins_x86; + version (X86_64) public import ldc.gccbuiltins_x86; } From 3d8cff374fa3d187c61da5ef14a2c7606831f51e Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Wed, 30 Aug 2023 16:21:13 +0200 Subject: [PATCH 156/176] Slightly weaken druntime-test-exceptions-debug on Win64 and macOS arm64 too For D v2.105; see https://github.com/ldc-developers/ldc/issues/3827. --- .../test/exceptions/src/assert_fail.d | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/runtime/druntime/test/exceptions/src/assert_fail.d b/runtime/druntime/test/exceptions/src/assert_fail.d index 5ba3c1ad814..cff9ab54711 100644 --- a/runtime/druntime/test/exceptions/src/assert_fail.d +++ b/runtime/druntime/test/exceptions/src/assert_fail.d @@ -529,15 +529,23 @@ void testDestruction() version (LDC) { - version (linux) enum allowFailure = true; - else version (FreeBSD) enum allowFailure = true; - else enum allowFailure = false; - - if (allowFailure && !Test.run) + version (D_Optimized) {} else { - fprintf(stderr, "FIXME: garbage wasn't collected, ignoring sporadic failure on Linux / consistent (?) failure on FreeBSD...\n"); - fprintf(stderr, " (see https://github.com/ldc-developers/ldc/issues/3827)\n"); - return; + version (OSX) version (AArch64) version = macOS_AArch64; + + version (linux) enum allowFailure = true; + else version (FreeBSD) enum allowFailure = true; + // started to fail on Win64 and macOS arm64 too with D v2.105 (apparently consistently) + else version (Win64) enum allowFailure = true; + else version (macOS_AArch64) enum allowFailure = true; + else enum allowFailure = false; + + if (allowFailure && !Test.run) + { + fprintf(stderr, "FIXME: garbage wasn't collected, ignoring sporadic failure on Linux / consistent (?) failure on FreeBSD, Win64, macOS arm64...\n"); + fprintf(stderr, " (see https://github.com/ldc-developers/ldc/issues/3827)\n"); + return; + } } } From 4eda2f9eba44c862e719e3900dd636fcb18004a7 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Thu, 31 Aug 2023 11:44:40 +0200 Subject: [PATCH 157/176] druntime: Fix malloc-leaks in ModuleGroup.sortCtors() (dlang/dmd!15559) I guess the recent removal of module constructors in druntime has brought these to light, for a little LDC ASan smoke test, which newly complains with D v2.105, e.g.: > Direct leak of 78624 byte(s) in 126 object(s) allocated from: > #0 0x55606978c40d in malloc /local/mnt/workspace/tmp/final/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:145:3 > #1 0x5560698050b1 in _D2rt5minfo11ModuleGroup9sortCtorsMFNbAyaZv --- runtime/druntime/src/rt/minfo.d | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/runtime/druntime/src/rt/minfo.d b/runtime/druntime/src/rt/minfo.d index b5c868f70bc..9bc10558981 100644 --- a/runtime/druntime/src/rt/minfo.d +++ b/runtime/druntime/src/rt/minfo.d @@ -267,10 +267,16 @@ struct ModuleGroup edge[nEdges++] = *impidx; } } - // trim space to what is needed. - edges[i] = nEdges > 0 - ? (cast(int*)realloc(edge, int.sizeof * nEdges))[0 .. nEdges] - : null; + if (nEdges > 0) + { + // trim space to what is needed + edges[i] = (cast(int*)realloc(edge, int.sizeof * nEdges))[0 .. nEdges]; + } + else + { + edges[i] = null; + .free(edge); + } } } From cff6dbdfb3d473d1b4eb41a37c2401056fe5d53c Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Fri, 1 Sep 2023 14:54:17 +0200 Subject: [PATCH 158/176] Adapt lit-test plugins/visitor_example.d to new AST --- tests/plugins/visitor_example.d | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tests/plugins/visitor_example.d b/tests/plugins/visitor_example.d index ec8af7d2c90..022d5485a8a 100644 --- a/tests/plugins/visitor_example.d +++ b/tests/plugins/visitor_example.d @@ -17,13 +17,8 @@ extern(C++) class MyVisitor : SemanticTimeTransitiveVisitor { alias visit = SemanticTimeTransitiveVisitor.visit; override void visit(VarDeclaration vd) { - if (vd.aliasTuple) { - vd.aliasTuple.foreachVar((s) { - auto vardecl = s.isVarDeclaration(); - if (vardecl && vardecl.type.needsDestruction()) { - warning(vardecl.loc, "It works!"); - } - }); + if (vd.type.needsDestruction()) { + warning(vd.loc, "It works!"); } } } From 2b49d6611719fd23d34587cc22c613aa2c3b5f24 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Fri, 1 Sep 2023 16:13:18 +0200 Subject: [PATCH 159/176] dmd-testsuite: Properly disable tests on Win32 with `DISABLED: win32mscoff` --- tests/dmd/tools/d_do_test.d | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/dmd/tools/d_do_test.d b/tests/dmd/tools/d_do_test.d index 04ac9eae59f..100b6a3d816 100755 --- a/tests/dmd/tools/d_do_test.d +++ b/tests/dmd/tools/d_do_test.d @@ -528,7 +528,9 @@ private bool consumeNextToken(ref string file, const string token, ref const Env // be an OS (e.g. "linux") or a combination of OS + MODEL (e.g. "windows32"). // The latter is important on windows because m32 might require other // parameters than m32mscoff/m64. - if (!oss.canFind!(o => o.skipOver(envData.os) && (o.empty || o == envData.model))) + if (!oss.canFind!(o => o.skipOver(envData.os) && (o.empty || o == envData.model || + // LDC: we don't use the 32mscoff model, but 32 instead + (o == "32mscoff" && envData.model == "32")))) continue; // Parameter was skipped } } @@ -636,7 +638,7 @@ string getDisabledReason(string[] disabledPlatforms, const ref EnvData envData) // additionally support `DISABLED: LDC_[]` const j = disabledPlatforms.countUntil!(p => p.startsWith("LDC_") && target.canFind(p[4 .. $])); if (j != -1) - return "on " ~ disabledPlatforms[j]; + return "for LDC on " ~ disabledPlatforms[j]; } return null; From db9323d2aaf78c81eecacee905a1b98468072cf3 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Fri, 1 Sep 2023 16:20:41 +0200 Subject: [PATCH 160/176] ImportC: Support weird `asm("_" "")` mangling stuff (#4486) These are apparently used in the Mac system headers... Co-authored-by: Martin Kinkelin --- gen/mangling.cpp | 3 +++ tests/dmd/runnable/test23343.c | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/gen/mangling.cpp b/gen/mangling.cpp index b384a97ff03..7d35c1335fc 100644 --- a/gen/mangling.cpp +++ b/gen/mangling.cpp @@ -98,6 +98,9 @@ std::string hashSymbolName(llvm::StringRef name, Dsymbol *symb) { std::string getIRMangledName(FuncDeclaration *fdecl, LINK link) { std::string mangledName = mangleExact(fdecl); + if (fdecl->adFlags & 4) { // nounderscore + mangledName.insert(0, "\1"); + } // Hash the name if necessary if (((link == LINK::d) || (link == LINK::default_)) && diff --git a/tests/dmd/runnable/test23343.c b/tests/dmd/runnable/test23343.c index 20829d2d980..69004d61b82 100644 --- a/tests/dmd/runnable/test23343.c +++ b/tests/dmd/runnable/test23343.c @@ -1,6 +1,4 @@ -/* DISABLED: win32 win64 linux32 linux64 freebsd32 freebsd64 osx32 dragonflybsd32 netbsd32 LDC - * LDC: this was apparently hacked around in DMD, requiring the glue layer to - know about this ImportC special case and only apply it for Mac targets... +/* DISABLED: win32 win64 linux32 linux64 freebsd32 freebsd64 osx32 dragonflybsd32 netbsd32 */ /* https://issues.dlang.org/show_bug.cgi?id=23343 From 3a1f9f4ebf6700201e00e78734b4c7f591accab6 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Fri, 1 Sep 2023 18:21:01 +0200 Subject: [PATCH 161/176] [fix silly mistakes] --- runtime/druntime/test/exceptions/src/assert_fail.d | 10 +++++----- tests/dmd/tools/d_do_test.d | 8 +++++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/runtime/druntime/test/exceptions/src/assert_fail.d b/runtime/druntime/test/exceptions/src/assert_fail.d index cff9ab54711..4775a9872a0 100644 --- a/runtime/druntime/test/exceptions/src/assert_fail.d +++ b/runtime/druntime/test/exceptions/src/assert_fail.d @@ -502,6 +502,8 @@ void testOverlappingFields() test(a, b, "S3(, , 8) != S3(, , 8)"); } +version (LDC) version (OSX) version (AArch64) version = LDC_macOS_AArch64; + void testDestruction() { static class Test @@ -531,14 +533,12 @@ void testDestruction() { version (D_Optimized) {} else { - version (OSX) version (AArch64) version = macOS_AArch64; - version (linux) enum allowFailure = true; else version (FreeBSD) enum allowFailure = true; // started to fail on Win64 and macOS arm64 too with D v2.105 (apparently consistently) - else version (Win64) enum allowFailure = true; - else version (macOS_AArch64) enum allowFailure = true; - else enum allowFailure = false; + else version (Win64) enum allowFailure = true; + else version (LDC_macOS_AArch64) enum allowFailure = true; + else enum allowFailure = false; if (allowFailure && !Test.run) { diff --git a/tests/dmd/tools/d_do_test.d b/tests/dmd/tools/d_do_test.d index 100b6a3d816..79be3835aca 100755 --- a/tests/dmd/tools/d_do_test.d +++ b/tests/dmd/tools/d_do_test.d @@ -528,9 +528,7 @@ private bool consumeNextToken(ref string file, const string token, ref const Env // be an OS (e.g. "linux") or a combination of OS + MODEL (e.g. "windows32"). // The latter is important on windows because m32 might require other // parameters than m32mscoff/m64. - if (!oss.canFind!(o => o.skipOver(envData.os) && (o.empty || o == envData.model || - // LDC: we don't use the 32mscoff model, but 32 instead - (o == "32mscoff" && envData.model == "32")))) + if (!oss.canFind!(o => o.skipOver(envData.os) && (o.empty || o == envData.model))) continue; // Parameter was skipped } } @@ -639,6 +637,10 @@ string getDisabledReason(string[] disabledPlatforms, const ref EnvData envData) const j = disabledPlatforms.countUntil!(p => p.startsWith("LDC_") && target.canFind(p[4 .. $])); if (j != -1) return "for LDC on " ~ disabledPlatforms[j]; + + // we don't use the 32mscoff model, but 32 instead + if (target == "win32" && disabledPlatforms.canFind("win32mscoff")) + return "on win32mscoff"; } return null; From 16b3c7e49a1ddf455b7d9f5c451c0dff686d44e5 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Mon, 4 Sep 2023 11:18:20 +0200 Subject: [PATCH 162/176] ImportC: Fix `static` linkage (#4487) Fixes #4484. --- gen/tollvm.cpp | 55 +++++++++++++++++++--------------- tests/codegen/importc_static.i | 10 +++++++ tests/lit.site.cfg.in | 3 +- 3 files changed, 42 insertions(+), 26 deletions(-) create mode 100644 tests/codegen/importc_static.i diff --git a/gen/tollvm.cpp b/gen/tollvm.cpp index 4f039293dd4..031085f6f9b 100644 --- a/gen/tollvm.cpp +++ b/gen/tollvm.cpp @@ -227,32 +227,39 @@ LLValue *DtoDelegateEquals(EXP op, LLValue *lhs, LLValue *rhs) { //////////////////////////////////////////////////////////////////////////////// -LinkageWithCOMDAT DtoLinkage(Dsymbol *sym) { - LLGlobalValue::LinkageTypes linkage = LLGlobalValue::ExternalLinkage; - if (hasWeakUDA(sym)) { - linkage = LLGlobalValue::WeakAnyLinkage; - } else { - /* Function (incl. delegate) literals are emitted into each referencing - * compilation unit, so use internal linkage for all lambdas and all global - * variables they define. - * This makes sure these symbols don't accidentally collide when linking - * object files compiled by different compiler invocations (lambda mangles - * aren't stable - see https://issues.dlang.org/show_bug.cgi?id=23722). - */ - auto potentialLambda = sym; - if (auto vd = sym->isVarDeclaration()) { - if (vd->isDataseg()) - potentialLambda = vd->toParent2(); - } +namespace { +LLGlobalValue::LinkageTypes DtoLinkageOnly(Dsymbol *sym) { + if (hasWeakUDA(sym)) + return LLGlobalValue::WeakAnyLinkage; + + // static in ImportC translates to internal linkage + if (auto decl = sym->isDeclaration()) + if ((decl->storage_class & STCstatic) && decl->isCsymbol()) + return LLGlobalValue::InternalLinkage; + + /* Function (incl. delegate) literals are emitted into each referencing + * compilation unit, so use internal linkage for all lambdas and all global + * variables they define. + * This makes sure these symbols don't accidentally collide when linking + * object files compiled by different compiler invocations (lambda mangles + * aren't stable - see https://issues.dlang.org/show_bug.cgi?id=23722). + */ + auto potentialLambda = sym; + if (auto vd = sym->isVarDeclaration()) + if (vd->isDataseg()) + potentialLambda = vd->toParent2(); + if (potentialLambda->isFuncLiteralDeclaration()) + return LLGlobalValue::InternalLinkage; - if (potentialLambda->isFuncLiteralDeclaration()) { - linkage = LLGlobalValue::InternalLinkage; - } else if (sym->isInstantiated()) { - linkage = templateLinkage; - } - } + if (sym->isInstantiated()) + return templateLinkage; - return {linkage, needsCOMDAT()}; + return LLGlobalValue::ExternalLinkage; +} +} + +LinkageWithCOMDAT DtoLinkage(Dsymbol *sym) { + return {DtoLinkageOnly(sym), needsCOMDAT()}; } bool needsCOMDAT() { diff --git a/tests/codegen/importc_static.i b/tests/codegen/importc_static.i new file mode 100644 index 00000000000..b0e5183cfae --- /dev/null +++ b/tests/codegen/importc_static.i @@ -0,0 +1,10 @@ +// Makes sure static in ImportC translates to `internal` IR linkage. +// See https://github.com/ldc-developers/ldc/issues/4484. + +// RUN: %ldc -output-ll %s -of=%t.ll && FileCheck %s < %t.ll + +// CHECK: myPrivateGlobal = internal global i32 0 +static int myPrivateGlobal; + +// CHECK: define internal void {{.*}}myPrivateFunc +static void myPrivateFunc() {} diff --git a/tests/lit.site.cfg.in b/tests/lit.site.cfg.in index 5d8fdde37fd..90b81aa4600 100644 --- a/tests/lit.site.cfg.in +++ b/tests/lit.site.cfg.in @@ -45,8 +45,7 @@ config.test_format = lit.formats.ShTest(execute_external=False) # suffixes: A list of file extensions to treat as test files. This is overriden # by individual lit.local.cfg files in the test subdirectories. -config.suffixes = ['.d', - ] +config.suffixes = ['.d', '.i'] # excludes: A list of directories to exclude from the testsuite. The 'inputs' # subdirectories contain auxiliary inputs for various tests in their parent From 8d052b83e4b029172fe1a019f3ce22d5805b0af5 Mon Sep 17 00:00:00 2001 From: Razvan Nitu Date: Thu, 7 Sep 2023 14:49:55 +0300 Subject: [PATCH 163/176] Fix Issue 24109 - [REG2.103] 'need this' when invoking outer method from inner method (dlang/dmd!15577) --- dmd/expressionsem.d | 10 +++++----- tests/dmd/compilable/test24109.d | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 tests/dmd/compilable/test24109.d diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index 8e42a8bf901..ff50198293b 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -1190,6 +1190,11 @@ private bool haveSameThis(FuncDeclaration outerFunc, FuncDeclaration calledFunc) if (thisAd == requiredAd) return true; + // if outerfunc is the member of a nested aggregate, then let + // getRightThis take care of this. + if (thisAd.isNested()) + return true; + // outerfunc is the member of a base class that contains calledFunc, // then we consider that they have the same this. auto cd = requiredAd.isClassDeclaration(); @@ -1199,11 +1204,6 @@ private bool haveSameThis(FuncDeclaration outerFunc, FuncDeclaration calledFunc) if (cd.isBaseOf2(thisAd.isClassDeclaration())) return true; - // if outerfunc is the member of a nested aggregate, then let - // getRightThis take care of this. - if (thisAd.isNested()) - return true; - return false; } diff --git a/tests/dmd/compilable/test24109.d b/tests/dmd/compilable/test24109.d new file mode 100644 index 00000000000..67d03b58b06 --- /dev/null +++ b/tests/dmd/compilable/test24109.d @@ -0,0 +1,17 @@ +// https://issues.dlang.org/show_bug.cgi?id=24109 + +struct Outer +{ + void method1() {} + + void method2() + { + class Inner + { + void innerMethod() + { + method1(); + } + } + } +} From 17da9f2332d21a1c2485f334fc6b59f24de5aa3b Mon Sep 17 00:00:00 2001 From: Razvan Nitu Date: Thu, 7 Sep 2023 14:52:18 +0300 Subject: [PATCH 164/176] Fix Issue 24110 - [REG2.104] Array comparison lowering apparently not handled properly in __traits(compiles) (dlang/dmd!15575) --- dmd/expressionsem.d | 3 +-- tests/dmd/fail_compilation/test24110.d | 12 ++++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 tests/dmd/fail_compilation/test24110.d diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index ff50198293b..6c21b75dc22 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -12068,8 +12068,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - if (sc.needsCodegen() && - (t1.ty == Tarray || t1.ty == Tsarray) && + if ((t1.ty == Tarray || t1.ty == Tsarray) && (t2.ty == Tarray || t2.ty == Tsarray)) { if (!verifyHookExist(exp.loc, *sc, Id.__cmp, "comparing arrays")) diff --git a/tests/dmd/fail_compilation/test24110.d b/tests/dmd/fail_compilation/test24110.d new file mode 100644 index 00000000000..acf7788c6e0 --- /dev/null +++ b/tests/dmd/fail_compilation/test24110.d @@ -0,0 +1,12 @@ +// https://issues.dlang.org/show_bug.cgi?id=24110 + +/* +TEST_OUTPUT: +--- +fail_compilation/test24110.d(12): Error: static assert: `__traits(compiles, __error)` is false +--- +*/ + +struct S { int x; } +alias T = shared S; +static assert(__traits(compiles, (T[] a, T[] b) => a < b)); From 3424320f75be44693e544319322ded0461730ee1 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Mon, 11 Sep 2023 08:55:13 +0100 Subject: [PATCH 165/176] Fix Issue 24139 - 'this' corruption in extern(C++) dtor when destructing via TypeInfo_Struct (dlang/dmd!15598) For the `TypeInfo_Struct.xdtor` field, the linkage of the aggregate itself plays no role; it's the linkage of the destructor that matters. A real-life example for this is DMD's own `OutBuffer`. --- dmd/clone.d | 2 +- tests/dmd/runnable/test24139.d | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tests/dmd/runnable/test24139.d diff --git a/dmd/clone.d b/dmd/clone.d index 3586f20ddbe..319dcf4aabc 100644 --- a/dmd/clone.d +++ b/dmd/clone.d @@ -1126,7 +1126,7 @@ private DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc) return null; // Generate shim only when ABI incompatible on target platform - if (ad.classKind != ClassKind.cpp || !target.cpp.wrapDtorInExternD) + if (dtor._linkage != LINK.cpp || !target.cpp.wrapDtorInExternD) return dtor; // generate member function that adjusts calling convention diff --git a/tests/dmd/runnable/test24139.d b/tests/dmd/runnable/test24139.d new file mode 100644 index 00000000000..af6215dd2ac --- /dev/null +++ b/tests/dmd/runnable/test24139.d @@ -0,0 +1,25 @@ +// https://issues.dlang.org/show_bug.cgi?id=24139 + +struct S1 +{ + int x; + extern(C++) ~this() { assert(&this == s1); } +} + +extern(C++) struct S2 +{ + int x; + ~this() { assert(&this == s2); } +} + +S1* s1; +S2* s2; + +void main() +{ + s1 = new S1; + s2 = new S2; + + typeid(S1).destroy(s1); + typeid(S2).destroy(s2); +} From cdde52cb3748b1739ee39e419a1ac3bf43e04fc3 Mon Sep 17 00:00:00 2001 From: Razvan Nitu Date: Mon, 11 Sep 2023 14:28:57 +0300 Subject: [PATCH 166/176] Fix Issue 24118 - ICE / regression from 2.103.1 - segfault on CTFE only code in 2.104.2 and 2.105.0 (dlang/dmd!15578) --- dmd/expressionsem.d | 8 +++++--- tests/dmd/compilable/test24118.d | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 tests/dmd/compilable/test24118.d diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index 6c21b75dc22..c154cbf306a 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -11013,7 +11013,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor (exp.e2.isStringExp() && (exp.e1.isIntegerExp() || exp.e1.isStringExp()))) return exp; - Identifier hook = global.params.tracegc ? Id._d_arraycatnTXTrace : Id._d_arraycatnTX; + bool useTraceGCHook = global.params.tracegc && sc.needsCodegen(); + + Identifier hook = useTraceGCHook ? Id._d_arraycatnTXTrace : Id._d_arraycatnTX; if (!verifyHookExist(exp.loc, *sc, hook, "concatenating arrays")) { setError(); @@ -11042,7 +11044,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } auto arguments = new Expressions(); - if (global.params.tracegc) + if (useTraceGCHook) { auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); @@ -11069,7 +11071,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* `_d_arraycatnTX` canot be used with `-betterC`, but `CatExp`s may be * used with `-betterC`, but only during CTFE. */ - if (global.params.betterC || !sc.needsCodegen()) + if (global.params.betterC) return; if (auto ce = exp.isCatExp()) diff --git a/tests/dmd/compilable/test24118.d b/tests/dmd/compilable/test24118.d new file mode 100644 index 00000000000..25376b73b18 --- /dev/null +++ b/tests/dmd/compilable/test24118.d @@ -0,0 +1,15 @@ +// https://issues.dlang.org/show_bug.cgi?id=24118 + +void map(alias fun, T)(T[] arr) +{ + fun(arr); +} + + +void foo() +{ + if( __ctfe ) + { + ["a", "b", "c"].map!( a => " " ~ a[0] ); + } +} From 9bf2e2753692a8ea7f7b2134981bb92f15024d3c Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Mon, 11 Sep 2023 13:53:25 +0200 Subject: [PATCH 167/176] Packaging: Bump bundled dlang tools / dub / reggae --- packaging/dlang-tools_version | 2 +- packaging/dub_version | 2 +- packaging/reggae_version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packaging/dlang-tools_version b/packaging/dlang-tools_version index 9a0ba479e62..1f9b2b47b5f 100644 --- a/packaging/dlang-tools_version +++ b/packaging/dlang-tools_version @@ -1 +1 @@ -v2.104.2 \ No newline at end of file +v2.105.1 \ No newline at end of file diff --git a/packaging/dub_version b/packaging/dub_version index 3fdd57c402b..3d29685a1e2 100644 --- a/packaging/dub_version +++ b/packaging/dub_version @@ -1 +1 @@ -v1.33.1 \ No newline at end of file +v1.34.0 \ No newline at end of file diff --git a/packaging/reggae_version b/packaging/reggae_version index dafb90e96a6..f78dc36529a 100644 --- a/packaging/reggae_version +++ b/packaging/reggae_version @@ -1 +1 @@ -051e7d192155693d309cf09439e395bccb4292cf \ No newline at end of file +v0.10.0 \ No newline at end of file From 7ed24a633372a743c83e0a1e70465871334c7468 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Mon, 11 Sep 2023 13:55:36 +0200 Subject: [PATCH 168/176] [add changelog entry] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34cf2a2f368..1b9a4220a39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # LDC master #### Big news +- Frontend, druntime and Phobos are at version [2.105.1+](https://dlang.org/changelog/2.105.0.html). (#4476) #### Platform support From 0ba78f4dafb389f64c8fbc5d4fc43515cc199fd6 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Thu, 14 Sep 2023 12:39:49 +0100 Subject: [PATCH 169/176] Fix Issue 24144 - [REG2.105] Silent file name index overflow (dlang/dmd!15604) * Print an ICE message for Loc.filename overflows * Increase the Loc size again, raising the file name limit from 64K to 4G but keeping the index indirection from dlang/dmd!15199. The `Loc` size for DMD-as-a-library is 16 bytes then, and 12 bytes otherwise. --- dmd/frontend.h | 10 +++++----- dmd/globals.h | 4 ++-- dmd/location.d | 20 ++++++++++++++------ 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/dmd/frontend.h b/dmd/frontend.h index 7273739898d..4065afabce8 100644 --- a/dmd/frontend.h +++ b/dmd/frontend.h @@ -379,8 +379,8 @@ struct Loc final { private: uint32_t _linnum; - uint16_t _charnum; - uint16_t fileIndex; + uint32_t _charnum; + uint32_t fileIndex; public: static bool showColumns; static MessageStyle messageStyle; @@ -7019,9 +7019,9 @@ struct UnionExp final private: union __AnonStruct__u { - char exp[25LLU]; + char exp[29LLU]; char integerexp[40LLU]; - char errorexp[25LLU]; + char errorexp[29LLU]; char realexp[48LLU]; char complexexp[64LLU]; char symoffexp[64LLU]; @@ -7030,7 +7030,7 @@ struct UnionExp final char assocarrayliteralexp[48LLU]; char structliteralexp[76LLU]; char compoundliteralexp[40LLU]; - char nullexp[25LLU]; + char nullexp[29LLU]; char dotvarexp[49LLU]; char addrexp[40LLU]; char indexexp[74LLU]; diff --git a/dmd/globals.h b/dmd/globals.h index 93dc4db96df..fd5e04d3538 100644 --- a/dmd/globals.h +++ b/dmd/globals.h @@ -357,8 +357,8 @@ struct Loc { private: unsigned _linnum; - unsigned short _charnum; - unsigned short fileIndex; + unsigned _charnum; + unsigned fileIndex; public: static void set(bool showColumns, MessageStyle messageStyle); diff --git a/dmd/location.d b/dmd/location.d index b2b366130ca..6e69cc33933 100644 --- a/dmd/location.d +++ b/dmd/location.d @@ -38,8 +38,8 @@ debug info etc. struct Loc { private uint _linnum; - private ushort _charnum; - private ushort fileIndex; // index into filenames[], starting from 1 (0 means no filename) + private uint _charnum; + private uint fileIndex; // index into filenames[], starting from 1 (0 means no filename) version (LocOffset) uint fileOffset; /// utf8 code unit index relative to start of file, starting from 0 @@ -67,7 +67,7 @@ nothrow: extern (D) this(const(char)* filename, uint linnum, uint charnum) { this._linnum = linnum; - this._charnum = cast(ushort) charnum; + this._charnum = charnum; this.filename = filename; } @@ -80,7 +80,7 @@ nothrow: /// ditto extern (C++) uint charnum(uint num) @nogc @safe { - return _charnum = cast(ushort) num; + return _charnum = num; } /// line number, starting from 1 @@ -114,8 +114,16 @@ nothrow: { //printf("setting %s\n", name); filenames.push(name); - fileIndex = cast(ushort)filenames.length; - assert(fileIndex); // no overflow + fileIndex = cast(uint)filenames.length; + if (!fileIndex) + { + import dmd.globals : global; + import dmd.errors : error, fatal; + + global.gag = 0; // ensure error message gets printed + error(Loc.initial, "internal compiler error: file name index overflow!"); + fatal(); + } } else fileIndex = 0; From 04e1064037706af1a0eda01d1776d94e2d28112a Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Mon, 18 Sep 2023 15:40:13 +0100 Subject: [PATCH 170/176] Windows installer: Add option to add to *system* PATH in admin install mode (#4495) Resolves #4494. --- packaging/windows_installer.iss | 91 +++++++++++++++++++++++++++------ 1 file changed, 74 insertions(+), 17 deletions(-) diff --git a/packaging/windows_installer.iss b/packaging/windows_installer.iss index f685ef4a409..69f50fe1bcf 100644 --- a/packaging/windows_installer.iss +++ b/packaging/windows_installer.iss @@ -16,7 +16,7 @@ AppVerName=LDC {#LDCVersion} ArchitecturesAllowed=x64 ; Enable /CURRENTUSER cmdline option to install for current user only, requiring no admin privileges. ; This affects the default install dir (override with /DIR="x:\dirname") and the registry root key (HKCU, not HKLM). -PrivilegesRequiredOverridesAllowed=commandline +PrivilegesRequiredOverridesAllowed=dialog WizardStyle=modern DisableProgramGroupPage=yes DisableReadyPage=yes @@ -40,7 +40,8 @@ Name: lib32; Description: "x86 libraries"; Types: full [Run] ; note: not added to PATH for silent installs with /SILENT or /VERYSILENT -Filename: "{cmd}"; Parameters: "/c echo hello"; Check: not IsInEnvPath; BeforeInstall: AddToEnvPath; Description: "Add to PATH environment variable for current user"; Flags: postinstall skipifsilent runhidden nowait +Filename: "{cmd}"; Parameters: "/c echo hello"; Check: not IsInUserEnvPath; BeforeInstall: AddToUserEnvPath; Description: "Add to PATH environment variable for current user"; Flags: postinstall skipifsilent runhidden nowait +Filename: "{cmd}"; Parameters: "/c echo hello"; Check: IsAdminInstallMode and not IsInSystemEnvPath; BeforeInstall: AddToSystemEnvPath; Description: "Add to system PATH environment variable"; Flags: postinstall skipifsilent runhidden nowait unchecked Filename: "{app}\README.txt"; Description: "View the README file"; Flags: postinstall shellexec skipifdoesntexist skipifsilent unchecked [Registry] @@ -67,13 +68,16 @@ begin SendBroadcastNotifyMessage(WM_SETTINGCHANGE, 0, CastStringToInteger(Dummy)); end; -{ add the target bin dir to user PATH if not already present } -procedure AddToEnvPath(); + +{ add the target bin dir to PATH if not already present } +function AddToEnvPath(const RootKey: Integer; const SubKeyName: string): Boolean; var Path: string; Dir: string; begin - if not RegQueryStringValue(HKCU, 'Environment', 'Path', Path) then Path := ''; + result := False; + + if not RegQueryStringValue(RootKey, SubKeyName, 'Path', Path) then Path := ''; Dir := GetTargetBinDir(); @@ -83,21 +87,40 @@ begin { prepend `;` } Path := Dir + ';' + Path; - if RegWriteStringValue(HKCU, 'Environment', 'Path', Path) then + result := RegWriteStringValue(RootKey, SubKeyName, 'Path', Path); +end; + +{ add the target bin dir to user PATH if not already present } +procedure AddToUserEnvPath(); +begin + if AddToEnvPath(HKCU, 'Environment') then begin - Log(Format('Added to PATH: %s', [Path])); + Log(Format('Added to user PATH: %s', [GetTargetBinDir()])); RefreshEnvironment(); end; end; -{ remove the target bin dir from user PATH if present } -procedure RemoveFromEnvPath(); +{ add the target bin dir to system PATH if not already present } +procedure AddToSystemEnvPath(); +begin + if AddToEnvPath(HKLM, 'System\CurrentControlSet\Control\Session Manager\Environment') then + begin + Log(Format('Added to system PATH: %s', [GetTargetBinDir()])); + RefreshEnvironment(); + end; +end; + + +{ remove the target bin dir from PATH if present } +function RemoveFromEnvPath(const RootKey: Integer; const SubKeyName: string): Boolean; var Path: string; Dir: string; P: Integer; begin - if not RegQueryStringValue(HKCU, 'Environment', 'Path', Path) then exit; + result := False; + + if not RegQueryStringValue(RootKey, SubKeyName, 'Path', Path) then exit; Dir := GetTargetBinDir(); @@ -107,23 +130,53 @@ begin { remove `;` from Path } Delete(Path, P, Length(Dir) + 1); - if RegWriteStringValue(HKCU, 'Environment', 'Path', Path) then + result := RegWriteStringValue(RootKey, SubKeyName, 'Path', Path); +end; + +{ remove the target bin dir from user PATH if present } +procedure RemoveFromUserEnvPath(); +begin + if RemoveFromEnvPath(HKCU, 'Environment') then begin - Log(Format('Removed from PATH: %s', [Path])); + Log(Format('Removed from user PATH: %s', [GetTargetBinDir()])); RefreshEnvironment(); end; end; -{ check if the target bin dir is already in user PATH } -function IsInEnvPath(): Boolean; +{ remove the target bin dir from system PATH if present } +procedure RemoveFromSystemEnvPath(); +begin + if RemoveFromEnvPath(HKLM, 'System\CurrentControlSet\Control\Session Manager\Environment') then + begin + Log(Format('Removed from system PATH: %s', [GetTargetBinDir()])); + RefreshEnvironment(); + end; +end; + + +{ check if the target bin dir is already in PATH } +function IsInEnvPath(const RootKey: Integer; const SubKeyName: string): Boolean; var Path: string; begin result := False; - if RegQueryStringValue(HKCU, 'Environment', 'Path', Path) then + if RegQueryStringValue(RootKey, SubKeyName, 'Path', Path) then result := Pos(';' + Uppercase(GetTargetBinDir()) + ';', ';' + Uppercase(Path) + ';') > 0; end; +{ check if the target bin dir is already in user PATH } +function IsInUserEnvPath(): Boolean; +begin + result := IsInEnvPath(HKCU, 'Environment'); +end; + +{ check if the target bin dir is already in system PATH } +function IsInSystemEnvPath(): Boolean; +begin + result := IsInEnvPath(HKLM, 'System\CurrentControlSet\Control\Session Manager\Environment'); +end; + + { adapt 'Next' button label because of hidden ready page } procedure CurPageChanged(CurPageID: Integer); begin @@ -131,9 +184,13 @@ begin WizardForm.NextButton.Caption := SetupMessage(msgButtonInstall); end; -{ remove bin dir from user PATH at post-uninstall } +{ remove bin dir from user/system PATH at post-uninstall } procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); begin if (CurUninstallStep = usPostUninstall) then - RemoveFromEnvPath(); + begin + RemoveFromUserEnvPath(); + if IsAdminInstallMode then + RemoveFromSystemEnvPath(); + end; end; From e192ec9139f428912ad09cddd4cca55139f8fc53 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Fri, 22 Sep 2023 13:52:43 +0200 Subject: [PATCH 171/176] Bump frontend version & Phobos submodule and add changelog entries --- CHANGELOG.md | 7 ++++++- CMakeLists.txt | 2 +- packaging/dlang-tools_version | 2 +- runtime/phobos | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b9a4220a39..5f6b98cc34c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,16 @@ # LDC master #### Big news -- Frontend, druntime and Phobos are at version [2.105.1+](https://dlang.org/changelog/2.105.0.html). (#4476) +- Frontend, druntime and Phobos are at version [2.105.2](https://dlang.org/changelog/2.105.0.html). (#4476, #4498) +- The Windows installer now supports non-admin installs *without* an explicit `/CURRENTUSER` switch. (#4495) #### Platform support #### Bug fixes +- ImportC: + - Fix `static` linkage. (#4484, 4487) + - Make gcc builtins available. (#4483) + - Apple: Support weird `asm("_" "")` mangling stuff. (#4485, #4486) # LDC 1.34.0 (2023-08-26) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4866d43a54a..5c86891277d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,7 +120,7 @@ include(GetLinuxDistribution) set(LDC_VERSION "1.35.0") # May be overridden by git hash tag set(DMDFE_MAJOR_VERSION 2) set(DMDFE_MINOR_VERSION 105) -set(DMDFE_PATCH_VERSION 1) +set(DMDFE_PATCH_VERSION 2) set(DMD_VERSION ${DMDFE_MAJOR_VERSION}.${DMDFE_MINOR_VERSION}.${DMDFE_PATCH_VERSION}) diff --git a/packaging/dlang-tools_version b/packaging/dlang-tools_version index 1f9b2b47b5f..d7b23d710b0 100644 --- a/packaging/dlang-tools_version +++ b/packaging/dlang-tools_version @@ -1 +1 @@ -v2.105.1 \ No newline at end of file +v2.105.2 \ No newline at end of file diff --git a/runtime/phobos b/runtime/phobos index d7f31b03664..a4d814cf4de 160000 --- a/runtime/phobos +++ b/runtime/phobos @@ -1 +1 @@ -Subproject commit d7f31b036640670fc9f8364ad9a21d8be302f132 +Subproject commit a4d814cf4de1420fd4a976810c8ec15caf065498 From 5a158843b51b309bf13b764643d30431e3ea557e Mon Sep 17 00:00:00 2001 From: liushuyu Date: Sun, 24 Sep 2023 18:21:02 -0600 Subject: [PATCH 172/176] CI: upgrade GHA steps version ... (#4502) ... this can suppress some warnings during the GitHub Actions CI run --- .github/workflows/main.yml | 6 +++--- .github/workflows/supported_llvm_versions.yml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b4dcffd598b..cc0a078a64e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -193,7 +193,7 @@ jobs: env: MACOSX_DEPLOYMENT_TARGET: 11.0 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true fetch-depth: 50 @@ -252,7 +252,7 @@ jobs: - build-native - build-cross steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Merge x86_64 & arm64 packages to universal one uses: ./.github/actions/merge-macos @@ -262,7 +262,7 @@ jobs: timeout-minutes: 30 needs: build-native steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Merge x64 & x86 packages to multilib one & build installer uses: ./.github/actions/merge-windows diff --git a/.github/workflows/supported_llvm_versions.yml b/.github/workflows/supported_llvm_versions.yml index 475223b2cfa..e30290ccae6 100644 --- a/.github/workflows/supported_llvm_versions.yml +++ b/.github/workflows/supported_llvm_versions.yml @@ -48,7 +48,7 @@ jobs: env: MACOSX_DEPLOYMENT_TARGET: 11.6 # silence `ld: warning: object file (…) was built for newer macOS version (…) than being linked (…)` steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true fetch-depth: 50 @@ -75,7 +75,7 @@ jobs: sudo apt-get install gdb=9.1-0ubuntu1 llvm - name: Try to restore cached LLVM - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: llvm key: llvm-${{ matrix.llvm_version }}-${{ runner.os }} From a49db8e5d383094cb569057966689bf32ae599d5 Mon Sep 17 00:00:00 2001 From: liushuyu Date: Thu, 5 Oct 2023 04:36:01 -0600 Subject: [PATCH 173/176] Add initial support for LoongArch64 (#4500) --- dmd/cond.d | 4 ++ driver/main.cpp | 10 +++ driver/targetmachine.cpp | 54 +++++++++++++++ driver/tool.cpp | 7 +- gen/abi/abi.cpp | 4 ++ gen/abi/loongarch64.cpp | 73 +++++++++++++++++++++ gen/abi/targets.h | 2 +- gen/target.cpp | 4 ++ runtime/druntime/src/core/thread/osthread.d | 21 ++++++ tests/driver/loongarch64_abi.d | 11 ++++ 10 files changed, 188 insertions(+), 2 deletions(-) create mode 100644 gen/abi/loongarch64.cpp create mode 100644 tests/driver/loongarch64_abi.d diff --git a/dmd/cond.d b/dmd/cond.d index 467f9f1a990..8ce692e4905 100644 --- a/dmd/cond.d +++ b/dmd/cond.d @@ -728,6 +728,10 @@ extern (C++) final class VersionCondition : DVCondition case "SPARC_HardFloat": case "SPARC_SoftFloat": case "SPARC_V8Plus": + case "LoongArch32": + case "LoongArch64": + case "LoongArch_HardFloat": + case "LoongArch_SoftFloat": case "SystemZ": case "SysV3": case "SysV4": diff --git a/driver/main.cpp b/driver/main.cpp index da570b96ade..9e18b63ac02 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -765,6 +765,16 @@ void registerPredefinedTargetVersions() { case llvm::Triple::wasm64: VersionCondition::addPredefinedGlobalIdent("WebAssembly"); break; +#if LDC_LLVM_VER >= 1600 + case llvm::Triple::loongarch32: + VersionCondition::addPredefinedGlobalIdent("LoongArch32"); + registerPredefinedFloatABI("LoongArch_SoftFloat", "LoongArch_HardFloat"); + break; + case llvm::Triple::loongarch64: + VersionCondition::addPredefinedGlobalIdent("LoongArch64"); + registerPredefinedFloatABI("LoongArch_SoftFloat", "LoongArch_HardFloat"); + break; +#endif // LDC_LLVM_VER >= 1600 default: warning(Loc(), "unknown target CPU architecture: %s", triple.getArchName().str().c_str()); diff --git a/driver/targetmachine.cpp b/driver/targetmachine.cpp index b454fa2c8e1..2221c3ed616 100644 --- a/driver/targetmachine.cpp +++ b/driver/targetmachine.cpp @@ -117,6 +117,24 @@ const char *getABI(const llvm::Triple &triple, const llvm::SmallVectorImpl= 1600 + case llvm::Triple::loongarch32: + if (ABIName.startswith("ilp32s")) + return "ilp32s"; + if (ABIName.startswith("ilp32f")) + return "ilp32f"; + if (ABIName.startswith("ilp32d")) + return "ilp32d"; + break; + case llvm::Triple::loongarch64: + if (ABIName.startswith("lp64f")) + return "lp64f"; + if (ABIName.startswith("lp64d")) + return "lp64d"; + if (ABIName.startswith("lp64s")) + return "lp64s"; + break; +#endif // LDC_LLVM_VER >= 1600 default: break; } @@ -140,6 +158,20 @@ const char *getABI(const llvm::Triple &triple, const llvm::SmallVectorImpl= 1600 + case llvm::Triple::loongarch32: + if (isFeatureEnabled(features, "d")) + return "ilp32d"; + if (isFeatureEnabled(features, "f")) + return "ilp32f"; + return "ilp32s"; + case llvm::Triple::loongarch64: + if (isFeatureEnabled(features, "d")) + return "lp64d"; + if (isFeatureEnabled(features, "f")) + return "lp64f"; + return "lp64d"; +#endif // LDC_LLVM_VER >= 1600 default: return ""; } @@ -237,6 +269,14 @@ static std::string getRiscv64TargetCPU(const llvm::Triple &triple) { return "generic-rv64"; } +static std::string getLoongArch32TargetCPU(const llvm::Triple &triple) { + return "generic-la32"; +} + +static std::string getLoongArch64TargetCPU(const llvm::Triple &triple) { + return "generic-la64"; +} + /// Returns the LLVM name of the default CPU for the provided target triple. static std::string getTargetCPU(const llvm::Triple &triple) { switch (triple.getArch()) { @@ -258,6 +298,12 @@ static std::string getTargetCPU(const llvm::Triple &triple) { return getRiscv32TargetCPU(triple); case llvm::Triple::riscv64: return getRiscv64TargetCPU(triple); +#if LDC_LLVM_VER >= 1600 + case llvm::Triple::loongarch32: + return getLoongArch32TargetCPU(triple); + case llvm::Triple::loongarch64: + return getLoongArch64TargetCPU(triple); +#endif // LDC_LLVM_VER >= 1600 } } @@ -468,6 +514,14 @@ createTargetMachine(const std::string targetTriple, const std::string arch, } } + // For LoongArch 64-bit target default to la64 if nothing has been selected + // All current LoongArch targets have 64-bit floating point registers. +#if LDC_LLVM_VER >= 1600 + if (triple.getArch() == llvm::Triple::loongarch64 && features.empty()) { + features = {"+d"}; + } +#endif + // Handle cases where LLVM picks wrong default relocModel #if LDC_LLVM_VER >= 1600 if (relocModel.has_value()) {} diff --git a/driver/tool.cpp b/driver/tool.cpp index dea42d05a58..b072038c081 100644 --- a/driver/tool.cpp +++ b/driver/tool.cpp @@ -95,7 +95,12 @@ void appendTargetArgsForGcc(std::vector &args) { case Triple::nvptx64: args.push_back(triple.isArch64Bit() ? "-m64" : "-m32"); return; - +#if LDC_LLVM_VER >= 1600 + // LoongArch does not use -m32/-m64 and uses -mabi=. + case Triple::loongarch64: + args.emplace_back(triple.isArch64Bit() ? "-mabi=lp64d" : "-mabi=ilp32d"); + return; +#endif // LDC_LLVM_VER >= 1600 // MIPS does not have -m32/-m64 but requires -mabi=. case Triple::mips64: case Triple::mips64el: diff --git a/gen/abi/abi.cpp b/gen/abi/abi.cpp index 8abb49a18cb..a6523fff101 100644 --- a/gen/abi/abi.cpp +++ b/gen/abi/abi.cpp @@ -284,6 +284,10 @@ TargetABI *TargetABI::getTarget() { case llvm::Triple::thumb: case llvm::Triple::thumbeb: return getArmTargetABI(); +#if LDC_LLVM_VER >= 1600 + case llvm::Triple::loongarch64: + return getLoongArch64TargetABI(); +#endif // LDC_LLVM_VER >= 1600 default: Logger::cout() << "WARNING: Unknown ABI, guessing...\n"; return new UnknownTargetABI; diff --git a/gen/abi/loongarch64.cpp b/gen/abi/loongarch64.cpp new file mode 100644 index 00000000000..f0f2d853d59 --- /dev/null +++ b/gen/abi/loongarch64.cpp @@ -0,0 +1,73 @@ +//===-- gen/abi-loongarch64.cpp - LoongArch64 ABI description -----------*- C++ +//-*-===// +// +// LDC – the LLVM D compiler +// +// This file is distributed under the BSD-style LDC license. See the LICENSE +// file for details. +// +//===----------------------------------------------------------------------===// +// +// ABI spec: +// https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html +// +//===----------------------------------------------------------------------===// + +#include "gen/abi/abi.h" +#include "gen/abi/generic.h" +#include "gen/dvalue.h" +#include "gen/irstate.h" +#include "gen/llvmhelpers.h" +#include "gen/tollvm.h" + +struct LoongArch64TargetABI : TargetABI { +private: + IndirectByvalRewrite indirectByvalRewrite{}; + +public: + auto returnInArg(TypeFunction *tf, bool) -> bool override { + if (tf->isref()) { + return false; + } + Type *rt = tf->next->toBasetype(); + if (!isPOD(rt)) { + return true; + } + // pass by reference when > 2*GRLEN + return rt->size() > 16; + } + + auto passByVal(TypeFunction *, Type *t) -> bool override { + if (!isPOD(t)) { + return false; + } + return t->size() > 16; + } + + void rewriteFunctionType(IrFuncTy &fty) override { + if (!fty.ret->byref) { + rewriteArgument(fty, *fty.ret); + } + + for (auto arg : fty.args) { + if (!arg->byref) { + rewriteArgument(fty, *arg); + } + } + } + + void rewriteArgument(IrFuncTy &fty, IrFuncTyArg &arg) override { + if (arg.byref) { + return; + } + + if (!isPOD(arg.type)) { + // non-PODs should be passed in memory + indirectByvalRewrite.applyTo(arg); + return; + } + } +}; + +// The public getter for abi.cpp +TargetABI *getLoongArch64TargetABI() { return new LoongArch64TargetABI(); } diff --git a/gen/abi/targets.h b/gen/abi/targets.h index b08177be2e2..e913b657cad 100644 --- a/gen/abi/targets.h +++ b/gen/abi/targets.h @@ -37,4 +37,4 @@ TargetABI *getX86_64TargetABI(); TargetABI *getX86TargetABI(); - +TargetABI *getLoongArch64TargetABI(); diff --git a/gen/target.cpp b/gen/target.cpp index 6e2499bb1e6..cd54c01c5c9 100644 --- a/gen/target.cpp +++ b/gen/target.cpp @@ -59,6 +59,10 @@ llvm::Type *getRealType(const llvm::Triple &triple) { case Triple::riscv32: case Triple::riscv64: +#if LDC_LLVM_VER >= 1600 + case Triple::loongarch32: + case Triple::loongarch64: +#endif // LDC_LLVM_VER >= 1600 return LLType::getFP128Ty(ctx); default: diff --git a/runtime/druntime/src/core/thread/osthread.d b/runtime/druntime/src/core/thread/osthread.d index bc47c17e890..575aa584ca1 100644 --- a/runtime/druntime/src/core/thread/osthread.d +++ b/runtime/druntime/src/core/thread/osthread.d @@ -1595,6 +1595,27 @@ in (fn) }} asm pure nothrow @nogc { (store ~ " sp, %0") : "=m" (sp); } } + else version (LoongArch64) + { + // Callee-save registers, according to LoongArch Calling Convention + // https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html + size_t[18] regs = void; + static foreach (i; 0 .. 8) + {{ + enum int j = i; + // save $fs0 - $fs7 + asm pure nothrow @nogc { ( "fst.d $fs"~j.stringof~", %0") : "=m" (regs[i]); } + }} + static foreach (i; 0 .. 9) + {{ + enum int j = i; + // save $s0 - $s8 + asm pure nothrow @nogc { ( "st.d $s"~j.stringof~", %0") : "=m" (regs[i + 8]); } + }} + // save $fp (or $s9) and $sp + asm pure nothrow @nogc { ( "st.d $fp, %0") : "=m" (regs[17]); } + asm pure nothrow @nogc { ( "st.d $sp, %0") : "=m" (sp); } + } else { static assert(false, "Architecture not supported."); diff --git a/tests/driver/loongarch64_abi.d b/tests/driver/loongarch64_abi.d new file mode 100644 index 00000000000..599261d5390 --- /dev/null +++ b/tests/driver/loongarch64_abi.d @@ -0,0 +1,11 @@ +// REQUIRES: target_LoongArch + +// RUN: %ldc %s -mtriple=loongarch64-unknown-linux-gnu -mattr=+f,+d --gcc=echo > %t && FileCheck %s < %t +// CHECK: -mabi=lp64d + +version (LoongArch64) {} else static assert(0); +// the next line checks -mattr=+f,+d +version (LoongArch_HardFloat) {} else static assert(0); +version (D_HardFloat) {} else static assert(0); + +void main() {} From 9ef1df2832cab977e4a157a2e12423853f943e19 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Mon, 9 Oct 2023 17:08:58 +0100 Subject: [PATCH 174/176] Time trace: JSON-escape process name (#4507) As it's likely to contain backslashes on Windows (argv[0]). Fixes #4506. --- driver/timetrace.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/driver/timetrace.d b/driver/timetrace.d index a19c9a91b1d..5ed7cb798c3 100644 --- a/driver/timetrace.d +++ b/driver/timetrace.d @@ -289,12 +289,12 @@ struct TimeTraceProfiler // {"ph":"M","ts":0,"args":{"name":"bin/ldc2"},"name":"thread_name","pid":0,"tid":0}, buf.write(`{"ph":"M","ts":0,"args":{"name":"`); - buf.write(processName); + buf.writeEscapeJSONString(processName); buf.write(`"},"name":"process_name",`); buf.write(pidtid_string); buf.write("},\n"); buf.write(`{"ph":"M","ts":0,"args":{"name":"`); - buf.write(processName); + buf.writeEscapeJSONString(processName); buf.write(`"},"cat":"","name":"thread_name",`); buf.write(pidtid_string); buf.write("},\n"); From 6967dd472317bee5caee797a2a92c1e68414c7bd Mon Sep 17 00:00:00 2001 From: Johan Engelen Date: Tue, 10 Oct 2023 12:16:56 +0200 Subject: [PATCH 175/176] Unconditionally define m_allowMigration field in Fiber, fixes issue #4508 (#4509) --- runtime/druntime/src/core/thread/fiber.d | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/runtime/druntime/src/core/thread/fiber.d b/runtime/druntime/src/core/thread/fiber.d index 161e2ff766c..75ac0a2af5d 100644 --- a/runtime/druntime/src/core/thread/fiber.d +++ b/runtime/druntime/src/core/thread/fiber.d @@ -1160,17 +1160,20 @@ private: // Callable m_call; bool m_isRunning; + version (LDC) + { + // Unconditionally add this field, that is only used with version(CheckFiberMigration), + // such that version(SupportSanitizers) does not change the ABI. + // (what is needed is version(SupportSanitizers_ABI || CheckFiberMigration)) + // The field is positioned after another bool, using up alignment padding space. + bool m_allowMigration; + } Throwable m_unhandled; State m_state; // Set first time switchIn called to indicate this Fiber's Thread Thread m_curThread; - version (CheckFiberMigration) - { - bool m_allowMigration; - } - version (SjLj_Exceptions) { SjLjFuncContext* m_sjljExStackTop; From 60e45d619a00e32f79976c9e0047a7828d47c1ea Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Wed, 11 Oct 2023 18:10:40 +0900 Subject: [PATCH 176/176] Fix a regression in gc2stack optimization (#4511) --- gen/passes/GarbageCollect2Stack.cpp | 24 +++++++++++++----------- tests/codegen/gh4510.d | 13 +++++++++++++ 2 files changed, 26 insertions(+), 11 deletions(-) create mode 100644 tests/codegen/gh4510.d diff --git a/gen/passes/GarbageCollect2Stack.cpp b/gen/passes/GarbageCollect2Stack.cpp index af710b18f3e..cfc9cd46d85 100644 --- a/gen/passes/GarbageCollect2Stack.cpp +++ b/gen/passes/GarbageCollect2Stack.cpp @@ -161,16 +161,17 @@ bool ArrayFI::analyze(CallBase *CB, const G2StackAnalysis &A) { } Value* ArrayFI::promote(CallBase *CB, IRBuilder<> &B, const G2StackAnalysis &A) { + IRBuilder<> Builder(B.GetInsertBlock(), B.GetInsertPoint()); + // If the allocation is of constant size it's best to put it in the // entry block, so do so if we're not already there. // For dynamically-sized allocations it's best to avoid the overhead // of allocating them if possible, so leave those where they are. // While we're at it, update statistics too. - const IRBuilderBase::InsertPointGuard savedInsertPoint(B); if (isa(arrSize)) { BasicBlock &Entry = CB->getCaller()->getEntryBlock(); - if (B.GetInsertBlock() != &Entry) { - B.SetInsertPoint(&Entry, Entry.begin()); + if (Builder.GetInsertBlock() != &Entry) { + Builder.SetInsertPoint(&Entry, Entry.begin()); } NumGcToStack++; } else { @@ -178,26 +179,27 @@ Value* ArrayFI::promote(CallBase *CB, IRBuilder<> &B, const G2StackAnalysis &A) } // Convert array size to 32 bits if necessary - Value *count = B.CreateIntCast(arrSize, B.getInt32Ty(), false); + Value *count = Builder.CreateIntCast(arrSize, Builder.getInt32Ty(), false); AllocaInst *alloca = - B.CreateAlloca(Ty, count, ".nongc_mem"); // FIXME: align? + Builder.CreateAlloca(Ty, count, ".nongc_mem"); // FIXME: align? if (Initialized) { // For now, only zero-init is supported. uint64_t size = A.DL.getTypeStoreSize(Ty); Value *TypeSize = ConstantInt::get(arrSize->getType(), size); - // Use the original B to put initialization at the - // allocation site. + // The initialization must be put at the original source variable + // definition location, because it could be in a loop and because + // of lifetime start-end annotation. Value *Size = B.CreateMul(TypeSize, arrSize); EmitMemZero(B, alloca, Size, A); } if (ReturnType == ReturnType::Array) { Value *arrStruct = llvm::UndefValue::get(CB->getType()); - arrStruct = B.CreateInsertValue(arrStruct, arrSize, 0); + arrStruct = Builder.CreateInsertValue(arrStruct, arrSize, 0); Value *memPtr = - B.CreateBitCast(alloca, PointerType::getUnqual(B.getInt8Ty())); - arrStruct = B.CreateInsertValue(arrStruct, memPtr, 1); + Builder.CreateBitCast(alloca, PointerType::getUnqual(B.getInt8Ty())); + arrStruct = Builder.CreateInsertValue(arrStruct, memPtr, 1); return arrStruct; } @@ -406,7 +408,7 @@ bool GarbageCollect2Stack::run(Function &F, std::function get .Case("_d_allocclass", &AllocClass) .Case("_d_allocmemory", &AllocMemory) .Default(nullptr); - + // Ignore unknown calls. if (!info) { continue; diff --git a/tests/codegen/gh4510.d b/tests/codegen/gh4510.d new file mode 100644 index 00000000000..1e15df63dc6 --- /dev/null +++ b/tests/codegen/gh4510.d @@ -0,0 +1,13 @@ +// RUN: %ldc --O2 -run %s + +void main() +{ + int count; + foreach (i; 0..34) + { + auto flags = new bool[](1); + if (flags[0] == false) count++; + flags[] = true; + } + assert(count == 34); +}