diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 26d5d08979391..cde904ebaac1e 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -88,6 +88,24 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the are now ill-formed. +- `__has_feature(modules)` is no longer true when just `-std=c++20` (or higher) + is passed. It's only true if `-fmodules` is passed, which enables Clang's + module map semantics. Objective-C++ of the form + + ```objc + #if __has_feature(modules) + @import Foundation; + #else + #import + #endif + ``` + + previously took the `@import` branch under `-std=c++20` even though no module + maps were in use, which would always fail. + + `__cpp_modules` continues to be the standard macro to use to check if C++20 + modules are available. + ### C++ Specific Potentially Breaking Changes - Clang now more aggressively optimizes away stores to objects after they are diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index 2f7741ff74f9b..f0a9c4889ea2d 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -186,7 +186,7 @@ FEATURE(objc_default_synthesize_properties, LangOpts.ObjC) FEATURE(objc_fixed_enum, LangOpts.ObjC) FEATURE(objc_instancetype, LangOpts.ObjC) FEATURE(objc_kindof, LangOpts.ObjC) -FEATURE(objc_modules, LangOpts.ObjC && LangOpts.Modules) +FEATURE(objc_modules, LangOpts.ObjC && LangOpts.ClangModules) FEATURE(objc_nonfragile_abi, LangOpts.ObjCRuntime.isNonFragile()) FEATURE(objc_property_explicit_atomic, true) FEATURE(objc_protocol_qualifier_mangling, true) @@ -318,7 +318,7 @@ FEATURE(cfi_nvcall_sanitizer, LangOpts.Sanitize.has(SanitizerKind::CFINVCall)) FEATURE(cfi_vcall_sanitizer, LangOpts.Sanitize.has(SanitizerKind::CFIVCall)) FEATURE(kcfi, LangOpts.Sanitize.has(SanitizerKind::KCFI)) FEATURE(kcfi_arity, LangOpts.Sanitize.has(SanitizerKind::KCFI)) -FEATURE(modules, LangOpts.Modules) +FEATURE(modules, LangOpts.ClangModules) FEATURE(safe_stack, LangOpts.Sanitize.has(SanitizerKind::SafeStack)) FEATURE(shadow_call_stack, LangOpts.Sanitize.has(SanitizerKind::ShadowCallStack)) diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index d68784b7efbcd..b4d03a1a3e0b5 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -153,6 +153,7 @@ LANGOPT(Blocks , 1, 0, NotCompatible, "blocks extension to C") LANGOPT(EmitAllDecls , 1, 0, Benign, "emitting all declarations") LANGOPT(MathErrno , 1, 1, NotCompatible, "errno in math functions") LANGOPT(Modules , 1, 0, NotCompatible, "modules semantics") +LANGOPT(ClangModules , 1, 0, Compatible, "Clang header modules") LANGOPT(CPlusPlusModules , 1, 0, Compatible, "C++ modules syntax") LANGOPT(SkipODRCheckInGMF , 1, 0, NotCompatible, "Skip ODR checks for decls in the global module fragment") LANGOPT(BuiltinHeadersInSystemModules, 1, 0, NotCompatible, "builtin headers belong to system modules, and _Builtin_ modules are ignored for cstdlib headers") diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 3a3952a4397be..9f1f4a5a682ee 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -3770,7 +3770,7 @@ defm modulemap_allow_subdirectory_search : BoolFOption <"modulemap-allow-subdire PosFlag, NegFlag, BothFlags<[NoXarchOption], [ClangOption, CC1Option]>>; defm modules : BoolFOption<"modules", - LangOpts<"Modules">, Default, + LangOpts<"ClangModules">, DefaultFalse, PosFlag, NegFlag, BothFlags< diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 6f50defcfaf07..50a2359c0e986 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -4137,6 +4137,11 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, #include "clang/Options/Options.inc" #undef LANG_OPTION_WITH_MARSHALLING + // "Modules semantics" (e.g. cross-translation-unit declaration merging) are + // needed for both Clang (header) modules and C++20 modules, so enable them + // for either. + Opts.Modules = Opts.ClangModules || Opts.CPlusPlusModules; + if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ)) { StringRef Name = A->getValue(); if (Name == "full") { diff --git a/clang/test/Lexer/has_feature_modules.m b/clang/test/Lexer/has_feature_modules.m index 6cea3246892ad..e1f52aedd0793 100644 --- a/clang/test/Lexer/has_feature_modules.m +++ b/clang/test/Lexer/has_feature_modules.m @@ -6,6 +6,13 @@ // RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-NO-MODULES %s // RUN: %clang_cc1 -E -x c -fmodules %s -o - | FileCheck --check-prefix=CHECK-HAS-MODULES %s +// -std=c++20 enables C++ modules but not Clang modules, so __has_feature(modules) +// must only be set when -fmodules is also passed. +// RUN: %clang_cc1 -E -x c++ -std=c++20 %s -o - | FileCheck --check-prefix=CHECK-NO-MODULES %s +// RUN: %clang_cc1 -E -x c++ -std=c++20 -fmodules %s -o - | FileCheck --check-prefix=CHECK-HAS-MODULES %s +// RUN: %clang_cc1 -E -x objective-c++ -std=c++20 %s -o - | FileCheck --check-prefix=CHECK-NO-MODULES %s + + #if __has_feature(modules) int has_modules(); #else