diff options
Diffstat (limited to 'lib/Sema/SemaOverload.cpp')
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 129 |
1 files changed, 16 insertions, 113 deletions
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 93acf89e90..79aa305b86 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -3644,6 +3644,18 @@ TryCopyInitialization(Sema &S, Expr *From, QualType ToType, AllowObjCWritebackConversion); } +static bool TryCopyInitialization(const CanQualType FromQTy, + const CanQualType ToQTy, + Sema &S, + SourceLocation Loc, + ExprValueKind FromVK) { + OpaqueValueExpr TmpExpr(Loc, FromQTy, FromVK); + ImplicitConversionSequence ICS = + TryCopyInitialization(S, &TmpExpr, ToQTy, true, true, false); + + return !ICS.isBad(); +} + /// TryObjectArgumentInitialization - Try to initialize the object /// parameter of the given member function (@c Method) from the /// expression @p From. @@ -6729,108 +6741,6 @@ void ImplicitConversionSequence::DiagnoseAmbiguousConversion( namespace { -/// Try to find a fix for the bad conversion. Populate the ConvFix structure -/// on success. Produces the hints for the following cases: -/// - The user forgot to apply * or & operator to one or more arguments. -static bool TryToFixBadConversion(Sema &S, - const ImplicitConversionSequence &Conv, - OverloadCandidate::FixInfo &ConvFix) { - assert(Conv.isBad() && "Only try to fix a bad conversion."); - - const Expr *Arg = Conv.Bad.FromExpr; - if (!Arg) - return false; - - // The conversion is from argument type to parameter type. - const CanQualType FromQTy = S.Context.getCanonicalType(Conv.Bad - .getFromType()); - const CanQualType ToQTy = S.Context.getCanonicalType(Conv.Bad.getToType()); - const SourceLocation Begin = Arg->getSourceRange().getBegin(); - const SourceLocation End = S.PP.getLocForEndOfToken(Arg->getSourceRange() - .getEnd()); - bool NeedParen = true; - if (isa<ParenExpr>(Arg) || - isa<DeclRefExpr>(Arg) || - isa<ArraySubscriptExpr>(Arg) || - isa<CallExpr>(Arg) || - isa<MemberExpr>(Arg)) - NeedParen = false; - if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Arg)) - if (UO->isPostfix()) - NeedParen = false; - - // Check if the argument needs to be dereferenced - // (type * -> type) or (type * -> type &). - if (const PointerType *FromPtrTy = dyn_cast<PointerType>(FromQTy)) { - // Try to construct an implicit conversion from argument type to the - // parameter type. - OpaqueValueExpr TmpExpr(Arg->getExprLoc(), FromPtrTy->getPointeeType(), - VK_LValue); - ImplicitConversionSequence ICS = - TryCopyInitialization(S, &TmpExpr, ToQTy, true, true, false); - - OverloadFixItKind FixKind = OFIK_Dereference; - if (!ICS.isBad()) { - // Do not suggest dereferencing a Null pointer. - if (Arg->IgnoreParenCasts()-> - isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)) - return false; - - if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Arg)) { - if (UO->getOpcode() == UO_AddrOf) { - ConvFix.Hints.push_back( - FixItHint::CreateRemoval(Arg->getSourceRange())); - FixKind = OFIK_RemoveTakeAddress; - } - } else if (NeedParen) { - ConvFix.Hints.push_back(FixItHint::CreateInsertion(Begin, "*(")); - ConvFix.Hints.push_back(FixItHint::CreateInsertion(End, ")")); - } else { - ConvFix.Hints.push_back(FixItHint::CreateInsertion(Begin, "*")); - } - ConvFix.NumConversionsFixed++; - if (ConvFix.NumConversionsFixed == 1) - ConvFix.Kind = FixKind; - return true; - } - } - - // Check if the pointer to the argument needs to be passed - // (type -> type *) or (type & -> type *). - if (isa<PointerType>(ToQTy)) { - // Only suggest taking address of L-values. - if (!Arg->isLValue() || Arg->getObjectKind() != OK_Ordinary) - return false; - - OpaqueValueExpr TmpExpr(Arg->getExprLoc(), - S.Context.getPointerType(FromQTy), VK_RValue); - ImplicitConversionSequence ICS = - TryCopyInitialization(S, &TmpExpr, ToQTy, true, true, false); - - OverloadFixItKind FixKind = OFIK_TakeAddress; - if (!ICS.isBad()) { - - if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Arg)) { - if (UO->getOpcode() == UO_Deref) { - ConvFix.Hints.push_back( - FixItHint::CreateRemoval(Arg->getSourceRange())); - FixKind = OFIK_RemoveDereference; - } - } else if (NeedParen) { - ConvFix.Hints.push_back(FixItHint::CreateInsertion(Begin, "&(")); - ConvFix.Hints.push_back(FixItHint::CreateInsertion(End, ")")); - } else { - ConvFix.Hints.push_back(FixItHint::CreateInsertion(Begin, "&")); - } - ConvFix.NumConversionsFixed++; - if (ConvFix.NumConversionsFixed == 1) - ConvFix.Kind = FixKind; - return true; - } - } - return false; -} - void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { const ImplicitConversionSequence &Conv = Cand->Conversions[I]; assert(Conv.isBad()); @@ -7015,7 +6925,6 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { } } - // TODO: specialize more based on the kind of mismatch // Emit the generic diagnostic and, optionally, add the hints to it. PartialDiagnostic FDiag = S.PDiag(diag::note_ovl_candidate_bad_conv); FDiag << (unsigned) FnKind << FnDesc @@ -7446,6 +7355,8 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, // We only want the FixIts if all the arguments can be corrected. bool Unfixable = false; + // Use a implicit copy initialization to check conversion fixes. + Cand->Fix.setConversionChecker(TryCopyInitialization); // Skip forward to the first bad conversion. unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0); @@ -7454,9 +7365,7 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, assert(ConvIdx != ConvCount && "no bad conversion in candidate"); ConvIdx++; if (Cand->Conversions[ConvIdx - 1].isBad()) { - if ((Unfixable = !TryToFixBadConversion(S, Cand->Conversions[ConvIdx - 1], - Cand->Fix))) - Cand->Fix.Hints.clear(); + Unfixable = !Cand->TryToFixBadConversion(ConvIdx - 1, S); break; } } @@ -7512,17 +7421,11 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, S.getLangOptions().ObjCAutoRefCount); // Store the FixIt in the candidate if it exists. if (!Unfixable && Cand->Conversions[ConvIdx].isBad()) - Unfixable = !TryToFixBadConversion(S, Cand->Conversions[ConvIdx], - Cand->Fix); + Unfixable = !Cand->TryToFixBadConversion(ConvIdx, S); } else Cand->Conversions[ConvIdx].setEllipsis(); } - - if (Unfixable) { - Cand->Fix.Hints.clear(); - Cand->Fix.NumConversionsFixed = 0; - } } } // end anonymous namespace |