Skip to content

Commit 2067574

Browse files
efriedma-quictru
authored andcommitted
[clang] Fix pointer comparisons between pointers to constexpr-unknown (#147663)
A constexpr-unknown reference can be equal to an arbitrary value, except values allocated during constant evaluation. Fix the handling. The standard is unclear exactly which pointer comparisons count as "unknown" in this context; for example, in some cases we could use alignment to prove two constexpr-unknown references are not equal. I decided to ignore all the cases involving variables not allocated during constant evaluation. While looking at this, I also spotted that there might be issues with lifetimes, but I didn't try to address it. (cherry picked from commit 20c8e3c)
1 parent 38158a9 commit 2067574

File tree

4 files changed

+44
-14
lines changed

4 files changed

+44
-14
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,7 @@ Bug Fixes to C++ Support
967967
- Fix a crash with NTTP when instantiating local class.
968968
- Fixed a crash involving list-initialization of an empty class with a
969969
non-empty initializer list. (#GH147949)
970+
- Fixed constant evaluation of equality comparisons of constexpr-unknown references. (#GH147663)
970971

971972
Bug Fixes to AST Handling
972973
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/AST/ExprConstant.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14478,12 +14478,6 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
1447814478
if (!EvaluatePointer(E->getRHS(), RHSValue, Info) || !LHSOK)
1447914479
return false;
1448014480

14481-
// If we have Unknown pointers we should fail if they are not global values.
14482-
if (!(IsGlobalLValue(LHSValue.getLValueBase()) &&
14483-
IsGlobalLValue(RHSValue.getLValueBase())) &&
14484-
(LHSValue.AllowConstexprUnknown || RHSValue.AllowConstexprUnknown))
14485-
return false;
14486-
1448714481
// Reject differing bases from the normal codepath; we special-case
1448814482
// comparisons to null.
1448914483
if (!HasSameBase(LHSValue, RHSValue)) {
@@ -14545,6 +14539,10 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
1454514539
(LHSValue.Base && isZeroSized(RHSValue)))
1454614540
return DiagComparison(
1454714541
diag::note_constexpr_pointer_comparison_zero_sized);
14542+
if (LHSValue.AllowConstexprUnknown || RHSValue.AllowConstexprUnknown)
14543+
return DiagComparison(
14544+
diag::note_constexpr_pointer_comparison_unspecified);
14545+
// FIXME: Verify both variables are live.
1454814546
return Success(CmpResult::Unequal, E);
1454914547
}
1455014548

clang/test/SemaCXX/constant-expression-cxx14.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,3 +1321,18 @@ constexpr bool check = different_in_loop();
13211321
// expected-error@-1 {{}} expected-note@-1 {{in call}}
13221322

13231323
}
1324+
1325+
namespace comparison_dead_variable {
1326+
constexpr bool f() {
1327+
int *p1 = 0, *p2 = 0;
1328+
{
1329+
int x = 0; p1 = &x;
1330+
}
1331+
{
1332+
int x = 0; p2 = &x;
1333+
}
1334+
return p1 != p2;
1335+
}
1336+
// FIXME: This should fail.
1337+
static_assert(f(),"");
1338+
}

clang/test/SemaCXX/constant-expression-p2280r4.cpp

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ namespace casting {
319319
}
320320

321321
namespace pointer_comparisons {
322-
extern int &extern_n; // interpreter-note 2 {{declared here}}
322+
extern int &extern_n; // interpreter-note 4 {{declared here}}
323323
extern int &extern_n2;
324324
constexpr int f1(bool b, int& n) {
325325
if (b) {
@@ -330,14 +330,30 @@ namespace pointer_comparisons {
330330
// FIXME: interpreter incorrectly rejects; both sides are the same constexpr-unknown value.
331331
static_assert(f1(false, extern_n)); // interpreter-error {{static assertion expression is not an integral constant expression}} \
332332
// interpreter-note {{initializer of 'extern_n' is unknown}}
333-
// FIXME: We should diagnose this: we don't know if the references bind
334-
// to the same object.
335-
static_assert(&extern_n != &extern_n2); // interpreter-error {{static assertion expression is not an integral constant expression}} \
333+
static_assert(&extern_n != &extern_n2); // expected-error {{static assertion expression is not an integral constant expression}} \
334+
// nointerpreter-note {{comparison between pointers to unrelated objects '&extern_n' and '&extern_n2' has unspecified value}} \
336335
// interpreter-note {{initializer of 'extern_n' is unknown}}
337336
void f2(const int &n) {
338-
// FIXME: We should not diagnose this: the two objects provably have
339-
// different addresses because the lifetime of "n" extends across
340-
// the initialization.
341-
constexpr int x = &x == &n; // nointerpreter-error {{must be initialized by a constant expression}}
337+
constexpr int x = &x == &n; // nointerpreter-error {{must be initialized by a constant expression}} \
338+
// nointerpreter-note {{comparison between pointers to unrelated objects '&x' and '&n' has unspecified value}}
339+
// Distinct variables are not equal, even if they're local variables.
340+
constexpr int y = &x == &y;
341+
static_assert(!y);
342342
}
343+
constexpr int f3() {
344+
int x;
345+
return &x == &extern_n; // nointerpreter-note {{comparison between pointers to unrelated objects '&x' and '&extern_n' has unspecified value}} \
346+
// interpreter-note {{initializer of 'extern_n' is unknown}}
347+
}
348+
static_assert(!f3()); // expected-error {{static assertion expression is not an integral constant expression}} \
349+
// expected-note {{in call to 'f3()'}}
350+
constexpr int f4() {
351+
int *p = new int;
352+
bool b = p == &extern_n; // nointerpreter-note {{comparison between pointers to unrelated objects '&{*new int#0}' and '&extern_n' has unspecified value}} \
353+
// interpreter-note {{initializer of 'extern_n' is unknown}}
354+
delete p;
355+
return b;
356+
}
357+
static_assert(!f4()); // expected-error {{static assertion expression is not an integral constant expression}} \
358+
// expected-note {{in call to 'f4()'}}
343359
}

0 commit comments

Comments
 (0)