diff --git a/src/.dscanner.ini b/src/.dscanner.ini index d6e14cdc02e9..45dbfd836814 100644 --- a/src/.dscanner.ini +++ b/src/.dscanner.ini @@ -115,5 +115,5 @@ redundant_storage_classes="enabled" redundant_storage_classes="-dmd.id,-dmd.toir,-dmd.tokens" trust_too_much="-dmd.root.longdouble" builtin_property_names_check="-dmd.backend.obj,-dmd.backend.code,-dmd.backend.cc" -object_const_check="-dmd.dtemplate,-dmd.backend.outbuf" +object_const_check="-dmd.dtemplate,-dmd.backend.outbuf,-dmd.root.rootobject" final_attribute_check="-dmd.statement" ; https://github.com/dlang/dmd/pull/856 diff --git a/src/dmd/dmodule.d b/src/dmd/dmodule.d index 52c4c2c72e0e..aa7a6b422041 100644 --- a/src/dmd/dmodule.d +++ b/src/dmd/dmodule.d @@ -38,6 +38,7 @@ import dmd.root.port; import dmd.semantic2; import dmd.semantic3; import dmd.target; +import dmd.utils; import dmd.visitor; version(Windows) { @@ -1337,19 +1338,24 @@ struct ModuleDeclaration this.isdeprecated = isdeprecated; } - extern (C++) const(char)* toChars() + extern (C++) const(char)* toChars() const { OutBuffer buf; if (packages && packages.dim) { - for (size_t i = 0; i < packages.dim; i++) + foreach (pid; *packages) { - Identifier pid = (*packages)[i]; - buf.writestring(pid.toChars()); + buf.writestring(pid.toString()); buf.writeByte('.'); } } - buf.writestring(id.toChars()); + buf.writestring(id.toString()); return buf.extractString(); } + + /// Provide a human readable representation + extern (D) const(char)[] toString() const + { + return this.toChars().toDString; + } } diff --git a/src/dmd/globals.h b/src/dmd/globals.h index 2f1d86c44056..1ed47a94e214 100644 --- a/src/dmd/globals.h +++ b/src/dmd/globals.h @@ -15,6 +15,7 @@ #pragma once #endif +#include "root/dcompat.h" #include "ctfloat.h" #include "outbuffer.h" #include "filename.h" @@ -292,14 +293,6 @@ typedef uint32_t d_uns32; typedef int64_t d_int64; typedef uint64_t d_uns64; -// Represents a D [ ] array -template -struct DArray -{ - size_t length; - T *ptr; -}; - // file location struct Loc { diff --git a/src/dmd/hdrgen.d b/src/dmd/hdrgen.d index 550a44d563a6..ef0fef36b18c 100644 --- a/src/dmd/hdrgen.d +++ b/src/dmd/hdrgen.d @@ -3347,6 +3347,16 @@ extern (C++) const(char)* stcToChars(ref StorageClass stc) return null; } + +/** + * Returns: + * a human readable representation of `stc` + */ +extern (D) const(char)[] stcToString(ref StorageClass stc) +{ + return stcToChars(stc).toDString; +} + extern (C++) void trustToBuffer(OutBuffer* buf, TRUST trust) { const(char)* p = trustToChars(trust); @@ -3354,7 +3364,19 @@ extern (C++) void trustToBuffer(OutBuffer* buf, TRUST trust) buf.writestring(p); } +/** + * Returns: + * a human readable representation of `trust`, + * which is the token `trust` corresponds to + */ extern (C++) const(char)* trustToChars(TRUST trust) +{ + /// Works because we return a literal + return trustToString(trust).ptr; +} + +/// Ditto +extern (D) string trustToString(TRUST trust) { final switch (trust) { @@ -3416,7 +3438,18 @@ extern (C++) void protectionToBuffer(OutBuffer* buf, Prot prot) } } +/** + * Returns: + * a human readable representation of `kind` + */ extern (C++) const(char)* protectionToChars(Prot.Kind kind) +{ + // Null terminated because we return a literal + return protectionToString(kind).ptr; +} + +/// Ditto +extern (D) string protectionToString(Prot.Kind kind) { final switch (kind) { diff --git a/src/dmd/identifier.d b/src/dmd/identifier.d index 3f7a7cd8a425..bd4648a6aa15 100644 --- a/src/dmd/identifier.d +++ b/src/dmd/identifier.d @@ -74,7 +74,7 @@ nothrow: return name; } - extern (D) const(char)[] toString() const pure + extern (D) override const(char)[] toString() const pure { return name[0 .. len]; } diff --git a/src/dmd/json.d b/src/dmd/json.d index 1937393edee9..d222c623be6a 100644 --- a/src/dmd/json.d +++ b/src/dmd/json.d @@ -33,6 +33,8 @@ import dmd.id; import dmd.identifier; import dmd.mtype; import dmd.root.outbuffer; +import dmd.root.rootobject; +import dmd.utils; import dmd.visitor; version(Windows) { @@ -47,13 +49,14 @@ private extern (C++) final class ToJsonVisitor : Visitor public: OutBuffer* buf; int indentLevel; - const(char)* filename; + const(char)[] filename; extern (D) this(OutBuffer* buf) { this.buf = buf; } + void indent() { if (buf.offset >= 1 && buf.data[buf.offset - 1] == '\n') @@ -83,11 +86,10 @@ public: buf.writeByte('\"'); } - void stringPart(const(char)* s) + extern(D) void stringPart(const(char)[] s) { - for (; *s; s++) + foreach (char c; s) { - char c = cast(char)*s; switch (c) { case '\n': @@ -128,7 +130,7 @@ public: /********************************* * Encode string into buf, and wrap it in double quotes. */ - void value(const(char)* s) + extern(D) void value(const(char)[] s) { stringStart(); stringPart(s); @@ -153,7 +155,7 @@ public: /********************************* * Item is an intented value and a comma, for use in arrays */ - void item(const(char)* s) + extern(D) void item(const(char)[] s) { indent(); value(s); @@ -221,7 +223,7 @@ public: } // Json object property functions - void propertyStart(const(char)* name) + extern(D) void propertyStart(const(char)[] name) { indent(); value(name); @@ -235,7 +237,7 @@ public: name = the name of the object property s = the string value of the object property */ - void property(const(char)* name, const(char)* s) + extern(D) void property(const(char)[] name, const(char)[] s) { if (s is null) return; @@ -251,7 +253,7 @@ public: name = the name of the object property s = the string value of the object property */ - void requiredProperty(const(char)* name, const(char)* s) + extern(D) void requiredProperty(const(char)[] name, const(char)[] s) { propertyStart(name); if (s is null) @@ -261,21 +263,21 @@ public: comma(); } - void property(const(char)* name, int i) + extern(D) void property(const(char)[] name, int i) { propertyStart(name); value(i); comma(); } - void propertyBool(const(char)* name, const bool b) + extern(D) void propertyBool(const(char)[] name, const bool b) { propertyStart(name); valueBool(b); comma(); } - void property(const(char)* name, TRUST trust) + extern(D) void property(const(char)[] name, TRUST trust) { final switch (trust) { @@ -295,7 +297,7 @@ public: } } - void property(const(char)* name, PURE purity) + extern(D) void property(const(char)[] name, PURE purity) { final switch (purity) { @@ -318,7 +320,7 @@ public: } } - void property(const(char)* name, const LINK linkage) + extern(D) void property(const(char)[] name, const LINK linkage) { final switch (linkage) { @@ -352,7 +354,7 @@ public: } } - void propertyStorageClass(const(char)* name, StorageClass stc) + extern(D) void propertyStorageClass(const(char)[] name, StorageClass stc) { stc &= STCStorageClass; if (stc) @@ -361,22 +363,21 @@ public: arrayStart(); while (stc) { - const(char)* p = stcToChars(stc); - assert(p); + auto p = stcToString(stc); + assert(p.length); item(p); } arrayEnd(); } } - void property(const(char)* linename, const(char)* charname, Loc* loc) + extern(D) void property(const(char)[] linename, const(char)[] charname, Loc* loc) { if (loc) { - const(char)* filename = loc.filename; - if (filename) + if (auto filename = loc.filename.toDString) { - if (!this.filename || strcmp(filename, this.filename)) + if (filename != this.filename) { this.filename = filename; property("file", filename); @@ -391,26 +392,26 @@ public: } } - void property(const(char)* name, Type type) + extern(D) void property(const(char)[] name, Type type) { if (type) { - property(name, type.toChars()); + property(name, type.toString()); } } - void property(const(char)* name, const(char)* deconame, Type type) + extern(D) void property(const(char)[] name, const(char)[] deconame, Type type) { if (type) { if (type.deco) - property(deconame, type.deco); + property(deconame, type.deco.toDString); else - property(name, type.toChars()); + property(name, type.toString()); } } - void property(const(char)* name, Parameters* parameters) + extern(D) void property(const(char)[] name, Parameters* parameters) { if (parameters is null || parameters.dim == 0) return; @@ -423,11 +424,11 @@ public: Parameter p = (*parameters)[i]; objectStart(); if (p.ident) - property("name", p.ident.toChars()); + property("name", p.ident.toString()); property("type", "deco", p.type); propertyStorageClass("storageClass", p.storageClass); if (p.defaultArg) - property("default", p.defaultArg.toChars()); + property("default", p.defaultArg.toString()); objectEnd(); } } @@ -441,17 +442,17 @@ public: return; if (!s.isTemplateDeclaration()) // TemplateDeclaration::kind() acts weird sometimes { - property("name", s.toChars()); - property("kind", s.kind()); + property("name", s.toString()); + property("kind", s.kind.toDString); } if (s.prot().kind != Prot.Kind.public_) // TODO: How about package(names)? - property("protection", protectionToChars(s.prot().kind)); + property("protection", protectionToString(s.prot().kind)); if (EnumMember em = s.isEnumMember()) { if (em.origValue) - property("value", em.origValue.toChars()); + property("value", em.origValue.toString()); } - property("comment", s.comment); + property("comment", s.comment.toDString); property("line", "char", &s.loc); } @@ -466,11 +467,11 @@ public: // Emit originalType if it differs from type if (d.type != d.originalType && d.originalType) { - const(char)* ostr = d.originalType.toChars(); + auto ostr = d.originalType.toString(); if (d.type) { - const(char)* tstr = d.type.toChars(); - if (strcmp(tstr, ostr)) + auto tstr = d.type.toString(); + if (ostr != tstr) { //printf("tstr = %s, ostr = %s\n", tstr, ostr); property("originalType", ostr); @@ -487,7 +488,7 @@ public: if (td.onemember && td.onemember.isCtorDeclaration()) property("name", "this"); // __ctor -> this else - property("name", td.ident.toChars()); // Foo(T) -> Foo + property("name", td.ident.toString()); // Foo(T) -> Foo } /* ========================================================================== */ @@ -499,11 +500,11 @@ public: { objectStart(); if (s.md) - property("name", s.md.toChars()); - property("kind", s.kind()); - filename = s.srcfile.toChars(); + property("name", s.md.toString()); + property("kind", s.kind.toDString); + filename = s.srcfile.toString(); property("file", filename); - property("comment", s.comment); + property("comment", s.comment.toDString); propertyStart("members"); arrayStart(); for (size_t i = 0; i < s.members.dim; i++) @@ -526,20 +527,20 @@ public: for (size_t i = 0; i < s.packages.dim; i++) { Identifier pid = (*s.packages)[i]; - stringPart(pid.toChars()); + stringPart(pid.toString()); buf.writeByte('.'); } } - stringPart(s.id.toChars()); + stringPart(s.id.toString()); stringEnd(); comma(); - property("kind", s.kind()); - property("comment", s.comment); + property("kind", s.kind.toDString); + property("comment", s.comment.toDString); property("line", "char", &s.loc); if (s.prot().kind != Prot.Kind.public_) - property("protection", protectionToChars(s.prot().kind)); + property("protection", protectionToString(s.prot().kind)); if (s.aliasId) - property("alias", s.aliasId.toChars()); + property("alias", s.aliasId.toString()); bool hasRenamed = false; bool hasSelective = false; for (size_t i = 0; i < s.aliases.dim; i++) @@ -562,7 +563,7 @@ public: Identifier name = s.names[i]; Identifier _alias = s.aliases[i]; if (_alias) - property(_alias.toChars(), name.toChars()); + property(_alias.toString(), name.toString()); } objectEnd(); } @@ -571,11 +572,10 @@ public: // import foo : target1; propertyStart("selective"); arrayStart(); - for (size_t i = 0; i < s.names.dim; i++) + foreach (i, name; s.names) { - Identifier name = s.names[i]; if (!s.aliases[i]) - item(name.toChars()); + item(name.toString()); } arrayEnd(); } @@ -634,7 +634,7 @@ public: { if (cd.baseClass && cd.baseClass.ident != Id.Object) { - property("base", cd.baseClass.toPrettyChars(true)); + property("base", cd.baseClass.toPrettyChars(true).toDString); } if (cd.interfaces.length) { @@ -642,7 +642,7 @@ public: arrayStart(); foreach (b; cd.interfaces) { - item(b.sym.toPrettyChars(true)); + item(b.sym.toPrettyChars(true).toDString); } arrayEnd(); } @@ -676,7 +676,7 @@ public: for (size_t i = 0; i < d.foverrides.dim; i++) { FuncDeclaration fd = d.foverrides[i]; - item(fd.toPrettyChars()); + item(fd.toPrettyChars().toDString); } arrayEnd(); } @@ -705,7 +705,7 @@ public: { TemplateParameter s = (*d.parameters)[i]; objectStart(); - property("name", s.ident.toChars()); + property("name", s.ident.toString()); TemplateTypeParameter type = s.isTemplateTypeParameter(); if (type) { @@ -722,9 +722,9 @@ public: property("kind", "value"); property("type", "deco", value.valType); if (value.specValue) - property("specValue", value.specValue.toChars()); + property("specValue", value.specValue.toString()); if (value.defaultValue) - property("defaultValue", value.defaultValue.toChars()); + property("defaultValue", value.defaultValue.toString()); } TemplateAliasParameter _alias = s.isTemplateAliasParameter(); if (_alias) @@ -732,9 +732,9 @@ public: property("kind", "alias"); property("type", "deco", _alias.specType); if (_alias.specAlias) - property("specAlias", _alias.specAlias.toChars()); + property("specAlias", _alias.specAlias.toString()); if (_alias.defaultAlias) - property("defaultAlias", _alias.defaultAlias.toChars()); + property("defaultAlias", _alias.defaultAlias.toString()); } TemplateTupleParameter tuple = s.isTemplateTupleParameter(); if (tuple) @@ -747,7 +747,7 @@ public: Expression expression = d.constraint; if (expression) { - property("constraint", expression.toChars()); + property("constraint", expression.toString()); } propertyStart("members"); arrayStart(); @@ -806,7 +806,7 @@ public: objectStart(); jsonProperties(d); if (d._init) - property("init", d._init.toChars()); + property("init", d._init.toString()); if (d.isField()) property("offset", d.offset); if (d.alignment && d.alignment != STRUCTALIGN_DEFAULT) @@ -850,8 +850,8 @@ public: private void generateCompilerInfo() { objectStart(); - requiredProperty("vendor", global.compiler.vendor); - requiredProperty("version", global._version); + requiredProperty("vendor", global.compiler.vendor.toDString); + requiredProperty("version", global._version.toDString); property("__VERSION__", global.versionNumber()); requiredProperty("interface", determineCompilerInterface()); property("size_t", size_t.sizeof); @@ -900,7 +900,7 @@ public: { foreach (const versionid; *global.versionids) { - item(versionid.toChars()); + item(versionid.toString()); } } arrayEnd(); @@ -921,10 +921,10 @@ public: private void generateBuildInfo() { objectStart(); - requiredProperty("cwd", getcwd(null, 0)); - requiredProperty("argv0", global.params.argv0); - requiredProperty("config", global.inifilename); - requiredProperty("libName", global.params.libname); + requiredProperty("cwd", getcwd(null, 0).toDString); + requiredProperty("argv0", global.params.argv0.toDString); + requiredProperty("config", global.inifilename.toDString); + requiredProperty("libName", global.params.libname.toDString); propertyStart("importPaths"); arrayStart(); @@ -932,7 +932,7 @@ public: { foreach (importPath; *global.params.imppath) { - item(importPath); + item(importPath.toDString); } } arrayEnd(); @@ -941,7 +941,7 @@ public: arrayStart(); foreach (objfile; global.params.objfiles) { - item(objfile); + item(objfile.toDString); } arrayEnd(); @@ -949,7 +949,7 @@ public: arrayStart(); foreach (lib; global.params.libfiles) { - item(lib); + item(lib.toDString); } arrayEnd(); @@ -957,13 +957,13 @@ public: arrayStart(); foreach (ddocFile; global.params.ddocfiles) { - item(ddocFile); + item(ddocFile.toDString); } arrayEnd(); - requiredProperty("mapFile", global.params.mapfile); - requiredProperty("resourceFile", global.params.resfile); - requiredProperty("defFile", global.params.deffile); + requiredProperty("mapFile", global.params.mapfile.toDString); + requiredProperty("resourceFile", global.params.resfile.toDString); + requiredProperty("defFile", global.params.deffile.toDString); objectEnd(); } @@ -981,8 +981,8 @@ public: foreach (m; Module.amodules) { objectStart(); - requiredProperty("name", m.md ? m.md.toChars() : null); - requiredProperty("file", m.srcfile.toChars()); + requiredProperty("name", m.md ? m.md.toString() : null); + requiredProperty("file", m.srcfile.toString()); propertyBool("isRoot", m.isRoot()); if(m.contentImportedFiles.dim > 0) { @@ -990,7 +990,7 @@ public: arrayStart(); foreach (file; m.contentImportedFiles) { - item(file); + item(file.toDString); } arrayEnd(); } @@ -1088,7 +1088,7 @@ JsonFieldFlags tryParseJsonField(const(char)* fieldName) Determines and returns the compiler interface which is one of `dmd`, `ldc`, `gdc` or `sdc`. Returns `null` if no interface can be determined. */ -private const(char)* determineCompilerInterface() +private extern(D) string determineCompilerInterface() { if (!strcmp(global.compiler.vendor, "Digital Mars D")) return "dmd"; diff --git a/src/dmd/module.h b/src/dmd/module.h index 7482adee9cb7..24dc6f7e2817 100644 --- a/src/dmd/module.h +++ b/src/dmd/module.h @@ -177,7 +177,7 @@ struct ModuleDeclaration bool isdeprecated; // if it is a deprecated module Expression *msg; - const char *toChars(); + const char *toChars() const; }; #endif /* DMD_MODULE_H */ diff --git a/src/dmd/root/dcompat.h b/src/dmd/root/dcompat.h new file mode 100644 index 000000000000..e5026ead7d9d --- /dev/null +++ b/src/dmd/root/dcompat.h @@ -0,0 +1,25 @@ +/* Compiler implementation of the D programming language + * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved + * written by Walter Bright + * http://www.digitalmars.com + * Distributed under the Boost Software License, Version 1.0. + * http://www.boost.org/LICENSE_1_0.txt + * https://github.com/dlang/dmd/blob/master/src/mars.h + */ + +#ifndef DMD_ROOT_DCOMPAT_H +#define DMD_ROOT_DCOMPAT_H + +#ifdef __DMC__ +#pragma once +#endif + +/// Represents a D [ ] array +template +struct DArray +{ + size_t length; + T *ptr; +}; + +#endif /* DMD_ROOT_DCOMPAT_H */ diff --git a/src/dmd/root/object.h b/src/dmd/root/object.h index b990693b3d41..e3067e91dbe5 100644 --- a/src/dmd/root/object.h +++ b/src/dmd/root/object.h @@ -16,6 +16,7 @@ #pragma once #endif +#include "dcompat.h" #include typedef size_t hash_t; @@ -57,6 +58,9 @@ class RootObject virtual void print(); virtual const char *toChars(); + /// This function is `extern(D)` and should not be called from C++, + /// as the ABI does not match on some platforms + virtual DArray toString(); virtual void toBuffer(OutBuffer *buf); /** diff --git a/src/dmd/root/outbuffer.d b/src/dmd/root/outbuffer.d index 4ef3528687a5..1695f889e45d 100644 --- a/src/dmd/root/outbuffer.d +++ b/src/dmd/root/outbuffer.d @@ -459,4 +459,3 @@ char[] unsignedToTempString(ulong value, char[] buf, uint radix = 10) @safe } while (value); return buf[i .. $]; } - diff --git a/src/dmd/root/rootobject.d b/src/dmd/root/rootobject.d index 44f2d7cdc7e4..7ece1b69836b 100644 --- a/src/dmd/root/rootobject.d +++ b/src/dmd/root/rootobject.d @@ -62,6 +62,14 @@ extern (C++) class RootObject assert(0); } + /// + extern(D) const(char)[] toString() + { + import core.stdc.string : strlen; + auto p = this.toChars(); + return p[0 .. strlen(p)]; + } + void toBuffer(OutBuffer* buf) nothrow pure @nogc @safe { assert(0); diff --git a/src/dmd/utils.d b/src/dmd/utils.d index d07ad29d2b67..6c438ba75a4f 100644 --- a/src/dmd/utils.d +++ b/src/dmd/utils.d @@ -132,3 +132,9 @@ extern (C++) void escapePath(OutBuffer* buf, const(char)* fname) fname++; } } + +/// Slices a `\0`-terminated C-string, excluding the terminator +const(char)[] toDString (const(char)* s) pure nothrow @nogc +{ + return s ? s[0 .. strlen(s)] : null; +}