[cfe-commits] r107222 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaExprCXX.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaStmt.cpp test/Sema/complex-int.c
Douglas Gregor
dgregor at apple.com
Tue Jun 29 16:17:37 PDT 2010
Author: dgregor
Date: Tue Jun 29 18:17:37 2010
New Revision: 107222
URL: http://llvm.org/viewvc/llvm-project?rev=107222&view=rev
Log:
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.
Modified:
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaStmt.cpp
cfe/trunk/test/Sema/complex-int.c
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=107222&r1=107221&r2=107222&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Jun 29 18:17:37 2010
@@ -1188,6 +1188,15 @@
ImplicitConversionSequence TryContextuallyConvertToObjCId(Expr *From);
bool PerformContextuallyConvertToObjCId(Expr *&From);
+ OwningExprResult
+ ConvertToIntegralOrEnumerationType(SourceLocation Loc, ExprArg FromE,
+ const PartialDiagnostic &NotIntDiag,
+ const PartialDiagnostic &IncompleteDiag,
+ const PartialDiagnostic &ExplicitConvDiag,
+ const PartialDiagnostic &ExplicitConvNote,
+ const PartialDiagnostic &AmbigDiag,
+ const PartialDiagnostic &AmbigNote);
+
bool PerformObjectMemberConversion(Expr *&From,
NestedNameSpecifier *Qualifier,
NamedDecl *FoundDecl,
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=107222&r1=107221&r2=107222&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Jun 29 18:17:37 2010
@@ -722,6 +722,7 @@
Expr *ArraySize = (Expr *)ArraySizeE.get();
if (ArraySize && !ArraySize->isTypeDependent()) {
QualType SizeType = ArraySize->getType();
+
if (!SizeType->isIntegralOrEnumerationType())
return ExprError(Diag(ArraySize->getSourceRange().getBegin(),
diag::err_array_size_not_integral)
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=107222&r1=107221&r2=107222&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Jun 29 18:17:37 2010
@@ -3068,6 +3068,140 @@
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
Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=107222&r1=107221&r2=107222&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Tue Jun 29 18:17:37 2010
@@ -410,112 +410,6 @@
return expr->getType();
}
-/// \brief Check (and possibly convert) the condition in a switch
-/// statement in C++.
-static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc,
- Expr *&CondExpr) {
- if (CondExpr->isTypeDependent())
- return false;
-
- QualType CondType = CondExpr->getType();
-
- // C++ 6.4.2.p2:
- // The condition shall be of integral type, enumeration type, or of a class
- // type for which a single conversion function to integral or enumeration
- // type exists (12.3). If the condition is of class type, the condition is
- // converted by calling that conversion function, and the result of the
- // conversion is used in place of the original condition for the remainder
- // of this section. Integral promotions are performed.
-
- // Make sure that the condition expression has a complete type,
- // otherwise we'll never find any conversions.
- if (S.RequireCompleteType(SwitchLoc, CondType,
- S.PDiag(diag::err_switch_incomplete_class_type)
- << CondExpr->getSourceRange()))
- return true;
-
- UnresolvedSet<4> ViableConversions;
- UnresolvedSet<4> ExplicitConversions;
- if (const RecordType *RecordTy = CondType->getAs<RecordType>()) {
- 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, S.Context.PrintingPolicy);
-
- S.Diag(SwitchLoc, diag::err_switch_explicit_conversion)
- << CondType << ConvTy << CondExpr->getSourceRange()
- << FixItHint::CreateInsertion(CondExpr->getLocStart(),
- "static_cast<" + TypeStr + ">(")
- << FixItHint::CreateInsertion(
- S.PP.getLocForEndOfToken(CondExpr->getLocEnd()),
- ")");
- S.Diag(Conversion->getLocation(), diag::note_switch_conversion)
- << ConvTy->isEnumeralType() << ConvTy;
-
- // If we aren't in a SFINAE context, build a call to the
- // explicit conversion function.
- if (S.isSFINAEContext())
- return true;
-
- S.CheckMemberOperatorAccess(CondExpr->getExprLoc(),
- CondExpr, 0, Found);
- CondExpr = S.BuildCXXMemberCallExpr(CondExpr, Found, Conversion);
- }
-
- // We'll complain below about a non-integral condition type.
- break;
-
- case 1: {
- // Apply this conversion.
- DeclAccessPair Found = ViableConversions[0];
- S.CheckMemberOperatorAccess(CondExpr->getExprLoc(),
- CondExpr, 0, Found);
- CondExpr = S.BuildCXXMemberCallExpr(CondExpr, Found,
- cast<CXXConversionDecl>(Found->getUnderlyingDecl()));
- break;
- }
-
- default:
- S.Diag(SwitchLoc, diag::err_switch_multiple_conversions)
- << CondType << CondExpr->getSourceRange();
- for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {
- CXXConversionDecl *Conv
- = cast<CXXConversionDecl>(ViableConversions[I]->getUnderlyingDecl());
- QualType ConvTy = Conv->getConversionType().getNonReferenceType();
- S.Diag(Conv->getLocation(), diag::note_switch_conversion)
- << ConvTy->isEnumeralType() << ConvTy;
- }
- return true;
- }
- }
-
- return false;
-}
-
Action::OwningStmtResult
Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, ExprArg Cond,
DeclPtrTy CondVar) {
@@ -529,14 +423,24 @@
Cond = move(CondE);
}
- Expr *CondExpr = Cond.takeAs<Expr>();
- if (!CondExpr)
+ if (!Cond.get())
return StmtError();
- if (getLangOptions().CPlusPlus &&
- CheckCXXSwitchCondition(*this, SwitchLoc, CondExpr))
- return StmtError();
-
+ Expr *CondExpr = static_cast<Expr *>(Cond.get());
+ OwningExprResult ConvertedCond
+ = ConvertToIntegralOrEnumerationType(SwitchLoc, move(Cond),
+ PDiag(diag::err_typecheck_statement_requires_integer),
+ PDiag(diag::err_switch_incomplete_class_type)
+ << CondExpr->getSourceRange(),
+ PDiag(diag::err_switch_explicit_conversion),
+ PDiag(diag::note_switch_conversion),
+ PDiag(diag::err_switch_multiple_conversions),
+ PDiag(diag::note_switch_conversion));
+ if (ConvertedCond.isInvalid())
+ return StmtError();
+
+ CondExpr = ConvertedCond.takeAs<Expr>();
+
if (!CondVar.get()) {
CondExpr = MaybeCreateCXXExprWithTemporaries(CondExpr);
if (!CondExpr)
Modified: cfe/trunk/test/Sema/complex-int.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/complex-int.c?rev=107222&r1=107221&r2=107222&view=diff
==============================================================================
--- cfe/trunk/test/Sema/complex-int.c (original)
+++ cfe/trunk/test/Sema/complex-int.c Tue Jun 29 18:17:37 2010
@@ -16,9 +16,13 @@
result = xx*yy;
switch (arr) { // expected-error{{statement requires expression of integer type ('_Complex int' invalid)}}
+ default: ;
+}
+
+ switch (ii) {
case brr: ; // expected-error{{expression is not an integer constant expression}}
case xx: ; // expected-error{{expression is not an integer constant expression}}
-}
+ }
}
void Tester() {
More information about the cfe-commits
mailing list