Skip to content

Commit d1f5a7e

Browse files
muscarAlex Muscar
andauthored
Move some semantic functions from func.d to funcsem.d and typesem.d (dlang#16531)
Co-authored-by: Alex Muscar <[email protected]>
1 parent b0d277c commit d1f5a7e

File tree

5 files changed

+161
-162
lines changed

5 files changed

+161
-162
lines changed

compiler/src/dmd/frontend.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3814,7 +3814,6 @@ class FuncDeclaration : public Declaration
38143814
bool needsClosure();
38153815
bool checkClosure();
38163816
bool hasNestedFrameRefs();
3817-
static bool needsFensure(FuncDeclaration* fd);
38183817
ParameterList getParameterList();
38193818
static FuncDeclaration* genCfunc(Array<Parameter* >* fparams, Type* treturn, const char* name, StorageClass stc = 0);
38203819
static FuncDeclaration* genCfunc(Array<Parameter* >* fparams, Type* treturn, Identifier* id, StorageClass stc = 0);

compiler/src/dmd/func.d

Lines changed: 0 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,27 +1501,6 @@ extern (C++) class FuncDeclaration : Declaration
15011501
return false;
15021502
}
15031503

1504-
/****************************************************
1505-
* Determine whether an 'out' contract is declared inside
1506-
* the given function or any of its overrides.
1507-
* Params:
1508-
* fd = the function to search
1509-
* Returns:
1510-
* true found an 'out' contract
1511-
*/
1512-
static bool needsFensure(FuncDeclaration fd) @safe
1513-
{
1514-
if (fd.fensures)
1515-
return true;
1516-
1517-
foreach (fdv; fd.foverrides)
1518-
{
1519-
if (needsFensure(fdv))
1520-
return true;
1521-
}
1522-
return false;
1523-
}
1524-
15251504
/*********************************************
15261505
* Returns: the function's parameter list, and whether
15271506
* it is variadic or not.
@@ -1578,127 +1557,6 @@ extern (C++) class FuncDeclaration : Declaration
15781557
return fd;
15791558
}
15801559

1581-
/+
1582-
+ Checks the parameter and return types iff this is a `main` function.
1583-
+
1584-
+ The following signatures are allowed for a `D main`:
1585-
+ - Either no or a single parameter of type `string[]`
1586-
+ - Return type is either `void`, `int` or `noreturn`
1587-
+
1588-
+ The following signatures are standard C:
1589-
+ - `int main()`
1590-
+ - `int main(int, char**)`
1591-
+
1592-
+ This function accepts the following non-standard extensions:
1593-
+ - `char** envp` as a third parameter
1594-
+ - `void` / `noreturn` as return type
1595-
+
1596-
+ This function will issue errors for unexpected arguments / return types.
1597-
+/
1598-
extern (D) final void checkMain()
1599-
{
1600-
if (ident != Id.main || isMember() || isNested())
1601-
return; // Not a main function
1602-
1603-
TypeFunction tf = type.toTypeFunction();
1604-
1605-
Type retType = tf.nextOf();
1606-
if (!retType)
1607-
{
1608-
// auto main(), check after semantic
1609-
assert(this.inferRetType);
1610-
return;
1611-
}
1612-
1613-
/// Checks whether `t` is equivalent to `char**`
1614-
/// Ignores qualifiers and treats enums according to their base type
1615-
static bool isCharPtrPtr(Type t)
1616-
{
1617-
auto tp = t.toBasetype().isTypePointer();
1618-
if (!tp)
1619-
return false;
1620-
1621-
tp = tp.next.toBasetype().isTypePointer();
1622-
if (!tp)
1623-
return false;
1624-
1625-
return tp.next.toBasetype().ty == Tchar;
1626-
}
1627-
1628-
// Neither of these qualifiers is allowed because they affect the ABI
1629-
enum invalidSTC = STC.out_ | STC.ref_ | STC.lazy_;
1630-
1631-
const nparams = tf.parameterList.length;
1632-
bool argerr;
1633-
1634-
const linkage = resolvedLinkage();
1635-
if (linkage == LINK.d)
1636-
{
1637-
if (nparams == 1)
1638-
{
1639-
auto fparam0 = tf.parameterList[0];
1640-
auto t = fparam0.type.toBasetype();
1641-
if (t.ty != Tarray ||
1642-
t.nextOf().ty != Tarray ||
1643-
t.nextOf().nextOf().ty != Tchar ||
1644-
fparam0.storageClass & invalidSTC)
1645-
{
1646-
argerr = true;
1647-
}
1648-
}
1649-
1650-
if (tf.parameterList.varargs || nparams >= 2 || argerr)
1651-
.error(loc, "%s `%s` parameter list must be empty or accept one parameter of type `string[]`", kind, toPrettyChars);
1652-
}
1653-
1654-
else if (linkage == LINK.c)
1655-
{
1656-
if (nparams == 2 || nparams == 3)
1657-
{
1658-
// Argument count must be int
1659-
auto argCount = tf.parameterList[0];
1660-
argerr |= !!(argCount.storageClass & invalidSTC);
1661-
argerr |= argCount.type.toBasetype().ty != Tint32;
1662-
1663-
// Argument pointer must be char**
1664-
auto argPtr = tf.parameterList[1];
1665-
argerr |= !!(argPtr.storageClass & invalidSTC);
1666-
argerr |= !isCharPtrPtr(argPtr.type);
1667-
1668-
// `char** environ` is a common extension, see J.5.1 of the C standard
1669-
if (nparams == 3)
1670-
{
1671-
auto envPtr = tf.parameterList[2];
1672-
argerr |= !!(envPtr.storageClass & invalidSTC);
1673-
argerr |= !isCharPtrPtr(envPtr.type);
1674-
}
1675-
}
1676-
else
1677-
argerr = nparams != 0;
1678-
1679-
// Disallow variadic main() - except for K&R declarations in C files.
1680-
// E.g. int main(), int main(argc, argv) int argc, char** argc { ... }
1681-
if (tf.parameterList.varargs && (!this.isCsymbol() || (!tf.parameterList.hasIdentifierList && nparams)))
1682-
argerr |= true;
1683-
1684-
if (argerr)
1685-
{
1686-
.error(loc, "%s `%s` parameters must match one of the following signatures", kind, toPrettyChars);
1687-
loc.errorSupplemental("`main()`");
1688-
loc.errorSupplemental("`main(int argc, char** argv)`");
1689-
loc.errorSupplemental("`main(int argc, char** argv, char** environ)` [POSIX extension]");
1690-
}
1691-
}
1692-
else
1693-
return; // Neither C nor D main, ignore (should probably be an error)
1694-
1695-
// Allow enums with appropriate base types (same ABI)
1696-
retType = retType.toBasetype();
1697-
1698-
if (retType.ty != Tint32 && retType.ty != Tvoid && retType.ty != Tnoreturn)
1699-
.error(loc, "%s `%s` must return `int`, `void` or `noreturn`, not `%s`", kind, toPrettyChars, tf.nextOf().toChars());
1700-
}
1701-
17021560
/***********************************************
17031561
* Check all return statements for a function to verify that returning
17041562
* using NRVO is possible.
@@ -1960,23 +1818,6 @@ unittest
19601818
assert(mismatches.isMutable);
19611819
}
19621820

1963-
/**************************************
1964-
* Returns an indirect type one step from t.
1965-
*/
1966-
Type getIndirection(Type t)
1967-
{
1968-
t = t.baseElemOf();
1969-
if (t.ty == Tarray || t.ty == Tpointer)
1970-
return t.nextOf().toBasetype();
1971-
if (t.ty == Taarray || t.ty == Tclass)
1972-
return t;
1973-
if (t.ty == Tstruct)
1974-
return t.hasPointers() ? t : null; // TODO
1975-
1976-
// should consider TypeDelegate?
1977-
return null;
1978-
}
1979-
19801821
/**************************************
19811822
* Performs type-based alias analysis between a newly created value and a pre-
19821823
* existing memory reference:

compiler/src/dmd/funcsem.d

Lines changed: 143 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2602,6 +2602,27 @@ void buildEnsureRequire(FuncDeclaration thisfd)
26022602
}
26032603
}
26042604

2605+
/****************************************************
2606+
* Determine whether an 'out' contract is declared inside
2607+
* the given function or any of its overrides.
2608+
* Params:
2609+
* fd = the function to search
2610+
* Returns:
2611+
* true found an 'out' contract
2612+
*/
2613+
bool needsFensure(FuncDeclaration fd) @safe
2614+
{
2615+
if (fd.fensures)
2616+
return true;
2617+
2618+
foreach (fdv; fd.foverrides)
2619+
{
2620+
if (needsFensure(fdv))
2621+
return true;
2622+
}
2623+
return false;
2624+
}
2625+
26052626
/****************************************************
26062627
* Merge into this function the 'out' contracts of all it overrides.
26072628
* 'out's are AND'd together, i.e. all of them need to pass.
@@ -2624,7 +2645,7 @@ Statement mergeFensure(FuncDeclaration fd, Statement sf, Identifier oid, Express
26242645
* https://issues.dlang.org/show_bug.cgi?id=3602 and
26252646
* https://issues.dlang.org/show_bug.cgi?id=5230
26262647
*/
2627-
if (fd.needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done)
2648+
if (needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done)
26282649
{
26292650
assert(fdv._scope);
26302651
Scope* sc = fdv._scope.push();
@@ -2844,3 +2865,124 @@ bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)
28442865
return false;
28452866
}
28462867
}
2868+
2869+
/+
2870+
+ Checks the parameter and return types iff this is a `main` function.
2871+
+
2872+
+ The following signatures are allowed for a `D main`:
2873+
+ - Either no or a single parameter of type `string[]`
2874+
+ - Return type is either `void`, `int` or `noreturn`
2875+
+
2876+
+ The following signatures are standard C:
2877+
+ - `int main()`
2878+
+ - `int main(int, char**)`
2879+
+
2880+
+ This function accepts the following non-standard extensions:
2881+
+ - `char** envp` as a third parameter
2882+
+ - `void` / `noreturn` as return type
2883+
+
2884+
+ This function will issue errors for unexpected arguments / return types.
2885+
+/
2886+
extern (D) void checkMain(FuncDeclaration fd)
2887+
{
2888+
if (fd.ident != Id.main || fd.isMember() || fd.isNested())
2889+
return; // Not a main function
2890+
2891+
TypeFunction tf = fd.type.toTypeFunction();
2892+
2893+
Type retType = tf.nextOf();
2894+
if (!retType)
2895+
{
2896+
// auto main(), check after semantic
2897+
assert(fd.inferRetType);
2898+
return;
2899+
}
2900+
2901+
/// Checks whether `t` is equivalent to `char**`
2902+
/// Ignores qualifiers and treats enums according to their base type
2903+
static bool isCharPtrPtr(Type t)
2904+
{
2905+
auto tp = t.toBasetype().isTypePointer();
2906+
if (!tp)
2907+
return false;
2908+
2909+
tp = tp.next.toBasetype().isTypePointer();
2910+
if (!tp)
2911+
return false;
2912+
2913+
return tp.next.toBasetype().ty == Tchar;
2914+
}
2915+
2916+
// Neither of these qualifiers is allowed because they affect the ABI
2917+
enum invalidSTC = STC.out_ | STC.ref_ | STC.lazy_;
2918+
2919+
const nparams = tf.parameterList.length;
2920+
bool argerr;
2921+
2922+
const linkage = fd.resolvedLinkage();
2923+
if (linkage == LINK.d)
2924+
{
2925+
if (nparams == 1)
2926+
{
2927+
auto fparam0 = tf.parameterList[0];
2928+
auto t = fparam0.type.toBasetype();
2929+
if (t.ty != Tarray ||
2930+
t.nextOf().ty != Tarray ||
2931+
t.nextOf().nextOf().ty != Tchar ||
2932+
fparam0.storageClass & invalidSTC)
2933+
{
2934+
argerr = true;
2935+
}
2936+
}
2937+
2938+
if (tf.parameterList.varargs || nparams >= 2 || argerr)
2939+
.error(fd.loc, "%s `%s` parameter list must be empty or accept one parameter of type `string[]`", fd.kind, fd.toPrettyChars);
2940+
}
2941+
2942+
else if (linkage == LINK.c)
2943+
{
2944+
if (nparams == 2 || nparams == 3)
2945+
{
2946+
// Argument count must be int
2947+
auto argCount = tf.parameterList[0];
2948+
argerr |= !!(argCount.storageClass & invalidSTC);
2949+
argerr |= argCount.type.toBasetype().ty != Tint32;
2950+
2951+
// Argument pointer must be char**
2952+
auto argPtr = tf.parameterList[1];
2953+
argerr |= !!(argPtr.storageClass & invalidSTC);
2954+
argerr |= !isCharPtrPtr(argPtr.type);
2955+
2956+
// `char** environ` is a common extension, see J.5.1 of the C standard
2957+
if (nparams == 3)
2958+
{
2959+
auto envPtr = tf.parameterList[2];
2960+
argerr |= !!(envPtr.storageClass & invalidSTC);
2961+
argerr |= !isCharPtrPtr(envPtr.type);
2962+
}
2963+
}
2964+
else
2965+
argerr = nparams != 0;
2966+
2967+
// Disallow variadic main() - except for K&R declarations in C files.
2968+
// E.g. int main(), int main(argc, argv) int argc, char** argc { ... }
2969+
if (tf.parameterList.varargs && (!fd.isCsymbol() || (!tf.parameterList.hasIdentifierList && nparams)))
2970+
argerr |= true;
2971+
2972+
if (argerr)
2973+
{
2974+
.error(fd.loc, "%s `%s` parameters must match one of the following signatures", fd.kind, fd.toPrettyChars);
2975+
fd.loc.errorSupplemental("`main()`");
2976+
fd.loc.errorSupplemental("`main(int argc, char** argv)`");
2977+
fd.loc.errorSupplemental("`main(int argc, char** argv, char** environ)` [POSIX extension]");
2978+
}
2979+
}
2980+
else
2981+
return; // Neither C nor D main, ignore (should probably be an error)
2982+
2983+
// Allow enums with appropriate base types (same ABI)
2984+
retType = retType.toBasetype();
2985+
2986+
if (retType.ty != Tint32 && retType.ty != Tvoid && retType.ty != Tnoreturn)
2987+
.error(fd.loc, "%s `%s` must return `int`, `void` or `noreturn`, not `%s`", fd.kind, fd.toPrettyChars, tf.nextOf().toChars());
2988+
}

compiler/src/dmd/semantic3.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
314314
fds.checkInContractOverrides();
315315

316316
// Remember whether we need to generate an 'out' contract.
317-
immutable bool needEnsure = FuncDeclaration.needsFensure(funcdecl);
317+
immutable bool needEnsure = funcdecl.needsFensure();
318318

319319
if (funcdecl.fbody || funcdecl.frequires || needEnsure)
320320
{

compiler/src/dmd/typesem.d

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1282,6 +1282,23 @@ bool hasPointers(Type t)
12821282
}
12831283
}
12841284

1285+
/**************************************
1286+
* Returns an indirect type one step from t.
1287+
*/
1288+
Type getIndirection(Type t)
1289+
{
1290+
t = t.baseElemOf();
1291+
if (t.ty == Tarray || t.ty == Tpointer)
1292+
return t.nextOf().toBasetype();
1293+
if (t.ty == Taarray || t.ty == Tclass)
1294+
return t;
1295+
if (t.ty == Tstruct)
1296+
return t.hasPointers() ? t : null; // TODO
1297+
1298+
// should consider TypeDelegate?
1299+
return null;
1300+
}
1301+
12851302
/******************************************
12861303
* Perform semantic analysis on a type.
12871304
* Params:

0 commit comments

Comments
 (0)