mirror of
https://github.com/dlang/dmd.git
synced 2025-04-26 05:00:16 +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)
|
if (!funcdecl.originalType)
|
||||||
funcdecl.originalType = funcdecl.type.syntaxCopy();
|
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)
|
if (sc.inCfile)
|
||||||
{
|
{
|
||||||
/* C11 allows a function to be declared with a typedef, D does not.
|
/* 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())
|
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);
|
parent = cd = objc.getParent(funcdecl, cd);
|
||||||
|
|
||||||
if (funcdecl.isCtorDeclaration())
|
if (funcdecl.isCtorDeclaration())
|
||||||
{
|
{
|
||||||
goto Ldone;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (funcdecl.storage_class & STC.abstract_)
|
if (funcdecl.storage_class & STC.abstract_)
|
||||||
|
@ -587,11 +702,11 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
|
||||||
if (!funcdecl.isVirtual())
|
if (!funcdecl.isVirtual())
|
||||||
{
|
{
|
||||||
//printf("\tnot virtual\n");
|
//printf("\tnot virtual\n");
|
||||||
goto Ldone;
|
return 1;
|
||||||
}
|
}
|
||||||
// Suppress further errors if the return type is an error
|
// Suppress further errors if the return type is an error
|
||||||
if (funcdecl.type.nextOf() == Type.terror)
|
if (funcdecl.type.nextOf() == Type.terror)
|
||||||
goto Ldone;
|
return 1;
|
||||||
|
|
||||||
bool may_override = false;
|
bool may_override = false;
|
||||||
for (size_t i = 0; i < cd.baseclasses.length; i++)
|
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 (cbd.parent && cbd.parent.isTemplateInstance())
|
||||||
{
|
{
|
||||||
if (!functionSemantic(f2))
|
if (!functionSemantic(f2))
|
||||||
goto Ldone;
|
return 1;
|
||||||
}
|
}
|
||||||
may_override = true;
|
may_override = true;
|
||||||
}
|
}
|
||||||
|
@ -727,7 +842,7 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
|
||||||
case -2:
|
case -2:
|
||||||
// can't determine because of forward references
|
// can't determine because of forward references
|
||||||
funcdecl.errors = true;
|
funcdecl.errors = true;
|
||||||
return;
|
return 2;
|
||||||
|
|
||||||
default:
|
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());
|
.error(funcdecl.loc, "%s `%s` circular reference to class `%s`", funcdecl.kind, funcdecl.toPrettyChars, cd.toChars());
|
||||||
funcdecl.errors = true;
|
funcdecl.errors = true;
|
||||||
return;
|
return 2;
|
||||||
}
|
}
|
||||||
FuncDeclaration fdv = cd.baseClass.vtbl[vi].isFuncDeclaration();
|
FuncDeclaration fdv = cd.baseClass.vtbl[vi].isFuncDeclaration();
|
||||||
FuncDeclaration fdc = cd.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
|
* If this function is covariant with any members of those interface
|
||||||
* functions, set the tintro.
|
* functions, set the tintro.
|
||||||
*/
|
*/
|
||||||
Linterfaces:
|
Linterfaces:
|
||||||
bool foundVtblMatch = false;
|
bool foundVtblMatch = false;
|
||||||
|
|
||||||
for (ClassDeclaration bcd = cd; !foundVtblMatch && bcd; bcd = bcd.baseClass)
|
for (ClassDeclaration bcd = cd; !foundVtblMatch && bcd; bcd = bcd.baseClass)
|
||||||
|
@ -898,7 +1013,7 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
|
||||||
case -2:
|
case -2:
|
||||||
// can't determine because of forward references
|
// can't determine because of forward references
|
||||||
funcdecl.errors = true;
|
funcdecl.errors = true;
|
||||||
return;
|
return 2;
|
||||||
|
|
||||||
default:
|
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);
|
.error(funcdecl.loc, "%s `%s` does not override any function", funcdecl.kind, funcdecl.toPrettyChars);
|
||||||
}
|
}
|
||||||
|
|
||||||
L2:
|
L2:
|
||||||
objc.setSelector(funcdecl, sc);
|
objc.setSelector(funcdecl, sc);
|
||||||
objc.checkLinkage(funcdecl);
|
objc.checkLinkage(funcdecl);
|
||||||
objc.addToClassMethodList(funcdecl, cd);
|
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",
|
"`%s` cannot be marked as `deprecated` because it is overriding a function in the base class",
|
||||||
funcdecl.toPrettyChars);
|
funcdecl.toPrettyChars);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
private TypeFunction getFunctionType(FuncDeclaration fd)
|
||||||
else if (funcdecl.isOverride() && !parent.isTemplateInstance())
|
{
|
||||||
.error(funcdecl.loc, "%s `%s` `override` only applies to class member functions", funcdecl.kind, funcdecl.toPrettyChars);
|
if (auto tf = fd.type.isTypeFunction())
|
||||||
|
return tf;
|
||||||
|
|
||||||
if (auto ti = parent.isTemplateInstance)
|
if (!fd.type.isTypeError())
|
||||||
{
|
{
|
||||||
objc.setSelector(funcdecl, sc);
|
.error(fd.loc, "%s `%s` `%s` must be a function instead of `%s`", fd.kind, fd.toPrettyChars, fd.toChars(), fd.type.toChars());
|
||||||
objc.setAsOptional(funcdecl, sc);
|
fd.type = Type.terror;
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
fd.errors = true;
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************
|
/*****************************************
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue