Skip to content

Commit 4a7fb44

Browse files
tbaederraokblast
authored andcommitted
[clang][bytecode] Check overrider for pure virtual (llvm#165262)
Instead of checking the initial callee, check the callee after the virtual dispatch. This means we need to check whether we're in a ctor to not regress existing tests. Fixes llvm#165234
1 parent 7afcbed commit 4a7fb44

File tree

2 files changed

+33
-17
lines changed

2 files changed

+33
-17
lines changed

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1651,8 +1651,8 @@ static bool GetDynamicDecl(InterpState &S, CodePtr OpPC, Pointer TypePtr,
16511651

16521652
QualType DynamicType = TypePtr.getType();
16531653
if (TypePtr.isStatic() || TypePtr.isConst()) {
1654-
const VarDecl *VD = TypePtr.getDeclDesc()->asVarDecl();
1655-
if (!VD->isConstexpr()) {
1654+
if (const VarDecl *VD = TypePtr.getDeclDesc()->asVarDecl();
1655+
VD && !VD->isConstexpr()) {
16561656
const Expr *E = S.Current->getExpr(OpPC);
16571657
APValue V = TypePtr.toAPValue(S.getASTContext());
16581658
QualType TT = S.getASTContext().getLValueReferenceType(DynamicType);
@@ -1683,20 +1683,6 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
16831683
Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
16841684
const FunctionDecl *Callee = Func->getDecl();
16851685

1686-
if (!Func->isFullyCompiled())
1687-
compileFunction(S, Func);
1688-
1689-
// C++2a [class.abstract]p6:
1690-
// the effect of making a virtual call to a pure virtual function [...] is
1691-
// undefined
1692-
if (Callee->isPureVirtual()) {
1693-
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_pure_virtual_call,
1694-
1)
1695-
<< Callee;
1696-
S.Note(Callee->getLocation(), diag::note_declared_at);
1697-
return false;
1698-
}
1699-
17001686
const CXXRecordDecl *DynamicDecl = nullptr;
17011687
if (!GetDynamicDecl(S, OpPC, ThisPtr, DynamicDecl))
17021688
return false;
@@ -1706,7 +1692,8 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
17061692
const auto *InitialFunction = cast<CXXMethodDecl>(Callee);
17071693
const CXXMethodDecl *Overrider;
17081694

1709-
if (StaticDecl != DynamicDecl) {
1695+
if (StaticDecl != DynamicDecl &&
1696+
!llvm::is_contained(S.InitializingBlocks, ThisPtr.block())) {
17101697
if (!DynamicDecl->isDerivedFrom(StaticDecl))
17111698
return false;
17121699
Overrider = S.getContext().getOverridingFunction(DynamicDecl, StaticDecl,
@@ -1716,6 +1703,17 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
17161703
Overrider = InitialFunction;
17171704
}
17181705

1706+
// C++2a [class.abstract]p6:
1707+
// the effect of making a virtual call to a pure virtual function [...] is
1708+
// undefined
1709+
if (Overrider->isPureVirtual()) {
1710+
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_pure_virtual_call,
1711+
1)
1712+
<< Callee;
1713+
S.Note(Callee->getLocation(), diag::note_declared_at);
1714+
return false;
1715+
}
1716+
17191717
if (Overrider != InitialFunction) {
17201718
// DR1872: An instantiated virtual constexpr function can't be called in a
17211719
// constant expression (prior to C++20). We can still constant-fold such a

clang/test/AST/ByteCode/cxx20.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,3 +1183,21 @@ namespace VirtualFunctionCallThroughArrayElem {
11831183
static_assert(a[2][3].foo()); // both-error {{not an integral constant expression}} \
11841184
// both-note {{virtual function called on object 'a[2][3]' whose dynamic type is not constant}}
11851185
}
1186+
1187+
namespace NonPureVirtualCall {
1188+
struct A {
1189+
constexpr virtual void call(int) = 0;
1190+
constexpr void call2() { call(0); }
1191+
};
1192+
1193+
struct B : A {
1194+
constexpr void call(int) override {}
1195+
};
1196+
1197+
consteval void check() {
1198+
B b;
1199+
b.call2();
1200+
}
1201+
1202+
int main() { check(); }
1203+
}

0 commit comments

Comments
 (0)