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

Issue 9047 - Expression requiring std.math fails with local import #1438

Closed
wants to merge 1 commit into from
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
2 changes: 2 additions & 0 deletions src/dsymbol.c
Expand Up @@ -820,6 +820,7 @@ ScopeDsymbol::ScopeDsymbol()
symtab = NULL;
imports = NULL;
prots = NULL;
hasStdMathImport = false;
}

ScopeDsymbol::ScopeDsymbol(Identifier *id)
Expand All @@ -829,6 +830,7 @@ ScopeDsymbol::ScopeDsymbol(Identifier *id)
symtab = NULL;
imports = NULL;
prots = NULL;
hasStdMathImport = false;
}

Dsymbol *ScopeDsymbol::syntaxCopy(Dsymbol *s)
Expand Down
1 change: 1 addition & 0 deletions src/dsymbol.h
Expand Up @@ -267,6 +267,7 @@ class ScopeDsymbol : public Dsymbol

Dsymbols *imports; // imported Dsymbol's
unsigned char *prots; // array of PROT, one for each import
bool hasStdMathImport; // std.math import (if 'this' is a function => local import)

ScopeDsymbol();
ScopeDsymbol(Identifier *id);
Expand Down
42 changes: 24 additions & 18 deletions src/expression.c
Expand Up @@ -12128,38 +12128,44 @@ Expression *PowExp::semantic(Scope *sc)
return e;
}

static int importMathChecked = 0;
static bool importMathChecked = false;
static bool importMath = false;
static bool isLocalImport = false;
if (!importMathChecked)
{
importMathChecked = 1;
for (size_t i = 0; i < Module::amodules.dim; i++)
{ Module *mi = Module::amodules[i];
//printf("\t[%d] %s\n", i, mi->toChars());
if (mi->ident == Id::math &&
mi->parent->ident == Id::std &&
!mi->parent->parent)
importMathChecked = true;
if (sc && sc->module && sc->module->hasStdMathImport)
importMath = true;

for (Scope *s = sc;
s && s->scopesym && !s->scopesym->isPackage() && !s->scopesym->isModule();
s = s->enclosing)
{
if (s->scopesym->hasStdMathImport)
{
importMath = true;
goto L1;
isLocalImport = true;
break;
}
}
}

if (!importMath)
{
error("must import std.math to use ^^ operator");
return new ErrorExp();
}

L1: ;
if (isLocalImport)
{ // use 'std.math' for local import
e = new IdentifierExp(loc, Id::std);
}
else
{
if (!importMath)
{
error("must import std.math to use ^^ operator");
return new ErrorExp();
}
{ // use '.std.math' for regular import
e = new IdentifierExp(loc, Id::empty);
e = new DotIdExp(loc, e, Id::std);
}

e = new IdentifierExp(loc, Id::empty);
e = new DotIdExp(loc, e, Id::std);
e = new DotIdExp(loc, e, Id::math);
if (e2->op == TOKfloat64 && e2->toReal() == 0.5)
{ // Replace e1 ^^ 0.5 with .std.math.sqrt(x)
Expand Down
7 changes: 7 additions & 0 deletions src/import.c
Expand Up @@ -242,6 +242,13 @@ void Import::semantic(Scope *sc)

mod->semantic();

if (sc && sc->scopesym && mod->ident == Id::math
&& mod->parent->ident == Id::std && !mod->parent->parent)
{
sc->scopesym->hasStdMathImport = true;
sc->module->hasStdMathImport = true;
}

if (mod->needmoduleinfo)
{ //printf("module4 %s because of %s\n", sc->module->toChars(), mod->toChars());
sc->module->needmoduleinfo = 1;
Expand Down
21 changes: 21 additions & 0 deletions test/compilable/test9047a.d
@@ -0,0 +1,21 @@
// PERMUTE_ARGS:

// sentinel: should not be picked up
struct std { struct math { @disable static void pow(T...)(T t) { } } }

void t1()
{
import std.math;
auto f = (double a, double b) => a ^^ b;
}

void t2()
{
import std.math;
{
auto f = (double a, double b) => a ^^ b;
{
auto y = (double a, double b) => a ^^ b;
}
}
}
22 changes: 22 additions & 0 deletions test/compilable/test9047b.d
@@ -0,0 +1,22 @@
// PERMUTE_ARGS:

import std.math;

void t1()
{
// sentinel: should not be picked up
struct std { struct math { @disable static void pow(T...)(T t) { } } }
auto f = (double a, double b) => a ^^ b;
}

void t2()
{
// sentinel: should not be picked up
struct std { struct math { @disable static void pow(T...)(T t) { } } }
{
auto f = (double a, double b) => a ^^ b;
{
auto y = (double a, double b) => a ^^ b;
}
}
}
9 changes: 9 additions & 0 deletions test/compilable/test9047c.d
@@ -0,0 +1,9 @@
// PERMUTE_ARGS:

import std.math;

void t1()
{
import std.math;
auto f = (double a, double b) => a ^^ b;
}
40 changes: 40 additions & 0 deletions test/fail_compilation/diag9047.d
@@ -0,0 +1,40 @@
/*
TEST_OUTPUT:
---
fail_compilation/diag9047.d(17): Error: must import std.math to use ^^ operator
fail_compilation/diag9047.d(22): Error: must import std.math to use ^^ operator
fail_compilation/diag9047.d(28): Error: must import std.math to use ^^ operator
fail_compilation/diag9047.d(32): Error: must import std.math to use ^^ operator
fail_compilation/diag9047.d(39): Error: must import std.math to use ^^ operator
---
*/

// sentinel: should not be picked up
struct std { struct math { @disable static void pow(T...)(T t) { } } }

void f1()
{
auto f = (double a, double b) => a ^^ b;
}

void f2()
{
auto f2 = (double a, double b) => a ^^ b;
import std.math;
}

void f3()
{
auto f1 = (double a, double b) => a ^^ b;
{
import std.math;
}
auto f2 = (double a, double b) => a ^^ b;
}

void f4()
{
// sentinel: should not be picked up
struct std { struct math { @disable static void pow(T...)(T t) { } } }
auto f = (double a, double b) => a ^^ b;
}