зеркало из https://github.com/microsoft/clang-1.git
Rename CGT::VerifyFuncTypeComplete to isFuncTypeConvertible since
it is a predicate, not an action. Change the return type to be a bool, not the incomplete member. Enhace it to detect the recursive compilation case, allowing us to compile Eli's testcase on llvmdev: struct T { struct T (*p)(void); } t; into: %struct.T = type { {}* } @t = common global %struct.T zeroinitializer, align 8 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@134853 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
064fa99dbe
Коммит
f742eb0196
|
@ -704,16 +704,15 @@ const llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) {
|
|||
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
|
||||
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
|
||||
|
||||
if (!VerifyFuncTypeComplete(FPT)) {
|
||||
const CGFunctionInfo *Info;
|
||||
if (isa<CXXDestructorDecl>(MD))
|
||||
Info = &getFunctionInfo(cast<CXXDestructorDecl>(MD), GD.getDtorType());
|
||||
else
|
||||
Info = &getFunctionInfo(MD);
|
||||
return GetFunctionType(*Info, FPT->isVariadic());
|
||||
}
|
||||
|
||||
return llvm::StructType::get(getLLVMContext());
|
||||
if (!isFuncTypeConvertible(FPT))
|
||||
return llvm::StructType::get(getLLVMContext());
|
||||
|
||||
const CGFunctionInfo *Info;
|
||||
if (isa<CXXDestructorDecl>(MD))
|
||||
Info = &getFunctionInfo(cast<CXXDestructorDecl>(MD), GD.getDtorType());
|
||||
else
|
||||
Info = &getFunctionInfo(MD);
|
||||
return GetFunctionType(*Info, FPT->isVariadic());
|
||||
}
|
||||
|
||||
void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
|
||||
|
|
|
@ -2937,7 +2937,8 @@ void CodeGenVTables::MaybeEmitThunkAvailableExternally(GlobalDecl GD,
|
|||
|
||||
// We can't emit thunks for member functions with incomplete types.
|
||||
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
|
||||
if (CGM.getTypes().VerifyFuncTypeComplete(MD->getType().getTypePtr()))
|
||||
if (!CGM.getTypes().isFuncTypeConvertible(
|
||||
cast<FunctionType>(MD->getType().getTypePtr())))
|
||||
return;
|
||||
|
||||
EmitThunk(GD, Thunk, /*UseAvailableExternallyLinkage=*/true);
|
||||
|
|
|
@ -93,19 +93,55 @@ llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T){
|
|||
|
||||
}
|
||||
|
||||
// Code to verify a given function type is complete, i.e. the return type
|
||||
// and all of the argument types are complete.
|
||||
const TagType *CodeGenTypes::VerifyFuncTypeComplete(const Type* T) {
|
||||
const FunctionType *FT = cast<FunctionType>(T);
|
||||
if (const TagType* TT = FT->getResultType()->getAs<TagType>())
|
||||
if (!TT->getDecl()->isDefinition())
|
||||
return TT;
|
||||
if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(T))
|
||||
/// isFuncTypeArgumentConvertible - Return true if the specified type in a
|
||||
/// function argument or result position can be converted to an IR type at this
|
||||
/// point. This boils down to being whether it is complete, as well as whether
|
||||
/// we've temporarily deferred expanding the type because we're in a recursive
|
||||
/// context.
|
||||
bool CodeGenTypes::isFuncTypeArgumentConvertible(QualType Ty){
|
||||
// If this isn't a tagged type, we can convert it!
|
||||
const TagType *TT = Ty->getAs<TagType>();
|
||||
if (TT == 0) return true;
|
||||
|
||||
// If it's a tagged type, but is a forward decl, we can't convert it.
|
||||
if (!TT->getDecl()->isDefinition())
|
||||
return false;
|
||||
|
||||
// If we're not under a pointer under a struct, then we can convert it if
|
||||
// needed.
|
||||
if (RecursionState != RS_StructPointer)
|
||||
return true;
|
||||
|
||||
// If this is an enum, then it is safe to convert.
|
||||
const RecordType *RT = dyn_cast<RecordType>(TT);
|
||||
if (RT == 0) return true;
|
||||
|
||||
// Otherwise, we have to be careful. If it is a struct that we're in the
|
||||
// process of expanding, then we can't convert the function type. That's ok
|
||||
// though because we must be in a pointer context under the struct, so we can
|
||||
// just convert it to a dummy type.
|
||||
//
|
||||
// We decide this by checking whether ConvertRecordDeclType returns us an
|
||||
// opaque type for a struct that we know is defined.
|
||||
return !ConvertRecordDeclType(RT->getDecl())->isOpaque();
|
||||
}
|
||||
|
||||
|
||||
/// Code to verify a given function type is complete, i.e. the return type
|
||||
/// and all of the argument types are complete. Also check to see if we are in
|
||||
/// a RS_StructPointer context, and if so whether any struct types have been
|
||||
/// pended. If so, we don't want to ask the ABI lowering code to handle a type
|
||||
/// that cannot be converted to an IR type.
|
||||
bool CodeGenTypes::isFuncTypeConvertible(const FunctionType *FT) {
|
||||
if (!isFuncTypeArgumentConvertible(FT->getResultType()))
|
||||
return false;
|
||||
|
||||
if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT))
|
||||
for (unsigned i = 0, e = FPT->getNumArgs(); i != e; i++)
|
||||
if (const TagType *TT = FPT->getArgType(i)->getAs<TagType>())
|
||||
if (!TT->getDecl()->isDefinition())
|
||||
return TT;
|
||||
return 0;
|
||||
if (!isFuncTypeArgumentConvertible(FPT->getArgType(i)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// UpdateCompletedType - When we find the full definition for a TagDecl,
|
||||
|
@ -296,7 +332,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
|
|||
// First, check whether we can build the full function type. If the
|
||||
// function type depends on an incomplete type (e.g. a struct or enum), we
|
||||
// cannot lower the function type.
|
||||
if (VerifyFuncTypeComplete(Ty)) {
|
||||
if (!isFuncTypeConvertible(cast<FunctionType>(Ty))) {
|
||||
// This function's type depends on an incomplete tag type.
|
||||
// Return a placeholder type.
|
||||
ResultType = llvm::StructType::get(getLLVMContext());
|
||||
|
|
|
@ -137,11 +137,12 @@ public:
|
|||
|
||||
llvm::FunctionType *GetFunctionType(GlobalDecl GD);
|
||||
|
||||
/// VerifyFuncTypeComplete - Utility to check whether a function type can
|
||||
/// isFuncTypeConvertible - Utility to check whether a function type can
|
||||
/// be converted to an LLVM type (i.e. doesn't depend on an incomplete tag
|
||||
/// type).
|
||||
static const TagType *VerifyFuncTypeComplete(const Type* T);
|
||||
|
||||
bool isFuncTypeConvertible(const FunctionType *FT);
|
||||
bool isFuncTypeArgumentConvertible(QualType Ty);
|
||||
|
||||
/// GetFunctionTypeForVTable - Get the LLVM function type for use in a vtable,
|
||||
/// given a CXXMethodDecl. If the method to has an incomplete return type,
|
||||
/// and/or incomplete argument types, this will return the opaque type.
|
||||
|
|
|
@ -537,7 +537,7 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
|
|||
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
|
||||
const llvm::Type *Ty;
|
||||
// Check whether the function has a computable LLVM signature.
|
||||
if (!CodeGenTypes::VerifyFuncTypeComplete(FPT)) {
|
||||
if (Types.isFuncTypeConvertible(FPT)) {
|
||||
// The function has a computable LLVM signature; use the correct type.
|
||||
Ty = Types.GetFunctionType(Types.getFunctionInfo(MD),
|
||||
FPT->isVariadic());
|
||||
|
|
|
@ -115,3 +115,11 @@ void test11(struct test11S *P) {
|
|||
// CHECK: store i32 4
|
||||
// CHECK: ret void
|
||||
}
|
||||
|
||||
|
||||
// Verify that we can convert a recursive struct with a memory that returns
|
||||
// an instance of the struct we're converting.
|
||||
struct test12 {
|
||||
struct test12 (*p)(void);
|
||||
} test12g;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче