From 6d799f0aed18be25a5c908499b6411ab6d06b78c Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Fri, 9 Dec 2022 18:59:38 +0100 Subject: d: Merge upstream dmd, druntime c8ae4adb2e, phobos 792c8b7c1. D front-end changes: - Import dmd v2.101.0. - Deprecate the ability to call `__traits(getAttributes)' on overload sets. - Deprecate non-empty `for' statement increment clause with no effect. - Array literals assigned to `scope' array variables can now be allocated on the stack. D runtime changes: - Import druntime v2.101.0. Phobos changes: - Import phobos v2.101.0. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd c8ae4adb2e. * typeinfo.cc (check_typeinfo_type): Update for new front-end interface. (TypeInfoVisitor::visit (TypeInfoStructDeclaration *)): Remove warning that toHash() must be declared 'nothrow @safe`. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime c8ae4adb2e. * src/MERGE: Merge upstream phobos 792c8b7c1. --- gcc/d/dmd/file_manager.d | 138 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 116 insertions(+), 22 deletions(-) (limited to 'gcc/d/dmd/file_manager.d') diff --git a/gcc/d/dmd/file_manager.d b/gcc/d/dmd/file_manager.d index 0ea7303..a941115 100644 --- a/gcc/d/dmd/file_manager.d +++ b/gcc/d/dmd/file_manager.d @@ -12,7 +12,7 @@ module dmd.file_manager; import dmd.root.stringtable : StringTable; import dmd.root.file : File, Buffer; -import dmd.root.filename : FileName; +import dmd.root.filename : FileName, isDirSeparator; import dmd.root.string : toDString; import dmd.globals; import dmd.identifier; @@ -26,14 +26,86 @@ bool isPackageFileName(scope FileName fileName) nothrow return FileName.equals(fileName.name, package_d) || FileName.equals(fileName.name, package_di); } +// A path stack that allows one to go up and down the path using directory +// separators. `cur` is the current path, `up` goes up one path, `down` goes +// down one path. if `up` or `down` return false, there are no further paths. +private struct PathStack +{ + private const(char)[] path; + private size_t pos; + + @safe @nogc nothrow pure: + + this(const(char)[] p) + { + path = p; + pos = p.length; + } + + const(char)[] cur() + { + return path[0 .. pos]; + } + + bool up() + { + if (pos == 0) + return false; + while (--pos != 0) + if (isDirSeparator(path[pos])) + return true; + return false; + } + + bool down() + { + if (pos == path.length) + return false; + while (++pos != path.length) + if (isDirSeparator(path[pos])) + return true; + return false; + } +} + final class FileManager { private StringTable!(const(ubyte)[]) files; + private StringTable!(bool) packageStatus; + + // check if the package path of the given path exists. The input path is + // expected to contain the full path to the module, so the parent + // directories of that path are checked. + private bool packageExists(const(char)[] p) nothrow + { + // step 1, look for the closest parent path that is cached + bool exists = true; + auto st = PathStack(p); + while (st.up) { + if (auto cached = packageStatus.lookup(st.cur)) { + exists = cached.value; + break; + } + } + // found a parent that is cached (or reached the end of the stack). + // step 2, traverse back up the stack storing either false if the + // parent doesn't exist, or the result of the `exists` call if it does. + while (st.down) { + if (!exists) + packageStatus.insert(st.cur, false); + else + exists = packageStatus.insert(st.cur, FileName.exists(st.cur) == 2).value; + } + + // at this point, exists should be the answer. + return exists; + } /// public this () nothrow { this.files._init(); + this.packageStatus._init(); } nothrow: @@ -48,13 +120,15 @@ nothrow: * the found file name or * `null` if it is not different from filename. */ - static const(char)[] lookForSourceFile(const char[] filename, const char*[] path) + const(char)[] lookForSourceFile(const char[] filename, const char*[] path) { //printf("lookForSourceFile(`%.*s`)\n", cast(int)filename.length, filename.ptr); /* Search along path[] for .di file, then .d file, then .i file, then .c file. */ + // see if we should check for the module locally. + bool checkLocal = packageExists(filename); const sdi = FileName.forceExt(filename, hdr_ext); - if (FileName.exists(sdi) == 1) + if (checkLocal && FileName.exists(sdi) == 1) return sdi; scope(exit) FileName.free(sdi.ptr); @@ -62,36 +136,43 @@ nothrow: // Special file name representing `stdin`, always assume its presence if (sd == "__stdin.d") return sd; - if (FileName.exists(sd) == 1) + if (checkLocal && FileName.exists(sd) == 1) return sd; scope(exit) FileName.free(sd.ptr); const si = FileName.forceExt(filename, i_ext); - if (FileName.exists(si) == 1) + if (checkLocal && FileName.exists(si) == 1) return si; scope(exit) FileName.free(si.ptr); const sc = FileName.forceExt(filename, c_ext); - if (FileName.exists(sc) == 1) + if (checkLocal && FileName.exists(sc) == 1) return sc; scope(exit) FileName.free(sc.ptr); - if (FileName.exists(filename) == 2) + if (checkLocal) { - /* The filename exists and it's a directory. - * Therefore, the result should be: filename/package.d - * iff filename/package.d is a file - */ - const ni = FileName.combine(filename, package_di); - if (FileName.exists(ni) == 1) - return ni; - FileName.free(ni.ptr); - - const n = FileName.combine(filename, package_d); - if (FileName.exists(n) == 1) - return n; - FileName.free(n.ptr); + auto cached = packageStatus.lookup(filename); + if (!cached) + cached = packageStatus.insert(filename, FileName.exists(filename) == 2); + if (cached.value) + { + /* The filename exists and it's a directory. + * Therefore, the result should be: filename/package.d + * iff filename/package.d is a file + */ + const ni = FileName.combine(filename, package_di); + if (FileName.exists(ni) == 1) + return ni; + FileName.free(ni.ptr); + + const n = FileName.combine(filename, package_d); + if (FileName.exists(n) == 1) + return n; + FileName.free(n.ptr); + } } + if (FileName.absolute(filename)) return null; if (!path.length) @@ -101,6 +182,11 @@ nothrow: const p = entry.toDString(); const(char)[] n = FileName.combine(p, sdi); + + if (!packageExists(n)) { + FileName.free(n.ptr); + continue; // no need to check for anything else. + } if (FileName.exists(n) == 1) { return n; } @@ -127,7 +213,16 @@ nothrow: const b = FileName.removeExt(filename); n = FileName.combine(p, b); FileName.free(b.ptr); - if (FileName.exists(n) == 2) + + scope(exit) FileName.free(n.ptr); + + // also cache this if we are looking for package.d[i] + auto cached = packageStatus.lookup(n); + if (!cached) { + cached = packageStatus.insert(n, FileName.exists(n) == 2); + } + + if (cached.value) { const n2i = FileName.combine(n, package_di); if (FileName.exists(n2i) == 1) @@ -139,7 +234,6 @@ nothrow: } FileName.free(n2.ptr); } - FileName.free(n.ptr); } return null; } -- cgit v1.1