diff --git a/changelog/changelog17425.dd b/changelog/changelog17425.dd new file mode 100644 index 000000000000..3f3430df58f5 --- /dev/null +++ b/changelog/changelog17425.dd @@ -0,0 +1,18 @@ +add __traits(getParameterStorageClasses, f, i) + +$(LINK2 https://issues.dlang.org/show_bug.cgi?id=17425, Bugzilla 17425) + +--- +ref int foo(return ref const int* p, scope int* a, out int b, lazy int c); + +pragma(msg, __traits(getParameterStorageClasses, foo, 0)); + +static assert(__traits(getParameterStorageClasses, foo, 0)[0] == "return"); +static assert(__traits(getParameterStorageClasses, foo, 0)[1] == "ref"); + +pragma(msg, __traits(getParameterStorageClasses, foo, 1)); +static assert(__traits(getParameterStorageClasses, foo, 1)[0] == "scope"); +static assert(__traits(getParameterStorageClasses, foo, 2)[0] == "out"); +static assert(__traits(getParameterStorageClasses, typeof(&foo), 3)[0] == "lazy"); +--- + diff --git a/src/ddmd/idgen.d b/src/ddmd/idgen.d index 607d3480bb77..7f1c29a95f9b 100644 --- a/src/ddmd/idgen.d +++ b/src/ddmd/idgen.d @@ -357,6 +357,7 @@ Msgtable[] msgtable = { "getAttributes" }, { "getFunctionAttributes" }, { "getFunctionVariadicStyle" }, + { "getParameterStorageClasses" }, { "getLinkage" }, { "getUnitTests" }, { "getVirtualIndex" }, diff --git a/src/ddmd/traits.d b/src/ddmd/traits.d index e9a54b75b18b..41aac11bc097 100644 --- a/src/ddmd/traits.d +++ b/src/ddmd/traits.d @@ -97,6 +97,7 @@ static this() "getAttributes", "getFunctionAttributes", "getFunctionVariadicStyle", + "getParameterStorageClasses", "getUnitTests", "getVirtualIndex", "getPointerBitmap", @@ -968,6 +969,109 @@ extern (C++) Expression semanticTraits(TraitsExp e, Scope* sc) auto se = new StringExp(e.loc, cast(char*)style); return se.semantic(sc); } + if (e.ident == Id.getParameterStorageClasses) + { + /* Accept a function symbol or a type, followed by a parameter index. + * Returns a tuple of strings of the parameter's storage classes. + */ + // get symbol linkage as a string + if (dim != 2) + return dimError(2); + + auto o1 = (*e.args)[1]; + auto o = (*e.args)[0]; + auto t = isType(o); + TypeFunction tf = null; + if (t) + { + if (t.ty == Tfunction) + tf = cast(TypeFunction)t; + else if (t.ty == Tdelegate) + tf = cast(TypeFunction)t.nextOf(); + else if (t.ty == Tpointer && t.nextOf().ty == Tfunction) + tf = cast(TypeFunction)t.nextOf(); + } + Parameters* fparams; + if (tf) + { + fparams = tf.parameters; + } + else + { + auto s = getDsymbol(o); + FuncDeclaration fd; + if (!s || (fd = s.isFuncDeclaration()) is null) + { + e.error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function", + o.toChars(), o1.toChars()); + return new ErrorExp(); + } + fparams = fd.getParameters(null); + } + + StorageClass stc; + + // Set stc to storage class of the ith parameter + auto ex = isExpression((*e.args)[1]); + if (!ex) + { + e.error("expression expected as second argument of `__traits(getParameterStorageClasses, %s, %s)`", + o.toChars(), o1.toChars()); + return new ErrorExp(); + } + ex = ex.ctfeInterpret(); + auto ii = ex.toUInteger(); + if (ii >= fparams.dim) + { + e.error("parameter index must be in range 0..%u not %s", cast(uint)fparams.dim, ex.toChars()); + return new ErrorExp(); + } + + uint n = cast(uint)ii; + Parameter p = Parameter.getNth(fparams, n); + stc = p.storageClass; + + // This mirrors hdrgen.visit(Parameter p) + if (p.type && p.type.mod & MODshared) + stc &= ~STCshared; + + auto exps = new Expressions; + + void push(string s) + { + exps.push(new StringExp(e.loc, cast(char*)s.ptr, cast(uint)s.length)); + } + + if (stc & STCauto) + push("auto"); + if (stc & STCreturn) + push("return"); + + if (stc & STCout) + push("out"); + else if (stc & STCref) + push("ref"); + else if (stc & STCin) + push("in"); + else if (stc & STClazy) + push("lazy"); + else if (stc & STCalias) + push("alias"); + + if (stc & STCconst) + push("const"); + if (stc & STCimmutable) + push("immutable"); + if (stc & STCwild) + push("inout"); + if (stc & STCshared) + push("shared"); + if (stc & STCscope) + push("scope"); + + auto tup = new TupleExp(e.loc, exps); + return tup.semantic(sc); + } if (e.ident == Id.getLinkage) { // get symbol linkage as a string diff --git a/test/fail_compilation/test17425.d b/test/fail_compilation/test17425.d new file mode 100644 index 000000000000..f7628b83e22b --- /dev/null +++ b/test/fail_compilation/test17425.d @@ -0,0 +1,32 @@ +/* TEST_OUTPUT: +--- +fail_compilation/test17425.d(24): Error: parameter index must be in range 0..4 not 4 +fail_compilation/test17425.d(27): Error: first argument to `__traits(getParameterStorageClasses, i, 4)` is not a function +fail_compilation/test17425.d(29): Error: expression expected as second argument of `__traits(getParameterStorageClasses, foo, int)` +fail_compilation/test17425.d(31): Error: expected 2 arguments for `getParameterStorageClasses` but had 3 +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=17425 + +ref int foo(return ref const int* p, scope int* a, out int b, lazy int c); + +//pragma(msg, __traits(getParameterStorageClasses, foo, 0)); + +static assert(__traits(getParameterStorageClasses, foo, 0)[0] == "return"); +static assert(__traits(getParameterStorageClasses, foo, 0)[1] == "ref"); + +//pragma(msg, __traits(getParameterStorageClasses, foo, 1)); +static assert(__traits(getParameterStorageClasses, foo, 1)[0] == "scope"); +static assert(__traits(getParameterStorageClasses, foo, 2)[0] == "out"); +static assert(__traits(getParameterStorageClasses, typeof(&foo), 3)[0] == "lazy"); + +enum a1 = __traits(getParameterStorageClasses, foo, 4); + +int i; +enum a2 = __traits(getParameterStorageClasses, i, 4); + +enum a3 = __traits(getParameterStorageClasses, foo, int); + +enum a4 = __traits(getParameterStorageClasses, foo, 0, 1); +