summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaOverload.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-06-29 23:17:37 +0000
committerDouglas Gregor <dgregor@apple.com>2010-06-29 23:17:37 +0000
commitf4ea725d38cc52d34512a11bc0d40a3e9bfffaec (patch)
treeeb3c2d8fda69c9438ea7b79ce489e0633c425681 /clang/lib/Sema/SemaOverload.cpp
parent94a6899e2314964db5b1fb3fb9f37ee511a2f2fa (diff)
downloadbcm5719-llvm-f4ea725d38cc52d34512a11bc0d40a3e9bfffaec.tar.gz
bcm5719-llvm-f4ea725d38cc52d34512a11bc0d40a3e9bfffaec.zip
Factor the conversion from a switch condition to an integral or
enumeration type out into a separate, reusable routine. The only functionality change here is that we recover a little more aggressively from ill-formed switch conditions. llvm-svn: 107222
Diffstat (limited to 'clang/lib/Sema/SemaOverload.cpp')
-rw-r--r--clang/lib/Sema/SemaOverload.cpp134
1 files changed, 134 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 317e8cd6d38..af28d46b5fe 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -3068,6 +3068,140 @@ bool Sema::PerformContextuallyConvertToObjCId(Expr *&From) {
return true;
}
+/// \brief Attempt to convert the given expression to an integral or
+/// enumeration type.
+///
+/// This routine will attempt to convert an expression of class type to an
+/// integral or enumeration type, if that class type only has a single
+/// conversion to an integral or enumeration type.
+///
+/// \param From The expression we're converting from.
+///
+/// \returns The expression converted to an integral or enumeration type,
+/// if successful, or an invalid expression.
+Sema::OwningExprResult
+Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, ExprArg FromE,
+ const PartialDiagnostic &NotIntDiag,
+ const PartialDiagnostic &IncompleteDiag,
+ const PartialDiagnostic &ExplicitConvDiag,
+ const PartialDiagnostic &ExplicitConvNote,
+ const PartialDiagnostic &AmbigDiag,
+ const PartialDiagnostic &AmbigNote) {
+ Expr *From = static_cast<Expr *>(FromE.get());
+
+ // We can't perform any more checking for type-dependent expressions.
+ if (From->isTypeDependent())
+ return move(FromE);
+
+ // If the expression already has integral or enumeration type, we're golden.
+ QualType T = From->getType();
+ if (T->isIntegralOrEnumerationType())
+ return move(FromE);
+
+ // FIXME: Check for missing '()' if T is a function type?
+
+ // If we don't have a class type in C++, there's no way we can get an
+ // expression of integral or enumeration type.
+ const RecordType *RecordTy = T->getAs<RecordType>();
+ if (!RecordTy || !getLangOptions().CPlusPlus) {
+ Diag(Loc, NotIntDiag)
+ << T << From->getSourceRange();
+ return ExprError();
+ }
+
+ // We must have a complete class type.
+ if (RequireCompleteType(Loc, T, IncompleteDiag))
+ return ExprError();
+
+ // Look for a conversion to an integral or enumeration type.
+ UnresolvedSet<4> ViableConversions;
+ UnresolvedSet<4> ExplicitConversions;
+ const UnresolvedSetImpl *Conversions
+ = cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions();
+
+ for (UnresolvedSetImpl::iterator I = Conversions->begin(),
+ E = Conversions->end();
+ I != E;
+ ++I) {
+ if (CXXConversionDecl *Conversion
+ = dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl()))
+ if (Conversion->getConversionType().getNonReferenceType()
+ ->isIntegralOrEnumerationType()) {
+ if (Conversion->isExplicit())
+ ExplicitConversions.addDecl(I.getDecl(), I.getAccess());
+ else
+ ViableConversions.addDecl(I.getDecl(), I.getAccess());
+ }
+ }
+
+ switch (ViableConversions.size()) {
+ case 0:
+ if (ExplicitConversions.size() == 1) {
+ DeclAccessPair Found = ExplicitConversions[0];
+ CXXConversionDecl *Conversion
+ = cast<CXXConversionDecl>(Found->getUnderlyingDecl());
+
+ // The user probably meant to invoke the given explicit
+ // conversion; use it.
+ QualType ConvTy
+ = Conversion->getConversionType().getNonReferenceType();
+ std::string TypeStr;
+ ConvTy.getAsStringInternal(TypeStr, Context.PrintingPolicy);
+
+ Diag(Loc, ExplicitConvDiag)
+ << T << ConvTy
+ << FixItHint::CreateInsertion(From->getLocStart(),
+ "static_cast<" + TypeStr + ">(")
+ << FixItHint::CreateInsertion(PP.getLocForEndOfToken(From->getLocEnd()),
+ ")");
+ Diag(Conversion->getLocation(), ExplicitConvNote)
+ << ConvTy->isEnumeralType() << ConvTy;
+
+ // If we aren't in a SFINAE context, build a call to the
+ // explicit conversion function.
+ if (isSFINAEContext())
+ return ExprError();
+
+ CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);
+ From = BuildCXXMemberCallExpr(FromE.takeAs<Expr>(), Found, Conversion);
+ FromE = Owned(From);
+ }
+
+ // We'll complain below about a non-integral condition type.
+ break;
+
+ case 1: {
+ // Apply this conversion.
+ DeclAccessPair Found = ViableConversions[0];
+ CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);
+ From = BuildCXXMemberCallExpr(FromE.takeAs<Expr>(), Found,
+ cast<CXXConversionDecl>(Found->getUnderlyingDecl()));
+ FromE = Owned(From);
+ break;
+ }
+
+ default:
+ Diag(Loc, AmbigDiag)
+ << T << From->getSourceRange();
+ for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {
+ CXXConversionDecl *Conv
+ = cast<CXXConversionDecl>(ViableConversions[I]->getUnderlyingDecl());
+ QualType ConvTy = Conv->getConversionType().getNonReferenceType();
+ Diag(Conv->getLocation(), AmbigNote)
+ << ConvTy->isEnumeralType() << ConvTy;
+ }
+ return ExprError();
+ }
+
+ if (!From->getType()->isIntegralOrEnumerationType()) {
+ Diag(Loc, NotIntDiag)
+ << From->getType() << From->getSourceRange();
+ return ExprError();
+ }
+
+ return move(FromE);
+}
+
/// AddOverloadCandidate - Adds the given function to the set of
/// candidate functions, using the given function call arguments. If
/// @p SuppressUserConversions, then don't allow user-defined
OpenPOWER on IntegriCloud