summaryrefslogtreecommitdiff
path: root/gcc/d/dmd/mtype.d
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/d/dmd/mtype.d')
-rw-r--r--gcc/d/dmd/mtype.d169
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)