Skip to content

Commit 95717b9

Browse files
committed
Add diagnostic when dynamic type is not constant
+ test cases
1 parent 7c01c2b commit 95717b9

File tree

3 files changed

+59
-23
lines changed

3 files changed

+59
-23
lines changed

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,8 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
445445
return true;
446446
}
447447

448-
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
448+
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc,
449+
bool NoDiag) {
449450
assert(Desc);
450451

451452
const auto *D = Desc->asVarDecl();
@@ -470,15 +471,15 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
470471
}
471472

472473
if (IsConstant) {
473-
if (S.getLangOpts().CPlusPlus) {
474+
if (S.getLangOpts().CPlusPlus && !NoDiag) {
474475
S.CCEDiag(S.Current->getLocation(OpPC),
475476
S.getLangOpts().CPlusPlus11
476477
? diag::note_constexpr_ltor_non_constexpr
477478
: diag::note_constexpr_ltor_non_integral,
478479
1)
479480
<< D << T;
480481
S.Note(D->getLocation(), diag::note_declared_at);
481-
} else {
482+
} else if (!NoDiag) {
482483
S.CCEDiag(S.Current->getLocation(OpPC));
483484
}
484485
return true;
@@ -493,16 +494,18 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
493494
return true;
494495
}
495496

496-
diagnoseNonConstVariable(S, OpPC, D);
497+
if (!NoDiag)
498+
diagnoseNonConstVariable(S, OpPC, D);
497499
return false;
498500
}
499501

500-
static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
502+
static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
503+
bool NoDiag = false) {
501504
if (!Ptr.isStatic() || !Ptr.isBlockPointer())
502505
return true;
503506
if (!Ptr.getDeclID())
504507
return true;
505-
return CheckConstant(S, OpPC, Ptr.getDeclDesc());
508+
return CheckConstant(S, OpPC, Ptr.getDeclDesc(), NoDiag);
506509
}
507510

508511
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
@@ -1636,6 +1639,33 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
16361639
return true;
16371640
}
16381641

1642+
static bool GetDynamicDecl(InterpState &S, CodePtr OpPC, Pointer TypePtr,
1643+
const CXXRecordDecl *&DynamicDecl) {
1644+
while (TypePtr.isBaseClass())
1645+
TypePtr = TypePtr.getBase();
1646+
1647+
QualType DynamicType = TypePtr.getType();
1648+
if (DynamicType->isPointerType() || DynamicType->isReferenceType()) {
1649+
DynamicDecl = DynamicType->getPointeeCXXRecordDecl();
1650+
} else if (DynamicType->isArrayType()) {
1651+
const Type *ElemType = DynamicType->getPointeeOrArrayElementType();
1652+
assert(ElemType);
1653+
DynamicDecl = ElemType->getAsCXXRecordDecl();
1654+
} else {
1655+
DynamicDecl = DynamicType->getAsCXXRecordDecl();
1656+
}
1657+
1658+
if (!CheckConstant(S, OpPC, TypePtr, true)) {
1659+
const Expr *E = S.Current->getExpr(OpPC);
1660+
APValue V = TypePtr.toAPValue(S.getASTContext());
1661+
QualType TT = S.getASTContext().getLValueReferenceType(DynamicType);
1662+
S.FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type)
1663+
<< AccessKinds::AK_MemberCall << V.getAsString(S.getASTContext(), TT);
1664+
return false;
1665+
}
1666+
return true;
1667+
}
1668+
16391669
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
16401670
uint32_t VarArgSize) {
16411671
assert(Func->hasThisPointer());
@@ -1660,22 +1690,8 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
16601690
}
16611691

16621692
const CXXRecordDecl *DynamicDecl = nullptr;
1663-
{
1664-
Pointer TypePtr = ThisPtr;
1665-
while (TypePtr.isBaseClass())
1666-
TypePtr = TypePtr.getBase();
1667-
1668-
QualType DynamicType = TypePtr.getType();
1669-
if (DynamicType->isPointerType() || DynamicType->isReferenceType()) {
1670-
DynamicDecl = DynamicType->getPointeeCXXRecordDecl();
1671-
} else if (DynamicType->isArrayType()) {
1672-
const Type *ElemType = DynamicType->getPointeeOrArrayElementType();
1673-
assert(ElemType);
1674-
DynamicDecl = ElemType->getAsCXXRecordDecl();
1675-
} else {
1676-
DynamicDecl = DynamicType->getAsCXXRecordDecl();
1677-
}
1678-
}
1693+
if (!GetDynamicDecl(S, OpPC, ThisPtr, DynamicDecl))
1694+
return false;
16791695
assert(DynamicDecl);
16801696

16811697
const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());

clang/lib/AST/ByteCode/Interp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
7878
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
7979

8080
/// Checks if the Descriptor is of a constexpr or const global variable.
81-
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc);
81+
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc, bool NoDiag = false);
8282

8383
/// Checks if a pointer points to a mutable field.
8484
bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);

clang/test/AST/ByteCode/cxx20.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,10 @@ namespace Virtual {
10731073
virtual constexpr int f() { return 10; }
10741074
};
10751075

1076+
K k;
1077+
static_assert(k.f() == 10); // both-error {{not an integral constant expression}} \
1078+
// both-note {{virtual function called on object 'k' whose dynamic type is not constant}}
1079+
10761080
class L : public K {
10771081
public:
10781082
int b = f();
@@ -1083,6 +1087,18 @@ namespace Virtual {
10831087
static_assert(l.a == 10);
10841088
static_assert(l.b == 10);
10851089
static_assert(l.c == 10);
1090+
1091+
struct M {
1092+
K& mk = k;
1093+
};
1094+
static_assert(M{}.mk.f() == 10); // both-error {{not an integral constant expression}} \
1095+
// both-note {{virtual function called on object 'k' whose dynamic type is not constant}}
1096+
1097+
struct N {
1098+
K* mk = &k;
1099+
};
1100+
static_assert(N{}.mk->f() == 10); // both-error {{not an integral constant expression}} \
1101+
// both-note {{virtual function called on object 'k' whose dynamic type is not constant}}
10861102
}
10871103

10881104
namespace DiscardedTrivialCXXConstructExpr {
@@ -1121,4 +1137,8 @@ namespace VirtualFunctionCallThroughArrayElem {
11211137
};
11221138
constexpr Y ys[20];
11231139
static_assert(ys[12].foo() == static_cast<const X&>(ys[12]).foo());
1140+
1141+
X a[3][4];
1142+
static_assert(a[2][3].foo()); // both-error {{not an integral constant expression}} \
1143+
// both-note {{virtual function called on object 'a[2][3]' whose dynamic type is not constant}}
11241144
}

0 commit comments

Comments
 (0)