-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
[clang] implement current direction of CWG2765 for string literal comparisons in constant evaluation #109208
[clang] implement current direction of CWG2765 for string literal comparisons in constant evaluation #109208
Changes from all commits
8119356
2f8cfbe
def1aa7
0e8200b
7286ca9
8dbf826
077f4f8
4c869c9
f221777
fe947fa
be369dd
2b033b2
9939280
a9d6923
6cf8d3b
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 |
---|---|---|
|
@@ -99,7 +99,7 @@ constexpr int f() { | |
static_assert(f()); | ||
#endif | ||
|
||
/// Distinct literals have disctinct addresses. | ||
/// Distinct literals have distinct addresses. | ||
/// see https://github.com/llvm/llvm-project/issues/58754 | ||
constexpr auto foo(const char *p) { return p; } | ||
constexpr auto p1 = "test1"; | ||
|
@@ -108,22 +108,16 @@ constexpr auto p2 = "test2"; | |
constexpr bool b1 = foo(p1) == foo(p1); | ||
static_assert(b1); | ||
|
||
constexpr bool b2 = foo(p1) == foo(p2); // ref-error {{must be initialized by a constant expression}} \ | ||
// ref-note {{comparison of addresses of literals}} \ | ||
// ref-note {{declared here}} | ||
static_assert(!b2); // ref-error {{not an integral constant expression}} \ | ||
// ref-note {{not a constant expression}} | ||
constexpr bool b2 = foo(p1) == foo(p2); | ||
static_assert(!b2); | ||
|
||
constexpr auto name1() { return "name1"; } | ||
constexpr auto name2() { return "name2"; } | ||
|
||
constexpr auto b3 = name1() == name1(); | ||
static_assert(b3); | ||
constexpr auto b4 = name1() == name2(); // ref-error {{must be initialized by a constant expression}} \ | ||
// ref-note {{has unspecified value}} \ | ||
// ref-note {{declared here}} | ||
static_assert(!b4); // ref-error {{not an integral constant expression}} \ | ||
// ref-note {{not a constant expression}} | ||
constexpr auto b3 = name1() == name1(); // ref-error {{must be initialized by a constant expression}} \ | ||
// ref-note {{comparison of addresses of literals}} | ||
constexpr auto b4 = name1() == name2(); | ||
static_assert(!b4); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just from looking at these few lines, I don't understand why The bytecode interpreter simply creates global variables for string literals, so There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The C++ model in general is that each evaluation of a string literal expression can produce a distinct object, and that these objects can fully or partially overlap each other in memory when they have suitable values; that's the model that this PR is implementing.
|
||
|
||
namespace UninitializedFields { | ||
class A { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// RUN: rm -rf %t | ||
// RUN: mkdir -p %t | ||
// RUN: split-file %s %t | ||
|
||
// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/a.cpp \ | ||
// RUN: -o %t/A.pcm | ||
|
||
// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/b.cpp \ | ||
// RUN: -fmodule-file=A=%t/A.pcm -o %t/B.pcm | ||
|
||
// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/c.cpp \ | ||
// RUN: -fmodule-file=A=%t/A.pcm -o %t/C.pcm | ||
|
||
// RUN: %clang_cc1 -std=c++20 -verify %t/main.cpp \ | ||
// RUN: -fmodule-file=A=%t/A.pcm \ | ||
// RUN: -fmodule-file=B=%t/B.pcm \ | ||
// RUN: -fmodule-file=C=%t/C.pcm | ||
|
||
// expected-no-diagnostics | ||
|
||
//--- a.cpp | ||
|
||
export module A; | ||
export consteval const char *hello() { return "hello"; } | ||
export constexpr const char *helloA0 = hello(); | ||
export constexpr const char *helloA1 = helloA0; | ||
export constexpr const char *helloA2 = hello(); | ||
|
||
//--- b.cpp | ||
|
||
export module B; | ||
import A; | ||
export constexpr const char *helloB1 = helloA0; | ||
export constexpr const char *helloB2 = hello(); | ||
|
||
//--- c.cpp | ||
|
||
export module C; | ||
import A; | ||
export constexpr const char *helloC1 = helloA1; | ||
export constexpr const char *helloC2 = hello(); | ||
|
||
//--- main.cpp | ||
|
||
import A; | ||
import B; | ||
import C; | ||
|
||
// These are valid: they refer to the same evaluation of the same constant. | ||
static_assert(helloA0 == helloA1); | ||
static_assert(helloA0 == helloB1); | ||
static_assert(helloA0 == helloC1); | ||
|
||
// These refer to distinct evaluations, and so may or may not be equal. | ||
static_assert(helloA1 == helloA2); // expected-error {{}} expected-note {{unspecified value}} | ||
static_assert(helloA1 == helloB2); // expected-error {{}} expected-note {{unspecified value}} | ||
static_assert(helloA1 == helloC2); // expected-error {{}} expected-note {{unspecified value}} | ||
static_assert(helloA2 == helloB2); // expected-error {{}} expected-note {{unspecified value}} | ||
static_assert(helloA2 == helloC2); // expected-error {{}} expected-note {{unspecified value}} | ||
static_assert(helloB2 == helloC2); // expected-error {{}} expected-note {{unspecified value}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we get test coverage for these cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added.