diff --git a/compiler/src/dmd/astenums.d b/compiler/src/dmd/astenums.d index 3a2d65735c..1e30b9f8fc 100644 --- a/compiler/src/dmd/astenums.d +++ b/compiler/src/dmd/astenums.d @@ -18,6 +18,15 @@ enum Sizeok : ubyte done, /// size of aggregate is set correctly } +/// D Language version +enum Edition : ubyte +{ + none, + legacy, /// Before the introduction of editions + v2024, /// Experimental first new edition + latest = v2024 /// Newest edition that this compiler knows of +} + enum Baseok : ubyte { none, /// base classes not computed yet diff --git a/compiler/src/dmd/dmodule.d b/compiler/src/dmd/dmodule.d index 4f84eec7c0..a1a337bd3a 100644 --- a/compiler/src/dmd/dmodule.d +++ b/compiler/src/dmd/dmodule.d @@ -358,6 +358,7 @@ extern (C++) final class Module : Package FileType filetype; // source file type bool hasAlwaysInlines; // contains references to functions that must be inlined bool isPackageFile; // if it is a package.d + Edition edition; // language edition that this module is compiled with Package pkg; // if isPackageFile is true, the Package that contains this package.d Strings contentImportedFiles; // array of files whose content was imported int needmoduleinfo; @@ -477,6 +478,8 @@ extern (C++) final class Module : Package setDocfile(); if (doHdrGen) hdrfile = setOutfilename(global.params.dihdr.name, global.params.dihdr.dir, arg, hdr_ext); + + this.edition = Edition.legacy; } extern (D) this(const(char)[] filename, Identifier ident, int doDocComment, int doHdrGen) diff --git a/compiler/src/dmd/dscope.d b/compiler/src/dmd/dscope.d index 76a26a245f..4719529554 100644 --- a/compiler/src/dmd/dscope.d +++ b/compiler/src/dmd/dscope.d @@ -830,12 +830,18 @@ extern (C++) struct Scope /// Returns: whether to raise DIP1000 warnings (FeatureStabe.default) or errors (FeatureState.enabled) extern (D) FeatureState useDIP1000() { - return (flags & SCOPE.dip1000) ? FeatureState.enabled : FeatureState.disabled; + return (flags & SCOPE.dip1000 || hasEdition(Edition.v2024)) ? FeatureState.enabled : FeatureState.disabled; } /// Returns: whether to raise DIP25 warnings (FeatureStabe.default) or errors (FeatureState.enabled) extern (D) FeatureState useDIP25() { - return (flags & SCOPE.dip25) ? FeatureState.enabled : FeatureState.disabled; + return (flags & SCOPE.dip25 || hasEdition(Edition.v2024)) ? FeatureState.enabled : FeatureState.disabled; + } + + /// Returns: whether this scope compiles with `edition` or later + extern (D) bool hasEdition(Edition edition) + { + return _module && _module.edition >= edition; } } diff --git a/compiler/src/dmd/frontend.h b/compiler/src/dmd/frontend.h index 22e02c382f..0bbabafbcf 100644 --- a/compiler/src/dmd/frontend.h +++ b/compiler/src/dmd/frontend.h @@ -834,6 +834,14 @@ enum class FileType : uint8_t c = 3u, }; +enum class Edition : uint8_t +{ + none = 0u, + legacy = 1u, + v2024 = 2u, + latest = 2u, +}; + struct OutBuffer final { private: @@ -7073,6 +7081,7 @@ public: FileType filetype; bool hasAlwaysInlines; bool isPackageFile; + Edition edition; Package* pkg; Array contentImportedFiles; int32_t needmoduleinfo; diff --git a/compiler/src/dmd/id.d b/compiler/src/dmd/id.d index 9dcf2f5d47..6dbc60b020 100644 --- a/compiler/src/dmd/id.d +++ b/compiler/src/dmd/id.d @@ -531,6 +531,9 @@ immutable Msgtable[] msgtable = { "udaMustUse", "mustuse" }, { "udaStandalone", "standalone" }, + // Editions + { "__edition_latest_do_not_use", }, + // C names, for undefined identifier error messages { "NULL" }, { "TRUE" }, diff --git a/compiler/src/dmd/module.h b/compiler/src/dmd/module.h index 379e8e6973..7f02bec2f3 100644 --- a/compiler/src/dmd/module.h +++ b/compiler/src/dmd/module.h @@ -28,6 +28,14 @@ enum PKG PKGpackage // already determined that's an actual package }; +enum class Edition : unsigned char +{ + none = 0u, + legacy = 1u, + v2024 = 2u, + latest = 2u, +}; + class Package : public ScopeDsymbol { public: @@ -75,6 +83,7 @@ public: FileType filetype; // source file type d_bool hasAlwaysInlines; // contains references to functions that must be inlined d_bool isPackageFile; // if it is a package.d + Edition edition; // language edition that this module is compiled with Package *pkg; // if isPackageFile is true, the Package that contains this package.d Strings contentImportedFiles; // array of files whose content was imported int needmoduleinfo; diff --git a/compiler/src/dmd/parse.d b/compiler/src/dmd/parse.d index 646c4b7d3d..f3a844dff2 100644 --- a/compiler/src/dmd/parse.d +++ b/compiler/src/dmd/parse.d @@ -233,6 +233,15 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } else { + static if (is(typeof(mod.edition))) + if (exps && exps.length > 0) + if (auto id = (*exps)[0].isIdentifierExp()) + if (id.ident == Id.__edition_latest_do_not_use) + { + mod.edition = Edition.latest; + continue; + } + udas = AST.UserAttributeDeclaration.concat(udas, exps); } if (stc) diff --git a/compiler/test/fail_compilation/editions.d b/compiler/test/fail_compilation/editions.d new file mode 100644 index 0000000000..869ee22c11 --- /dev/null +++ b/compiler/test/fail_compilation/editions.d @@ -0,0 +1,16 @@ +/** +Test language editions (currently experimental) + +TEST_OUTPUT: +--- +fail_compilation/editions.d(15): Error: scope parameter `x` may not be returned +--- +*/ +@__edition_latest_do_not_use +module editions; + +@safe: +int* f(scope int* x) +{ + return x; +}