зеркало из https://github.com/microsoft/clang.git
After some discussion with Doug, we decided that it made a lot more sense
for __unknown_anytype resolution to destructively modify the AST. So that's what it does now, which significantly simplifies some of the implementation. Normal member calls work pretty cleanly now, and I added support for propagating unknown-ness through &. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129331 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
235c02f79e
Коммит
755d8497e3
|
@ -2221,8 +2221,6 @@ private:
|
|||
case CK_MemberPointerToBoolean:
|
||||
case CK_FloatingComplexToBoolean:
|
||||
case CK_IntegralComplexToBoolean:
|
||||
case CK_ResolveUnknownAnyType:
|
||||
case CK_ResolveUnknownAnyTypeToReference:
|
||||
case CK_LValueBitCast: // -> bool&
|
||||
case CK_UserDefinedConversion: // operator bool()
|
||||
assert(path_empty() && "Cast kind should not have a base path!");
|
||||
|
|
|
@ -245,13 +245,7 @@ enum CastKind {
|
|||
|
||||
/// \brief Converts from an integral complex to a floating complex.
|
||||
/// _Complex unsigned -> _Complex float
|
||||
CK_IntegralComplexToFloatingComplex,
|
||||
|
||||
/// \brief Assign an unknown-any declaration a type.
|
||||
CK_ResolveUnknownAnyType,
|
||||
|
||||
/// \brief Assign an unknown-any declaration a reference type.
|
||||
CK_ResolveUnknownAnyTypeToReference
|
||||
CK_IntegralComplexToFloatingComplex
|
||||
};
|
||||
|
||||
#define CK_Invalid ((CastKind) -1)
|
||||
|
|
|
@ -3859,6 +3859,13 @@ def err_unsupported_unknown_any_decl : Error<
|
|||
"%0 has unknown type, which is unsupported for this kind of declaration">;
|
||||
def err_unsupported_unknown_any_expr : Error<
|
||||
"unsupported expression with unknown type">;
|
||||
def err_unsupported_unknown_any_call : Error<
|
||||
"call to unsupported expression with unknown type">;
|
||||
def err_unknown_any_addrof : Error<
|
||||
"the address of a declaration with unknown type "
|
||||
"can only be cast to a pointer type">;
|
||||
def err_unknown_any_var_function_type : Error<
|
||||
"variable %0 with unknown type cannot be given a function type">;
|
||||
|
||||
} // end of sema category
|
||||
|
||||
|
|
|
@ -1055,10 +1055,6 @@ const char *CastExpr::getCastKindName() const {
|
|||
return "IntegralComplexCast";
|
||||
case CK_IntegralComplexToFloatingComplex:
|
||||
return "IntegralComplexToFloatingComplex";
|
||||
case CK_ResolveUnknownAnyType:
|
||||
return "ResolveUnknownAnyType";
|
||||
case CK_ResolveUnknownAnyTypeToReference:
|
||||
return "ResolveUnknownAnyTypeToReference";
|
||||
}
|
||||
|
||||
llvm_unreachable("Unhandled cast kind!");
|
||||
|
|
|
@ -170,6 +170,9 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
|
|||
// C++ [expr.prim.general]p3: The result is an lvalue if the entity is a
|
||||
// function or variable and a prvalue otherwise.
|
||||
case Expr::DeclRefExprClass:
|
||||
if (E->getType() == Ctx.UnknownAnyTy)
|
||||
return isa<FunctionDecl>(cast<DeclRefExpr>(E)->getDecl())
|
||||
? Cl::CL_PRValue : Cl::CL_LValue;
|
||||
return ClassifyDecl(Ctx, cast<DeclRefExpr>(E)->getDecl());
|
||||
// We deal with names referenced from blocks the same way.
|
||||
case Expr::BlockDeclRefExprClass:
|
||||
|
@ -375,6 +378,10 @@ static Cl::Kinds ClassifyUnnamed(ASTContext &Ctx, QualType T) {
|
|||
}
|
||||
|
||||
static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E) {
|
||||
if (E->getType() == Ctx.UnknownAnyTy)
|
||||
return (isa<FunctionDecl>(E->getMemberDecl())
|
||||
? Cl::CL_PRValue : Cl::CL_LValue);
|
||||
|
||||
// Handle C first, it's easier.
|
||||
if (!Ctx.getLangOptions().CPlusPlus) {
|
||||
// C99 6.5.2.3p3
|
||||
|
|
|
@ -1798,8 +1798,6 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) {
|
|||
case CK_GetObjCProperty:
|
||||
case CK_LValueBitCast:
|
||||
case CK_UserDefinedConversion:
|
||||
case CK_ResolveUnknownAnyType:
|
||||
case CK_ResolveUnknownAnyTypeToReference:
|
||||
return false;
|
||||
|
||||
case CK_LValueToRValue:
|
||||
|
@ -2353,8 +2351,6 @@ bool ComplexExprEvaluator::VisitCastExpr(CastExpr *E) {
|
|||
case CK_GetObjCProperty:
|
||||
case CK_LValueBitCast:
|
||||
case CK_UserDefinedConversion:
|
||||
case CK_ResolveUnknownAnyType:
|
||||
case CK_ResolveUnknownAnyTypeToReference:
|
||||
return false;
|
||||
|
||||
case CK_FloatingRealToComplex: {
|
||||
|
|
|
@ -99,8 +99,7 @@ CGCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
|
|||
return GetBogusMemberPointer(CGM, QualType(MPT, 0));
|
||||
}
|
||||
|
||||
llvm::Constant *CGCXXABI::EmitMemberPointer(const CXXMethodDecl *MD,
|
||||
QualType unknownType) {
|
||||
llvm::Constant *CGCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
|
||||
return GetBogusMemberPointer(CGM,
|
||||
CGM.getContext().getMemberPointerType(MD->getType(),
|
||||
MD->getParent()->getTypeForDecl()));
|
||||
|
|
|
@ -119,12 +119,7 @@ public:
|
|||
virtual llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT);
|
||||
|
||||
/// Create a member pointer for the given method.
|
||||
///
|
||||
/// \param unknownType - if non-null, use this type as the operand
|
||||
/// to CodeGenModule::getAddrOfUnknownAnyDecl instead of
|
||||
/// fetching the method's address in the normal way
|
||||
virtual llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD,
|
||||
QualType unknownType = QualType());
|
||||
virtual llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD);
|
||||
|
||||
/// Create a member pointer for the given field.
|
||||
virtual llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT,
|
||||
|
|
|
@ -1792,35 +1792,6 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
|
|||
return MakeAddrLValue(phi, expr->getType());
|
||||
}
|
||||
|
||||
static LValue emitUnknownAnyLValue(CodeGenFunction &CGF,
|
||||
const Expr *operand,
|
||||
QualType resolvedType) {
|
||||
const ValueDecl *decl;
|
||||
if (const DeclRefExpr *ref = dyn_cast<DeclRefExpr>(operand)) {
|
||||
decl = ref->getDecl();
|
||||
} else if (const MemberExpr *mem = dyn_cast<MemberExpr>(operand)) {
|
||||
decl = mem->getMemberDecl();
|
||||
|
||||
// Emit (and ignore) the base.
|
||||
if (mem->isArrow())
|
||||
CGF.EmitScalarExpr(mem->getBase());
|
||||
else
|
||||
CGF.EmitLValue(mem->getBase());
|
||||
} else {
|
||||
llvm_unreachable("unexpected operand of unknown-any resolution!");
|
||||
decl = 0;
|
||||
}
|
||||
llvm::Value *addr = CGF.CGM.getAddrOfUnknownAnyDecl(decl, resolvedType);
|
||||
|
||||
QualType type = resolvedType;
|
||||
if (const ReferenceType *ref = type->getAs<ReferenceType>()) {
|
||||
addr = CGF.Builder.CreateLoad(addr, "ref.value");
|
||||
type = ref->getPointeeType();
|
||||
}
|
||||
|
||||
return CGF.MakeAddrLValue(addr, type);
|
||||
}
|
||||
|
||||
/// EmitCastLValue - Casts are never lvalues unless that cast is a dynamic_cast.
|
||||
/// If the cast is a dynamic_cast, we can have the usual lvalue result,
|
||||
/// otherwise if a cast is needed by the code generator in an lvalue context,
|
||||
|
@ -1959,13 +1930,6 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
|
|||
ConvertType(ToType));
|
||||
return MakeAddrLValue(V, E->getType());
|
||||
}
|
||||
case CK_ResolveUnknownAnyType:
|
||||
return emitUnknownAnyLValue(*this, E->getSubExpr(), E->getType());
|
||||
case CK_ResolveUnknownAnyTypeToReference: {
|
||||
// l-value vs. r-value reference type shouldn't matter here.
|
||||
QualType type = getContext().getLValueReferenceType(E->getType());
|
||||
return emitUnknownAnyLValue(*this, E->getSubExpr(), type);
|
||||
}
|
||||
}
|
||||
|
||||
llvm_unreachable("Unhandled lvalue cast kind?");
|
||||
|
|
|
@ -310,11 +310,6 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
|
|||
llvm_unreachable("should not be emitting lvalue bitcast as rvalue");
|
||||
break;
|
||||
|
||||
case CK_ResolveUnknownAnyType:
|
||||
case CK_ResolveUnknownAnyTypeToReference:
|
||||
EmitAggLoadOfLValue(E);
|
||||
break;
|
||||
|
||||
case CK_Dependent:
|
||||
case CK_BitCast:
|
||||
case CK_ArrayToPointerDecay:
|
||||
|
|
|
@ -552,8 +552,6 @@ public:
|
|||
case CK_GetObjCProperty:
|
||||
case CK_ToVoid:
|
||||
case CK_Dynamic:
|
||||
case CK_ResolveUnknownAnyType:
|
||||
case CK_ResolveUnknownAnyTypeToReference:
|
||||
return 0;
|
||||
|
||||
// These might need to be supported for constexpr.
|
||||
|
|
|
@ -1127,22 +1127,6 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
|
|||
return RV.getScalarVal();
|
||||
}
|
||||
|
||||
case CK_ResolveUnknownAnyType:
|
||||
// Special case: resolving a member pointer constant.
|
||||
if (const UnaryOperator *uo = dyn_cast<UnaryOperator>(E)) {
|
||||
DeclRefExpr *declRef = cast<DeclRefExpr>(uo->getSubExpr());
|
||||
const CXXMethodDecl *method = cast<CXXMethodDecl>(declRef->getDecl());
|
||||
|
||||
const MemberPointerType *mpt = CE->getType()->castAs<MemberPointerType>();
|
||||
QualType resolvedType = mpt->getPointeeType();
|
||||
|
||||
return CGF.CGM.getCXXABI().EmitMemberPointer(method, resolvedType);
|
||||
}
|
||||
// fallthrough
|
||||
|
||||
case CK_ResolveUnknownAnyTypeToReference:
|
||||
return EmitLoadOfLValue(CE);
|
||||
|
||||
case CK_LValueToRValue:
|
||||
assert(CGF.getContext().hasSameUnqualifiedType(E->getType(), DestTy));
|
||||
assert(E->isGLValue() && "lvalue-to-rvalue applied to r-value!");
|
||||
|
|
|
@ -1072,54 +1072,6 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D,
|
|||
return GetOrCreateLLVMGlobal(MangledName, PTy, D);
|
||||
}
|
||||
|
||||
/// getAddrOfUnknownAnyDecl - Return an llvm::Constant for the address
|
||||
/// of a global which was declared with unknown type. It is possible
|
||||
/// for a VarDecl to end up getting resolved to have function type,
|
||||
/// which complicates this substantially; on the other hand, these are
|
||||
/// always external references, which does simplify the logic a lot.
|
||||
llvm::Constant *
|
||||
CodeGenModule::getAddrOfUnknownAnyDecl(const NamedDecl *decl, QualType type) {
|
||||
GlobalDecl global;
|
||||
|
||||
// FunctionDecls will always end up with function types, but
|
||||
// VarDecls can end up with them too.
|
||||
if (isa<FunctionDecl>(decl))
|
||||
global = GlobalDecl(cast<FunctionDecl>(decl));
|
||||
else
|
||||
global = GlobalDecl(cast<VarDecl>(decl));
|
||||
llvm::StringRef mangledName = getMangledName(global);
|
||||
|
||||
const llvm::Type *ty = getTypes().ConvertTypeForMem(type);
|
||||
const llvm::PointerType *pty =
|
||||
llvm::PointerType::get(ty, getContext().getTargetAddressSpace(type));
|
||||
|
||||
|
||||
// Check for an existing global value with this name.
|
||||
llvm::GlobalValue *entry = GetGlobalValue(mangledName);
|
||||
if (entry)
|
||||
return llvm::ConstantExpr::getBitCast(entry, pty);
|
||||
|
||||
// If we're creating something with function type, go ahead and
|
||||
// create a function.
|
||||
if (const llvm::FunctionType *fnty = dyn_cast<llvm::FunctionType>(ty)) {
|
||||
llvm::Function *fn = llvm::Function::Create(fnty,
|
||||
llvm::Function::ExternalLinkage,
|
||||
mangledName, &getModule());
|
||||
return fn;
|
||||
|
||||
// Otherwise, make a global variable.
|
||||
} else {
|
||||
llvm::GlobalVariable *var
|
||||
= new llvm::GlobalVariable(getModule(), ty, false,
|
||||
llvm::GlobalValue::ExternalLinkage,
|
||||
0, mangledName, 0,
|
||||
false, pty->getAddressSpace());
|
||||
if (isa<VarDecl>(decl) && cast<VarDecl>(decl)->isThreadSpecified())
|
||||
var->setThreadLocal(true);
|
||||
return var;
|
||||
}
|
||||
}
|
||||
|
||||
/// CreateRuntimeVariable - Create a new runtime global variable with the
|
||||
/// specified type and name.
|
||||
llvm::Constant *
|
||||
|
|
|
@ -358,7 +358,6 @@ public:
|
|||
llvm::Constant *GetAddrOfGlobalVar(const VarDecl *D,
|
||||
const llvm::Type *Ty = 0);
|
||||
|
||||
llvm::Constant *getAddrOfUnknownAnyDecl(const NamedDecl *D, QualType type);
|
||||
|
||||
/// GetAddrOfFunction - Return the address of the given function. If Ty is
|
||||
/// non-null, then this function will use the specified type if it has to
|
||||
|
|
|
@ -78,8 +78,7 @@ public:
|
|||
|
||||
llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT);
|
||||
|
||||
llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD,
|
||||
QualType unknownType);
|
||||
llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD);
|
||||
llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT,
|
||||
CharUnits offset);
|
||||
|
||||
|
@ -503,8 +502,7 @@ ItaniumCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
|
|||
return llvm::ConstantInt::get(getPtrDiffTy(), offset.getQuantity());
|
||||
}
|
||||
|
||||
llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD,
|
||||
QualType unknownType) {
|
||||
llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
|
||||
assert(MD->isInstance() && "Member function must not be static!");
|
||||
MD = MD->getCanonicalDecl();
|
||||
|
||||
|
@ -539,25 +537,20 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD,
|
|||
MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0);
|
||||
}
|
||||
} else {
|
||||
llvm::Constant *addr;
|
||||
if (!unknownType.isNull()) {
|
||||
addr = CGM.getAddrOfUnknownAnyDecl(MD, unknownType);
|
||||
QualType fnType = MD->getType();
|
||||
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
|
||||
const llvm::Type *Ty;
|
||||
// Check whether the function has a computable LLVM signature.
|
||||
if (!CodeGenTypes::VerifyFuncTypeComplete(FPT)) {
|
||||
// The function has a computable LLVM signature; use the correct type.
|
||||
Ty = Types.GetFunctionType(Types.getFunctionInfo(MD),
|
||||
FPT->isVariadic());
|
||||
} else {
|
||||
QualType fnType = MD->getType();
|
||||
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
|
||||
const llvm::Type *Ty;
|
||||
// Check whether the function has a computable LLVM signature.
|
||||
if (!CodeGenTypes::VerifyFuncTypeComplete(FPT)) {
|
||||
// The function has a computable LLVM signature; use the correct type.
|
||||
Ty = Types.GetFunctionType(Types.getFunctionInfo(MD),
|
||||
FPT->isVariadic());
|
||||
} else {
|
||||
// Use an arbitrary non-function type to tell GetAddrOfFunction that the
|
||||
// function type is incomplete.
|
||||
Ty = ptrdiff_t;
|
||||
}
|
||||
addr = CGM.GetAddrOfFunction(MD, Ty);
|
||||
// Use an arbitrary non-function type to tell GetAddrOfFunction that the
|
||||
// function type is incomplete.
|
||||
Ty = ptrdiff_t;
|
||||
}
|
||||
llvm::Constant *addr = CGM.GetAddrOfFunction(MD, Ty);
|
||||
|
||||
MemPtr[0] = llvm::ConstantExpr::getPtrToInt(addr, ptrdiff_t);
|
||||
MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0);
|
||||
|
|
|
@ -2488,6 +2488,16 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
|
|||
break;
|
||||
|
||||
case Decl::Function: {
|
||||
const FunctionType *fty = type->castAs<FunctionType>();
|
||||
|
||||
// If we're referring to a function with an __unknown_anytype
|
||||
// result type, make the entire expression __unknown_anytype.
|
||||
if (fty->getResultType() == Context.UnknownAnyTy) {
|
||||
type = Context.UnknownAnyTy;
|
||||
valueKind = VK_RValue;
|
||||
break;
|
||||
}
|
||||
|
||||
// Functions are l-values in C++.
|
||||
if (getLangOptions().CPlusPlus) {
|
||||
valueKind = VK_LValue;
|
||||
|
@ -2499,10 +2509,10 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
|
|||
// used for checking compatibility. Therefore, when referencing
|
||||
// the function, we pretend that we don't have the full function
|
||||
// type.
|
||||
if (!cast<FunctionDecl>(VD)->hasPrototype())
|
||||
if (const FunctionProtoType *proto = type->getAs<FunctionProtoType>())
|
||||
type = Context.getFunctionNoProtoType(proto->getResultType(),
|
||||
proto->getExtInfo());
|
||||
if (!cast<FunctionDecl>(VD)->hasPrototype() &&
|
||||
isa<FunctionProtoType>(fty))
|
||||
type = Context.getFunctionNoProtoType(fty->getResultType(),
|
||||
fty->getExtInfo());
|
||||
|
||||
// Functions are r-values in C.
|
||||
valueKind = VK_RValue;
|
||||
|
@ -2510,6 +2520,16 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
|
|||
}
|
||||
|
||||
case Decl::CXXMethod:
|
||||
// If we're referring to a method with an __unknown_anytype
|
||||
// result type, make the entire expression __unknown_anytype.
|
||||
// This should only be possible with a type written directly.
|
||||
if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(VD->getType()))
|
||||
if (proto->getResultType() == Context.UnknownAnyTy) {
|
||||
type = Context.UnknownAnyTy;
|
||||
valueKind = VK_RValue;
|
||||
break;
|
||||
}
|
||||
|
||||
// C++ methods are l-values if static, r-values if non-static.
|
||||
if (cast<CXXMethodDecl>(VD)->isStatic()) {
|
||||
valueKind = VK_LValue;
|
||||
|
@ -2533,8 +2553,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
|
|||
return ExprError();
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
|
||||
tok::TokenKind Kind) {
|
||||
ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
|
||||
PredefinedExpr::IdentType IT;
|
||||
|
||||
switch (Kind) {
|
||||
|
@ -4532,16 +4551,37 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
|
|||
|
||||
// If this is a variadic call, handle args passed through "...".
|
||||
if (CallType != VariadicDoesNotApply) {
|
||||
// Promote the arguments (C99 6.5.2.2p7).
|
||||
for (unsigned i = ArgIx; i != NumArgs; ++i) {
|
||||
ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], CallType, FDecl);
|
||||
Invalid |= Arg.isInvalid();
|
||||
AllArgs.push_back(Arg.take());
|
||||
|
||||
// Assume that extern "C" functions with variadic arguments that
|
||||
// return __unknown_anytype aren't *really* variadic.
|
||||
if (Proto->getResultType() == Context.UnknownAnyTy &&
|
||||
FDecl && FDecl->isExternC()) {
|
||||
for (unsigned i = ArgIx; i != NumArgs; ++i) {
|
||||
ExprResult arg;
|
||||
if (isa<ExplicitCastExpr>(Args[i]->IgnoreParens()))
|
||||
arg = DefaultFunctionArrayLvalueConversion(Args[i]);
|
||||
else
|
||||
arg = DefaultVariadicArgumentPromotion(Args[i], CallType, FDecl);
|
||||
Invalid |= arg.isInvalid();
|
||||
AllArgs.push_back(arg.take());
|
||||
}
|
||||
|
||||
// Otherwise do argument promotion, (C99 6.5.2.2p7).
|
||||
} else {
|
||||
for (unsigned i = ArgIx; i != NumArgs; ++i) {
|
||||
ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], CallType, FDecl);
|
||||
Invalid |= Arg.isInvalid();
|
||||
AllArgs.push_back(Arg.take());
|
||||
}
|
||||
}
|
||||
}
|
||||
return Invalid;
|
||||
}
|
||||
|
||||
/// Given a function expression of unknown-any type, try to rebuild it
|
||||
/// to have a function type.
|
||||
static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn);
|
||||
|
||||
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
|
||||
/// This provides the location of the left/right parens and a list of comma
|
||||
/// locations.
|
||||
|
@ -4602,6 +4642,12 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
|
|||
return Owned(BuildCallToObjectOfClassType(S, Fn, LParenLoc, Args, NumArgs,
|
||||
RParenLoc));
|
||||
|
||||
if (Fn->getType() == Context.UnknownAnyTy) {
|
||||
ExprResult result = rebuildUnknownAnyFunction(*this, Fn);
|
||||
if (result.isInvalid()) return ExprError();
|
||||
Fn = result.take();
|
||||
}
|
||||
|
||||
Expr *NakedFn = Fn->IgnoreParens();
|
||||
|
||||
// Determine whether this is a call to an unresolved member function.
|
||||
|
@ -4715,66 +4761,6 @@ Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc,
|
|||
return ActOnCallExpr(S, ConfigDR, LLLLoc, execConfig, GGGLoc, 0);
|
||||
}
|
||||
|
||||
/// Given a function expression of unknown-any type, rebuild it to
|
||||
/// have a type appropriate for being called with the given arguments,
|
||||
/// yielding a value of unknown-any type.
|
||||
static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn,
|
||||
Expr **args, unsigned numArgs) {
|
||||
// Strip an lvalue-to-rvalue conversion off.
|
||||
if (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(fn))
|
||||
if (ice->getCastKind() == CK_LValueToRValue)
|
||||
fn = ice->getSubExpr();
|
||||
|
||||
// Build a simple function type exactly matching the arguments.
|
||||
llvm::SmallVector<QualType, 8> argTypes;
|
||||
argTypes.reserve(numArgs);
|
||||
for (unsigned i = 0; i != numArgs; ++i) {
|
||||
// Require all the sub-expression to not be placeholders.
|
||||
ExprResult result = S.CheckPlaceholderExpr(args[i]);
|
||||
if (result.isInvalid()) return ExprError();
|
||||
args[i] = result.take();
|
||||
|
||||
QualType argType;
|
||||
|
||||
// If the argument is an explicit cast (possibly parenthesized),
|
||||
// use that type exactly. This allows users to pass by reference.
|
||||
if (ExplicitCastExpr *castExpr
|
||||
= dyn_cast<ExplicitCastExpr>(args[i]->IgnoreParens())) {
|
||||
argType = castExpr->getTypeAsWritten();
|
||||
|
||||
// Otherwise, do an l2r conversion on the argument before grabbing
|
||||
// its type.
|
||||
} else {
|
||||
ExprResult result = S.DefaultLvalueConversion(args[i]);
|
||||
if (result.isInvalid()) return ExprError();
|
||||
args[i] = result.take();
|
||||
argType = args[i]->getType();
|
||||
}
|
||||
|
||||
argTypes.push_back(argType);
|
||||
}
|
||||
|
||||
// Resolve the symbol to a function type that returns an unknown-any
|
||||
// type. In the fully resolved expression, this cast will surround
|
||||
// the DeclRefExpr.
|
||||
FunctionProtoType::ExtProtoInfo extInfo;
|
||||
QualType fnType = S.Context.getFunctionType(S.Context.UnknownAnyTy,
|
||||
argTypes.data(), numArgs,
|
||||
extInfo);
|
||||
fn = ImplicitCastExpr::Create(S.Context, fnType,
|
||||
CK_ResolveUnknownAnyType,
|
||||
fn, /*path*/ 0,
|
||||
(S.getLangOptions().CPlusPlus ? VK_LValue : VK_RValue));
|
||||
|
||||
// Decay that to a pointer.
|
||||
fnType = S.Context.getPointerType(fnType);
|
||||
fn = ImplicitCastExpr::Create(S.Context, fnType,
|
||||
CK_FunctionToPointerDecay,
|
||||
fn, /*path*/ 0, VK_RValue);
|
||||
|
||||
return S.Owned(fn);
|
||||
}
|
||||
|
||||
/// BuildResolvedCallExpr - Build a call to a resolved expression,
|
||||
/// i.e. an expression not of \p OverloadTy. The expression should
|
||||
/// unary-convert to an expression of function-pointer or
|
||||
|
@ -4834,11 +4820,10 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
|
|||
} else {
|
||||
// Handle calls to expressions of unknown-any type.
|
||||
if (Fn->getType() == Context.UnknownAnyTy) {
|
||||
ExprResult rewrite = rebuildUnknownAnyFunction(*this, Fn, Args, NumArgs);
|
||||
ExprResult rewrite = rebuildUnknownAnyFunction(*this, Fn);
|
||||
if (rewrite.isInvalid()) return ExprError();
|
||||
Fn = rewrite.take();
|
||||
TheCall->setCallee(Fn);
|
||||
NDecl = FDecl = 0;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
|
@ -8103,10 +8088,10 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp,
|
|||
return S.Context.DependentTy;
|
||||
if (OrigOp->getType() == S.Context.OverloadTy)
|
||||
return S.Context.OverloadTy;
|
||||
if (OrigOp->getType() == S.Context.UnknownAnyTy)
|
||||
return S.Context.UnknownAnyTy;
|
||||
|
||||
ExprResult PR = S.CheckPlaceholderExpr(OrigOp);
|
||||
if (PR.isInvalid()) return QualType();
|
||||
OrigOp = PR.take();
|
||||
assert(!OrigOp->getType()->isPlaceholderType());
|
||||
|
||||
// Make sure to ignore parentheses in subsequent checks
|
||||
Expr *op = OrigOp->IgnoreParens();
|
||||
|
@ -10158,6 +10143,93 @@ ExprResult Sema::ActOnBooleanCondition(Scope *S, SourceLocation Loc,
|
|||
return CheckBooleanCondition(Sub, Loc);
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// A visitor for rebuilding a call to an __unknown_any expression
|
||||
/// to have an appropriate type.
|
||||
struct RebuildUnknownAnyFunction
|
||||
: StmtVisitor<RebuildUnknownAnyFunction, ExprResult> {
|
||||
|
||||
Sema &S;
|
||||
|
||||
RebuildUnknownAnyFunction(Sema &S) : S(S) {}
|
||||
|
||||
ExprResult VisitStmt(Stmt *S) {
|
||||
llvm_unreachable("unexpected statement!");
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
ExprResult VisitExpr(Expr *expr) {
|
||||
S.Diag(expr->getExprLoc(), diag::err_unsupported_unknown_any_call)
|
||||
<< expr->getSourceRange();
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
/// Rebuild an expression which simply semantically wraps another
|
||||
/// expression which it shares the type and value kind of.
|
||||
template <class T> ExprResult rebuildSugarExpr(T *expr) {
|
||||
ExprResult subResult = Visit(expr->getSubExpr());
|
||||
if (subResult.isInvalid()) return ExprError();
|
||||
|
||||
Expr *subExpr = subResult.take();
|
||||
expr->setSubExpr(subExpr);
|
||||
expr->setType(subExpr->getType());
|
||||
expr->setValueKind(subExpr->getValueKind());
|
||||
assert(expr->getObjectKind() == OK_Ordinary);
|
||||
return expr;
|
||||
}
|
||||
|
||||
ExprResult VisitParenExpr(ParenExpr *paren) {
|
||||
return rebuildSugarExpr(paren);
|
||||
}
|
||||
|
||||
ExprResult VisitUnaryExtension(UnaryOperator *op) {
|
||||
return rebuildSugarExpr(op);
|
||||
}
|
||||
|
||||
ExprResult VisitUnaryAddrOf(UnaryOperator *op) {
|
||||
ExprResult subResult = Visit(op->getSubExpr());
|
||||
if (subResult.isInvalid()) return ExprError();
|
||||
|
||||
Expr *subExpr = subResult.take();
|
||||
op->setSubExpr(subExpr);
|
||||
op->setType(S.Context.getPointerType(subExpr->getType()));
|
||||
assert(op->getValueKind() == VK_RValue);
|
||||
assert(op->getObjectKind() == OK_Ordinary);
|
||||
return op;
|
||||
}
|
||||
|
||||
ExprResult resolveDecl(Expr *expr, ValueDecl *decl) {
|
||||
if (!isa<FunctionDecl>(decl)) return VisitExpr(expr);
|
||||
|
||||
expr->setType(decl->getType());
|
||||
|
||||
assert(expr->getValueKind() == VK_RValue);
|
||||
if (S.getLangOptions().CPlusPlus &&
|
||||
!(isa<CXXMethodDecl>(decl) &&
|
||||
cast<CXXMethodDecl>(decl)->isInstance()))
|
||||
expr->setValueKind(VK_LValue);
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
ExprResult VisitMemberExpr(MemberExpr *mem) {
|
||||
return resolveDecl(mem, mem->getMemberDecl());
|
||||
}
|
||||
|
||||
ExprResult VisitDeclRefExpr(DeclRefExpr *ref) {
|
||||
return resolveDecl(ref, ref->getDecl());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Given a function expression of unknown-any type, try to rebuild it
|
||||
/// to have a function type.
|
||||
static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn) {
|
||||
ExprResult result = RebuildUnknownAnyFunction(S).Visit(fn);
|
||||
if (result.isInvalid()) return ExprError();
|
||||
return S.DefaultFunctionArrayConversion(result.take());
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// A visitor for rebuilding an expression of type __unknown_anytype
|
||||
/// into one which resolves the type directly on the referring
|
||||
|
@ -10192,7 +10264,7 @@ namespace {
|
|||
/// expression which it shares the type and value kind of.
|
||||
template <class T> ExprResult rebuildSugarExpr(T *expr) {
|
||||
ExprResult subResult = Visit(expr->getSubExpr());
|
||||
if (!subResult.isUsable()) return ExprError();
|
||||
if (subResult.isInvalid()) return ExprError();
|
||||
Expr *subExpr = subResult.take();
|
||||
expr->setSubExpr(subExpr);
|
||||
expr->setType(subExpr->getType());
|
||||
|
@ -10209,11 +10281,32 @@ namespace {
|
|||
return rebuildSugarExpr(op);
|
||||
}
|
||||
|
||||
ExprResult VisitUnaryAddrOf(UnaryOperator *op) {
|
||||
const PointerType *ptr = DestType->getAs<PointerType>();
|
||||
if (!ptr) {
|
||||
S.Diag(op->getOperatorLoc(), diag::err_unknown_any_addrof)
|
||||
<< op->getSourceRange();
|
||||
return ExprError();
|
||||
}
|
||||
assert(op->getValueKind() == VK_RValue);
|
||||
assert(op->getObjectKind() == OK_Ordinary);
|
||||
op->setType(DestType);
|
||||
|
||||
// Build the sub-expression as if it were an object of the pointee type.
|
||||
DestType = ptr->getPointeeType();
|
||||
ExprResult subResult = Visit(op->getSubExpr());
|
||||
if (subResult.isInvalid()) return ExprError();
|
||||
op->setSubExpr(subResult.take());
|
||||
return op;
|
||||
}
|
||||
|
||||
ExprResult VisitImplicitCastExpr(ImplicitCastExpr *ice);
|
||||
|
||||
ExprResult resolveDecl(Expr *expr, NamedDecl *decl);
|
||||
ExprResult resolveDecl(Expr *expr, ValueDecl *decl);
|
||||
|
||||
ExprResult VisitMemberExpr(MemberExpr *mem);
|
||||
ExprResult VisitMemberExpr(MemberExpr *mem) {
|
||||
return resolveDecl(mem, mem->getMemberDecl());
|
||||
}
|
||||
|
||||
ExprResult VisitDeclRefExpr(DeclRefExpr *ref) {
|
||||
return resolveDecl(ref, ref->getDecl());
|
||||
|
@ -10296,63 +10389,34 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *call) {
|
|||
}
|
||||
|
||||
ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *msg) {
|
||||
// This is a long series of hacks around the problem that:
|
||||
// - we can't just cast the method because it's not an expr,
|
||||
// - we don't want to modify it in place, and
|
||||
// - there's no way to override the declared result type
|
||||
// of a method on a per-call basis.
|
||||
ObjCMethodDecl *method = msg->getMethodDecl();
|
||||
assert(method && "__unknown_anytype message without result type?");
|
||||
|
||||
const ReferenceType *refTy = DestType->getAs<ReferenceType>();
|
||||
if (refTy) {
|
||||
// Hack 1: if we're returning a reference, make the message
|
||||
// send return a pointer instead.
|
||||
DestType = S.Context.getPointerType(refTy->getPointeeType());
|
||||
// Verify that this is a legal result type of a call.
|
||||
if (DestType->isArrayType() || DestType->isFunctionType()) {
|
||||
S.Diag(msg->getExprLoc(), diag::err_func_returning_array_function)
|
||||
<< DestType->isFunctionType() << DestType;
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
assert(method->getResultType() == S.Context.UnknownAnyTy);
|
||||
method->setResultType(DestType);
|
||||
|
||||
// Change the type of the message.
|
||||
msg->setType(DestType);
|
||||
assert(msg->getValueKind() == VK_RValue);
|
||||
msg->setType(DestType.getNonReferenceType());
|
||||
msg->setValueKind(Expr::getValueKindForType(DestType));
|
||||
|
||||
// Hack 2: remove the method decl so that clients won't just
|
||||
// ignore the expression's type. This is imperfect and can lead
|
||||
// to expressions being completely lost.
|
||||
msg->setSelector(msg->getMethodDecl()->getSelector());
|
||||
|
||||
// Hack 3: if we're returning a reference, dereference the
|
||||
// pointer return.
|
||||
Expr *result = msg;
|
||||
if (refTy) {
|
||||
SourceLocation loc;
|
||||
result = new (S.Context) UnaryOperator(result, UO_Deref,
|
||||
refTy->getPointeeType(),
|
||||
VK_LValue, OK_Ordinary, loc);
|
||||
|
||||
// Hack 4: if we're returning an *rvalue* reference, cast to that.
|
||||
if (isa<RValueReferenceType>(refTy)) {
|
||||
TypeSourceInfo *tsi =
|
||||
S.Context.getTrivialTypeSourceInfo(QualType(refTy, 0), loc);
|
||||
result = CStyleCastExpr::Create(S.Context, refTy->getPointeeType(),
|
||||
VK_XValue, CK_LValueBitCast,
|
||||
result, 0, tsi, loc, loc);
|
||||
}
|
||||
}
|
||||
|
||||
return S.MaybeBindToTemporary(result);
|
||||
return S.MaybeBindToTemporary(msg);
|
||||
}
|
||||
|
||||
ExprResult RebuildUnknownAnyExpr::VisitImplicitCastExpr(ImplicitCastExpr *ice) {
|
||||
// Rebuild an inner resolution by stripping it and propagating
|
||||
// the new type down.
|
||||
if (ice->getCastKind() == CK_ResolveUnknownAnyType)
|
||||
return Visit(ice->getSubExpr());
|
||||
|
||||
// The only other case we should be able to get here is a
|
||||
// function-to-pointer decay.
|
||||
// The only case we should ever see here is a function-to-pointer decay.
|
||||
assert(ice->getCastKind() == CK_FunctionToPointerDecay);
|
||||
ice->setType(DestType);
|
||||
assert(ice->getValueKind() == VK_RValue);
|
||||
assert(ice->getObjectKind() == OK_Ordinary);
|
||||
|
||||
ice->setType(DestType);
|
||||
|
||||
// Rebuild the sub-expression as the pointee (function) type.
|
||||
DestType = DestType->castAs<PointerType>()->getPointeeType();
|
||||
|
||||
|
@ -10363,16 +10427,15 @@ ExprResult RebuildUnknownAnyExpr::VisitImplicitCastExpr(ImplicitCastExpr *ice) {
|
|||
return S.Owned(ice);
|
||||
}
|
||||
|
||||
ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *expr, NamedDecl *decl) {
|
||||
ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *expr, ValueDecl *decl) {
|
||||
ExprValueKind valueKind = VK_LValue;
|
||||
CastKind castKind = CK_ResolveUnknownAnyType;
|
||||
QualType type = DestType;
|
||||
|
||||
// We know how to make this work for certain kinds of decls:
|
||||
|
||||
// - functions
|
||||
if (isa<FunctionDecl>(decl)) {
|
||||
if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(decl))
|
||||
if (FunctionDecl *fn = dyn_cast<FunctionDecl>(decl)) {
|
||||
if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(fn))
|
||||
if (method->isInstance()) valueKind = VK_RValue;
|
||||
|
||||
// This is true because FunctionDecls must always have function
|
||||
|
@ -10385,17 +10448,12 @@ ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *expr, NamedDecl *decl) {
|
|||
|
||||
// - variables
|
||||
} else if (isa<VarDecl>(decl)) {
|
||||
if (S.getLangOptions().CPlusPlus) {
|
||||
// If we're resolving to a reference type, the type of the
|
||||
// expression is the pointee type, and we need to use a
|
||||
// different cast kind so that we know to do the extra load.
|
||||
if (const ReferenceType *refTy = type->getAs<ReferenceType>()) {
|
||||
type = refTy->getPointeeType();
|
||||
castKind = CK_ResolveUnknownAnyTypeToReference;
|
||||
}
|
||||
if (const ReferenceType *refTy = type->getAs<ReferenceType>()) {
|
||||
type = refTy->getPointeeType();
|
||||
} else if (type->isFunctionType()) {
|
||||
// Function references aren't l-values in C.
|
||||
valueKind = VK_RValue;
|
||||
S.Diag(expr->getExprLoc(), diag::err_unknown_any_var_function_type)
|
||||
<< decl << expr->getSourceRange();
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
// - nothing else
|
||||
|
@ -10405,47 +10463,10 @@ ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *expr, NamedDecl *decl) {
|
|||
return ExprError();
|
||||
}
|
||||
|
||||
return S.Owned(ImplicitCastExpr::Create(S.Context, type, castKind,
|
||||
expr, 0, valueKind));
|
||||
}
|
||||
|
||||
ExprResult RebuildUnknownAnyExpr::VisitMemberExpr(MemberExpr *mem) {
|
||||
NamedDecl *decl = mem->getMemberDecl();
|
||||
CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(decl);
|
||||
if (!method || !method->isInstance())
|
||||
return resolveDecl(mem, decl);
|
||||
|
||||
// Rebuild instance-method references as applications of .* or ->*.
|
||||
Expr *base = mem->getBase();
|
||||
|
||||
assert(DestType->isFunctionType());
|
||||
|
||||
// Make a decl ref.
|
||||
TemplateArgumentListInfo explicitArgs;
|
||||
mem->copyTemplateArgumentsInto(explicitArgs);
|
||||
Expr *rhs = DeclRefExpr::Create(S.Context, mem->getQualifierLoc(),
|
||||
method, mem->getMemberNameInfo(),
|
||||
method->getType(), VK_RValue, &explicitArgs);
|
||||
|
||||
// Turn that into a member pointer constant.
|
||||
const Type *recordTy =
|
||||
S.Context.getTypeDeclType(method->getParent()).getTypePtr();
|
||||
QualType mpt = S.Context.getMemberPointerType(method->getType(), recordTy);
|
||||
rhs = new (S.Context) UnaryOperator(rhs, UO_AddrOf, mpt, VK_RValue,
|
||||
OK_Ordinary, SourceLocation());
|
||||
|
||||
// Resolve that.
|
||||
rhs = ImplicitCastExpr::Create(S.Context,
|
||||
S.Context.getMemberPointerType(DestType, recordTy),
|
||||
CK_ResolveUnknownAnyType, rhs, 0, VK_RValue);
|
||||
|
||||
// Turn that into a binary .* or ->*.
|
||||
Expr *result = new (S.Context) BinaryOperator(base, rhs,
|
||||
mem->isArrow() ? BO_PtrMemI : BO_PtrMemD,
|
||||
DestType, VK_RValue,
|
||||
OK_Ordinary, SourceLocation());
|
||||
|
||||
return S.Owned(result);
|
||||
decl->setType(DestType);
|
||||
expr->setType(type);
|
||||
expr->setValueKind(valueKind);
|
||||
return S.Owned(expr);
|
||||
}
|
||||
|
||||
/// Check a cast of an unknown-any type. We intentionally only
|
||||
|
|
|
@ -2176,8 +2176,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
|||
continue;
|
||||
}
|
||||
// Various C++ casts that are not handled yet.
|
||||
case CK_ResolveUnknownAnyType:
|
||||
case CK_ResolveUnknownAnyTypeToReference:
|
||||
case CK_Dynamic:
|
||||
case CK_ToUnion:
|
||||
case CK_BaseToDerived:
|
||||
|
|
|
@ -7,21 +7,28 @@ int test0() {
|
|||
}
|
||||
|
||||
int test1() {
|
||||
extern __unknown_anytype test1_any;
|
||||
// CHECK: call i32 @test1_any()
|
||||
extern __unknown_anytype test1_any();
|
||||
// CHECK: call i32 @_Z9test1_anyv()
|
||||
return (int) test1_any();
|
||||
}
|
||||
|
||||
extern "C" __unknown_anytype test2_any(...);
|
||||
float test2() {
|
||||
extern __unknown_anytype test2_any;
|
||||
// CHECK: call float @test2_any(float {{[^,]+}})
|
||||
// CHECK: call float (...)* @test2_any(double {{[^,]+}})
|
||||
return (float) test2_any(0.5f);
|
||||
}
|
||||
|
||||
extern "C" __unknown_anytype test2a_any(...);
|
||||
float test2a() {
|
||||
// CHECK: call float (...)* @test2a_any(float {{[^,]+}})
|
||||
return (float) test2a_any((float) 0.5f);
|
||||
}
|
||||
|
||||
float test3() {
|
||||
extern __unknown_anytype test3_any;
|
||||
// CHECK: call float @test3_any(i32 5)
|
||||
return ((float(int)) test3_any)(5);
|
||||
// CHECK: [[FN:%.*]] = load float (i32)** @test3_any,
|
||||
// CHECK: call float [[FN]](i32 5)
|
||||
return ((float(*)(int)) test3_any)(5);
|
||||
}
|
||||
|
||||
namespace test4 {
|
||||
|
@ -30,28 +37,28 @@ namespace test4 {
|
|||
|
||||
int test() {
|
||||
// CHECK: load i32* @_ZN5test410test4_any1E
|
||||
// CHECK: call i32 @_ZN5test410test4_any2E
|
||||
return (int) test4_any1 + (int) test4_any2();
|
||||
// CHECK: load i8* @_ZN5test410test4_any2E
|
||||
return (int) test4_any1 + (char) test4_any2;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __unknown_anytype test5_any();
|
||||
void test5() {
|
||||
extern __unknown_anytype test5_any;
|
||||
// CHECK: call void @test5_any()
|
||||
return (void) test5_any();
|
||||
}
|
||||
|
||||
extern "C" __unknown_anytype test6_any(float *);
|
||||
long test6() {
|
||||
extern __unknown_anytype test6_any(float *);
|
||||
// CHECK: call i64 @_Z9test6_anyPf(float* null)
|
||||
// CHECK: call i64 @test6_any(float* null)
|
||||
return (long) test6_any(0);
|
||||
}
|
||||
|
||||
struct Test7 {
|
||||
~Test7();
|
||||
};
|
||||
extern "C" __unknown_anytype test7_any(int);
|
||||
Test7 test7() {
|
||||
extern __unknown_anytype test7_any;
|
||||
// CHECK: call void @test7_any({{%.*}}* sret {{%.*}}, i32 5)
|
||||
return (Test7) test7_any(5);
|
||||
}
|
||||
|
@ -63,14 +70,30 @@ struct Test8 {
|
|||
void test();
|
||||
};
|
||||
void Test8::test() {
|
||||
(int) foo();
|
||||
(int) foo(5);
|
||||
(float) this->foo();
|
||||
(float) this->foo(5);
|
||||
float f;
|
||||
// CHECK: call i32 @_ZN5Test83fooEv(
|
||||
f = (int) foo();
|
||||
// CHECK: call i32 @_ZN5Test83fooEi(
|
||||
f = (int) foo(5);
|
||||
// CHECK: call i32 @_ZN5Test83fooEv(
|
||||
f = (float) this->foo();
|
||||
// CHECK: call i32 @_ZN5Test83fooEi(
|
||||
f = (float) this->foo(5);
|
||||
}
|
||||
void test8(Test8 *p) {
|
||||
(double) p->foo();
|
||||
(double) p->foo(5);
|
||||
(bool) (*p).foo();
|
||||
(bool) (*p).foo(5);
|
||||
double d;
|
||||
// CHECK: call i32 @_ZN5Test83fooEv(
|
||||
d = (double) p->foo();
|
||||
// CHECK: call i32 @_ZN5Test83fooEi(
|
||||
d = (double) p->foo(5);
|
||||
// CHECK: call i32 @_ZN5Test83fooEv(
|
||||
d = (bool) (*p).foo();
|
||||
// CHECK: call i32 @_ZN5Test83fooEi(
|
||||
d = (bool) (*p).foo(5);
|
||||
}
|
||||
|
||||
extern "C" __unknown_anytype test9_foo;
|
||||
void *test9() {
|
||||
// CHECK: ret i8* bitcast (i32* @test9_foo to i8*)
|
||||
return (int*) &test9_foo;
|
||||
}
|
||||
|
|
|
@ -26,3 +26,11 @@ namespace test2 {
|
|||
foo(); // expected-error {{'foo' has unknown return type}}
|
||||
}
|
||||
}
|
||||
|
||||
namespace test3 {
|
||||
extern __unknown_anytype foo;
|
||||
void test() {
|
||||
foo(); // expected-error {{call to unsupported expression with unknown type}}
|
||||
((void(void)) foo)(); // expected-error {{variable 'foo' with unknown type cannot be given a function type}}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче