[cfe-commits] r89842 - /cfe/trunk/lib/Sema/SemaStmt.cpp
Douglas Gregor
dgregor at apple.com
Tue Nov 24 20:55:54 PST 2009
Author: dgregor
Date: Tue Nov 24 22:55:54 2009
New Revision: 89842
URL: http://llvm.org/viewvc/llvm-project?rev=89842&view=rev
Log:
Refactor ActOnFinishSwitchStmt to simplify and reduce nesting
Modified:
cfe/trunk/lib/Sema/SemaStmt.cpp
Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=89842&r1=89841&r2=89842&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Tue Nov 24 22:55:54 2009
@@ -388,6 +388,108 @@
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,
+ PDiag(diag::err_switch_incomplete_class_type)
+ << CondExpr->getSourceRange()))
+ return true;
+
+ llvm::SmallVector<CXXConversionDecl *, 4> ViableConversions;
+ llvm::SmallVector<CXXConversionDecl *, 4> ExplicitConversions;
+ if (const RecordType *RecordTy = CondType->getAs<RecordType>()) {
+ const UnresolvedSet *Conversions
+ = cast<CXXRecordDecl>(RecordTy->getDecl())
+ ->getVisibleConversionFunctions();
+ for (UnresolvedSet::iterator I = Conversions->begin(),
+ E = Conversions->end(); I != E; ++I) {
+ if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(*I))
+ if (Conversion->getConversionType().getNonReferenceType()
+ ->isIntegralType()) {
+ if (Conversion->isExplicit())
+ ExplicitConversions.push_back(Conversion);
+ else
+ ViableConversions.push_back(Conversion);
+ }
+ }
+
+ switch (ViableConversions.size()) {
+ case 0:
+ if (ExplicitConversions.size() == 1) {
+ // The user probably meant to invoke the given explicit
+ // conversion; use it.
+ QualType ConvTy
+ = ExplicitConversions[0]->getConversionType()
+ .getNonReferenceType();
+ std::string TypeStr;
+ ConvTy.getAsStringInternal(TypeStr, S.Context.PrintingPolicy);
+
+ S.Diag(SwitchLoc, diag::err_switch_explicit_conversion)
+ << CondType << ConvTy << CondExpr->getSourceRange()
+ << CodeModificationHint::CreateInsertion(CondExpr->getLocStart(),
+ "static_cast<" + TypeStr + ">(")
+ << CodeModificationHint::CreateInsertion(
+ S.PP.getLocForEndOfToken(CondExpr->getLocEnd()),
+ ")");
+ S.Diag(ExplicitConversions[0]->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;
+
+ CondExpr = S.BuildCXXMemberCallExpr(CondExpr, ExplicitConversions[0]);
+ }
+
+ // We'll complain below about a non-integral condition type.
+ break;
+
+ case 1:
+ // Apply this conversion.
+ CondExpr = S.BuildCXXMemberCallExpr(CondExpr, ViableConversions[0]);
+ break;
+
+ default:
+ S.Diag(SwitchLoc, diag::err_switch_multiple_conversions)
+ << CondType << CondExpr->getSourceRange();
+ for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {
+ QualType ConvTy
+ = ViableConversions[I]->getConversionType().getNonReferenceType();
+ S.Diag(ViableConversions[I]->getLocation(),
+ diag::note_switch_conversion)
+ << ConvTy->isEnumeralType() << ConvTy;
+ }
+ return true;
+ }
+ }
+ CondType = CondExpr->getType();
+
+ // Integral promotions are performed.
+ if (CondType->isIntegralType() || CondType->isEnumeralType())
+ S.UsualUnaryConversions(CondExpr);
+
+ return false;
+}
+
Action::OwningStmtResult
Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
StmtArg Body) {
@@ -405,100 +507,11 @@
QualType CondType = CondExpr->getType();
if (getLangOptions().CPlusPlus) {
- // 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.
- if (!CondExpr->isTypeDependent()) {
- // Make sure that the condition expression has a complete type,
- // otherwise we'll never find any conversions.
- if (RequireCompleteType(SwitchLoc, CondType,
- PDiag(diag::err_switch_incomplete_class_type)
- << CondExpr->getSourceRange()))
- return StmtError();
-
- llvm::SmallVector<CXXConversionDecl *, 4> ViableConversions;
- llvm::SmallVector<CXXConversionDecl *, 4> ExplicitConversions;
- if (const RecordType *RecordTy = CondType->getAs<RecordType>()) {
- const UnresolvedSet *Conversions
- = cast<CXXRecordDecl>(RecordTy->getDecl())
- ->getVisibleConversionFunctions();
- for (UnresolvedSet::iterator I = Conversions->begin(),
- E = Conversions->end(); I != E; ++I) {
- if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(*I))
- if (Conversion->getConversionType().getNonReferenceType()
- ->isIntegralType()) {
- if (Conversion->isExplicit())
- ExplicitConversions.push_back(Conversion);
- else
- ViableConversions.push_back(Conversion);
- }
- }
-
- switch (ViableConversions.size()) {
- case 0:
- if (ExplicitConversions.size() == 1) {
- // The user probably meant to invoke the given explicit
- // conversion; use it.
- QualType ConvTy
- = ExplicitConversions[0]->getConversionType()
- .getNonReferenceType();
- std::string TypeStr;
- ConvTy.getAsStringInternal(TypeStr, Context.PrintingPolicy);
-
-
- Diag(SwitchLoc, diag::err_switch_explicit_conversion)
- << CondType << ConvTy << CondExpr->getSourceRange()
- << CodeModificationHint::CreateInsertion(CondExpr->getLocStart(),
- "static_cast<" + TypeStr + ">(")
- << CodeModificationHint::CreateInsertion(
- PP.getLocForEndOfToken(CondExpr->getLocEnd()),
- ")");
- Diag(ExplicitConversions[0]->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 (!isSFINAEContext())
- CondExpr = BuildCXXMemberCallExpr(CondExpr,
- ExplicitConversions[0]);
- }
-
- // We'll complain below about a non-integral condition type.
- break;
-
- case 1:
- // Apply this conversion.
- CondExpr = BuildCXXMemberCallExpr(CondExpr, ViableConversions[0]);
- break;
-
- default:
- Diag(SwitchLoc, diag::err_switch_multiple_conversions)
- << CondType << CondExpr->getSourceRange();
- for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {
- QualType ConvTy
- = ViableConversions[I]->getConversionType()
- .getNonReferenceType();
- Diag(ViableConversions[I]->getLocation(),
- diag::note_switch_conversion)
- << ConvTy->isEnumeralType() << ConvTy;
- }
- return StmtError();
- }
- }
- CondType = CondExpr->getType();
-
- if (CondType->isIntegralType() || CondType->isEnumeralType()) {
- // Integral promotions are performed.
- UsualUnaryConversions(CondExpr);
- }
- }
+ if (CheckCXXSwitchCondition(*this, SwitchLoc, CondExpr))
+ return StmtError();
} else {
- // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
+ // C99 6.8.4.2p5 - Integer promotions are performed on the
+ // controlling expr.
UsualUnaryConversions(CondExpr);
}
CondType = CondExpr->getType();
More information about the cfe-commits
mailing list