From: John McCall Date: Mon, 11 Apr 2011 07:02:50 +0000 (+0000) Subject: More __unknown_anytype work. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=379b5155b4566f63679e1da6b0ceb5fdfa2aec6d;p=clang More __unknown_anytype work. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129269 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 110c4a7323..3879c48e9a 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -2222,6 +2222,7 @@ private: 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!"); diff --git a/include/clang/AST/OperationKinds.h b/include/clang/AST/OperationKinds.h index ab9d97dbb7..25598ff88b 100644 --- a/include/clang/AST/OperationKinds.h +++ b/include/clang/AST/OperationKinds.h @@ -248,7 +248,10 @@ enum CastKind { CK_IntegralComplexToFloatingComplex, /// \brief Assign an unknown-any declaration a type. - CK_ResolveUnknownAnyType + CK_ResolveUnknownAnyType, + + /// \brief Assign an unknown-any declaration a reference type. + CK_ResolveUnknownAnyTypeToReference }; #define CK_Invalid ((CastKind) -1) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 1ca042e4a8..9dfd2c8a29 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -3851,8 +3851,14 @@ def err_sizeof_pack_no_pack_name_suggest : Error< "%0 does not refer to the name of a parameter pack; did you mean %1?">; def note_parameter_pack_here : Note<"parameter pack %0 declared here">; -def err_bad_use_of_unknown_any : Error< - "no known type for %0; must explicitly cast this expression to use it">; +def err_uncasted_use_of_unknown_any : Error< + "%0 has unknown type; cast it to its declared type to use it">; +def err_uncasted_call_of_unknown_any : Error< + "%0 has unknown return type; cast the call to its declared return type">; +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">; } // end of sema category diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 28f42124f9..1598227249 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1057,6 +1057,8 @@ const char *CastExpr::getCastKindName() const { return "IntegralComplexToFloatingComplex"; case CK_ResolveUnknownAnyType: return "ResolveUnknownAnyType"; + case CK_ResolveUnknownAnyTypeToReference: + return "ResolveUnknownAnyTypeToReference"; } llvm_unreachable("Unhandled cast kind!"); diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index e0f9958298..b2f03a21ba 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -1799,6 +1799,7 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) { case CK_LValueBitCast: case CK_UserDefinedConversion: case CK_ResolveUnknownAnyType: + case CK_ResolveUnknownAnyTypeToReference: return false; case CK_LValueToRValue: @@ -2353,6 +2354,7 @@ bool ComplexExprEvaluator::VisitCastExpr(CastExpr *E) { case CK_LValueBitCast: case CK_UserDefinedConversion: case CK_ResolveUnknownAnyType: + case CK_ResolveUnknownAnyTypeToReference: return false; case CK_FloatingRealToComplex: { diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp index 92f1c63a38..e8b6f56724 100644 --- a/lib/CodeGen/CGCXXABI.cpp +++ b/lib/CodeGen/CGCXXABI.cpp @@ -99,7 +99,8 @@ CGCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) { return GetBogusMemberPointer(CGM, QualType(MPT, 0)); } -llvm::Constant *CGCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { +llvm::Constant *CGCXXABI::EmitMemberPointer(const CXXMethodDecl *MD, + QualType unknownType) { return GetBogusMemberPointer(CGM, CGM.getContext().getMemberPointerType(MD->getType(), MD->getParent()->getTypeForDecl())); diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index de4df3dcbe..a34ca9bcdc 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -119,7 +119,12 @@ public: virtual llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT); /// Create a member pointer for the given method. - virtual llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD); + /// + /// \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()); /// Create a member pointer for the given field. virtual llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT, diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index a35f81ca20..496c3fc0aa 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -1792,6 +1792,35 @@ 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(operand)) { + decl = ref->getDecl(); + } else if (const MemberExpr *mem = dyn_cast(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()) { + 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, @@ -1930,11 +1959,12 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { ConvertType(ToType)); return MakeAddrLValue(V, E->getType()); } - case CK_ResolveUnknownAnyType: { - const DeclRefExpr *declRef = cast(E->getSubExpr()); - llvm::Constant *addr = CGM.getAddrOfUnknownAnyDecl(declRef->getDecl(), - E->getType()); - return MakeAddrLValue(addr, 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); } } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 75e3a7879d..5d22fc3304 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -311,6 +311,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { break; case CK_ResolveUnknownAnyType: + case CK_ResolveUnknownAnyTypeToReference: EmitAggLoadOfLValue(E); break; diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index a3d3f439b6..ef71e89077 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -167,10 +167,12 @@ static bool canDevirtualizeMemberFunctionCalls(ASTContext &Context, // extensions allowing explicit constructor function call. RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, ReturnValueSlot ReturnValue) { - if (isa(CE->getCallee()->IgnoreParens())) + const Expr *callee = CE->getCallee()->IgnoreParens(); + + if (isa(callee)) return EmitCXXMemberPointerCallExpr(CE, ReturnValue); - - const MemberExpr *ME = cast(CE->getCallee()->IgnoreParens()); + + const MemberExpr *ME = cast(callee); const CXXMethodDecl *MD = cast(ME->getMemberDecl()); CGDebugInfo *DI = getDebugInfo(); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 822a999b96..b04ff0aefb 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -553,6 +553,7 @@ public: case CK_ToVoid: case CK_Dynamic: case CK_ResolveUnknownAnyType: + case CK_ResolveUnknownAnyTypeToReference: return 0; // These might need to be supported for constexpr. diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 65aa46fff0..f2ab0a2e06 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -1128,6 +1128,19 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { } case CK_ResolveUnknownAnyType: + // Special case: resolving a member pointer constant. + if (const UnaryOperator *uo = dyn_cast(E)) { + DeclRefExpr *declRef = cast(uo->getSubExpr()); + const CXXMethodDecl *method = cast(declRef->getDecl()); + + const MemberPointerType *mpt = CE->getType()->castAs(); + QualType resolvedType = mpt->getPointeeType(); + + return CGF.CGM.getCXXABI().EmitMemberPointer(method, resolvedType); + } + // fallthrough + + case CK_ResolveUnknownAnyTypeToReference: return EmitLoadOfLValue(CE); case CK_LValueToRValue: diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 53163ed6a5..6c864ca7f4 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -78,7 +78,8 @@ public: llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT); - llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD); + llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD, + QualType unknownType); llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT, CharUnits offset); @@ -502,7 +503,8 @@ ItaniumCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT, return llvm::ConstantInt::get(getPtrDiffTy(), offset.getQuantity()); } -llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { +llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD, + QualType unknownType) { assert(MD->isInstance() && "Member function must not be static!"); MD = MD->getCanonicalDecl(); @@ -537,20 +539,27 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0); } } else { - const FunctionProtoType *FPT = MD->getType()->getAs(); - 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()); + llvm::Constant *addr; + if (!unknownType.isNull()) { + addr = CGM.getAddrOfUnknownAnyDecl(MD, unknownType); } else { - // Use an arbitrary non-function type to tell GetAddrOfFunction that the - // function type is incomplete. - Ty = ptrdiff_t; + QualType fnType = MD->getType(); + const FunctionProtoType *FPT = MD->getType()->castAs(); + 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); } - llvm::Constant *Addr = CGM.GetAddrOfFunction(MD, Ty); - MemPtr[0] = llvm::ConstantExpr::getPtrToInt(Addr, ptrdiff_t); + MemPtr[0] = llvm::ConstantExpr::getPtrToInt(addr, ptrdiff_t); MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0); } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 3ced0fe66d..ca06decaf9 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -4734,10 +4734,24 @@ static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn, if (result.isInvalid()) return ExprError(); args[i] = result.take(); - // Do l2r conversions on all the arguments. - S.DefaultLvalueConversion(args[i]); + QualType argType; - argTypes.push_back(args[i]->getType()); + // 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(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 @@ -10145,6 +10159,10 @@ ExprResult Sema::ActOnBooleanCondition(Scope *S, SourceLocation Loc, } namespace { + /// A visitor for rebuilding an expression of type __unknown_anytype + /// into one which resolves the type directly on the referring + /// expression. Strict preservation of the original source + /// structure is not a goal. struct RebuildUnknownAnyExpr : StmtVisitor { @@ -10157,64 +10175,19 @@ namespace { : S(S), DestType(castType) {} ExprResult VisitStmt(Stmt *S) { - llvm_unreachable("unexpected expression kind!"); + llvm_unreachable("unexpected statement!"); return ExprError(); } - ExprResult VisitCallExpr(CallExpr *call) { - Expr *callee = call->getCallee(); - - bool wasBlock; - QualType type = callee->getType(); - if (const PointerType *ptr = type->getAs()) { - type = ptr->getPointeeType(); - wasBlock = false; - } else { - type = type->castAs()->getPointeeType(); - wasBlock = true; - } - const FunctionType *fnType = type->castAs(); - - // Verify that this is a legal result type of a function. - if (DestType->isArrayType() || DestType->isFunctionType()) { - unsigned diagID = diag::err_func_returning_array_function; - if (wasBlock) diagID = diag::err_block_returning_array_function; - - S.Diag(call->getExprLoc(), diagID) - << DestType->isFunctionType() << DestType; - return ExprError(); - } - - // Otherwise, go ahead and set DestType as the call's result. - call->setType(DestType.getNonLValueExprType(S.Context)); - call->setValueKind(Expr::getValueKindForType(DestType)); - assert(call->getObjectKind() == OK_Ordinary); - - // Rebuild the function type, replacing the result type with DestType. - if (const FunctionProtoType *proto = dyn_cast(fnType)) - DestType = S.Context.getFunctionType(DestType, - proto->arg_type_begin(), - proto->getNumArgs(), - proto->getExtProtoInfo()); - else - DestType = S.Context.getFunctionNoProtoType(DestType, - fnType->getExtInfo()); - - // Rebuild the appropriate pointer-to-function type. - if (wasBlock) - DestType = S.Context.getBlockPointerType(DestType); - else - DestType = S.Context.getPointerType(DestType); - - // Finally, we can recurse. - ExprResult calleeResult = Visit(callee); - if (!calleeResult.isUsable()) return ExprError(); - call->setCallee(calleeResult.take()); - - // Bind a temporary if necessary. - return S.MaybeBindToTemporary(call); + ExprResult VisitExpr(Expr *expr) { + S.Diag(expr->getExprLoc(), diag::err_unsupported_unknown_any_expr) + << expr->getSourceRange(); + return ExprError(); } + ExprResult VisitCallExpr(CallExpr *call); + ExprResult VisitObjCMessageExpr(ObjCMessageExpr *message); + /// Rebuild an expression which simply semantically wraps another /// expression which it shares the type and value kind of. template ExprResult rebuildSugarExpr(T *expr) { @@ -10236,45 +10209,243 @@ namespace { return rebuildSugarExpr(op); } - ExprResult 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()); + ExprResult VisitImplicitCastExpr(ImplicitCastExpr *ice); + + ExprResult resolveDecl(Expr *expr, NamedDecl *decl); + + ExprResult VisitMemberExpr(MemberExpr *mem); + + ExprResult VisitDeclRefExpr(DeclRefExpr *ref) { + return resolveDecl(ref, ref->getDecl()); + } + }; +} + +/// Rebuilds a call expression which yielded __unknown_anytype. +ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *call) { + Expr *callee = call->getCallee(); + + enum FnKind { + FK_Function, + FK_FunctionPointer, + FK_BlockPointer + }; + + FnKind kind; + QualType type = callee->getType(); + if (type->isFunctionType()) { + assert(isa(call) || isa(call)); + kind = FK_Function; + } else if (const PointerType *ptr = type->getAs()) { + type = ptr->getPointeeType(); + kind = FK_FunctionPointer; + } else { + type = type->castAs()->getPointeeType(); + kind = FK_BlockPointer; + } + const FunctionType *fnType = type->castAs(); + + // Verify that this is a legal result type of a function. + if (DestType->isArrayType() || DestType->isFunctionType()) { + unsigned diagID = diag::err_func_returning_array_function; + if (kind == FK_BlockPointer) + diagID = diag::err_block_returning_array_function; + + S.Diag(call->getExprLoc(), diagID) + << DestType->isFunctionType() << DestType; + return ExprError(); + } + + // Otherwise, go ahead and set DestType as the call's result. + call->setType(DestType.getNonLValueExprType(S.Context)); + call->setValueKind(Expr::getValueKindForType(DestType)); + assert(call->getObjectKind() == OK_Ordinary); + + // Rebuild the function type, replacing the result type with DestType. + if (const FunctionProtoType *proto = dyn_cast(fnType)) + DestType = S.Context.getFunctionType(DestType, + proto->arg_type_begin(), + proto->getNumArgs(), + proto->getExtProtoInfo()); + else + DestType = S.Context.getFunctionNoProtoType(DestType, + fnType->getExtInfo()); + + // Rebuild the appropriate pointer-to-function type. + switch (kind) { + case FK_Function: + // Nothing to do. + break; + + case FK_FunctionPointer: + DestType = S.Context.getPointerType(DestType); + break; + + case FK_BlockPointer: + DestType = S.Context.getBlockPointerType(DestType); + break; + } - // The only other case we should be able to get 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); + // Finally, we can recurse. + ExprResult calleeResult = Visit(callee); + if (!calleeResult.isUsable()) return ExprError(); + call->setCallee(calleeResult.take()); - // Rebuild the sub-expression as the pointee (function) type. - DestType = DestType->castAs()->getPointeeType(); + // Bind a temporary if necessary. + return S.MaybeBindToTemporary(call); +} - ExprResult result = Visit(ice->getSubExpr()); - if (!result.isUsable()) return ExprError(); +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. - ice->setSubExpr(result.take()); - return S.Owned(ice); + const ReferenceType *refTy = DestType->getAs(); + if (refTy) { + // Hack 1: if we're returning a reference, make the message + // send return a pointer instead. + DestType = S.Context.getPointerType(refTy->getPointeeType()); + } + + // Change the type of the message. + msg->setType(DestType); + assert(msg->getValueKind() == VK_RValue); + + // 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(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); } + } - ExprResult VisitDeclRefExpr(DeclRefExpr *ref) { - ExprValueKind valueKind = VK_LValue; - if (S.getLangOptions().CPlusPlus) { - // FIXME: if the value was resolved as a reference type, we - // should really remember that somehow, or else we'll be - // missing a load. - DestType = DestType.getNonReferenceType(); - } else if (DestType->isFunctionType()) { - valueKind = VK_RValue; - } + return S.MaybeBindToTemporary(result); +} + +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. + assert(ice->getCastKind() == CK_FunctionToPointerDecay); + ice->setType(DestType); + assert(ice->getValueKind() == VK_RValue); + assert(ice->getObjectKind() == OK_Ordinary); - return S.Owned(ImplicitCastExpr::Create(S.Context, DestType, - CK_ResolveUnknownAnyType, - ref, 0, valueKind)); + // Rebuild the sub-expression as the pointee (function) type. + DestType = DestType->castAs()->getPointeeType(); + + ExprResult result = Visit(ice->getSubExpr()); + if (!result.isUsable()) return ExprError(); + + ice->setSubExpr(result.take()); + return S.Owned(ice); +} + +ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *expr, NamedDecl *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(decl)) { + if (CXXMethodDecl *method = dyn_cast(decl)) + if (method->isInstance()) valueKind = VK_RValue; + + // This is true because FunctionDecls must always have function + // type, so we can't be resolving the entire thing at once. + assert(type->isFunctionType()); + + // Function references aren't l-values in C. + if (!S.getLangOptions().CPlusPlus) + valueKind = VK_RValue; + + // - variables + } else if (isa(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()) { + type = refTy->getPointeeType(); + castKind = CK_ResolveUnknownAnyTypeToReference; + } + } else if (type->isFunctionType()) { + // Function references aren't l-values in C. + valueKind = VK_RValue; } - }; + + // - nothing else + } else { + S.Diag(expr->getExprLoc(), diag::err_unsupported_unknown_any_decl) + << decl << expr->getSourceRange(); + 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(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); } /// Check a cast of an unknown-any type. We intentionally only @@ -10295,18 +10466,37 @@ ExprResult Sema::checkUnknownAnyCast(SourceRange typeRange, QualType castType, static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *e) { Expr *orig = e; + unsigned diagID = diag::err_uncasted_use_of_unknown_any; while (true) { e = e->IgnoreParenImpCasts(); - if (CallExpr *call = dyn_cast(e)) + if (CallExpr *call = dyn_cast(e)) { e = call->getCallee(); - else + diagID = diag::err_uncasted_call_of_unknown_any; + } else { break; + } + } + + SourceLocation loc; + NamedDecl *d; + if (DeclRefExpr *ref = dyn_cast(e)) { + loc = ref->getLocation(); + d = ref->getDecl(); + } else if (MemberExpr *mem = dyn_cast(e)) { + loc = mem->getMemberLoc(); + d = mem->getMemberDecl(); + } else if (ObjCMessageExpr *msg = dyn_cast(e)) { + diagID = diag::err_uncasted_call_of_unknown_any; + loc = msg->getSelectorLoc(); + d = msg->getMethodDecl(); + assert(d && "unknown method returning __unknown_any?"); + } else { + S.Diag(e->getExprLoc(), diag::err_unsupported_unknown_any_expr) + << e->getSourceRange(); + return ExprError(); } - assert(isa(e) && "unexpected form of unknown-any expression"); - DeclRefExpr *ref = cast(e); - S.Diag(ref->getLocation(), diag::err_bad_use_of_unknown_any) - << ref->getDecl() << orig->getSourceRange(); + S.Diag(loc, diagID) << d << orig->getSourceRange(); // Never recoverable. return ExprError(); diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 0a7f1e93af..7dd580475e 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -2177,6 +2177,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, } // Various C++ casts that are not handled yet. case CK_ResolveUnknownAnyType: + case CK_ResolveUnknownAnyTypeToReference: case CK_Dynamic: case CK_ToUnion: case CK_BaseToDerived: diff --git a/test/CodeGenCXX/unknown-anytype.cpp b/test/CodeGenCXX/unknown-anytype.cpp index fdf5fab9cf..06b6490168 100644 --- a/test/CodeGenCXX/unknown-anytype.cpp +++ b/test/CodeGenCXX/unknown-anytype.cpp @@ -55,3 +55,22 @@ Test7 test7() { // CHECK: call void @test7_any({{%.*}}* sret {{%.*}}, i32 5) return (Test7) test7_any(5); } + +struct Test8 { + __unknown_anytype foo(); + __unknown_anytype foo(int); + + void test(); +}; +void Test8::test() { + (int) foo(); + (int) foo(5); + (float) this->foo(); + (float) this->foo(5); +} +void test8(Test8 *p) { + (double) p->foo(); + (double) p->foo(5); + (bool) (*p).foo(); + (bool) (*p).foo(5); +} diff --git a/test/SemaCXX/unknown-anytype.cpp b/test/SemaCXX/unknown-anytype.cpp index bbf6a9e72f..053e0f8573 100644 --- a/test/SemaCXX/unknown-anytype.cpp +++ b/test/SemaCXX/unknown-anytype.cpp @@ -15,7 +15,14 @@ namespace test1 { // properly. int x = foo; // expected-error {{cannot initialize}} - int y = 0 + foo; // expected-error {{no known type for 'foo'; must explicitly cast this expression to use it}} + int y = 0 + foo; // expected-error {{'foo' has unknown type}} return foo; // expected-error {{cannot initialize}} } } + +namespace test2 { + extern __unknown_anytype foo(); + void test() { + foo(); // expected-error {{'foo' has unknown return type}} + } +}