-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[C++20] [Modules] Introduce -fskip-odr-check-in-gmf #79959
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -457,6 +457,28 @@ Note that **currently** the compiler doesn't consider inconsistent macro definit | |
| Currently Clang would accept the above example. But it may produce surprising results if the | ||
| debugging code depends on consistent use of ``NDEBUG`` also in other translation units. | ||
|
|
||
| Definitions consistency | ||
| ^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
|
||
| The C++ language defines that same declarations in different translation units should have | ||
| the same definition, as known as ODR (One Definition Rule). Prior to modules, the translation | ||
| units don't dependent on each other and the compiler itself don't and can't perform a strong | ||
| ODR violation check. Sometimes it is the linker does some jobs related to ODR, where the | ||
| higher level semantics are missing. With the introduction of modules, now the compiler have | ||
| the chance to perform ODR violations with language semantics across translation units. | ||
|
|
||
| However, in the practice we found the existing ODR checking mechanism may be too aggressive. | ||
| In the many issue reports about ODR violation diagnostics, most of them are false positive | ||
| ODR violations and the true positive ODR violations are rarely reported. Also MSVC don't | ||
| perform ODR check for declarations in the global module fragment. | ||
|
||
|
|
||
| So in order to get better user experience, save the time checking ODR and keep consistent | ||
| behavior with MSVC, we disabled the ODR check for the declarations in the global module | ||
| fragment by default. Users who want more strict check can still use the | ||
| ``-Xclang -fno-skip-odr-check-in-gmf`` flag to get the ODR check enabled. It is also | ||
| encouraged to report issues if users find false positive ODR violations or false negative ODR | ||
| violations with the flag enabled. | ||
mizvekov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| ABI Impacts | ||
| ----------- | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| // RUN: %clang -std=c++20 -### -c %s 2>&1 | FileCheck %s | ||
| // RUN: %clang -std=c++20 -fno-skip-odr-check-in-gmf -### -c %s 2>&1 \ | ||
| // RUN: | FileCheck %s --check-prefix=UNUSED | ||
| // RUN: %clang -std=c++20 -Xclang -fno-skip-odr-check-in-gmf -### -c %s 2>&1 \ | ||
| // RUN: | FileCheck %s --check-prefix=NO-SKIP | ||
|
|
||
| // CHECK: -fskip-odr-check-in-gmf | ||
| // UNUSED: warning: argument unused during compilation: '-fno-skip-odr-check-in-gmf' | ||
| // UNUSED-NOT: -fno-skip-odr-check-in-gmf | ||
| // NO-SKIP: -fskip-odr-check-in-gmf{{.*}}-fno-skip-odr-check-in-gmf |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,12 @@ | |
| // RUN: %clang_cc1 -std=c++20 %t/A.cppm -emit-module-interface -o %t/A.pcm | ||
| // RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t -I%t -DDIFFERENT %t/B.cppm -verify | ||
| // RUN: %clang_cc1 -std=c++20 -fprebuilt-module-path=%t -I%t %t/B.cppm -verify | ||
| // | ||
| // Testing the behavior of `-fskip-odr-check-in-gmf` | ||
| // RUN: %clang_cc1 -std=c++20 -fskip-odr-check-in-gmf %t/A.cppm -emit-module-interface -o %t/A.pcm | ||
| // RUN: %clang_cc1 -std=c++20 -fskip-odr-check-in-gmf -fprebuilt-module-path=%t -I%t \ | ||
| // RUN: -DDIFFERENT -DSKIP_ODR_CHECK_IN_GMF %t/B.cppm -verify | ||
|
|
||
|
|
||
| //--- foo.h | ||
| #ifndef FOO_H | ||
|
|
@@ -70,6 +76,16 @@ module; | |
| export module B; | ||
| import A; | ||
|
|
||
| #ifdef SKIP_ODR_CHECK_IN_GMF | ||
| // [email protected]:* {{call to object of type '__fn' is ambiguous}} | ||
| // expected-note@* 1+{{candidate function}} | ||
| #elif defined(DIFFERENT) | ||
| // [email protected]:41 {{'__fn::operator()' from module 'A.<global>' is not present in definition of '__fn' provided earlier}} | ||
| // expected-note@* 1+{{declaration of 'operator()' does not match}} | ||
| #else | ||
| // expected-no-diagnostics | ||
| #endif | ||
|
|
||
| template <class T> | ||
| struct U { | ||
| auto operator+(U) { return 0; } | ||
|
|
@@ -87,10 +103,3 @@ void foo() { | |
|
|
||
| __fn{}(U<int>(), U<int>()); | ||
| } | ||
|
|
||
| #ifdef DIFFERENT | ||
| // [email protected]:* {{call to object of type '__fn' is ambiguous}} | ||
| // expected-note@* 1+{{candidate function}} | ||
| #else | ||
| // expected-no-diagnostics | ||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,12 @@ | |
| // RUN: %clang_cc1 -std=c++20 %t/mod4.cppm -fmodule-file=mod3=%t/mod3.pcm \ | ||
| // RUN: -fsyntax-only -verify | ||
|
|
||
| // Testing the behavior of `-fskip-odr-check-in-gmf` | ||
| // RUN: %clang_cc1 -std=c++20 %t/mod3.cppm -fskip-odr-check-in-gmf \ | ||
| // RUN: -emit-module-interface -o %t/mod3.pcm | ||
| // RUN: %clang_cc1 -std=c++20 %t/mod4.cppm -fmodule-file=mod3=%t/mod3.pcm \ | ||
| // RUN: -fskip-odr-check-in-gmf -DSKIP_ODR_CHECK_IN_GMF -fsyntax-only -verify | ||
|
|
||
| //--- size_t.h | ||
|
|
||
| extern "C" { | ||
|
|
@@ -57,13 +63,17 @@ export module mod3; | |
| export using std::align_val_t; | ||
|
|
||
| //--- mod4.cppm | ||
| // This is actually an ODR violation. But given https://github.com/llvm/llvm-project/issues/79240, | ||
| // we don't count it as an ODR violation now. | ||
| // expected-no-diagnostics | ||
| module; | ||
| #include "signed_size_t.h" | ||
| #include "csize_t" | ||
| #include "align.h" | ||
| export module mod4; | ||
| import mod3; | ||
| export using std::align_val_t; | ||
|
|
||
| #ifdef SKIP_ODR_CHECK_IN_GMF | ||
| // expected-no-diagnostics | ||
| #else | ||
| // [email protected]:* {{'std::align_val_t' has different definitions in different modules; defined here first difference is enum with specified type 'size_t' (aka 'int')}} | ||
| // [email protected]:* {{but in 'mod3.<global>' found enum with specified type 'size_t' (aka 'unsigned int')}} | ||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| // RUN: rm -rf %t | ||
| // RUN: mkdir -p %t | ||
| // RUN: split-file %s %t | ||
| // | ||
| // Baseline testing to make sure we can detect the ODR violation from the CC1 invocation. | ||
| // RUNX: %clang_cc1 -std=c++20 %t/a.cppm -emit-module-interface -o %t/a.pcm | ||
| // RUNX: %clang_cc1 -std=c++20 %t/b.cppm -emit-module-interface -o %t/b.pcm | ||
| // RUNX: %clang_cc1 -std=c++20 %t/test.cc -fprebuilt-module-path=%t -fsyntax-only -verify | ||
| // | ||
| // Testing that we can ignore the ODR violation from the driver invocation. | ||
| // RUN: %clang -std=c++20 %t/a.cppm --precompile -o %t/a.pcm | ||
| // RUN: %clang -std=c++20 %t/b.cppm --precompile -o %t/b.pcm | ||
| // RUN: %clang -std=c++20 %t/test.cc -fprebuilt-module-path=%t -fsyntax-only -Xclang -verify \ | ||
| // RUN: -DIGNORE_ODR_VIOLATION | ||
| // | ||
| // Testing that the driver can require to check the ODR violation. | ||
| // RUN: %clang -std=c++20 -Xclang -fno-skip-odr-check-in-gmf %t/a.cppm --precompile -o %t/a.pcm | ||
| // RUN: %clang -std=c++20 -Xclang -fno-skip-odr-check-in-gmf %t/b.cppm --precompile -o %t/b.pcm | ||
| // RUN: %clang -std=c++20 -Xclang -fno-skip-odr-check-in-gmf %t/test.cc -fprebuilt-module-path=%t \ | ||
| // RUN: -fsyntax-only -Xclang -verify | ||
|
|
||
| //--- func1.h | ||
| bool func(int x, int y) { | ||
| return true; | ||
| } | ||
|
|
||
| //--- func2.h | ||
| bool func(int x, int y) { | ||
| return false; | ||
| } | ||
|
|
||
| //--- a.cppm | ||
| module; | ||
| #include "func1.h" | ||
| export module a; | ||
| export using ::func; | ||
|
|
||
| //--- b.cppm | ||
| module; | ||
| #include "func2.h" | ||
| export module b; | ||
| export using ::func; | ||
|
|
||
| //--- test.cc | ||
| import a; | ||
| import b; | ||
| bool test() { | ||
| return func(1, 2); | ||
| } | ||
|
|
||
| #ifdef IGNORE_ODR_VIOLATION | ||
| // expected-no-diagnostics | ||
| #else | ||
| // [email protected]:1 {{'func' has different definitions in different modules;}} | ||
| // [email protected]:1 {{but in 'a.<global>' found a different body}} | ||
| #endif |
Uh oh!
There was an error while loading. Please reload this page.