diff options
author | John McCall <rjmccall@apple.com> | 2011-04-07 08:22:57 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-04-07 08:22:57 +0000 |
commit | 1de4d4e8cb2e9c88809fea8092bc6e835a5473d2 (patch) | |
tree | 882a7f7c98e0dd8f015d2d7364c941026ecd19c2 /lib/Sema/SemaExpr.cpp | |
parent | 1a7f7526b7fd817e3f49c210302d189eff981b5e (diff) |
Basic, untested implementation for an "unknown any" type requested by LLDB.
The idea is that you can create a VarDecl with an unknown type, or a
FunctionDecl with an unknown return type, and it will still be valid to
access that object as long as you explicitly cast it at every use. I'm
still going back and forth about how I want to test this effectively, but
I wanted to go ahead and provide a skeletal implementation for the LLDB
folks' benefit and because it also improves some diagnostic goodness for
placeholder expressions.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129065 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaExpr.cpp')
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 220 |
1 files changed, 185 insertions, 35 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 13ac32dcb1..b62b2eeff1 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -4658,6 +4658,47 @@ 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) { + // 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], SourceLocation()); + if (result.isInvalid()) return ExprError(); + args[i] = result.take(); + + // Do l2r conversions on all the arguments. + S.DefaultLvalueConversion(args[i]); + + argTypes.push_back(args[i]->getType()); + } + + // 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 @@ -4699,6 +4740,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID)) return CheckBuiltinFunctionCall(BuiltinID, TheCall); + retry: const FunctionType *FuncT; if (const PointerType *PT = Fn->getType()->getAs<PointerType>()) { // C99 6.5.2.2p1 - "The expression that denotes the called function shall @@ -4711,6 +4753,15 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, Fn->getType()->getAs<BlockPointerType>()) { FuncT = BPT->getPointeeType()->castAs<FunctionType>(); } else { + // Handle calls to expressions of unknown-any type. + if (Fn->getType() == Context.UnknownAnyTy) { + ExprResult rewrite = rebuildUnknownAnyFunction(*this, Fn, Args, NumArgs); + if (rewrite.isInvalid()) return ExprError(); + Fn = rewrite.take(); + NDecl = FDecl = 0; + goto retry; + } + return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function) << Fn->getType() << Fn->getSourceRange()); } @@ -5038,6 +5089,9 @@ static CastKind PrepareScalarCast(Sema &S, Expr *&Src, QualType DestTy) { bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, CastKind& Kind, ExprValueKind &VK, CXXCastPath &BasePath, bool FunctionalStyle) { + if (castExpr->getType() == Context.UnknownAnyTy) + return checkUnknownAnyCast(TyR, castType, castExpr, Kind, VK, BasePath); + if (getLangOptions().CPlusPlus) return CXXCheckCStyleCast(SourceRange(TyR.getBegin(), castExpr->getLocEnd()), @@ -5398,19 +5452,13 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, SourceLocation QuestionLoc) { // If either LHS or RHS are overloaded functions, try to resolve them. - if (LHS->getType() == Context.OverloadTy || - RHS->getType() == Context.OverloadTy) { - ExprResult LHSResult = CheckPlaceholderExpr(LHS, QuestionLoc); - if (LHSResult.isInvalid()) - return QualType(); - - ExprResult RHSResult = CheckPlaceholderExpr(RHS, QuestionLoc); - if (RHSResult.isInvalid()) - return QualType(); + ExprResult lhsResult = CheckPlaceholderExpr(LHS, QuestionLoc); + if (!lhsResult.isUsable()) return QualType(); + LHS = lhsResult.take(); - LHS = LHSResult.take(); - RHS = RHSResult.take(); - } + ExprResult rhsResult = CheckPlaceholderExpr(RHS, QuestionLoc); + if (!rhsResult.isUsable()) return QualType(); + RHS = rhsResult.take(); // C++ is sufficiently different to merit its own checker. if (getLangOptions().CPlusPlus) @@ -8161,16 +8209,13 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, // f<int> == 0; // resolve f<int> blindly // void (*p)(int); p = f<int>; // resolve f<int> using target if (Opc != BO_Assign) { - if (lhs->getType() == Context.OverloadTy) { - ExprResult resolvedLHS = - ResolveAndFixSingleFunctionTemplateSpecialization(lhs); - if (resolvedLHS.isUsable()) lhs = resolvedLHS.release(); - } - if (rhs->getType() == Context.OverloadTy) { - ExprResult resolvedRHS = - ResolveAndFixSingleFunctionTemplateSpecialization(rhs); - if (resolvedRHS.isUsable()) rhs = resolvedRHS.release(); - } + ExprResult resolvedLHS = CheckPlaceholderExpr(lhs, OpLoc); + if (!resolvedLHS.isUsable()) return ExprError(); + lhs = resolvedLHS.take(); + + ExprResult resolvedRHS = CheckPlaceholderExpr(rhs, OpLoc); + if (!resolvedRHS.isUsable()) return ExprError(); + rhs = resolvedRHS.take(); } switch (Opc) { @@ -8529,15 +8574,14 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, case UO_AddrOf: resultType = CheckAddressOfOperand(*this, Input, OpLoc); break; - case UO_Deref: - if (Input->getType() == Context.OverloadTy ) { - ExprResult er = ResolveAndFixSingleFunctionTemplateSpecialization(Input); - if (er.isUsable()) - Input = er.release(); - } + case UO_Deref: { + ExprResult resolved = CheckPlaceholderExpr(Input, OpLoc); + if (!resolved.isUsable()) return ExprError(); + Input = resolved.take(); DefaultFunctionArrayLvalueConversion(Input); resultType = CheckIndirectionOperand(*this, Input, VK, OpLoc); break; + } case UO_Plus: case UO_Minus: UsualUnaryConversions(Input); @@ -9904,16 +9948,122 @@ ExprResult Sema::ActOnBooleanCondition(Scope *S, SourceLocation Loc, return Owned(Sub); } +namespace { + struct RebuildUnknownAnyExpr + : StmtVisitor<RebuildUnknownAnyExpr, Expr*> { + + Sema &S; + + /// The current destination type. + QualType DestType; + + RebuildUnknownAnyExpr(Sema &S, QualType castType) + : S(S), DestType(castType) {} + + Expr *VisitStmt(Stmt *S) { + llvm_unreachable("unexpected expression kind!"); + return 0; + } + + Expr *VisitCallExpr(CallExpr *call) { + call->setCallee(Visit(call->getCallee())); + return call; + } + + Expr *VisitParenExpr(ParenExpr *paren) { + paren->setSubExpr(Visit(paren->getSubExpr())); + return paren; + } + + Expr *VisitUnaryExtension(UnaryOperator *op) { + op->setSubExpr(Visit(op->getSubExpr())); + return op; + } + + Expr *VisitImplicitCastExpr(ImplicitCastExpr *ice) { + // If this isn't an inner resolution, just recurse down. + if (ice->getCastKind() != CK_ResolveUnknownAnyType) { + assert(ice->getCastKind() == CK_FunctionToPointerDecay); + ice->setSubExpr(Visit(ice->getSubExpr())); + return ice; + } + + QualType type = ice->getType(); + assert(type.getUnqualifiedType() == type); + + // The only time it should be possible for this to appear + // internally to an unknown-any expression is when handling a call. + const FunctionProtoType *proto = type->castAs<FunctionProtoType>(); + DestType = S.Context.getFunctionType(DestType, + proto->arg_type_begin(), + proto->getNumArgs(), + proto->getExtProtoInfo()); + + // Strip the resolve cast when recursively rebuilding. + return Visit(ice->getSubExpr()); + } + + Expr *VisitDeclRefExpr(DeclRefExpr *ref) { + ExprValueKind valueKind = VK_LValue; + if (!S.getLangOptions().CPlusPlus && DestType->isFunctionType()) + valueKind = VK_RValue; + + return ImplicitCastExpr::Create(S.Context, DestType, + CK_ResolveUnknownAnyType, + ref, 0, valueKind); + } + }; +} + +/// Check a cast of an unknown-any type. We intentionally only +/// trigger this for C-style casts. +bool Sema::checkUnknownAnyCast(SourceRange typeRange, QualType castType, + Expr *&castExpr, CastKind &castKind, + ExprValueKind &VK, CXXCastPath &path) { + VK = Expr::getValueKindForType(castType); + + // Rewrite the casted expression from scratch. + castExpr = RebuildUnknownAnyExpr(*this, castType).Visit(castExpr); + + return CheckCastTypes(typeRange, castType, castExpr, castKind, VK, path); +} + +static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *e) { + Expr *orig = e; + while (true) { + e = e->IgnoreParenImpCasts(); + if (CallExpr *call = dyn_cast<CallExpr>(e)) + e = call->getCallee(); + else + break; + } + + assert(isa<DeclRefExpr>(e) && "unexpected form of unknown-any expression"); + DeclRefExpr *ref = cast<DeclRefExpr>(e); + S.Diag(ref->getLocation(), diag::err_bad_use_of_unknown_any) + << ref->getDecl() << orig->getSourceRange(); + + // Never recoverable. + return ExprError(); +} + /// Check for operands with placeholder types and complain if found. /// Returns true if there was an error and no recovery was possible. ExprResult Sema::CheckPlaceholderExpr(Expr *E, SourceLocation Loc) { - const BuiltinType *BT = E->getType()->getAs<BuiltinType>(); - if (!BT || !BT->isPlaceholderType()) return Owned(E); + // Placeholder types are always *exactly* the appropriate builtin type. + QualType type = E->getType(); - // If this is overload, check for a single overload. - assert(BT->getKind() == BuiltinType::Overload); - return ResolveAndFixSingleFunctionTemplateSpecialization(E, false, true, + // Overloaded expressions. + if (type == Context.OverloadTy) + return ResolveAndFixSingleFunctionTemplateSpecialization(E, false, true, E->getSourceRange(), - QualType(), - diag::err_ovl_unresolvable); + QualType(), + diag::err_ovl_unresolvable); + + // Expressions of unknown type. + if (type == Context.UnknownAnyTy) + return diagnoseUnknownAnyExpr(*this, E); + + assert(!type->isPlaceholderType()); + return Owned(E); } |