-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[Clang] Add __builtin_invoke and use it in libc++ #116709
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
e0bb550
2849e45
fd17bcc
e66f728
24427c9
54ea97a
e8a0c87
d046919
4053449
9317801
abbb273
dfbe219
7539895
d4f582d
497c915
635d6ef
faffb4e
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 |
---|---|---|
|
@@ -6540,67 +6540,70 @@ ExprResult Sema::ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc, | |
return BuildTypeTrait(Kind, KWLoc, ConvertedArgs, RParenLoc); | ||
} | ||
|
||
static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceInfo *Lhs, | ||
const TypeSourceInfo *Rhs, SourceLocation KeyLoc) { | ||
QualType LhsT = Lhs->getType(); | ||
QualType RhsT = Rhs->getType(); | ||
bool Sema::BuiltinIsBaseOf(SourceLocation RhsTLoc, QualType LhsT, | ||
QualType RhsT) { | ||
// C++0x [meta.rel]p2 | ||
// Base is a base class of Derived without regard to cv-qualifiers or | ||
// Base and Derived are not unions and name the same class type without | ||
// regard to cv-qualifiers. | ||
|
||
const RecordType *lhsRecord = LhsT->getAs<RecordType>(); | ||
const RecordType *rhsRecord = RhsT->getAs<RecordType>(); | ||
if (!rhsRecord || !lhsRecord) { | ||
const ObjCObjectType *LHSObjTy = LhsT->getAs<ObjCObjectType>(); | ||
const ObjCObjectType *RHSObjTy = RhsT->getAs<ObjCObjectType>(); | ||
if (!LHSObjTy || !RHSObjTy) | ||
return false; | ||
|
||
assert(!LhsT->isDependentType() && !RhsT->isDependentType() && | ||
"Cannot evaluate traits of dependent types"); | ||
ObjCInterfaceDecl *BaseInterface = LHSObjTy->getInterface(); | ||
ObjCInterfaceDecl *DerivedInterface = RHSObjTy->getInterface(); | ||
if (!BaseInterface || !DerivedInterface) | ||
return false; | ||
|
||
switch(BTT) { | ||
case BTT_IsBaseOf: { | ||
// C++0x [meta.rel]p2 | ||
// Base is a base class of Derived without regard to cv-qualifiers or | ||
// Base and Derived are not unions and name the same class type without | ||
// regard to cv-qualifiers. | ||
|
||
const RecordType *lhsRecord = LhsT->getAs<RecordType>(); | ||
const RecordType *rhsRecord = RhsT->getAs<RecordType>(); | ||
if (!rhsRecord || !lhsRecord) { | ||
const ObjCObjectType *LHSObjTy = LhsT->getAs<ObjCObjectType>(); | ||
const ObjCObjectType *RHSObjTy = RhsT->getAs<ObjCObjectType>(); | ||
if (!LHSObjTy || !RHSObjTy) | ||
return false; | ||
if (RequireCompleteType(RhsTLoc, RhsT, | ||
diag::err_incomplete_type_used_in_type_trait_expr)) | ||
return false; | ||
|
||
ObjCInterfaceDecl *BaseInterface = LHSObjTy->getInterface(); | ||
ObjCInterfaceDecl *DerivedInterface = RHSObjTy->getInterface(); | ||
if (!BaseInterface || !DerivedInterface) | ||
return false; | ||
return BaseInterface->isSuperClassOf(DerivedInterface); | ||
} | ||
|
||
if (Self.RequireCompleteType( | ||
Rhs->getTypeLoc().getBeginLoc(), RhsT, | ||
diag::err_incomplete_type_used_in_type_trait_expr)) | ||
return false; | ||
assert(Context.hasSameUnqualifiedType(LhsT, RhsT) == | ||
(lhsRecord == rhsRecord)); | ||
|
||
return BaseInterface->isSuperClassOf(DerivedInterface); | ||
} | ||
// Unions are never base classes, and never have base classes. | ||
// It doesn't matter if they are complete or not. See PR#41843 | ||
if (lhsRecord && lhsRecord->getDecl()->isUnion()) | ||
return false; | ||
if (rhsRecord && rhsRecord->getDecl()->isUnion()) | ||
return false; | ||
|
||
if (lhsRecord == rhsRecord) | ||
return true; | ||
|
||
assert(Self.Context.hasSameUnqualifiedType(LhsT, RhsT) | ||
== (lhsRecord == rhsRecord)); | ||
// C++0x [meta.rel]p2: | ||
// If Base and Derived are class types and are different types | ||
// (ignoring possible cv-qualifiers) then Derived shall be a | ||
// complete type. | ||
if (RequireCompleteType(RhsTLoc, RhsT, | ||
diag::err_incomplete_type_used_in_type_trait_expr)) | ||
return false; | ||
|
||
// Unions are never base classes, and never have base classes. | ||
// It doesn't matter if they are complete or not. See PR#41843 | ||
if (lhsRecord && lhsRecord->getDecl()->isUnion()) | ||
return false; | ||
if (rhsRecord && rhsRecord->getDecl()->isUnion()) | ||
return false; | ||
return cast<CXXRecordDecl>(rhsRecord->getDecl()) | ||
->isDerivedFrom(cast<CXXRecordDecl>(lhsRecord->getDecl())); | ||
} | ||
|
||
if (lhsRecord == rhsRecord) | ||
return true; | ||
static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceInfo *Lhs, | ||
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. Were these refactors necessary? 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 so. This allows me to use them in |
||
const TypeSourceInfo *Rhs, SourceLocation KeyLoc) { | ||
QualType LhsT = Lhs->getType(); | ||
QualType RhsT = Rhs->getType(); | ||
|
||
// C++0x [meta.rel]p2: | ||
// If Base and Derived are class types and are different types | ||
// (ignoring possible cv-qualifiers) then Derived shall be a | ||
// complete type. | ||
if (Self.RequireCompleteType( | ||
Rhs->getTypeLoc().getBeginLoc(), RhsT, | ||
diag::err_incomplete_type_used_in_type_trait_expr)) | ||
return false; | ||
assert(!LhsT->isDependentType() && !RhsT->isDependentType() && | ||
"Cannot evaluate traits of dependent types"); | ||
|
||
switch(BTT) { | ||
case BTT_IsBaseOf: | ||
return Self.BuiltinIsBaseOf(Rhs->getTypeLoc().getBeginLoc(), LhsT, RhsT); | ||
|
||
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>(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s | ||
|
||
extern "C" void* memcpy(void*, const void*, decltype(sizeof(int))); | ||
void func(); | ||
|
||
namespace std { | ||
template <class T> | ||
class reference_wrapper { | ||
T* ptr; | ||
|
||
public: | ||
T& get() { return *ptr; } | ||
}; | ||
} // namespace std | ||
|
||
struct Callable { | ||
void operator()() {} | ||
|
||
void func(); | ||
}; | ||
|
||
extern "C" void call1() { | ||
__builtin_invoke(func); | ||
__builtin_invoke(Callable{}); | ||
__builtin_invoke(memcpy, nullptr, nullptr, 0); | ||
|
||
// CHECK: define dso_local void @call1 | ||
// CHECK-NEXT: entry: | ||
// CHECK-NEXT: %ref.tmp = alloca %struct.Callable, align 1 | ||
// CHECK-NEXT: call void @_Z4funcv() | ||
// CHECK-NEXT: call void @_ZN8CallableclEv(ptr noundef nonnull align 1 dereferenceable(1) %ref.tmp) | ||
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 null, ptr align 1 null, i64 0, i1 false) | ||
// CHECK-NEXT: ret void | ||
} | ||
|
||
extern "C" void call_memptr(std::reference_wrapper<Callable> wrapper) { | ||
__builtin_invoke(&Callable::func, wrapper); | ||
|
||
// CHECK: define dso_local void @call_memptr | ||
// CHECK-NEXT: entry: | ||
// CHECK-NEXT: %wrapper = alloca %"class.std::reference_wrapper", align 8 | ||
// CHECK-NEXT: %coerce.dive = getelementptr inbounds nuw %"class.std::reference_wrapper", ptr %wrapper, i32 0, i32 0 | ||
// CHECK-NEXT: store ptr %wrapper.coerce, ptr %coerce.dive, align 8 | ||
// CHECK-NEXT: %call = call noundef nonnull align 1 dereferenceable(1) ptr @_ZNSt17reference_wrapperI8CallableE3getEv(ptr noundef nonnull align 8 dereferenceable(8) %wrapper) | ||
// CHECK-NEXT: %0 = getelementptr inbounds i8, ptr %call, i64 0 | ||
// CHECK-NEXT: br i1 false, label %memptr.virtual, label %memptr.nonvirtual | ||
// CHECK-EMPTY: | ||
// CHECK-NEXT: memptr.virtual: | ||
// CHECK-NEXT: %vtable = load ptr, ptr %0, align 8 | ||
// CHECK-NEXT: %1 = getelementptr i8, ptr %vtable, i64 sub (i64 ptrtoint (ptr @_ZN8Callable4funcEv to i64), i64 1), !nosanitize !2 | ||
// CHECK-NEXT: %memptr.virtualfn = load ptr, ptr %1, align 8, !nosanitize !2 | ||
// CHECK-NEXT: br label %memptr.end | ||
// CHECK-EMPTY: | ||
// CHECK-NEXT: memptr.nonvirtual: | ||
// CHECK-NEXT: br label %memptr.end | ||
// CHECK-EMPTY: | ||
// CHECK-NEXT: memptr.end: | ||
// CHECK-NEXT: %2 = phi ptr [ %memptr.virtualfn, %memptr.virtual ], [ @_ZN8Callable4funcEv, %memptr.nonvirtual ] | ||
// CHECK-NEXT: call void %2(ptr noundef nonnull align 1 dereferenceable(1) %0) | ||
// CHECK-NEXT: ret void | ||
} |
Uh oh!
There was an error while loading. Please reload this page.