aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaOverload.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaOverload.cpp')
-rw-r--r--lib/Sema/SemaOverload.cpp129
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