-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[clang] Implement __is_virtual_base_of()
intrinsic
#100393
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 2 commits
772b5d8
8b0b0c5
da449c9
8913119
46f02b2
60ccd79
8806fdb
47e274d
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 | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -6027,6 +6027,33 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI | |||||||||||||||
return cast<CXXRecordDecl>(rhsRecord->getDecl()) | ||||||||||||||||
->isDerivedFrom(cast<CXXRecordDecl>(lhsRecord->getDecl())); | ||||||||||||||||
} | ||||||||||||||||
case BTT_IsVirtualBaseOf: { | ||||||||||||||||
const RecordType *BaseRecord = LhsT->getAs<RecordType>(); | ||||||||||||||||
const RecordType *DerivedRecord = RhsT->getAs<RecordType>(); | ||||||||||||||||
|
||||||||||||||||
if (!BaseRecord || !DerivedRecord) { | ||||||||||||||||
DiagnoseVLAInCXXTypeTrait(Self, Lhs, tok::kw___is_virtual_base_of); | ||||||||||||||||
DiagnoseVLAInCXXTypeTrait(Self, Rhs, tok::kw___is_virtual_base_of); | ||||||||||||||||
return false; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
if (BaseRecord->isUnionType() || DerivedRecord->isUnionType()) | ||||||||||||||||
return false; | ||||||||||||||||
|
||||||||||||||||
if (!BaseRecord->isStructureOrClassType() || | ||||||||||||||||
!DerivedRecord->isStructureOrClassType()) | ||||||||||||||||
return false; | ||||||||||||||||
Comment on lines
+6048
to
+6050
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. Is this check necessary? If it’s not a union, it has to be a class type, right? Or am I missing something obvious? 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. It could be an enum (enums can't have an inheritance relationship) - but this check is enough, we don't need the union check above. 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.
I thought a 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. IIRC ObjC interfaces are also 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. ObjC types don't inherit from 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. (and I don't think you can have a virtual objective c interface so there is nothing of ObjC to support here) 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.
llvm-project/clang/lib/AST/Type.cpp Lines 657 to 663 in 0ee32c4
So (1) ObjC doesn't have to inherit from 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. Hmm, 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. It’s also maybe worth noting that the line containing the check is from 2014, so things may have been different back then |
||||||||||||||||
|
||||||||||||||||
if (Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT, | ||||||||||||||||
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. What does it mean for there to be a complete derived class type but an incomplete base class type? Shouldn't this require a complete type in both cases to give reasonable diagnostic behavior? 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. The proposal only mentions that the second type has to be complete. My guess is that the reasoning behind this is that in e.g. 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. I hadn't realized that
I think it would be much kinder to tell the user that 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.
There is no incomplete base type. We are asking whether some type is a base, and if it isn't, we don't care that it is complete. Type traits don't mandate completeness if they don't need to. |
||||||||||||||||
diag::err_incomplete_type)) | ||||||||||||||||
return false; | ||||||||||||||||
|
||||||||||||||||
if (Self.Context.hasSameUnqualifiedType(LhsT, RhsT)) | ||||||||||||||||
return false; | ||||||||||||||||
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. I’m assuming this is just short-circuiting? I’m aware that this case is mentioned in the paper (‘A class is never a virtual base class of itself’), but I don’t think it’s possible for a type to be its own base class—virtual or not—so I don’t think this is required for correctness. Is the check for virtual bases expensive? 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.
Well,
I haven't measured, but why do more work when we can help it? 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. I see how it is, yeah, in that sense, it’s be easier to just keep it. 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. I think this actually does more work instead of less; most code will not pass in the same type as both arguments, right? So that means this check won't catch anything useful most of the time, but the below check still will catch this case (I believe). |
||||||||||||||||
|
||||||||||||||||
return cast<CXXRecordDecl>(DerivedRecord->getDecl()) | ||||||||||||||||
->isVirtuallyDerivedFrom(cast<CXXRecordDecl>(BaseRecord->getDecl())); | ||||||||||||||||
} | ||||||||||||||||
case BTT_IsSame: | ||||||||||||||||
return Self.Context.hasSameType(LhsT, RhsT); | ||||||||||||||||
case BTT_TypeCompatible: { | ||||||||||||||||
|
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.
I guess I'm surprised by this -- why are VLAs special?
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.
We’ve been generally disallowing VLA’s in type-traits recently; there was some discussion about this somewhere. Don’t remember where exactly, but I think #88646 is a good starting point.
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.
I don't want to introduce even more VLA extensions in C++ mode (this builtin is exposed only in C++ mode). This began with #88473 (comment)