Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add -std=c++98 to compiler #9029

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions changelog/cpp98.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
Ddoc

$(H2 Transition to C++11 character types)

With C++11 comes the advent of changed character type mangling.
D's default behavior is now to conform to this. However, this
will break existing code. Therefore, the old behavior can be
retained by using the -std=c++98 compiler switch. This
will also set the predefined version Cpp98.
For Win32 compilations using Digital Mars C++, version Cpp98 will
be predefined.

Of particular note is the new difference between wchar and wchar_t on
Windows. This will manifest itself as compile errors when
interfacing wchar* with wchar_t* code when calling the Windows API.
A cast will resolve the issue.

Going forward we recommend using WCHAR instead of wchar or wchar_t
when interfacing to Windows API functions. (WCHAR is Microsoft
Windows' 16 bit character type.)

$(H3 C++ Type Equivalence)

$(H4 Cpp98 behavior:)

$(TABLE
$(THEAD D , Posix , DMC++ Windows , VC++ Windows)

$(TROW wchar , unsigned short , wchar_t , wchar_t)
$(TROW dchar , wchar_t , unsigned , unsigned)
$(TROW wchar_t , wchar_t , wchar_t , wchar_t)
$(TROW WCHAR , -- , wchar_t , wchar_t))

$(H4 New behavior:)

$(TABLE
$(THEAD D , Posix , DMC++ Windows , VC++ Windows)

$(TROW wchar , char16_t , wchar_t , char16_t)
$(TROW dchar , char32_t , unsigned , char32_t)
$(TROW wchar_t , wchar_t , wchar , wchar_t)
$(TROW WCHAR , -- , wchar , wchar_t))


$(H3 Name Mangling:)

$(H4 Cpp98 behavior:)

$(TABLE
$(THEAD D , Posix , DMC++ Windows , VC++ Windows)

$(TROW wchar , t , _Y , _W)
$(TROW dchar , w , I , I)
$(TROW wchar_t , w , _Y , _W))

$(H4 New behavior:)

$(TABLE
$(THEAD D , Posix , DMC++ Windows , VC++ Windows)

$(TROW wchar , Ds , _Y , _S)
$(TROW dchar , Di , I , _U)
$(TROW wchar_t , w , _Y , _W))

8 changes: 8 additions & 0 deletions src/dmd/cli.d
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,14 @@ dmd -cov -unittest myprog.d
`$(UNIX Generate shared library)
$(WINDOWS Generate DLL library)`,
),
Option("std=<standard>",
"set compatiblity with <standard>",
"Standards supported are:
$(UL
$(LI $(I c++98): Use older C++98 name mangling,
Predefines `Cpp98` $(LINK2 $(ROOT_DIR)spec/version.html#predefined-versions, version))
)",
),
Option("transition=<id>",
"help with language change identified by 'id'",
`Show additional info about language change identified by $(I id)`,
Expand Down
1 change: 1 addition & 0 deletions src/dmd/cond.d
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,7 @@ extern (C++) final class VersionCondition : DVCondition
case "CppRuntime_Gcc":
case "CppRuntime_Microsoft":
case "CppRuntime_Sun":
case "Cpp98":
case "unittest":
case "assert":
case "all":
Expand Down
2 changes: 2 additions & 0 deletions src/dmd/globals.d
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,14 @@ struct Param
bool fix16997; // fix integral promotions for unary + - ~ operators
// https://issues.dlang.org/show_bug.cgi?id=16997
bool fixAliasThis; // if the current scope has an alias this, check it before searching upper scopes

/** The --transition=safe switch should only be used to show code with
* silent semantics changes related to @safe improvements. It should not be
* used to hide a feature that will have to go through deprecate-then-error
* before becoming default.
*/
bool vsafe; // use enhanced @safe checking
bool cpp98; // follow C++98 type system issues rather than C++11
bool ehnogc; // use @nogc exception handling
bool dtorFields; // destruct fields of partially constructed objects
// https://issues.dlang.org/show_bug.cgi?id=14246
Expand Down
3 changes: 2 additions & 1 deletion src/dmd/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ struct Param
bool fix16997; // fix integral promotions for unary + - ~ operators
// https://issues.dlang.org/show_bug.cgi?id=16997
bool vsafe; // use enhanced @safe checking
bool ehnogc; // use @nogc exception handling
bool cpp98; // follow C++98 type system issues rather than C++11
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type system issues
type mangling rules?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a little more than just mangling.

bool ehnogc; // use @nogc exception handling
bool dtorFields; // destruct fields of partially constructed objects
// https://issues.dlang.org/show_bug.cgi?id=14246
bool showGaggedErrors; // print gagged errors anyway
Expand Down
15 changes: 15 additions & 0 deletions src/dmd/mars.d
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,9 @@ void addDefaultVersionIdentifiers(const ref Param params)
VersionCondition.addPredefinedGlobalIdent("D_Version2");
VersionCondition.addPredefinedGlobalIdent("all");

if (params.cpp98)
VersionCondition.addPredefinedGlobalIdent("Cpp98");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think a version identifier should be set. I think it's more suitable to use __traits(getTargetInfo) for this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a good point. versions are boolean; a version token is either on or off, whereas this is a case where the C++ compatibility mode is a value from an enum...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't see preferring:

static if (__traits(getTargetInfo, CppLevel) == 98)

over:

version (Cpp98)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is probably 90% use case:

static if (__traits(getTargetInfo, CppStd) >= CppStd.Cpp11)

This thing is definitely an enum, not a set of bool's.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@WalterBright If you want to use a version, then what do you do when you'll want to add Cpp11 or Cpp17?

  • Do you make Cpp17 not imply Cpp98? Then, D code needs to be updated to check for both.

  • Do you make Cpp17 also automatically enable Cpp98? Then, what do you do in D code to detect Cpp98 specifically? version(Cpp98) { version(Cpp17) {} else { /*do C++98 thing*/ }} is a mouthful, but also, it breaks if you decide to introduce Cpp11 or another interim version later.

Manu is right - an enum solves both of these problems. Version numbers are points on a range, not a set of flags.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That doesn't make sense... There's 2 moments with respect to everything that might have version distinction; before X, and after X. Versions dont express this.

What is your motive to resist on this? I don't understand the criticism.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'll be fine.

That doesn't tackle the problem, though. Do you duplicate the code in Cpp17? And what do you do when Cpp11 is introduced?

What is your motive to resist on this? I don't understand the criticism.

I'd be willing to guess 1) the implementation is much simpler 2) the implementation is already written.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That doesn't tackle the problem, though. Do you duplicate the code in Cpp17? And what do you do when Cpp11 is introduced?

The same thing we do with operating system versions. There's a very good reason why versions are binary, not a level. Levels result in bugs, because they are open-ended rather than closed. With that and the code duplication argument, I've gone over that in the forum innumerable times, though I can't seem to get the druntime code to follow the idea correctly. People can't let go of the brittle C way of doing it.

Lastly, the Cpp98 is purposely looking backwards, not forwards. C++98 is not going to be changing, by definition. Cpp98 means "be compatible with the old version which will not ever change", not "be compatible with the latest version whatever that may be". This is why the use is:

version (Cpp98)
   ... do it the old C++ 98 way ...
else
   ... do it the latest way ...

not:

version (Cpp11orNewer)
    ... do it the latest way ...
else
    ... do it the C++98 way ...

It's a different way of framing the problem, and in my not-so-humble opinion, a better way.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same thing we do with operating system versions. There's a very good reason why versions are binary, not a level.

Which ones are you referring to - linux / Windows / etc.?

  • WINVER is a number. (Theres _WIN32_WINNT_VISTA etc. but I don't think anyone uses those; also, those go in the other direction, i.e._WIN32_WINNT_WIN7 implies _WIN32_WINNT_VISTA is on).

  • _MSC_VER is a number.

  • __GNUC__ is a number.

  • __cplusplus is a number.

  • ???

I guess you're saying Cpp98 doesn't need to be a number because of what it does? Then, maybe, it is a bad / confusing name. Perhaps call it PreCpp11Mangling or something...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a waste having to add a new version identifier for each version of C++. It's also receivers yet another version identifier that cannot be used by the user. BTW, therefore this is a breaking change. I might already be using the Cpp98 version identifier and now my code will stop compiling since suddenly Cpp98 is reserved. Using a trait prevents that.


if (params.cpu >= CPU.sse2)
{
VersionCondition.addPredefinedGlobalIdent("D_SIMD");
Expand Down Expand Up @@ -2054,6 +2057,10 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param
params.manual = true;
return false;
}
else if (arg == "-std=c++98") // https://dlang.org/dmd.html#switch-std
{
params.cpp98 = true;
}
else if (arg == "-run") // https://dlang.org/dmd.html#switch-run
{
params.run = true;
Expand Down Expand Up @@ -2190,6 +2197,14 @@ private void reconcileCommands(ref Param params, size_t numSrcFiles)
params.useExceptions = false;
}

/* TEMPORARILY set this to true until the runtime library is updated,
* in order to not leave the system in an unbuildable state.
*/
params.cpp98 = true;

if (params.isWindows && !params.mscoff)
params.cpp98 = true; // DMC++ is a C++98 compiler


if (!params.obj || params.lib)
params.link = false;
Expand Down
3 changes: 3 additions & 0 deletions test/fail_compilation/reserved_version.d
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ fail_compilation/reserved_version.d(206): Error: version identifier `CppRuntime_
fail_compilation/reserved_version.d(207): Error: version identifier `CppRuntime_Gcc` is reserved and cannot be set
fail_compilation/reserved_version.d(208): Error: version identifier `CppRuntime_Microsoft` is reserved and cannot be set
fail_compilation/reserved_version.d(209): Error: version identifier `CppRuntime_Sun` is reserved and cannot be set
fail_compilation/reserved_version.d(210): Error: version identifier `Cpp98` is reserved and cannot be set
---
*/

Expand Down Expand Up @@ -216,6 +217,7 @@ version = CppRuntime_DigitalMars;
version = CppRuntime_Gcc;
version = CppRuntime_Microsoft;
version = CppRuntime_Sun;
version = Cpp98;

// This should work though
debug = DigitalMars;
Expand Down Expand Up @@ -300,6 +302,7 @@ debug = CppRuntime_DigitalMars;
debug = CppRuntime_Gcc;
debug = CppRuntime_Microsoft;
debug = CppRuntime_Sun;
debug = Cpp98;
debug = D_Coverage;
debug = D_Ddoc;
debug = D_InlineAsm_X86;
Expand Down
3 changes: 3 additions & 0 deletions test/fail_compilation/reserved_version_switch.d
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
// REQUIRED_ARGS: -version=CppRuntime_Gcc
// REQUIRED_ARGS: -version=CppRuntime_Microsoft
// REQUIRED_ARGS: -version=CppRuntime_Sun
// REQUIRED_ARGS: -version=Cpp98
// REQUIRED_ARGS: -version=D_Coverage
// REQUIRED_ARGS: -version=D_Ddoc
// REQUIRED_ARGS: -version=D_InlineAsm_X86
Expand Down Expand Up @@ -178,6 +179,7 @@
// REQUIRED_ARGS: -debug=CppRuntime_Gcc
// REQUIRED_ARGS: -debug=CppRuntime_Microsoft
// REQUIRED_ARGS: -debug=CppRuntime_Sun
// REQUIRED_ARGS: -debug=Cpp98
// REQUIRED_ARGS: -debug=D_Coverage
// REQUIRED_ARGS: -debug=D_Ddoc
// REQUIRED_ARGS: -debug=D_InlineAsm_X86
Expand Down Expand Up @@ -279,6 +281,7 @@ Error: version identifier `CppRuntime_DigitalMars` is reserved and cannot be set
Error: version identifier `CppRuntime_Gcc` is reserved and cannot be set
Error: version identifier `CppRuntime_Microsoft` is reserved and cannot be set
Error: version identifier `CppRuntime_Sun` is reserved and cannot be set
Error: version identifier `Cpp98` is reserved and cannot be set
Error: version identifier `D_Coverage` is reserved and cannot be set
Error: version identifier `D_Ddoc` is reserved and cannot be set
Error: version identifier `D_InlineAsm_X86` is reserved and cannot be set
Expand Down