mirror of
https://github.com/dlang/dmd.git
synced 2025-04-25 20:50:41 +03:00
[NFC] outline class function semantic analysis out of funcDeclarationSemantic
(#21182)
This closes over several `goto`s whose target labels are now contained completely within the outlined code.
This commit is contained in:
parent
493cd034a9
commit
5fdf5f3c68
1 changed files with 579 additions and 560 deletions
|
@ -283,20 +283,6 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
|
|||
if (!funcdecl.originalType)
|
||||
funcdecl.originalType = funcdecl.type.syntaxCopy();
|
||||
|
||||
static TypeFunction getFunctionType(FuncDeclaration fd)
|
||||
{
|
||||
if (auto tf = fd.type.isTypeFunction())
|
||||
return tf;
|
||||
|
||||
if (!fd.type.isTypeError())
|
||||
{
|
||||
.error(fd.loc, "%s `%s` `%s` must be a function instead of `%s`", fd.kind, fd.toPrettyChars, fd.toChars(), fd.type.toChars());
|
||||
fd.type = Type.terror;
|
||||
}
|
||||
fd.errors = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (sc.inCfile)
|
||||
{
|
||||
/* C11 allows a function to be declared with a typedef, D does not.
|
||||
|
@ -573,11 +559,140 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
|
|||
|
||||
if (ClassDeclaration cd = parent.isClassDeclaration())
|
||||
{
|
||||
switch (classFuncSemantic(cd, funcdecl, parent, sc, f))
|
||||
{
|
||||
case 0: break;
|
||||
case 1: goto Ldone;
|
||||
case 2: return;
|
||||
default: assert(0);
|
||||
}
|
||||
}
|
||||
else if (funcdecl.isOverride() && !parent.isTemplateInstance())
|
||||
.error(funcdecl.loc, "%s `%s` `override` only applies to class member functions", funcdecl.kind, funcdecl.toPrettyChars);
|
||||
|
||||
if (auto ti = parent.isTemplateInstance)
|
||||
{
|
||||
objc.setSelector(funcdecl, sc);
|
||||
objc.setAsOptional(funcdecl, sc);
|
||||
}
|
||||
|
||||
objc.validateSelector(funcdecl);
|
||||
objc.validateOptional(funcdecl);
|
||||
// Reflect this.type to f because it could be changed by findVtblIndex
|
||||
f = funcdecl.type.toTypeFunction();
|
||||
|
||||
Ldone:
|
||||
if (!funcdecl.fbody && !funcdecl.allowsContractWithoutBody())
|
||||
.error(funcdecl.loc, "%s `%s` `in` and `out` contracts can only appear without a body when they are virtual interface functions or abstract", funcdecl.kind, funcdecl.toPrettyChars);
|
||||
|
||||
/* Do not allow template instances to add virtual functions
|
||||
* to a class.
|
||||
*/
|
||||
if (funcdecl.isVirtual())
|
||||
{
|
||||
if (auto ti = parent.isTemplateInstance())
|
||||
{
|
||||
// Take care of nested templates
|
||||
while (1)
|
||||
{
|
||||
TemplateInstance ti2 = ti.tempdecl.parent.isTemplateInstance();
|
||||
if (!ti2)
|
||||
break;
|
||||
ti = ti2;
|
||||
}
|
||||
|
||||
// If it's a member template
|
||||
if (ClassDeclaration cd = ti.tempdecl.isClassMember())
|
||||
{
|
||||
.error(funcdecl.loc, "%s `%s` cannot use template to add virtual function to class `%s`", funcdecl.kind, funcdecl.toPrettyChars, cd.toChars());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
funcdecl.checkMain(); // Check main() parameters and return type
|
||||
|
||||
/* Purity and safety can be inferred for some functions by examining
|
||||
* the function body.
|
||||
*/
|
||||
if (funcdecl.canInferAttributes(sc))
|
||||
funcdecl.initInferAttributes();
|
||||
|
||||
funcdecl.semanticRun = PASS.semanticdone;
|
||||
|
||||
/* Save scope for possible later use (if we need the
|
||||
* function internals)
|
||||
*/
|
||||
funcdecl._scope = sc.copy();
|
||||
funcdecl._scope.setNoFree();
|
||||
|
||||
__gshared bool printedMain = false; // semantic might run more than once
|
||||
if (global.params.v.verbose && !printedMain)
|
||||
{
|
||||
const(char)* type = funcdecl.isMain() ? "main" : funcdecl.isWinMain() ? "winmain" : funcdecl.isDllMain() ? "dllmain" : cast(const(char)*)null;
|
||||
Module mod = sc._module;
|
||||
|
||||
if (type && mod)
|
||||
{
|
||||
printedMain = true;
|
||||
auto name = mod.srcfile.toChars();
|
||||
auto path = FileName.searchPath(global.importPaths, name, true);
|
||||
message("entry %-10s\t%s", type, path ? path : name);
|
||||
}
|
||||
}
|
||||
|
||||
if (funcdecl.fbody && sc._module.isRoot() &&
|
||||
(funcdecl.isMain() || funcdecl.isWinMain() || funcdecl.isDllMain() || funcdecl.isCMain()))
|
||||
global.hasMainFunction = true;
|
||||
|
||||
if (funcdecl.fbody && funcdecl.isMain() && sc._module.isRoot())
|
||||
{
|
||||
// check if `_d_cmain` is defined
|
||||
bool cmainTemplateExists()
|
||||
{
|
||||
Dsymbol pscopesym;
|
||||
auto rootSymbol = sc.search(funcdecl.loc, Id.empty, pscopesym);
|
||||
if (auto moduleSymbol = rootSymbol.search(funcdecl.loc, Id.object))
|
||||
if (moduleSymbol.search(funcdecl.loc, Id.CMain))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only mixin `_d_cmain` if it is defined
|
||||
if (cmainTemplateExists())
|
||||
{
|
||||
// add `mixin _d_cmain!();` to the declaring module
|
||||
auto tqual = new TypeIdentifier(funcdecl.loc, Id.CMain);
|
||||
auto tm = new TemplateMixin(funcdecl.loc, null, tqual, null);
|
||||
sc._module.members.push(tm);
|
||||
}
|
||||
}
|
||||
|
||||
assert(funcdecl.type.ty != Terror || funcdecl.errors);
|
||||
|
||||
// semantic for parameters' UDAs
|
||||
foreach (i, param; f.parameterList)
|
||||
{
|
||||
if (param && param.userAttribDecl)
|
||||
param.userAttribDecl.dsymbolSemantic(sc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns:
|
||||
0 if semantic analysis in `funcDeclarationSemantic` should continue as normal
|
||||
1 if it should skip over some analysis and `goto Ldone;`
|
||||
2 if `funcDeclarationSemantic` should return early because of forward refernce error or
|
||||
the derived class cd doesn't have its vtbl[] allocated yet
|
||||
*/
|
||||
private int classFuncSemantic(ClassDeclaration cd, FuncDeclaration funcdecl,
|
||||
ref Dsymbol parent, Scope* sc, TypeFunction f)
|
||||
{
|
||||
parent = cd = objc.getParent(funcdecl, cd);
|
||||
|
||||
if (funcdecl.isCtorDeclaration())
|
||||
{
|
||||
goto Ldone;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (funcdecl.storage_class & STC.abstract_)
|
||||
|
@ -587,11 +702,11 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
|
|||
if (!funcdecl.isVirtual())
|
||||
{
|
||||
//printf("\tnot virtual\n");
|
||||
goto Ldone;
|
||||
return 1;
|
||||
}
|
||||
// Suppress further errors if the return type is an error
|
||||
if (funcdecl.type.nextOf() == Type.terror)
|
||||
goto Ldone;
|
||||
return 1;
|
||||
|
||||
bool may_override = false;
|
||||
for (size_t i = 0; i < cd.baseclasses.length; i++)
|
||||
|
@ -608,7 +723,7 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
|
|||
if (cbd.parent && cbd.parent.isTemplateInstance())
|
||||
{
|
||||
if (!functionSemantic(f2))
|
||||
goto Ldone;
|
||||
return 1;
|
||||
}
|
||||
may_override = true;
|
||||
}
|
||||
|
@ -727,7 +842,7 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
|
|||
case -2:
|
||||
// can't determine because of forward references
|
||||
funcdecl.errors = true;
|
||||
return;
|
||||
return 2;
|
||||
|
||||
default:
|
||||
{
|
||||
|
@ -738,7 +853,7 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
|
|||
*/
|
||||
.error(funcdecl.loc, "%s `%s` circular reference to class `%s`", funcdecl.kind, funcdecl.toPrettyChars, cd.toChars());
|
||||
funcdecl.errors = true;
|
||||
return;
|
||||
return 2;
|
||||
}
|
||||
FuncDeclaration fdv = cd.baseClass.vtbl[vi].isFuncDeclaration();
|
||||
FuncDeclaration fdc = cd.vtbl[vi].isFuncDeclaration();
|
||||
|
@ -882,7 +997,7 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
|
|||
* If this function is covariant with any members of those interface
|
||||
* functions, set the tintro.
|
||||
*/
|
||||
Linterfaces:
|
||||
Linterfaces:
|
||||
bool foundVtblMatch = false;
|
||||
|
||||
for (ClassDeclaration bcd = cd; !foundVtblMatch && bcd; bcd = bcd.baseClass)
|
||||
|
@ -898,7 +1013,7 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
|
|||
case -2:
|
||||
// can't determine because of forward references
|
||||
funcdecl.errors = true;
|
||||
return;
|
||||
return 2;
|
||||
|
||||
default:
|
||||
{
|
||||
|
@ -1083,7 +1198,7 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
|
|||
.error(funcdecl.loc, "%s `%s` does not override any function", funcdecl.kind, funcdecl.toPrettyChars);
|
||||
}
|
||||
|
||||
L2:
|
||||
L2:
|
||||
objc.setSelector(funcdecl, sc);
|
||||
objc.checkLinkage(funcdecl);
|
||||
objc.addToClassMethodList(funcdecl, cd);
|
||||
|
@ -1120,117 +1235,21 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
|
|||
"`%s` cannot be marked as `deprecated` because it is overriding a function in the base class",
|
||||
funcdecl.toPrettyChars);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
else if (funcdecl.isOverride() && !parent.isTemplateInstance())
|
||||
.error(funcdecl.loc, "%s `%s` `override` only applies to class member functions", funcdecl.kind, funcdecl.toPrettyChars);
|
||||
private TypeFunction getFunctionType(FuncDeclaration fd)
|
||||
{
|
||||
if (auto tf = fd.type.isTypeFunction())
|
||||
return tf;
|
||||
|
||||
if (auto ti = parent.isTemplateInstance)
|
||||
if (!fd.type.isTypeError())
|
||||
{
|
||||
objc.setSelector(funcdecl, sc);
|
||||
objc.setAsOptional(funcdecl, sc);
|
||||
}
|
||||
|
||||
objc.validateSelector(funcdecl);
|
||||
objc.validateOptional(funcdecl);
|
||||
// Reflect this.type to f because it could be changed by findVtblIndex
|
||||
f = funcdecl.type.toTypeFunction();
|
||||
|
||||
Ldone:
|
||||
if (!funcdecl.fbody && !funcdecl.allowsContractWithoutBody())
|
||||
.error(funcdecl.loc, "%s `%s` `in` and `out` contracts can only appear without a body when they are virtual interface functions or abstract", funcdecl.kind, funcdecl.toPrettyChars);
|
||||
|
||||
/* Do not allow template instances to add virtual functions
|
||||
* to a class.
|
||||
*/
|
||||
if (funcdecl.isVirtual())
|
||||
{
|
||||
if (auto ti = parent.isTemplateInstance())
|
||||
{
|
||||
// Take care of nested templates
|
||||
while (1)
|
||||
{
|
||||
TemplateInstance ti2 = ti.tempdecl.parent.isTemplateInstance();
|
||||
if (!ti2)
|
||||
break;
|
||||
ti = ti2;
|
||||
}
|
||||
|
||||
// If it's a member template
|
||||
if (ClassDeclaration cd = ti.tempdecl.isClassMember())
|
||||
{
|
||||
.error(funcdecl.loc, "%s `%s` cannot use template to add virtual function to class `%s`", funcdecl.kind, funcdecl.toPrettyChars, cd.toChars());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
funcdecl.checkMain(); // Check main() parameters and return type
|
||||
|
||||
/* Purity and safety can be inferred for some functions by examining
|
||||
* the function body.
|
||||
*/
|
||||
if (funcdecl.canInferAttributes(sc))
|
||||
funcdecl.initInferAttributes();
|
||||
|
||||
funcdecl.semanticRun = PASS.semanticdone;
|
||||
|
||||
/* Save scope for possible later use (if we need the
|
||||
* function internals)
|
||||
*/
|
||||
funcdecl._scope = sc.copy();
|
||||
funcdecl._scope.setNoFree();
|
||||
|
||||
__gshared bool printedMain = false; // semantic might run more than once
|
||||
if (global.params.v.verbose && !printedMain)
|
||||
{
|
||||
const(char)* type = funcdecl.isMain() ? "main" : funcdecl.isWinMain() ? "winmain" : funcdecl.isDllMain() ? "dllmain" : cast(const(char)*)null;
|
||||
Module mod = sc._module;
|
||||
|
||||
if (type && mod)
|
||||
{
|
||||
printedMain = true;
|
||||
auto name = mod.srcfile.toChars();
|
||||
auto path = FileName.searchPath(global.importPaths, name, true);
|
||||
message("entry %-10s\t%s", type, path ? path : name);
|
||||
}
|
||||
}
|
||||
|
||||
if (funcdecl.fbody && sc._module.isRoot() &&
|
||||
(funcdecl.isMain() || funcdecl.isWinMain() || funcdecl.isDllMain() || funcdecl.isCMain()))
|
||||
global.hasMainFunction = true;
|
||||
|
||||
if (funcdecl.fbody && funcdecl.isMain() && sc._module.isRoot())
|
||||
{
|
||||
// check if `_d_cmain` is defined
|
||||
bool cmainTemplateExists()
|
||||
{
|
||||
Dsymbol pscopesym;
|
||||
auto rootSymbol = sc.search(funcdecl.loc, Id.empty, pscopesym);
|
||||
if (auto moduleSymbol = rootSymbol.search(funcdecl.loc, Id.object))
|
||||
if (moduleSymbol.search(funcdecl.loc, Id.CMain))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only mixin `_d_cmain` if it is defined
|
||||
if (cmainTemplateExists())
|
||||
{
|
||||
// add `mixin _d_cmain!();` to the declaring module
|
||||
auto tqual = new TypeIdentifier(funcdecl.loc, Id.CMain);
|
||||
auto tm = new TemplateMixin(funcdecl.loc, null, tqual, null);
|
||||
sc._module.members.push(tm);
|
||||
}
|
||||
}
|
||||
|
||||
assert(funcdecl.type.ty != Terror || funcdecl.errors);
|
||||
|
||||
// semantic for parameters' UDAs
|
||||
foreach (i, param; f.parameterList)
|
||||
{
|
||||
if (param && param.userAttribDecl)
|
||||
param.userAttribDecl.dsymbolSemantic(sc);
|
||||
.error(fd.loc, "%s `%s` `%s` must be a function instead of `%s`", fd.kind, fd.toPrettyChars, fd.toChars(), fd.type.toChars());
|
||||
fd.type = Type.terror;
|
||||
}
|
||||
fd.errors = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue