Skip to content

Add "-swift-version <n>" that sets LangOpts.EffectiveLanguageVersion. #4826

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

Merged
merged 1 commit into from
Sep 20, 2016

Conversation

graydon
Copy link
Contributor

@graydon graydon commented Sep 16, 2016

This flag switches the "effective language version" of the compiler,
at least to any version supported (as of this change: 3 <= x <= 4).

At the moment nothing uses it except the language version build
configuration statements (#if swift(...)) and various other places
that report, encode, or otherwise check version numbers.

In the future, it's intended as scaffolding for backwards compatibility.

Resolves SR-2582.

@slavapestov
Copy link
Contributor

@swift-ci Please smoke test

@@ -41,6 +42,9 @@ namespace swift {
/// Language features
///

/// \brief User-overridable language version to compile for.
version::Version EffectiveLanguageVersion = version::Version::getCurrentLanguageVersion();
Copy link
Member

Choose a reason for hiding this comment

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

Can we put this into ModuleDecl? It's plausible that, e.g., the optimizer might want to have multiple modules within the same ASTContext, and those modules might be built with different language modes.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm really hoping we don't need to know that at a module level, and putting it in ModuleDecl means it's not really possible to get at it from the importer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

(I do not feel qualified to judge here -- consensus?)

Copy link
Member

Choose a reason for hiding this comment

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

Ah, the Clang importer basically makes the scenario I'm describing unworkable, because there's only one and it has to pick a language mode. So, that means EffectiveLanguageVersion should stay in LangOptions. Thanks, @jrose-apple

// follows.
versionValid = (value->getValue(scratch)
== version::getSwiftFullVersion(
swift::version::Version::getCurrentLanguageVersion()));
Copy link
Member

Choose a reason for hiding this comment

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

version:: should suffice instead of swift::version::.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

// any version starting with major number 3 or 4.
return Components.size() > 0 &&
(Components[0] == 3 ||
Components[0] == 4);
Copy link
Member

@DougGregor DougGregor Sep 16, 2016

Choose a reason for hiding this comment

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

I think we should reject "3.2", "4.1", etc. dialects that don't exist, and whitelist only those dialects that are explicitly supported.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok. I put in support for 4.x as a sort of cheap means to enable testing that -swift-version actually does change the version (since current == 3.0 already) but I will change this to a shorter whitelist and weaken the test to just confirm that -swift-version 3 keeps working when we do bump the language version.

@@ -67,6 +68,9 @@ class IRGenOptions {
std::vector<std::string> OutputFilenames;
std::string ModuleName;

/// \brief User-overridable language version to compile for.
version::Version EffectiveLanguageVersion = version::Version::getCurrentLanguageVersion();

Copy link
Member

Choose a reason for hiding this comment

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

I don't think you need this; the information is always available (see below).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, thinko -- I was looking at IRGenOptions and for some reason didn't notice IRGenModule was also in scope for this usage.

std::tie(Major, Minor) = version::getSwiftNumericVersion();
unsigned MajorRuntimeVersion = Major;

assert(!Opts.EffectiveLanguageVersion.empty());
Copy link
Member

Choose a reason for hiding this comment

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

I don't know what the version is supposed to mean here... is it the compiler version (because clients want to make sure they're working with a compatible compiler) or is it the language dialect? I suspect the former is actually more useful for a debugger.

... but if we do need to use the EffectiveLanguageVersion, you can get it off the corresponding Swift module or ASTContext.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As far as "what it means", it appears to thread through to an attribute on the CU DIE called dwarf::DW_AT_APPLE_major_runtime_vers which, as far as google can tell, nobody in the world actually uses. It showed up in 2009 in LLVM (apple/swift-llvm@13319ce) and it looks like possibly it was intended to be related to LLDB logic around ObjC runtime versions, but LLDB currently just sniffs the existence of a "telltale section" (https://github.com/apple/swift-lldb/blob/master/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp#L401-L409) and uses it to switch between V1 and V2.

In any case if we're emitting 3 for it now -- as we seem to be doing as of swift 3.0 -- and if ObjC doesn't have a runtime version 3, we're probably already doing wrong here. I'll add a helper function that picks a runtime version to match the current language version, explicitly.

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

We are using the DW_AT_APPLE_runtime_version in the DW_LANG_Swift compile unit to encode the Swift runtime version (actually the swift compiler version because they are thus far identical, cf. rdar://problem/18729762).

The Objective-C runtime version can be found in the second, DW_LANG_ObjC compile unit that is also part of each object file generated by swiftc.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@adrian-prantl Oh, weird, I wonder why I thought this had to do with the associated ObjC runtime. Ok, that makes sense; reverting that change then. Thanks!

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, my understanding is that we always want to emit the current swift runtime version here, even if the source the object was compiled from had a lower effective language version.

@@ -2037,7 +2037,8 @@ class ModuleWriter {
}

void writePrologue(raw_ostream &out) {
out << "// Generated by " << version::getSwiftFullVersion() << "\n"
out << "// Generated by " << version::getSwiftFullVersion(
M.getASTContext().LangOpts.EffectiveLanguageVersion) << "\n"
Copy link
Member

Choose a reason for hiding this comment

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

I flip-flopped a few times, but now I agree: the printed headers from "Swift 3 mode" should be equivalent to what the Swift 3 compiler produced.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does this mean you want it to be something other than getSwiftFullVersion? Like obscure the fact that it came from a newer compiler altogether?

Copy link
Member

Choose a reason for hiding this comment

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

Using getFullSwiftVersion() is reasonable. I was convincing myself that we wanted '3.0' in there when emulating 3.0, but that seems like the right idea.

llvm::raw_svector_ostream versionString(versionStringBuf);
versionString << Version::getCurrentLanguageVersion();
versionString << version;
Copy link
Contributor

Choose a reason for hiding this comment

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

This is used in diagnostics to describe module format mismatches, so I think we have no choice but to print the new version. (Or use a more complicated string.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, it does put the full version string after the '/' in the header; I saw (and intended to preserve) the short bit at the beginning is used to detect format mismatches, but I thought that was the point here: that compiling in -swift-version 3 will produce a version-3-compatible module, and that we're going to conditionalize any evolution of the module format to being "in later effective versions".

Perhaps I'm misunderstanding?

Copy link
Contributor

Choose a reason for hiding this comment

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

Currently, only the short version string is used for diagnostics; actual mismatches are detected using the serialization's VERSION_MAJOR/VERSION_MINOR (itself designed for a stable serialization format that we haven't gotten to yet). The intent is that if the short diagnostic string has changed, we can offer a better diagnostic than just "the module is too old". The full string is mostly just so that we can run strings on a swiftmodule and see where it came from.

Copy link
Contributor Author

@graydon graydon Sep 17, 2016

Choose a reason for hiding this comment

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

Then I'm .. perhaps even more confused here. If the short version is intended for diagnostic output -- of the form "sorry, this is a version <m.n> module!" -- then I would think it should be set to the effective language used to build that module, no? I.e. the way I have it set in this proposal.

I'm happy to change this if I'm misunderstanding, I'm just not sure what to change it to, or why.

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 "I can't load this module because it was built with the Swift %0 compiler", not "I can't load this module because it only supports Swift %0 (as a language)". We are planning to support "Swift 3 modules" in Swift 4, but only if they were built with the Swift 4 compiler.

Copy link
Contributor

Choose a reason for hiding this comment

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

We can tweak the diagnostic too to make that more clear, now that we're planning on having one compiler with two language modes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah ok, setting back to just emit the compiler-associated "current" version in the short string, to help the user identify the cause of the mismatch ("wrong compiler" more than "wrong language version")


#if swift(>=4)
#if swift(>=3)
Copy link
Contributor

Choose a reason for hiding this comment

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

This would pass whether or not the -swift-version is set, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, based on Doug's preference for making an explicit whitelist (above) I can't really make a test that tests anything useful yet; you can only specify version 3, which is what the compiler is anyways. When there's more than one real version on the whiltelist, this test can be updated to be more interesting.

Copy link
Member

@DougGregor DougGregor left a comment

Choose a reason for hiding this comment

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

I'm okay with this.

// dwarf::DW_AT_APPLE_major_runtime_vers) that's appropriate for the effective
// language version in effect for the current compilation unit.
assert(!IGM.Context.LangOpts.EffectiveLanguageVersion.empty());
if (IGM.Context.LangOpts.EffectiveLanguageVersion[0] < 2) {
Copy link
Member

Choose a reason for hiding this comment

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

This is still weird, because Swift only supports the 'nonfragile' Objective-C ABI (i.e., 2), but I guess this maintains the old behavior.

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 this was the ObjC version; I think Clang sets that. @gparker42?

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, this is debug info. @adrian-prantl?

@graydon graydon force-pushed the SR-2582-swift-version branch 2 times, most recently from 47c9637 to 70e3705 Compare September 20, 2016 19:15
This flag switches the "effective language version" of the compiler,
at least to any version supported (as of this change: "3" or "3.0").

At the moment nothing uses it except the language version build
configuration statements (#if swift(...)) and various other places
that report, encode, or otherwise check version numbers.

In the future, it's intended as scaffolding for backwards compatibility.

Fixes SR-2582
@graydon graydon force-pushed the SR-2582-swift-version branch from 70e3705 to 8970d44 Compare September 20, 2016 22:19
@graydon
Copy link
Contributor Author

graydon commented Sep 20, 2016

@swift-ci Please test and merge

1 similar comment
@graydon
Copy link
Contributor Author

graydon commented Sep 20, 2016

@swift-ci Please test and merge

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants