diff options
Diffstat (limited to 'gcc/d/dmd/mtype.d')
-rw-r--r-- | gcc/d/dmd/mtype.d | 169 |
1 files changed, 69 insertions, 100 deletions
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index b2c7aa461ca..13df0d71f3f 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -4200,27 +4200,28 @@ extern (C++) final class TypeFunction : TypeNext // These flags can be accessed like `bool` properties, // getters and setters are generated for them - private enum FunctionFlag : uint - { - none = 0, - isnothrow = 0x0001, // nothrow - isnogc = 0x0002, // is @nogc - isproperty = 0x0004, // can be called without parentheses - isref = 0x0008, // returns a reference - isreturn = 0x0010, // 'this' is returned by ref - isScopeQual = 0x0020, // 'this' is scope - isreturninferred= 0x0040, // 'this' is return from inference - isscopeinferred = 0x0080, // 'this' is scope from inference - islive = 0x0100, // is @live - incomplete = 0x0200, // return type or default arguments removed - isInOutParam = 0x0400, // inout on the parameters - isInOutQual = 0x0800, // inout on the qualifier - isctor = 0x1000, // the function is a constructor - isreturnscope = 0x2000, // `this` is returned by value - } + private extern (D) static struct BitFields + { + bool isnothrow; /// nothrow + bool isnogc; /// is @nogc + bool isproperty; /// can be called without parentheses + bool isref; /// returns a reference + bool isreturn; /// 'this' is returned by ref + bool isScopeQual; /// 'this' is scope + bool isreturninferred; /// 'this' is return from inference + bool isscopeinferred; /// 'this' is scope from inference + bool islive; /// is @live + bool incomplete; /// return type or default arguments removed + bool isInOutParam; /// inout on the parameters + bool isInOutQual; /// inout on the qualifier + bool isctor; /// the function is a constructor + bool isreturnscope; /// `this` is returned by value + } + + import dmd.common.bitfields : generateBitFields; + mixin(generateBitFields!(BitFields, ushort)); LINK linkage; // calling convention - FunctionFlag funcFlags; TRUST trust; // level of trust PURE purity = PURE.impure; byte inuse; @@ -4359,29 +4360,6 @@ extern (C++) final class TypeFunction : TypeNext return linkage == LINK.d && parameterList.varargs == VarArg.variadic; } - /*************************** - * Examine function signature for parameter p and see if - * the value of p can 'escape' the scope of the function. - * This is useful to minimize the needed annotations for the parameters. - * Params: - * tthis = type of `this` parameter, null if none - * p = parameter to this function - * Returns: - * true if escapes via assignment to global or through a parameter - */ - bool parameterEscapes(Type tthis, Parameter p) - { - /* Scope parameters do not escape. - * Allow 'lazy' to imply 'scope' - - * lazy parameters can be passed along - * as lazy parameters to the next function, but that isn't - * escaping. - */ - if (parameterStorageClass(tthis, p) & (STC.scope_ | STC.lazy_)) - return false; - return true; - } - /************************************ * Take the specified storage class for p, * and use the function signature to infer whether @@ -4409,7 +4387,7 @@ extern (C++) final class TypeFunction : TypeNext /* If haven't inferred the return type yet, can't infer storage classes */ - if (!nextOf()) + if (!nextOf() || !isnothrow()) return stc; purityLevel(); @@ -4460,37 +4438,12 @@ extern (C++) final class TypeFunction : TypeNext } } - /* Inferring STC.return_ here has false positives - * for pure functions, producing spurious error messages - * about escaping references. - * Give up on it for now. - */ - version (none) - { - stc |= STC.scope_; - - Type tret = nextOf().toBasetype(); - if (isref || tret.hasPointers()) - { - /* The result has references, so p could be escaping - * that way. - */ - stc |= STC.return_; - } - } + // Check escaping through return value + Type tret = nextOf().toBasetype(); + if (isref || tret.hasPointers()) + return stc | STC.scope_ | STC.return_ | STC.returnScope; else - { - // Check escaping through return value - Type tret = nextOf().toBasetype(); - if (isref || tret.hasPointers() || !isnothrow()) - { - return stc; - } - - stc |= STC.scope_; - } - - return stc; + return stc | STC.scope_; } override Type addStorageClass(StorageClass stc) @@ -4684,6 +4637,16 @@ extern (C++) final class TypeFunction : TypeNext match = MATCH.convert; // match ... with a "conversion" match level } + // https://issues.dlang.org/show_bug.cgi?id=22997 + if (parameterList.varargs == VarArg.none && nparams > nargs && !parameterList[nargs].defaultArg) + { + OutBuffer buf; + buf.printf("too few arguments, expected `%d`, got `%d`", cast(int)nparams, cast(int)nargs); + if (pMessage) + *pMessage = buf.extractChars(); + goto Nomatch; + } + foreach (u, p; parameterList) { if (u == nargs) @@ -4780,14 +4743,40 @@ extern (C++) final class TypeFunction : TypeNext m = MATCH.exact; else { - m = MATCH.nomatch; if (pMessage) { + /* https://issues.dlang.org/show_bug.cgi?id=22202 + * + * If a function was deduced by semantic on the CallExp, + * it means that resolveFuncCall completed succesfully. + * Therefore, there exists a callable copy constructor, + * however, it cannot be called because scope constraints + * such as purity, safety or nogc. + */ OutBuffer buf; - buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies", - argStruct.toChars(), targ.toChars(), tprm.toChars()); + auto callExp = e.isCallExp(); + if (auto f = callExp.f) + { + char[] s; + if (!f.isPure && sc.func.setImpure()) + s ~= "pure "; + if (!f.isSafe() && !f.isTrusted() && sc.func.setUnsafe()) + s ~= "@safe "; + if (!f.isNogc && sc.func.setGC()) + s ~= "nogc "; + s[$-1] = '\0'; + buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr); + + } + else + { + buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies", + argStruct.toChars(), targ.toChars(), tprm.toChars()); + } + *pMessage = buf.extractChars(); } + m = MATCH.nomatch; goto Nomatch; } } @@ -5086,41 +5075,21 @@ extern (C++) final class TypeFunction : TypeNext return false; } - // Generate getter / setter functions for `FunctionFlag` members so they can be - // treated like regular `bool` fields, instead of requiring bit twiddling to read/write - extern (D) mixin(() { - string result = "extern(C++) pure nothrow @safe @nogc {"; - foreach (string mem; __traits(allMembers, FunctionFlag)) - { - result ~= " - /// set or get if the function has the FunctionFlag attribute of the same name - bool "~mem~"() const { return (funcFlags & FunctionFlag."~mem~") != 0; } - /// ditto - void "~mem~"(bool v) - { - if (v) funcFlags |= FunctionFlag."~mem~"; - else funcFlags &= ~FunctionFlag."~mem~"; - }"; - } - return result ~ "}\n"; - }()); /// Returns: `true` the function is `isInOutQual` or `isInOutParam` ,`false` otherwise. bool iswild() const pure nothrow @safe @nogc { - return (funcFlags & (FunctionFlag.isInOutParam | FunctionFlag.isInOutQual)) != 0; + return isInOutParam || isInOutQual; } /// Returns: whether `this` function type has the same attributes (`@safe`,...) as `other` bool attributesEqual(const scope TypeFunction other) const pure nothrow @safe @nogc { - enum attributes = FunctionFlag.isnothrow - | FunctionFlag.isnogc - | FunctionFlag.islive; - return this.trust == other.trust && this.purity == other.purity && - (this.funcFlags & attributes) == (other.funcFlags & attributes); + this.isnothrow == other.isnothrow && + this.isnogc == other.isnogc && + this.islive == other.islive; } override void accept(Visitor v) |