From cb8ac8e4b8c1fd9684f43fa5916f73d494ed817f Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 11 Apr 2019 15:29:25 +0200 Subject: Default to strict mode (/permissive-) from VC15.5 --- build2/cc/compile-rule.cxx | 2 +- build2/cxx/init.cxx | 376 +++++++++++++++++++++++---------------------- build2/target.hxx | 2 +- 3 files changed, 191 insertions(+), 189 deletions(-) (limited to 'build2') diff --git a/build2/cc/compile-rule.cxx b/build2/cc/compile-rule.cxx index 9e307b6..3ed6075 100644 --- a/build2/cc/compile-rule.cxx +++ b/build2/cc/compile-rule.cxx @@ -3183,7 +3183,7 @@ namespace build2 if (ps) psrc.active = true; // Re-arm. - // Prior to 15u5 (19.12) VC was not using the 'export module M;' + // Prior to 15.5 (19.12) VC was not using the 'export module M;' // syntax so we use the preprequisite type to distinguish between // interface and implementation units. // diff --git a/build2/cxx/init.cxx b/build2/cxx/init.cxx index 7174121..d32012c 100644 --- a/build2/cxx/init.cxx +++ b/build2/cxx/init.cxx @@ -73,245 +73,247 @@ namespace build2 bool modules (false); auto& v_m (enter ("cxx.features.modules")); // Translate "latest" and "experimental" to the compiler/version- - // appropriate option(s). + // appropriate option(s). Experimental is normally like latest with + // extra stuff enabled via additional flags. Otherwise translate the + // standard value. // - if (v != nullptr && (*v == "latest" || *v == "experimental")) - { - // Experimental is like latest with some extra stuff enabled via - // additional switches. - // - const char* o (nullptr); + bool experimental ( v != nullptr && *v == "experimental"); + bool latest (experimental || (v != nullptr && *v == "latest")); + + string o; - switch (ct) + switch (cl) + { + case compiler_class::msvc: { - case compiler_type::msvc: + // C++ standard-wise, with VC you got what you got up until 14.2. + // Starting with 14.3 there is now the /std: switch which defaults + // to c++14 but can be set to c++latest. And from 15.3 it can be + // c++17. + // + // The question is also whether we should verify that the requested + // standard is provided by this VC version. And if so, from which + // version should we say VC supports 11, 14, and 17? We should + // probably be as loose as possible here since the author will + // always be able to tighten (but not loosen) this in the buildfile + // (i.e., detect unsupported versions). + // + // For now we are not going to bother doing this for C++03. + // + if (latest) { - // VC14u3 and later has /std:c++latest. - // if (mj > 19 || (mj == 19 && (mi > 0 || (mi == 0 && p >= 24215)))) o = "/std:c++latest"; - - break; } - case compiler_type::gcc: + else if (v == nullptr) + ; + else if (*v != "98" && *v != "03") { - if (mj >= 8) o = "-std=c++2a"; // 20 - else if (mj >= 5) o = "-std=c++1z"; // 17 - else if (mj == 4 && mi >= 8) o = "-std=c++1y"; // 14 - else if (mj == 4 && mi >= 4) o = "-std=c++0x"; // 11 + bool sup (false); - break; - } - case compiler_type::clang: - { - // Remap Apple versions to vanilla Clang based on the following - // release point. Note that Apple no longer discloses the mapping - // so it's a guesswork and we try to be conservative. For details - // see: - // - // https://gist.github.com/yamaya/2924292 - // - // 5.1 -> 3.4 - // 6.0 -> 3.5 - // 7.0 -> 3.7 - // 7.3 -> 3.8 - // 8.0 -> 3.9 - // 9.0 -> 4.0 (later ones could be 5.0) - // 9.1 -> ? - // 10.0 -> ? - // - // Note that this mapping is also used to enable experimental - // features below. - // - if (ci.id.variant == "apple") + if (*v == "11") // C++11 since VS2010/10.0. + { + sup = mj >= 16; + } + else if (*v == "14") // C++14 since VS2015/14.0. + { + sup = mj >= 19; + } + else if (*v == "17") // C++17 since VS2015/14.0u2. { - if (mj >= 9) {mj = 4; mi = 0;} - else if (mj == 8) {mj = 3; mi = 9;} - else if (mj == 7 && mi >= 3) {mj = 3; mi = 8;} - else if (mj == 7) {mj = 3; mi = 7;} - else if (mj == 6) {mj = 3; mi = 5;} - else if (mj == 5 && mi >= 1) {mj = 3; mi = 4;} - else {mj = 3; mi = 0;} + // Note: the VC15 compiler version is 19.10. + // + sup = (mj > 19 || + (mj == 19 && (mi > 0 || (mi == 0 && p >= 23918)))); } - if (mj >= 5) o = "-std=c++2a"; // 20 - else if (mj > 3 || (mj == 3 && mi >= 5)) o = "-std=c++1z"; // 17 - else if (mj == 3 && mi >= 4) o = "-std=c++1y"; // 14 - else /* ??? */ o = "-std=c++0x"; // 11 + if (!sup) + fail << "C++" << *v << " is not supported by " << ci.signature << + info << "required by " << project (rs) << '@' << rs.out_path (); - break; + if (mj > 19 || (mj == 19 && mi >= 11)) // 15.3 + { + if (*v == "14") o = "/std:c++14"; + else if (*v == "17") o = "/std:c++17"; + } + else if (mj == 19 && (mi > 0 || (mi == 0 && p >= 24215))) // 14.3 + { + if (*v == "14") o = "/std:c++14"; + else if (*v == "17") o = "/std:c++latest"; + } } - case compiler_type::icc: - { - if (mj >= 17) o = "-std=c++1z"; // 17 - else if (mj > 15 || (mj == 15 && p >= 3)) o = "-std=c++1y"; // 14 - else /* ??? */ o = "-std=c++0x"; // 11 - break; - } - } + if (!o.empty ()) + r.push_back (move (o)); - if (o != nullptr) - r.push_back (o); + // Starting with 15.5 (19.12) Visual Studio-created projects default + // to the strict mode. + // + if (mj > 19 || (mj == 19 && mi >= 12)) + r.push_back ("/permissive-"); - if (*v == "experimental") + break; + } + case compiler_class::gcc: { - // Unless disabled by the user, try to enable C++ modules. Here - // we use a tri-state: - // - // - false - disabled - // - unspecified - enabled if practically usable - // - true - enabled even if practically unusable - // - lookup l; - if (!(l = rs[v_m]) || cast (l)) + if (latest) { switch (ct) { - case compiler_type::msvc: - { - // While modules are supported in VC15u0 (19.10), there is a - // bug in separate interface/implementation unit support which - // makes them pretty much unusable. This has been fixed in - // VC15u3 (19.11). And VC15u5 (19.12) supports the 'export - // module M;' syntax. - // - if (mj > 19 || (mj == 19 && mi >= (l ? 10 : 12))) - { - r.push_back ( - mj > 19 || mi > 11 - ? "/D__cpp_modules=201704" // p0629r0 (export module M;) - : "/D__cpp_modules=201703"); // n4647 ( module M;) - - r.push_back ("/experimental:module"); - modules = true; - } - break; - } case compiler_type::gcc: { - // Enable starting with GCC 9.0.0 (currently the c++-modules - // branch). - // - if (mj >= 9 && - ci.version.build.find ("c++-modules") != string::npos) - { - // Currently defines __cpp_modules=201810 which is said to - // correspond to p1103 (merged modules). - // - r.push_back ("-fmodules-ts"); - modules = true; - } + if (mj >= 8) o = "-std=c++2a"; // 20 + else if (mj >= 5) o = "-std=c++1z"; // 17 + else if (mj == 4 && mi >= 8) o = "-std=c++1y"; // 14 + else if (mj == 4 && mi >= 4) o = "-std=c++0x"; // 11 + break; } case compiler_type::clang: { - // Enable starting with Clang 6.0.0. + // Remap Apple versions to vanilla Clang based on the + // following release point. Note that Apple no longer + // discloses the mapping so it's a guesswork and we try to be + // conservative. For details see: // - // Note that we are using Apple to vanilla Clang version re- - // map from above so may need to update things there as well. + // https://gist.github.com/yamaya/2924292 // - // Also see Clang modules support hack in cc::compile. + // 5.1 -> 3.4 + // 6.0 -> 3.5 + // 7.0 -> 3.7 + // 7.3 -> 3.8 + // 8.0 -> 3.9 + // 9.0 -> 4.0 (later ones could be 5.0) + // 9.1 -> ? + // 10.0 -> ? // - if (mj >= 6) + // Note that this mapping is also used to enable experimental + // features below. + // + if (ci.id.variant == "apple") { - r.push_back ("-D__cpp_modules=201704"); // p0629r0 - r.push_back ("-fmodules-ts"); - modules = true; + if (mj >= 9) {mj = 4; mi = 0;} + else if (mj == 8) {mj = 3; mi = 9;} + else if (mj == 7 && mi >= 3) {mj = 3; mi = 8;} + else if (mj == 7) {mj = 3; mi = 7;} + else if (mj == 6) {mj = 3; mi = 5;} + else if (mj == 5 && mi >= 1) {mj = 3; mi = 4;} + else {mj = 3; mi = 0;} } + + if (mj >= 5) o = "-std=c++2a"; + else if (mj > 3 || (mj == 3 && mi >= 5)) o = "-std=c++1z"; + else if (mj == 3 && mi >= 4) o = "-std=c++1y"; + else /* ??? */ o = "-std=c++0x"; + break; } case compiler_type::icc: - break; // No modules support yet. + { + if (mj >= 17) o = "-std=c++1z"; + else if (mj > 15 || (mj == 15 && p >= 3)) o = "-std=c++1y"; + else /* ??? */ o = "-std=c++0x"; + + break; + } + default: + assert (false); } } + else if (v == nullptr) + ; + else + { + // Translate 11 to 0x, 14 to 1y, 17 to 1z, and 20 to 2a for + // compatibility with older versions of the compilers. + // + o = "-std="; + + if (*v == "98") o += "c++98"; + else if (*v == "03") o += "c++03"; + else if (*v == "11") o += "c++0x"; + else if (*v == "14") o += "c++1y"; + else if (*v == "17") o += "c++1z"; + else if (*v == "20") o += "c++2a"; + else o += *v; // In case the user specifies e.g., 'gnu++17'. + } + + if (!o.empty ()) + r.push_back (move (o)); + + break; } } - else + + if (experimental) { - // Otherwise translate the standard value. + // Unless disabled by the user, try to enable C++ modules. Here we use + // a tri-state: // - switch (cl) + // - false - disabled + // - unspecified - enabled if practically usable + // - true - enabled even if practically unusable + // + lookup l; + if (!(l = rs[v_m]) || cast (l)) { - case compiler_class::msvc: + switch (ct) { - // C++ standard-wise, with VC you got what you got up until 14u2. - // Starting with 14u3 there is now the /std: switch which defaults - // to c++14 but can be set to c++latest. And from 15u3 it can be - // c++17. - // - // The question is also whether we should verify that the - // requested standard is provided by this VC version. And if so, - // from which version should we say VC supports 11, 14, and 17? We - // should probably be as loose as possible here since the author - // will always be able to tighten (but not loosen) this in the - // buildfile (i.e., detect unsupported versions). - // - // For now we are not going to bother doing this for C++03. - // - if (v == nullptr) - ; - else if (*v != "98" && *v != "03") + case compiler_type::msvc: { - bool sup (false); - - if (*v == "11") // C++11 since VS2010/10.0. + // While modules are supported in VC15.0 (19.10), there is a bug + // in separate interface/implementation unit support which makes + // them pretty much unusable. This has been fixed in VC15.3 + // (19.11). And VC15.5 (19.12) supports the 'export module M;' + // syntax. + // + if (mj > 19 || (mj == 19 && mi >= (l ? 10 : 12))) { - sup = mj >= 16; - } - else if (*v == "14") // C++14 since VS2015/14.0. - { - sup = mj >= 19; - } - else if (*v == "17") // C++17 since VS2015/14.0u2. - { - // Note: the VC15 compiler version is 19.10. - // - sup = (mj > 19 || - (mj == 19 && (mi > 0 || (mi == 0 && p >= 23918)))); - } - - if (!sup) - fail << "C++" << *v << " is not supported by " - << ci.signature << - info << "required by " << project (rs) << '@' - << rs.out_path (); + r.push_back ( + mj > 19 || mi > 11 + ? "/D__cpp_modules=201704" // p0629r0 (export module M;) + : "/D__cpp_modules=201703"); // n4647 ( module M;) - if (mj > 19 || (mj == 19 && mi >= 11)) // 15u3 - { - if (*v == "14") r.push_back ("/std:c++14"); - else if (*v == "17") r.push_back ("/std:c++17"); + r.push_back ("/experimental:module"); + modules = true; } - else if (mj == 19 && (mi > 0 || (mi == 0 && p >= 24215))) // 14u3 + break; + } + case compiler_type::gcc: + { + // Enable starting with GCC 9.0.0 (currently the c++-modules + // branch). + // + if (mj >= 9 && + ci.version.build.find ("c++-modules") != string::npos) { - if (*v == "14") r.push_back ("/std:c++14"); - else if (*v == "17") r.push_back ("/std:c++latest"); + // Currently defines __cpp_modules=201810 which is said to + // correspond to p1103 (merged modules). + // + r.push_back ("-fmodules-ts"); + modules = true; } + break; } - break; - } - case compiler_class::gcc: - { - // Translate 11 to 0x, 14 to 1y, 17 to 1z, and 20 to 2a for - // compatibility with older versions of the compilers. - // - if (v == nullptr) - ; - else + case compiler_type::clang: { - string o ("-std="); - - if (*v == "98") o += "c++98"; - else if (*v == "03") o += "c++03"; - else if (*v == "11") o += "c++0x"; - else if (*v == "14") o += "c++1y"; - else if (*v == "17") o += "c++1z"; - else if (*v == "20") o += "c++2a"; - else o += *v; // In case the user specifies e.g., 'gnu++17'. - - r.push_back (move (o)); + // Enable starting with Clang 6.0.0. + // + // Note that we are using Apple to vanilla Clang version re-map + // from above so may need to update things there as well. + // + // Also see Clang modules support hack in cc::compile. + // + if (mj >= 6) + { + r.push_back ("-D__cpp_modules=201704"); // p0629r0 + r.push_back ("-fmodules-ts"); + modules = true; + } + break; } - break; + case compiler_type::icc: + break; // No modules support yet. } } } diff --git a/build2/target.hxx b/build2/target.hxx index fafb689..cb1163f 100644 --- a/build2/target.hxx +++ b/build2/target.hxx @@ -51,7 +51,7 @@ namespace build2 // // Note that max size for the "small capture optimization" in std::function // ranges (in pointer sizes) from 0 (GCC prior to 5) to 2 (GCC 5) to 6 (VC - // 14u2). With the size ranging (in bytes for 64-bit target) from 32 (GCC) + // 14.2). With the size ranging (in bytes for 64-bit target) from 32 (GCC) // to 64 (VC). // using recipe_function = target_state (action, const target&); -- cgit v1.1