Skip to content

Commit e2392c8

Browse files
author
git apple-llvm automerger
committed
Merge commit '071765749a70' from llvm.org/main into next
2 parents a7ff813 + 0717657 commit e2392c8

File tree

5 files changed

+118
-52
lines changed

5 files changed

+118
-52
lines changed

clang/include/clang/Basic/DiagnosticASTKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,8 @@ def note_constexpr_access_static_temporary : Note<
240240
"outside the expression that created the temporary">;
241241
def note_constexpr_access_unreadable_object : Note<
242242
"%sub{access_kind}0 object '%1' whose value is not known">;
243+
def note_constexpr_access_unknown_variable : Note<
244+
"%sub{access_kind}0 variable %1 whose value is not known">;
243245
def note_constexpr_access_deleted_object : Note<
244246
"%sub{access_kind}0 heap allocated object that has been deleted">;
245247
def note_constexpr_modify_global : Note<

clang/lib/AST/APValue.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -937,7 +937,7 @@ void APValue::printPretty(raw_ostream &Out, const PrintingPolicy &Policy,
937937
else if (isLValueOnePastTheEnd())
938938
Out << "*(&";
939939

940-
QualType ElemTy = Base.getType();
940+
QualType ElemTy = Base.getType().getNonReferenceType();
941941
if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) {
942942
Out << *VD;
943943
} else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) {

clang/lib/AST/ExprConstant.cpp

Lines changed: 27 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,9 @@ namespace {
214214
assert(!isBaseAnAllocSizeCall(Base) &&
215215
"Unsized arrays shouldn't appear here");
216216
unsigned MostDerivedLength = 0;
217-
Type = getType(Base);
217+
// The type of Base is a reference type if the base is a constexpr-unknown
218+
// variable. In that case, look through the reference type.
219+
Type = getType(Base).getNonReferenceType();
218220

219221
for (unsigned I = 0, N = Path.size(); I != N; ++I) {
220222
if (Type->isArrayType()) {
@@ -305,7 +307,7 @@ namespace {
305307
: Invalid(false), IsOnePastTheEnd(false),
306308
FirstEntryIsAnUnsizedArray(false), MostDerivedIsArrayElement(false),
307309
MostDerivedPathLength(0), MostDerivedArraySize(0),
308-
MostDerivedType(T) {}
310+
MostDerivedType(T.isNull() ? QualType() : T.getNonReferenceType()) {}
309311

310312
SubobjectDesignator(ASTContext &Ctx, const APValue &V)
311313
: Invalid(!V.isLValue() || !V.hasLValuePath()), IsOnePastTheEnd(false),
@@ -616,7 +618,6 @@ namespace {
616618
typedef std::map<MapKeyTy, APValue> MapTy;
617619
/// Temporaries - Temporary lvalues materialized within this stack frame.
618620
MapTy Temporaries;
619-
MapTy ConstexprUnknownAPValues;
620621

621622
/// CallRange - The source range of the call expression for this call.
622623
SourceRange CallRange;
@@ -691,9 +692,6 @@ namespace {
691692
APValue &createTemporary(const KeyT *Key, QualType T,
692693
ScopeKind Scope, LValue &LV);
693694

694-
APValue &createConstexprUnknownAPValues(const VarDecl *Key,
695-
APValue::LValueBase Base);
696-
697695
/// Allocate storage for a parameter of a function call made in this frame.
698696
APValue &createParam(CallRef Args, const ParmVarDecl *PVD, LValue &LV);
699697

@@ -1886,7 +1884,8 @@ namespace {
18861884
return;
18871885
}
18881886
if (checkSubobject(Info, E, CSK_ArrayToPointer)) {
1889-
assert(getType(Base)->isPointerType() || getType(Base)->isArrayType());
1887+
assert(getType(Base).getNonReferenceType()->isPointerType() ||
1888+
getType(Base).getNonReferenceType()->isArrayType());
18901889
Designator.FirstEntryIsAnUnsizedArray = true;
18911890
Designator.addUnsizedArrayUnchecked(ElemTy);
18921891
}
@@ -2131,15 +2130,6 @@ APValue &CallStackFrame::createTemporary(const KeyT *Key, QualType T,
21312130
return createLocal(Base, Key, T, Scope);
21322131
}
21332132

2134-
APValue &
2135-
CallStackFrame::createConstexprUnknownAPValues(const VarDecl *Key,
2136-
APValue::LValueBase Base) {
2137-
APValue &Result = ConstexprUnknownAPValues[MapKeyTy(Key, Base.getVersion())];
2138-
Result = APValue(Base, CharUnits::Zero(), APValue::ConstexprUnknown{});
2139-
2140-
return Result;
2141-
}
2142-
21432133
/// Allocate storage for a parameter of a function call made in this frame.
21442134
APValue &CallStackFrame::createParam(CallRef Args, const ParmVarDecl *PVD,
21452135
LValue &LV) {
@@ -3670,7 +3660,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
36703660
APValue::LValueBase Base(VD, Frame ? Frame->Index : 0, Version);
36713661

36723662
auto CheckUninitReference = [&](bool IsLocalVariable) {
3673-
if (!Result->hasValue() && VD->getType()->isReferenceType()) {
3663+
if (!Result || (!Result->hasValue() && VD->getType()->isReferenceType())) {
36743664
// C++23 [expr.const]p8
36753665
// ... For such an object that is not usable in constant expressions, the
36763666
// dynamic type of the object is constexpr-unknown. For such a reference
@@ -3686,7 +3676,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
36863676
Info.FFDiag(E, diag::note_constexpr_use_uninit_reference);
36873677
return false;
36883678
}
3689-
Result = &Info.CurrentCall->createConstexprUnknownAPValues(VD, Base);
3679+
Result = nullptr;
36903680
}
36913681
return true;
36923682
};
@@ -3729,7 +3719,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
37293719
// ... its lifetime began within the evaluation of E;
37303720
if (isa<ParmVarDecl>(VD)) {
37313721
if (AllowConstexprUnknown) {
3732-
Result = &Info.CurrentCall->createConstexprUnknownAPValues(VD, Base);
3722+
Result = nullptr;
37333723
return true;
37343724
}
37353725

@@ -3836,12 +3826,8 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
38363826

38373827
Result = VD->getEvaluatedValue();
38383828

3839-
if (!Result) {
3840-
if (AllowConstexprUnknown)
3841-
Result = &Info.CurrentCall->createConstexprUnknownAPValues(VD, Base);
3842-
else
3843-
return false;
3844-
}
3829+
if (!Result && !AllowConstexprUnknown)
3830+
return false;
38453831

38463832
return CheckUninitReference(/*IsLocalVariable=*/false);
38473833
}
@@ -4124,11 +4110,6 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
41244110
const FieldDecl *LastField = nullptr;
41254111
const FieldDecl *VolatileField = nullptr;
41264112

4127-
// C++23 [expr.const]p8 If we have an unknown reference or pointers and it
4128-
// does not have a value then bail out.
4129-
if (O->allowConstexprUnknown() && !O->hasValue())
4130-
return false;
4131-
41324113
// Walk the designator's path to find the subobject.
41334114
for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) {
41344115
// Reading an indeterminate value is undefined, but assigning over one is OK.
@@ -4668,6 +4649,15 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
46684649

46694650
if (!evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(), BaseVal))
46704651
return CompleteObject();
4652+
// If evaluateVarDeclInit sees a constexpr-unknown variable, it returns
4653+
// a null BaseVal. Any constexpr-unknown variable seen here is an error:
4654+
// we can't access a constexpr-unknown object.
4655+
if (!BaseVal) {
4656+
Info.FFDiag(E, diag::note_constexpr_access_unknown_variable, 1)
4657+
<< AK << VD;
4658+
Info.Note(VD->getLocation(), diag::note_declared_at);
4659+
return CompleteObject();
4660+
}
46714661
} else if (DynamicAllocLValue DA = LVal.Base.dyn_cast<DynamicAllocLValue>()) {
46724662
std::optional<DynAlloc *> Alloc = Info.lookupDynamicAlloc(DA);
46734663
if (!Alloc) {
@@ -6234,15 +6224,6 @@ struct CheckDynamicTypeHandler {
62346224
/// dynamic type.
62356225
static bool checkDynamicType(EvalInfo &Info, const Expr *E, const LValue &This,
62366226
AccessKinds AK, bool Polymorphic) {
6237-
// We are not allowed to invoke a virtual function whose dynamic type
6238-
// is constexpr-unknown, so stop early and let this fail later on if we
6239-
// attempt to do so.
6240-
// C++23 [expr.const]p5.6
6241-
// an invocation of a virtual function ([class.virtual]) for an object whose
6242-
// dynamic type is constexpr-unknown;
6243-
if (This.allowConstexprUnknown())
6244-
return true;
6245-
62466227
if (This.Designator.Invalid)
62476228
return false;
62486229

@@ -6316,9 +6297,7 @@ static std::optional<DynamicType> ComputeDynamicType(EvalInfo &Info,
63166297
// meaningful dynamic type. (We consider objects of non-class type to have no
63176298
// dynamic type.)
63186299
if (!checkDynamicType(Info, E, This, AK,
6319-
(AK == AK_TypeId
6320-
? (E->getType()->isReferenceType() ? true : false)
6321-
: true)))
6300+
AK != AK_TypeId || This.AllowConstexprUnknown))
63226301
return std::nullopt;
63236302

63246303
if (This.Designator.Invalid)
@@ -9271,6 +9250,12 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
92719250
if (!evaluateVarDeclInit(Info, E, VD, Frame, Version, V))
92729251
return false;
92739252

9253+
if (!V) {
9254+
Result.set(VD);
9255+
Result.AllowConstexprUnknown = true;
9256+
return true;
9257+
}
9258+
92749259
return Success(*V, E);
92759260
}
92769261

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,7 +1466,7 @@ namespace InstantiateCaseStmt {
14661466

14671467
namespace ConvertedConstantExpr {
14681468
extern int &m;
1469-
extern int &n; // pre-cxx23-note 2{{declared here}}
1469+
extern int &n; // expected-note 2{{declared here}}
14701470

14711471
constexpr int k = 4;
14721472
int &m = const_cast<int&>(k);
@@ -1475,9 +1475,9 @@ namespace ConvertedConstantExpr {
14751475
// useless note and instead just point to the non-constant subexpression.
14761476
enum class E {
14771477
em = m,
1478-
en = n, // expected-error {{enumerator value is not a constant expression}} cxx11_20-note {{initializer of 'n' is unknown}}
1478+
en = n, // expected-error {{enumerator value is not a constant expression}} cxx11_20-note {{initializer of 'n' is unknown}} cxx23-note {{read of non-constexpr variable 'n'}}
14791479
eo = (m + // expected-error {{not a constant expression}}
1480-
n // cxx11_20-note {{initializer of 'n' is unknown}}
1480+
n // cxx11_20-note {{initializer of 'n' is unknown}} cxx23-note {{read of non-constexpr variable 'n'}}
14811481
),
14821482
eq = reinterpret_cast<long>((int*)0) // expected-error {{not a constant expression}} expected-note {{reinterpret_cast}}
14831483
};

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

Lines changed: 85 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,26 @@ constexpr int how_many(Swim& swam) {
3535
return (p + 1 - 1)->phelps();
3636
}
3737

38-
void splash(Swim& swam) {
38+
void splash(Swim& swam) { // nointerpreter-note {{declared here}}
3939
static_assert(swam.phelps() == 28); // ok
4040
static_assert((&swam)->phelps() == 28); // ok
4141
Swim* pswam = &swam; // expected-note {{declared here}}
4242
static_assert(pswam->phelps() == 28); // expected-error {{static assertion expression is not an integral constant expression}} \
4343
// expected-note {{read of non-constexpr variable 'pswam' is not allowed in a constant expression}}
4444
static_assert(how_many(swam) == 28); // ok
4545
static_assert(Swim().lochte() == 12); // ok
46-
static_assert(swam.lochte() == 12); // expected-error {{static assertion expression is not an integral constant expression}}
47-
static_assert(swam.coughlin == 12); // expected-error {{static assertion expression is not an integral constant expression}}
46+
static_assert(swam.lochte() == 12); // expected-error {{static assertion expression is not an integral constant expression}} \
47+
// nointerpreter-note {{virtual function called on object 'swam' whose dynamic type is not constant}}
48+
static_assert(swam.coughlin == 12); // expected-error {{static assertion expression is not an integral constant expression}} \
49+
// nointerpreter-note {{read of variable 'swam' whose value is not known}}
4850
}
4951

5052
extern Swim dc;
5153
extern Swim& trident; // interpreter-note {{declared here}}
5254

5355
constexpr auto& sandeno = typeid(dc); // ok: can only be typeid(Swim)
5456
constexpr auto& gallagher = typeid(trident); // expected-error {{constexpr variable 'gallagher' must be initialized by a constant expression}} \
57+
// nointerpreter-note {{typeid applied to object 'trident' whose dynamic type is not constant}} \
5558
// interpreter-note {{initializer of 'trident' is unknown}}
5659

5760
namespace explicitThis {
@@ -253,12 +256,88 @@ namespace uninit_reference_used {
253256

254257
namespace param_reference {
255258
constexpr int arbitrary = -12345;
256-
constexpr void f(const int &x = arbitrary) { // expected-note {{declared here}}
259+
constexpr void f(const int &x = arbitrary) { // nointerpreter-note 3 {{declared here}} interpreter-note {{declared here}}
257260
constexpr const int &v1 = x; // expected-error {{must be initialized by a constant expression}} \
258261
// expected-note {{reference to 'x' is not a constant expression}}
259262
constexpr const int &v2 = (x, arbitrary); // expected-warning {{left operand of comma operator has no effect}}
260-
constexpr int v3 = x; // expected-error {{must be initialized by a constant expression}}
261-
static_assert(x==arbitrary); // expected-error {{static assertion expression is not an integral constant expression}}
263+
constexpr int v3 = x; // expected-error {{must be initialized by a constant expression}} \
264+
// nointerpreter-note {{read of variable 'x' whose value is not known}}
265+
static_assert(x==arbitrary); // expected-error {{static assertion expression is not an integral constant expression}} \
266+
// nointerpreter-note {{read of variable 'x' whose value is not known}}
262267
static_assert(&x - &x == 0);
263268
}
264269
}
270+
271+
namespace dropped_note {
272+
extern int &x; // expected-note {{declared here}}
273+
constexpr int f() { return x; } // nointerpreter-note {{read of non-constexpr variable 'x'}} \
274+
// interpreter-note {{initializer of 'x' is unknown}}
275+
constexpr int y = f(); // expected-error {{constexpr variable 'y' must be initialized by a constant expression}} expected-note {{in call to 'f()'}}
276+
}
277+
278+
namespace dynamic {
279+
struct A {virtual ~A();};
280+
struct B : A {};
281+
void f(A& a) {
282+
constexpr B* b = dynamic_cast<B*>(&a); // expected-error {{must be initialized by a constant expression}} \
283+
// nointerpreter-note {{dynamic_cast applied to object 'a' whose dynamic type is not constant}}
284+
constexpr void* b2 = dynamic_cast<void*>(&a); // expected-error {{must be initialized by a constant expression}} \
285+
// nointerpreter-note {{dynamic_cast applied to object 'a' whose dynamic type is not constant}}
286+
}
287+
}
288+
289+
namespace unsized_array {
290+
void f(int (&a)[], int (&b)[], int (&c)[4]) {
291+
constexpr int t1 = a - a;
292+
constexpr int t2 = a - b; // expected-error {{constexpr variable 't2' must be initialized by a constant expression}} \
293+
// nointerpreter-note {{arithmetic involving unrelated objects '&a[0]' and '&b[0]' has unspecified value}} \
294+
// interpreter-note {{arithmetic involving unrelated objects 'a' and 'b' has unspecified value}}
295+
constexpr int t3 = a - &c[2]; // expected-error {{constexpr variable 't3' must be initialized by a constant expression}} \
296+
// nointerpreter-note {{arithmetic involving unrelated objects '&a[0]' and '&c[2]' has unspecified value}} \
297+
// interpreter-note {{arithmetic involving unrelated objects 'a' and '*((char*)&c + 8)' has unspecified value}}
298+
}
299+
}
300+
301+
namespace casting {
302+
struct A {};
303+
struct B : A {};
304+
struct C : A {};
305+
extern A &a; // interpreter-note {{declared here}}
306+
extern B &b; // expected-note {{declared here}} interpreter-note 2 {{declared here}}
307+
constexpr B &t1 = (B&)a; // expected-error {{must be initialized by a constant expression}} \
308+
// nointerpreter-note {{cannot cast object of dynamic type 'A' to type 'B'}} \
309+
// interpreter-note {{initializer of 'a' is unknown}}
310+
constexpr B &t2 = (B&)(A&)b; // expected-error {{must be initialized by a constant expression}} \
311+
// nointerpreter-note {{initializer of 'b' is not a constant expression}} \
312+
// interpreter-note {{initializer of 'b' is unknown}}
313+
// FIXME: interpreter incorrectly rejects.
314+
constexpr bool t3 = &b + 1 == &(B&)(A&)b; // interpreter-error {{must be initialized by a constant expression}} \
315+
// interpreter-note {{initializer of 'b' is unknown}}
316+
constexpr C &t4 = (C&)(A&)b; // expected-error {{must be initialized by a constant expression}} \
317+
// nointerpreter-note {{cannot cast object of dynamic type 'B' to type 'C'}} \
318+
// interpreter-note {{initializer of 'b' is unknown}}
319+
}
320+
321+
namespace pointer_comparisons {
322+
extern int &extern_n; // interpreter-note 2 {{declared here}}
323+
extern int &extern_n2;
324+
constexpr int f1(bool b, int& n) {
325+
if (b) {
326+
return &extern_n == &n;
327+
}
328+
return f1(true, n);
329+
}
330+
// FIXME: interpreter incorrectly rejects; both sides are the same constexpr-unknown value.
331+
static_assert(f1(false, extern_n)); // interpreter-error {{static assertion expression is not an integral constant expression}} \
332+
// 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}} \
336+
// interpreter-note {{initializer of 'extern_n' is unknown}}
337+
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}}
342+
}
343+
}

0 commit comments

Comments
 (0)