Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Issue 19731: throw away semantic3 run after return type inference to avoid missing invariants #9448

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 23 additions & 2 deletions src/dmd/func.d
Expand Up @@ -271,6 +271,7 @@ extern (C++) class FuncDeclaration : Declaration
Type tintro;

bool inferRetType; /// true if return type is to be inferred
bool inferRetTypePlaceholder; /// true if function is a throwaway placeholder for return type inference
StorageClass storage_class2; /// storage class for template onemember's

// Things that should really go into Scope
Expand Down Expand Up @@ -326,7 +327,7 @@ extern (C++) class FuncDeclaration : Declaration
/* The type given for "infer the return type" is a TypeFunction with
* NULL for the return type.
*/
inferRetType = (type && type.nextOf() is null);
this.inferRetType = (type && type.nextOf() is null);
}

static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type)
Expand Down Expand Up @@ -375,7 +376,27 @@ extern (C++) class FuncDeclaration : Declaration
// the inferred return type is valid.
// So, the body errors should become the function signature error.
if (inferRetType && type && !type.nextOf())
return functionSemantic3();
{
if (inferRetTypePlaceholder)
{
return functionSemantic3();
}
else
{
// Create a sacrificial copy of the function to run semantic3 on
// to determine the correct return type.
// This is to avoid semantic3 prematurely assigning invariants that
// may not exist yet.
FuncDeclaration fcopy = cast(FuncDeclaration) syntaxCopy(null);
fcopy._scope = _scope;
fcopy.inferRetTypePlaceholder = true;
bool success = fcopy.functionSemantic();
type = fcopy.type;
inferRetType = (type && type.nextOf() is null);
if (!success)
return false;
}
}

TemplateInstance ti;
if (isInstantiated() && !isVirtualMethod() &&
Expand Down
28 changes: 28 additions & 0 deletions test/runnable/test19731.d
@@ -0,0 +1,28 @@
struct Foo
{
Object obj_;

invariant (obj_ !is null);

auto obj()
{
return this.obj_;
}

alias type = typeof(&Foo.init.obj);
}

void main()
{
import core.exception : AssertError;

Foo foo = Foo.init;

try
{
foo.obj.toString();
}
catch (AssertError)
{
}
}