From e5be0735919ce89dca7488e72229823d4a221773 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Thu, 11 Feb 2016 22:05:01 -0800 Subject: [PATCH] fix Issue 10378 - Local imports hide local symbols --- changelog.dd | 25 +++++++ src/dclass.d | 8 +-- src/declaration.d | 2 +- src/denum.d | 2 +- src/dimport.d | 4 +- src/dmodule.d | 15 +++- src/dscope.d | 104 +++++++++++++++++++++++---- src/dstruct.d | 4 +- src/dsymbol.d | 69 +++++++++++++----- src/expression.d | 61 +++++++++++----- src/globals.d | 1 + src/mars.d | 13 +++- src/nspace.d | 2 +- test/fail_compilation/diag12598.d | 3 +- test/fail_compilation/imports/imp1.d | 5 ++ test/fail_compilation/imports/imp2.d | 5 ++ test/fail_compilation/lookup.d | 26 +++++++ test/runnable/imports/bar10378.d | 4 ++ test/runnable/test10378.d | 13 ++++ test/runnable/traits.d | 2 +- 20 files changed, 303 insertions(+), 65 deletions(-) create mode 100644 test/fail_compilation/imports/imp1.d create mode 100644 test/fail_compilation/imports/imp2.d create mode 100644 test/fail_compilation/lookup.d create mode 100644 test/runnable/imports/bar10378.d create mode 100644 test/runnable/test10378.d diff --git a/changelog.dd b/changelog.dd index 5f16ac18fa69..972116328c3f 100644 --- a/changelog.dd +++ b/changelog.dd @@ -9,6 +9,7 @@ $(BUGSTITLE Compiler Changes, $(BUGSTITLE Language Changes, $(LI $(RELATIVE_LINK2 extended-deprecated, Manifest constant can now be used for deprecation message.)) + $(LI $(RELATIVE_LINK2 import-lookup, Imports no longer hide locals declared in outer scopes.)) ) $(BUGSTITLE Compiler Changes, @@ -28,6 +29,30 @@ $(BUGSTITLE Language Changes, deprecated("Some long deprecation " ~ "message") class Bar {} --- ) + + $(LI $(LNAME2 import-lookup, Imports no longer hide locals declared in outer scopes.)) + + These changes were made to the name lookup algorithm: + + $(OL + $(LI Lookup for unqualified names is change from one pass to two pass. The first + pass goes through the scopes but does not check import declarations. If not found, + the second pass goes through the scopes and only looks at import declarations. + ) + $(LI Qualified name lookups, base class lookups, and WithStatement lookups no longer + search import declarations, unless a module is the subject of the lookup, where the + behavior remains as before. + ) + ) + + $(P This can break existing code, although reliance on the previous behavior tends to be + unintended, and fixing it improves the comprehensibility of the code. Breakage tends + to take the form of a symbol now being flagged as undefined. Fixing the breakage can + be done by fully qualifying the name, or adding an alias to the import declaration.) + + $(P Restore old behavior using the -transition=import compiler switch.) + + $(P See also $(BUGZILLA 10378)) ) Macros: diff --git a/src/dclass.d b/src/dclass.d index 448c4498ce3c..6c508b303239 100644 --- a/src/dclass.d +++ b/src/dclass.d @@ -1076,9 +1076,9 @@ public: return baseok >= BASEOKdone; } - override final Dsymbol search(Loc loc, Identifier ident, int flags = IgnoreNone) + override final Dsymbol search(Loc loc, Identifier ident, int flags = SearchLocalsOnly) { - //printf("%s.ClassDeclaration.search('%s')\n", toChars(), ident.toChars()); + //printf("%s.ClassDeclaration.search('%s', flags=x%x)\n", toChars(), ident.toChars(), flags); //if (scope) printf("%s baseok = %d\n", toChars(), baseok); if (_scope && baseok < BASEOKdone) { @@ -1098,7 +1098,7 @@ public: return null; } - Dsymbol s = ScopeDsymbol.search(loc, ident, flags); + Dsymbol s = ScopeDsymbol.search(loc, ident, (flags & SearchImportsOnly) ? flags : flags | SearchLocalsOnly); if (!s) { // Search bases classes in depth-first, left to right order @@ -1111,7 +1111,7 @@ public: error("base %s is forward referenced", b.sym.ident.toChars()); else { - s = b.sym.search(loc, ident, flags); + s = b.sym.search(loc, ident, flags | SearchLocalsOnly); if (s == this) // happens if s is nested in this and derives from this s = null; else if (s) diff --git a/src/declaration.d b/src/declaration.d index e258cf740ad6..3fd8776bb4b9 100644 --- a/src/declaration.d +++ b/src/declaration.d @@ -234,7 +234,7 @@ public: return 1; } - override final Dsymbol search(Loc loc, Identifier ident, int flags = IgnoreNone) + override final Dsymbol search(Loc loc, Identifier ident, int flags = SearchLocalsOnly) { Dsymbol s = Dsymbol.search(loc, ident, flags); if (!s && type) diff --git a/src/denum.d b/src/denum.d index e67737fcf60b..c8718585c18b 100644 --- a/src/denum.d +++ b/src/denum.d @@ -308,7 +308,7 @@ public: return "enum"; } - override Dsymbol search(Loc loc, Identifier ident, int flags = IgnoreNone) + override Dsymbol search(Loc loc, Identifier ident, int flags = SearchLocalsOnly) { //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident->toChars()); if (_scope) diff --git a/src/dimport.d b/src/dimport.d index 71e689d5751b..e087a244d587 100644 --- a/src/dimport.d +++ b/src/dimport.d @@ -443,9 +443,9 @@ public: } } - override Dsymbol search(Loc loc, Identifier ident, int flags = IgnoreNone) + override Dsymbol search(Loc loc, Identifier ident, int flags = SearchLocalsOnly) { - //printf("%s.Import::search(ident = '%s', flags = x%x)\n", toChars(), ident.toChars(), flags); + //printf("%s.Import.search(ident = '%s', flags = x%x)\n", toChars(), ident.toChars(), flags); if (!pkg) { load(null); diff --git a/src/dmodule.d b/src/dmodule.d index f8ccb6f0a734..21dc62a20c8c 100644 --- a/src/dmodule.d +++ b/src/dmodule.d @@ -222,8 +222,10 @@ public: { } - override Dsymbol search(Loc loc, Identifier ident, int flags = IgnoreNone) + override Dsymbol search(Loc loc, Identifier ident, int flags = SearchLocalsOnly) { + //printf("%s Package.search('%s', flags = x%x)\n", toChars(), ident.toChars(), flags); + flags &= ~SearchLocalsOnly; // searching an import is always transitive if (!isModule() && mod) { // Prefer full package name. @@ -1068,15 +1070,22 @@ public: return needmoduleinfo || global.params.cov; } - override Dsymbol search(Loc loc, Identifier ident, int flags = IgnoreNone) + override Dsymbol search(Loc loc, Identifier ident, int flags = SearchLocalsOnly) { /* Since modules can be circularly referenced, * need to stop infinite recursive searches. * This is done with the cache. */ - //printf("%s Module::search('%s', flags = %d) insearch = %d\n", toChars(), ident->toChars(), flags, insearch); + //printf("%s Module.search('%s', flags = x%x) insearch = %d\n", toChars(), ident.toChars(), flags, insearch); if (insearch) return null; + + /* Qualified module searches always search their imports, + * even if SearchLocalsOnly + */ + if (!(flags & SearchUnqualifiedModule)) + flags &= ~(SearchUnqualifiedModule | SearchLocalsOnly); + if (searchCacheIdent == ident && searchCacheFlags == flags) { //printf("%s Module::search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n", diff --git a/src/dscope.d b/src/dscope.d index 1d8d8afae536..ac1fc7f4afa7 100644 --- a/src/dscope.d +++ b/src/dscope.d @@ -32,6 +32,8 @@ import ddmd.root.speller; import ddmd.root.stringtable; import ddmd.statement; +//version=LOGSEARCH; + extern (C++) bool mergeFieldInit(Loc loc, ref uint fieldInit, uint fi, bool mustInit) { if (fi != fieldInit) @@ -419,9 +421,44 @@ struct Scope return minst ? minst : _module; } + /************************************ + * Perform unqualified name lookup by following the chain of scopes up + * until found. + * + * Params: + * loc = location to use for error messages + * ident = name to look up + * pscopesym = if supplied and name is found, set to scope that ident was found in + * flags = modify search based on flags + * + * Returns: + * symbol if found, null if not + */ extern (C++) Dsymbol search(Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone) { - //printf("Scope::search(%p, '%s')\n", this, ident->toChars()); + version (LOGSEARCH) + { + printf("Scope.search(%p, '%s' flags=x%x)\n", &this, ident.toChars(), flags); + // Print scope chain + for (Scope* sc = &this; sc; sc = sc.enclosing) + { + if (!sc.scopesym) + continue; + printf("\tscope %s\n", sc.scopesym.toChars()); + } + + static void printMsg(string txt, Dsymbol s) + { + printf("%.*s %s.%s, kind = '%s'\n", cast(int)msg.length, msg.ptr, + s.parent ? s.parent.toChars() : "", s.toChars(), s.kind()); + } + } + + // This function is called only for unqualified lookup + assert(!(flags & (SearchLocalsOnly | SearchImportsOnly))); + + /* If ident is "start at module scope", only look at module scope + */ if (ident == Id.empty) { // Look for module scope @@ -432,7 +469,7 @@ struct Scope continue; if (Dsymbol s = sc.scopesym.isModule()) { - //printf("\tfound %s.%s\n", s->parent ? s->parent->toChars() : "", s->toChars()); + //printMsg("\tfound", s); if (pscopesym) *pscopesym = sc.scopesym; return s; @@ -440,25 +477,62 @@ struct Scope } return null; } - for (Scope* sc = &this; sc; sc = sc.enclosing) + + Dsymbol searchScopes(int flags) { - assert(sc != sc.enclosing); - if (!sc.scopesym) - continue; - //printf("\tlooking in scopesym '%s', kind = '%s'\n", sc->scopesym->toChars(), sc->scopesym->kind()); - if (Dsymbol s = sc.scopesym.search(loc, ident, flags)) + for (Scope* sc = &this; sc; sc = sc.enclosing) { - if (ident == Id.length && sc.scopesym.isArrayScopeSymbol() && sc.enclosing && sc.enclosing.search(loc, ident, null, flags)) + assert(sc != sc.enclosing); + if (!sc.scopesym) + continue; + //printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc.scopesym.toChars(), sc.scopesym.kind(), flags); + + if (sc.scopesym.isModule()) + flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed + + if (Dsymbol s = sc.scopesym.search(loc, ident, flags)) { - warning(s.loc, "array 'length' hides other 'length' name in outer scope"); + if (!(flags & (SearchImportsOnly | IgnoreErrors)) && + ident == Id.length && sc.scopesym.isArrayScopeSymbol() && + sc.enclosing && sc.enclosing.search(loc, ident, null, flags)) + { + warning(s.loc, "array 'length' hides other 'length' name in outer scope"); + } + //printMsg("\tfound local", s); + if (pscopesym) + *pscopesym = sc.scopesym; + return s; } - //printf("\tfound %s.%s, kind = '%s'\n", s->parent ? s->parent->toChars() : "", s->toChars(), s->kind()); - if (pscopesym) - *pscopesym = sc.scopesym; - return s; + // Stop when we hit a module, but keep going if that is not just under the global scope + if (sc.scopesym.isModule() && !(sc.enclosing && !sc.enclosing.enclosing)) + break; } + return null; } - return null; + + if (global.params.bug10378) + return searchScopes(flags); + + // First look in local scopes + Dsymbol s = searchScopes(flags | SearchLocalsOnly); + + if (s) + { + version (LOGSEARCH) + printMsg("-Scope.search() found local", s); + return s; + } + + s = searchScopes(flags | SearchImportsOnly); // look in imported modules + + version (LOGSEARCH) + { + if (s) + printMsg("-Scope.search() found import", s); + else + printf("-Scope.search() not found\n"); + } + return s; } extern (C++) Dsymbol search_correct(Identifier ident) diff --git a/src/dstruct.d b/src/dstruct.d index 92bfe0e3d52f..49e369658f17 100644 --- a/src/dstruct.d +++ b/src/dstruct.d @@ -576,9 +576,9 @@ public: } } - override final Dsymbol search(Loc loc, Identifier ident, int flags = IgnoreNone) + override final Dsymbol search(Loc loc, Identifier ident, int flags = SearchLocalsOnly) { - //printf("%s.StructDeclaration::search('%s')\n", toChars(), ident->toChars()); + //printf("%s.StructDeclaration::search('%s', flags = x%x)\n", toChars(), ident.toChars(), flags); if (_scope && !symtab) semantic(_scope); diff --git a/src/dsymbol.d b/src/dsymbol.d index 3176f58e9203..f4613253a762 100644 --- a/src/dsymbol.d +++ b/src/dsymbol.d @@ -166,12 +166,19 @@ alias PASSinline = PASS.PASSinline; alias PASSinlinedone = PASS.PASSinlinedone; alias PASSobj = PASS.PASSobj; +// Search options enum : int { IgnoreNone = 0x00, // default IgnorePrivateMembers = 0x01, // don't find private members IgnoreErrors = 0x02, // don't give error messages IgnoreAmbiguous = 0x04, // return NULL if ambiguous + SearchLocalsOnly = 0x08, // only look at locals (don't search imports) + SearchImportsOnly = 0x10, // only look in imports + SearchUnqualifiedModule = 0x20, // the module scope search is unqualified, + // meaning don't search imports in that scope, + // because qualified module searches search + // their imports } extern (C++) alias Dsymbol_apply_ft_t = int function(Dsymbol, void*); @@ -606,14 +613,16 @@ public: /********************************************* * Search for ident as member of s. - * Input: - * flags: (see IgnoreXXX declared in dsymbol.h) + * Params: + * loc = location to print for error messages + * ident = identifier to search for + * flags = IgnoreXXXX * Returns: - * NULL if not found + * null if not found */ Dsymbol search(Loc loc, Identifier ident, int flags = IgnoreNone) { - //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); + //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars()); return null; } @@ -1224,32 +1233,55 @@ public: * This function is #1 on the list of functions that eat cpu time. * Be very, very careful about slowing it down. */ - override Dsymbol search(Loc loc, Identifier ident, int flags = IgnoreNone) + override Dsymbol search(Loc loc, Identifier ident, int flags = SearchLocalsOnly) { - //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); + //printf("%s.ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident.toChars(), flags); //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0; + + if (global.params.bug10378) + flags &= ~(SearchImportsOnly | SearchLocalsOnly); + // Look in symbols declared in this module - Dsymbol s1 = symtab ? symtab.lookup(ident) : null; - //printf("\ts1 = %p, importedScopes = %p, %d\n", - // s1, importedScopes, importedScopes ? importedScopes.dim : 0); - if (s1) + if (symtab && !(flags & SearchImportsOnly)) { - //printf("\ts = '%s.%s'\n",toChars(),s1->toChars()); - return s1; + //printf(" look in locals\n"); + auto s1 = symtab.lookup(ident); + if (s1) + { + //printf("\tfound in locals = '%s.%s'\n",toChars(),s1.toChars()); + return s1; + } } + //printf(" not found in locals\n"); + + // Look in imported scopes if (importedScopes) { + //printf(" look in imports\n"); Dsymbol s = null; OverloadSet a = null; - int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches // Look in imported modules for (size_t i = 0; i < importedScopes.dim; i++) { // If private import, don't search it if ((flags & IgnorePrivateMembers) && prots[i] == PROTprivate) continue; + int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches Dsymbol ss = (*importedScopes)[i]; //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); + + if (ss.isModule()) + { + if (flags & SearchLocalsOnly) + continue; + } + else + { + if (flags & SearchImportsOnly) + continue; + sflags |= SearchLocalsOnly; + } + /* Don't find private members if ss is a module */ Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateMembers : IgnoreNone)); @@ -1320,10 +1352,12 @@ public: if (!s.isImport()) error(loc, "%s %s is private", s.kind(), s.toPrettyChars()); } + //printf("\tfound in imports %s.%s\n", toChars(), s.toChars()); return s; } + //printf(" not found in imports\n"); } - return s1; + return null; } final OverloadSet mergeOverloadSet(Identifier ident, OverloadSet os, Dsymbol s) @@ -1588,8 +1622,11 @@ public: this.withstate = withstate; } - override Dsymbol search(Loc loc, Identifier ident, int flags = IgnoreNone) + override Dsymbol search(Loc loc, Identifier ident, int flags = SearchLocalsOnly) { + //printf("WithScopeSymbol.search(%s)\n", ident.toChars()); + if (flags & SearchImportsOnly) + return null; // Acts as proxy to the with class declaration Dsymbol s = null; Expression eold = null; @@ -1610,7 +1647,7 @@ public: } if (s) { - s = s.search(loc, ident); + s = s.search(loc, ident, flags); if (s) return s; } diff --git a/src/expression.d b/src/expression.d index ce278c66cd41..e6d41acd6e56 100644 --- a/src/expression.d +++ b/src/expression.d @@ -637,31 +637,56 @@ extern (C++) Expression resolvePropertiesOnly(Scope* sc, Expression e1) */ extern (C++) Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident) { + //printf("searchUFCS(ident = %s)\n", ident.toChars()); Loc loc = ue.loc; - Dsymbol s = null; - for (Scope* scx = sc; scx; scx = scx.enclosing) + + // TODO: merge with Scope.search.searchScopes() + Dsymbol searchScopes(int flags) { - if (!scx.scopesym) - continue; - s = scx.scopesym.search(loc, ident); - if (s) + Dsymbol s = null; + for (Scope* scx = sc; scx; scx = scx.enclosing) { - // overload set contains only module scope symbols. - if (s.isOverloadSet()) - break; - // selective/renamed imports also be picked up - if (AliasDeclaration ad = s.isAliasDeclaration()) + if (!scx.scopesym) + continue; + if (scx.scopesym.isModule()) + flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed + s = scx.scopesym.search(loc, ident, flags); + if (s) { - if (ad._import) + // overload set contains only module scope symbols. + if (s.isOverloadSet()) + break; + // selective/renamed imports also be picked up + if (AliasDeclaration ad = s.isAliasDeclaration()) + { + if (ad._import) + break; + } + // See only module scope symbols for UFCS target. + Dsymbol p = s.toParent2(); + if (p && p.isModule()) break; } - // See only module scope symbols for UFCS target. - Dsymbol p = s.toParent2(); - if (p && p.isModule()) + s = null; + + // Stop when we hit a module, but keep going if that is not just under the global scope + if (scx.scopesym.isModule() && !(scx.enclosing && !scx.enclosing.enclosing)) break; } - s = null; + return s; + } + + Dsymbol s; + + if (global.params.bug10378) + s = searchScopes(0); + else + { + s = searchScopes(SearchLocalsOnly); + if (!s) + s = searchScopes(SearchImportsOnly); } + if (!s) return ue.e1.type.Type.getProperty(loc, ident, 0); FuncDeclaration f = s.isFuncDeclaration(); @@ -686,6 +711,7 @@ extern (C++) Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident) } else { + //printf("-searchUFCS() %s\n", s.toChars()); return new DsymbolExp(loc, s); } } @@ -8269,7 +8295,8 @@ public: * The check for 'is sds our current module' is because * the current module should have access to its own imports. */ - Dsymbol s = ie.sds.search(loc, ident, (ie.sds.isModule() && ie.sds != sc._module) ? IgnorePrivateMembers : IgnoreNone); + Dsymbol s = ie.sds.search(loc, ident, + (ie.sds.isModule() && ie.sds != sc._module) ? IgnorePrivateMembers | SearchLocalsOnly : SearchLocalsOnly); if (s) { /* Check for access before resolving aliases because public diff --git a/src/globals.d b/src/globals.d index 28424f61fd18..49e4a228688d 100644 --- a/src/globals.d +++ b/src/globals.d @@ -115,6 +115,7 @@ struct Param bool addMain; // add a default main() function bool allInst; // generate code for all template instantiations bool dwarfeh; // generate dwarf eh exception handling + bool bug10378; // use pre-bugzilla 10378 search strategy BOUNDSCHECK useArrayBounds; diff --git a/src/mars.d b/src/mars.d index afcd0b1bdec8..4b06e557b045 100644 --- a/src/mars.d +++ b/src/mars.d @@ -231,7 +231,7 @@ Usage: -release compile release version -run srcfile args... run resulting program, passing args -shared generate shared library (DLL) - -transition=id show additional info about language change identified by 'id' + -transition=id help with language change identified by 'id' -transition=? list all language changes -unittest compile in unit tests -v verbose @@ -683,6 +683,7 @@ Language changes listed by -transition=id: =all list information on all language changes =complex,14488 list all usages of complex or imaginary types =field,3449 list all non-mutable fields which occupy an object instance + =import,10378 revert to single phase name lookup =tls list all variables going into thread local storage "); return EXIT_FAILURE; @@ -700,6 +701,9 @@ Language changes listed by -transition=id: case 3449: global.params.vfield = true; break; + case 10378: + global.params.bug10378 = true; + break; case 14488: global.params.vcomplex = true; break; @@ -733,6 +737,13 @@ Language changes listed by -transition=id: break; } goto Lerror; + case 6: + if (strcmp(ident, "import") == 0) + { + global.params.bug10378 = true; + break; + } + goto Lerror; case 7: if (strcmp(ident, "complex") == 0) { diff --git a/src/nspace.d b/src/nspace.d index f8d6cc35b2b1..c5543433db2c 100644 --- a/src/nspace.d +++ b/src/nspace.d @@ -186,7 +186,7 @@ public: return Dsymbol.oneMember(ps, ident); } - override final Dsymbol search(Loc loc, Identifier ident, int flags = IgnoreNone) + override final Dsymbol search(Loc loc, Identifier ident, int flags = SearchLocalsOnly) { //printf("%s.Nspace.search('%s')\n", toChars(), ident.toChars()); if (_scope && !symtab) diff --git a/test/fail_compilation/diag12598.d b/test/fail_compilation/diag12598.d index 63eb66aacc16..236692d38669 100644 --- a/test/fail_compilation/diag12598.d +++ b/test/fail_compilation/diag12598.d @@ -1,7 +1,8 @@ /* +REQUIRED_ARGS: -transition=import TEST_OUTPUT: --- -fail_compilation/diag12598.d(13): Error: struct 'lines' is a type, not an lvalue +fail_compilation/diag12598.d(14): Error: struct 'lines' is a type, not an lvalue --- */ diff --git a/test/fail_compilation/imports/imp1.d b/test/fail_compilation/imports/imp1.d new file mode 100644 index 000000000000..e32008cbcdd4 --- /dev/null +++ b/test/fail_compilation/imports/imp1.d @@ -0,0 +1,5 @@ +module imp1; + +enum X = 1; +enum Y = 1; +enum Z = 1; diff --git a/test/fail_compilation/imports/imp2.d b/test/fail_compilation/imports/imp2.d new file mode 100644 index 000000000000..178059148555 --- /dev/null +++ b/test/fail_compilation/imports/imp2.d @@ -0,0 +1,5 @@ +module imp2; + +enum X = 2; +enum Y = 2; +enum Z = 2; diff --git a/test/fail_compilation/lookup.d b/test/fail_compilation/lookup.d new file mode 100644 index 000000000000..27597074b6df --- /dev/null +++ b/test/fail_compilation/lookup.d @@ -0,0 +1,26 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/lookup.d(21): Error: no property 'X' for type 'lookup.B' +fail_compilation/lookup.d(22): Error: no property 'Y' for type 'lookup.B' +--- +*/ + +import imports.imp1; + +enum X = 0; + +class B +{ + import imports.imp2; + static assert(X == 0); + static assert(Y == 2); +} +class C : B +{ + static assert(B.X == 0); + static assert(B.Y == 2); + + static assert(X == 0); + static assert(Y == 1); +} diff --git a/test/runnable/imports/bar10378.d b/test/runnable/imports/bar10378.d new file mode 100644 index 000000000000..f4d3bcb5b9b0 --- /dev/null +++ b/test/runnable/imports/bar10378.d @@ -0,0 +1,4 @@ + +module bar; + +void writeln() { } diff --git a/test/runnable/test10378.d b/test/runnable/test10378.d new file mode 100644 index 000000000000..f83ece18bbfc --- /dev/null +++ b/test/runnable/test10378.d @@ -0,0 +1,13 @@ + +int writeln() { return 3; } + +struct S { + import imports.bar10378; + void abc() { assert(writeln() == 3); } +} + + +void main() { + S s; + s.abc(); +} diff --git a/test/runnable/traits.d b/test/runnable/traits.d index 7e69371d2c0b..51b53518a475 100644 --- a/test/runnable/traits.d +++ b/test/runnable/traits.d @@ -943,7 +943,7 @@ void getProtection() void test9546() { - import imports.a9546; + import imports.a9546 : S; S s; static assert(__traits(getProtection, s.privA) == "private");