diff --git a/changelog.dd b/changelog.dd index 8b12e5f8ccf3..0974b66f2d21 100644 --- a/changelog.dd +++ b/changelog.dd @@ -8,12 +8,41 @@ $(BUGSTITLE Language Changes, ) $(BUGSTITLE Compiler Changes, + $(LI $(RELATIVE_LINK2 deferred_alias, Analysis for aliases in imported modules is deferred.)) ) $(BUGSTITLE Language Changes, ) $(BUGSTITLE Compiler Changes, + $(LI $(LNAME2 deferred_alias, Analysis for aliases in imported modules is deferred.) + + $(P Example:) + + --- + module lib; + template ExpensiveApiImpl(int ver) + { + ... + void func() {} + pragma(msg, "instantiated ExpensiveApiImpl ", ver); + } + alias api1 = ExpensiveApiImpl!(1); + alias api2 = ExpensiveApiImpl!(2); + --- + + --- + import lib; + void main() + { + // OK, prints "instantiated ExpensiveApiImpl 1" + api1.func(); + + // Don't print "instantiated ExpensiveApiImpl 2", because + // the alias name 'api2' is not used. + } + --- + ) ) Macros: diff --git a/src/declaration.d b/src/declaration.d index 50d8d5723455..6a13b10df4ed 100644 --- a/src/declaration.d +++ b/src/declaration.d @@ -542,6 +542,22 @@ public: } override void semantic(Scope* sc) + { + if (semanticRun >= PASSsemanticdone) + return; + assert(semanticRun <= PASSsemantic); + + storage_class |= sc.stc & STCdeprecated; + protection = sc.protection; + userAttribDecl = sc.userAttribDecl; + + if (!sc.func && inNonRoot()) + return; + + aliasSemantic(sc); + } + + final void aliasSemantic(Scope* sc) { //printf("AliasDeclaration::semantic() %s\n", toChars()); if (aliassym) @@ -574,10 +590,6 @@ public: } inuse = 1; - storage_class |= sc.stc & STCdeprecated; - protection = sc.protection; - userAttribDecl = sc.userAttribDecl; - // Given: // alias foo.bar.abc def; // it is not knowable from the syntax whether this is an alias @@ -799,24 +811,31 @@ public: type = Type.terror; return aliassym; } - if (aliassym) + + if (semanticRun >= PASSsemanticdone) { // semantic is already done. - // Even if type.deco !is null, "alias T = const int;` needs semantic - // call to take the storage class `const` as type qualifier. - } - else if (_import && _import._scope) - { - /* If this is an internal alias for selective/renamed import, - * resolve it under the correct scope. - */ - _import.semantic(null); + // Do not see aliassym !is null, because of lambda aliases. + + // Do not see type.deco !is null, even so "alias T = const int;` needs + // semantic analysis to take the storage class `const` as type qualifier. } - else if (_scope) + else { - semantic(_scope); + if (_import && _import._scope) + { + /* If this is an internal alias for selective/renamed import, + * load the module first. + */ + _import.semantic(null); + } + if (_scope) + { + aliasSemantic(_scope); + } } + inuse = 1; Dsymbol s = aliassym ? aliassym.toAlias() : this; inuse = 0; diff --git a/src/declaration.h b/src/declaration.h index bed3c6044f56..458b4724334b 100644 --- a/src/declaration.h +++ b/src/declaration.h @@ -205,6 +205,7 @@ class AliasDeclaration : public Declaration AliasDeclaration(Loc loc, Identifier *ident, Dsymbol *s); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); + void aliasSmantic(Scope *sc); bool overloadInsert(Dsymbol *s); const char *kind(); Type *getType(); diff --git a/src/dimport.d b/src/dimport.d index d49c7aca8a37..332544566039 100644 --- a/src/dimport.d +++ b/src/dimport.d @@ -291,6 +291,7 @@ public: //printf("module4 %s because of %s\n", sc.module.toChars(), mod.toChars()); sc._module.needmoduleinfo = 1; } + sc = sc.push(mod); sc.protection = protection; for (size_t i = 0; i < aliasdecls.dim; i++) @@ -300,6 +301,9 @@ public: if (mod.search(loc, names[i])) { ad.semantic(sc); + // If the import declaration is in non-root module, + // analysis of the aliased symbol is deferred. + // Therefore, don't see the ad.aliassym or ad.type here. } else { @@ -313,6 +317,7 @@ public: } sc = sc.pop(); } + // object self-imports itself, so skip that (Bugzilla 7547) // don't list pseudo modules __entrypoint.d, __main.d (Bugzilla 11117, 11164) if (global.params.moduleDeps !is null && !(id == Id.object && sc._module.ident == Id.object) && sc._module.ident != Id.entrypoint && strcmp(sc._module.ident.string, "__main") != 0) diff --git a/src/dsymbol.d b/src/dsymbol.d index d7eed7d330c7..c7313a039275 100644 --- a/src/dsymbol.d +++ b/src/dsymbol.d @@ -1016,11 +1016,11 @@ public: Dsymbol s = parent; for (; s; s = s.toParent()) { - if (TemplateInstance ti = s.isTemplateInstance()) + if (auto ti = s.isTemplateInstance()) { return false; } - if (Module m = s.isModule()) + if (auto m = s.isModule()) { if (!m.isRoot()) return true; diff --git a/test/compilable/imports/test13242a.d b/test/compilable/imports/test13242a.d new file mode 100644 index 000000000000..941c9941b1bd --- /dev/null +++ b/test/compilable/imports/test13242a.d @@ -0,0 +1,19 @@ +module imports.test13242a; + +template expensiveArgs(alias v) +{ + pragma(msg, "a.expensiveArgs: ", v); +} + +template expensiveTemplate(Args...) +{ + pragma(msg, "a.expensiveTemplate: ", Args[0]); +} + +alias apiSym1 = expensiveTemplate!(1, expensiveArgs!(1)); + +alias apiSym2 = expensiveTemplate!(2, expensiveArgs!(2)); + +public import imports.test13242b : apiSym3; + +void cheapFunc() {} diff --git a/test/compilable/imports/test13242b.d b/test/compilable/imports/test13242b.d new file mode 100644 index 000000000000..fab8d686726a --- /dev/null +++ b/test/compilable/imports/test13242b.d @@ -0,0 +1,13 @@ +module imports.test13242b; + +template expensiveArgs(alias v) +{ + pragma(msg, "b.expensiveArgs: ", v); +} + +template expensiveTemplate(Args...) +{ + pragma(msg, "b.expensiveTemplate: ", Args[0]); +} + +alias apiSym3 = expensiveTemplate!(3, expensiveArgs!(3)); diff --git a/test/compilable/test13242.d b/test/compilable/test13242.d new file mode 100644 index 000000000000..0d6ef276aa08 --- /dev/null +++ b/test/compilable/test13242.d @@ -0,0 +1,34 @@ +// REQUIRED_ARGS: -o- +/* +TEST_OUTPUT: +--- +main ++alias apiSym1 +a.expensiveArgs: 1 +a.expensiveTemplate: 1 +-alias apiSym1 ++alias apiSym3 +b.expensiveArgs: 3 +b.expensiveTemplate: 3 +-alias apiSym3 +--- +*/ + +import imports.test13242a; + +void main() +{ + pragma(msg, "main"); + + cheapFunc(); + + pragma(msg, "+alias apiSym1"); + alias apiSym1 = .apiSym1; + pragma(msg, "-alias apiSym1"); + + // imports.test13242a.apiSym2 is not analyzed. + + pragma(msg, "+alias apiSym3"); + alias apiSym3 = .apiSym3; + pragma(msg, "-alias apiSym3"); +}