-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[clang][bytecode] Assert on virtual func call from array elem #158502
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
Changes from 3 commits
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 | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -445,7 +445,8 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, | |||||||
return true; | ||||||||
} | ||||||||
|
||||||||
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { | ||||||||
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc, | ||||||||
bool NoDiag) { | ||||||||
assert(Desc); | ||||||||
|
||||||||
const auto *D = Desc->asVarDecl(); | ||||||||
|
@@ -470,15 +471,15 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { | |||||||
} | ||||||||
|
||||||||
if (IsConstant) { | ||||||||
if (S.getLangOpts().CPlusPlus) { | ||||||||
if (S.getLangOpts().CPlusPlus && !NoDiag) { | ||||||||
S.CCEDiag(S.Current->getLocation(OpPC), | ||||||||
S.getLangOpts().CPlusPlus11 | ||||||||
? diag::note_constexpr_ltor_non_constexpr | ||||||||
: diag::note_constexpr_ltor_non_integral, | ||||||||
1) | ||||||||
<< D << T; | ||||||||
S.Note(D->getLocation(), diag::note_declared_at); | ||||||||
} else { | ||||||||
} else if (!NoDiag) { | ||||||||
S.CCEDiag(S.Current->getLocation(OpPC)); | ||||||||
} | ||||||||
return true; | ||||||||
|
@@ -493,16 +494,18 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { | |||||||
return true; | ||||||||
} | ||||||||
|
||||||||
diagnoseNonConstVariable(S, OpPC, D); | ||||||||
if (!NoDiag) | ||||||||
diagnoseNonConstVariable(S, OpPC, D); | ||||||||
return false; | ||||||||
} | ||||||||
|
||||||||
static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { | ||||||||
static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr, | ||||||||
bool NoDiag = false) { | ||||||||
if (!Ptr.isStatic() || !Ptr.isBlockPointer()) | ||||||||
return true; | ||||||||
if (!Ptr.getDeclID()) | ||||||||
return true; | ||||||||
return CheckConstant(S, OpPC, Ptr.getDeclDesc()); | ||||||||
return CheckConstant(S, OpPC, Ptr.getDeclDesc(), NoDiag); | ||||||||
} | ||||||||
|
||||||||
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, | ||||||||
|
@@ -1636,6 +1639,33 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func, | |||||||
return true; | ||||||||
} | ||||||||
|
||||||||
static bool GetDynamicDecl(InterpState &S, CodePtr OpPC, Pointer TypePtr, | ||||||||
const CXXRecordDecl *&DynamicDecl) { | ||||||||
while (TypePtr.isBaseClass()) | ||||||||
TypePtr = TypePtr.getBase(); | ||||||||
|
||||||||
QualType DynamicType = TypePtr.getType(); | ||||||||
if (DynamicType->isPointerType() || DynamicType->isReferenceType()) { | ||||||||
DynamicDecl = DynamicType->getPointeeCXXRecordDecl(); | ||||||||
} else if (DynamicType->isArrayType()) { | ||||||||
const Type *ElemType = DynamicType->getPointeeOrArrayElementType(); | ||||||||
assert(ElemType); | ||||||||
DynamicDecl = ElemType->getAsCXXRecordDecl(); | ||||||||
} else { | ||||||||
DynamicDecl = DynamicType->getAsCXXRecordDecl(); | ||||||||
} | ||||||||
|
||||||||
if (!CheckConstant(S, OpPC, TypePtr, true)) { | ||||||||
const Expr *E = S.Current->getExpr(OpPC); | ||||||||
APValue V = TypePtr.toAPValue(S.getASTContext()); | ||||||||
QualType TT = S.getASTContext().getLValueReferenceType(DynamicType); | ||||||||
|
if (!IsReference) | |
Out << '&'; | |
else if (isLValueOnePastTheEnd()) |
we would get messages like
note: virtual function called on object '&k' whose dynamic type is not constant
while the other interpreter outputs
note: virtual function called on object 'k' whose dynamic type is not constant
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1073,6 +1073,10 @@ namespace Virtual { | |
virtual constexpr int f() { return 10; } | ||
}; | ||
|
||
K k; | ||
static_assert(k.f() == 10); // both-error {{not an integral constant expression}} \ | ||
// both-note {{virtual function called on object 'k' whose dynamic type is not constant}} | ||
|
||
class L : public K { | ||
public: | ||
int b = f(); | ||
|
@@ -1083,6 +1087,18 @@ namespace Virtual { | |
static_assert(l.a == 10); | ||
static_assert(l.b == 10); | ||
static_assert(l.c == 10); | ||
|
||
struct M { | ||
K& mk = k; | ||
}; | ||
static_assert(M{}.mk.f() == 10); // both-error {{not an integral constant expression}} \ | ||
// both-note {{virtual function called on object 'k' whose dynamic type is not constant}} | ||
|
||
struct N { | ||
K* mk = &k; | ||
}; | ||
static_assert(N{}.mk->f() == 10); // both-error {{not an integral constant expression}} \ | ||
// both-note {{virtual function called on object 'k' whose dynamic type is not constant}} | ||
} | ||
|
||
namespace DiscardedTrivialCXXConstructExpr { | ||
|
@@ -1100,3 +1116,29 @@ namespace DiscardedTrivialCXXConstructExpr { | |
constexpr int y = foo(12); // both-error {{must be initialized by a constant expression}} \ | ||
// both-note {{in call to}} | ||
} | ||
|
||
namespace VirtualFunctionCallThroughArrayElem { | ||
struct X { | ||
constexpr virtual int foo() const { | ||
return 3; | ||
} | ||
}; | ||
constexpr X xs[5]; | ||
static_assert(xs[3].foo() == 3); | ||
|
||
constexpr X xs2[1][2]; | ||
static_assert(xs2[0].foo() == 3); // both-error {{is not a structure or union}} | ||
static_assert(xs2[0][0].foo() == 3); | ||
|
||
struct Y: public X { | ||
constexpr int foo() const override { | ||
return 1; | ||
} | ||
}; | ||
constexpr Y ys[20]; | ||
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. can you include the original reproducer from #152893 as well? This patch fixes the assertion failure but the diagnostic output is still different between the two interpreters. 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. Added that test case and the diagnostic. For normal globals the interpreters also disagreed in their diagnostics outputs (https://godbolt.org/z/84zeeYxd3), now they raise the same messages. |
||
static_assert(ys[12].foo() == static_cast<const X&>(ys[12]).foo()); | ||
|
||
X a[3][4]; | ||
static_assert(a[2][3].foo()); // both-error {{not an integral constant expression}} \ | ||
// both-note {{virtual function called on object 'a[2][3]' whose dynamic type is not constant}} | ||
} |
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.
So what is actually the relevant part of
CheckConstant
? Is it just the call toQualType::isConstant()
?Uh oh!
There was an error while loading. Please reload this page.
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.
Checking only
DynamicType.isConstant()
would reject valid code likehere
TypePtr.isStatic()
inGetDynamicDecl()
is false soCheckConstant()
would return early but I'm not sure if it is sufficient to only check those two things. Tests pass at least withif (TypePtr.isStatic() && !DynamicType.isConstant(S.getASTContext()))
instead ofCheckConstant()
.Uh oh!
There was an error while loading. Please reload this page.
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.
Removed the call to
CheckConstant
, added more test cases. Check should be more explicit now, i.e. check storage class ofthis
, and if its var decl is constexpr.