[cfe-commits] r89655 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaStmt.cpp test/FixIt/fixit-cxx0x.cpp test/SemaCXX/switch-0x.cpp test/SemaCXX/switch.cpp
Douglas Gregor
dgregor at apple.com
Mon Nov 23 05:46:09 PST 2009
Author: dgregor
Date: Mon Nov 23 07:46:08 2009
New Revision: 89655
URL: http://llvm.org/viewvc/llvm-project?rev=89655&view=rev
Log:
Implement conversion from a switch condition with class type to an
integral or enumeration type (vi user-defined conversions). Fixes PR5518.
Added:
cfe/trunk/test/FixIt/fixit-cxx0x.cpp (with props)
cfe/trunk/test/SemaCXX/switch-0x.cpp (with props)
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/SemaStmt.cpp
cfe/trunk/test/SemaCXX/switch.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=89655&r1=89654&r2=89655&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Nov 23 07:46:08 2009
@@ -2292,6 +2292,13 @@
"statement requires expression of integer type (%0 invalid)">;
def err_multiple_default_labels_defined : Error<
"multiple default labels in one switch">;
+def err_switch_multiple_conversions : Error<
+ "multiple conversions from switch condition type %0 to an integral or "
+ "enumeration type">;
+def note_switch_conversion : Note<
+ "conversion to %select{integral|enumeration}0 type %1">;
+def err_switch_explicit_conversion : Error<
+ "switch condition type %0 requires explicit conversion to %1">;
def warn_empty_if_body : Warning<
"if statement has empty body">, InGroup<EmptyBody>;
def err_va_start_used_in_non_variadic_function : Error<
Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=89655&r1=89654&r2=89655&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Mon Nov 23 07:46:08 2009
@@ -15,9 +15,11 @@
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
@@ -269,35 +271,7 @@
Action::OwningStmtResult
Sema::ActOnStartOfSwitchStmt(ExprArg cond) {
- Expr *Cond = cond.takeAs<Expr>();
-
- 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 (!Cond->isTypeDependent()) {
- QualType Ty = Cond->getType();
-
- // FIXME: Handle class types.
-
- // If the type is wrong a diagnostic will be emitted later at
- // ActOnFinishSwitchStmt.
- if (Ty->isIntegralType() || Ty->isEnumeralType()) {
- // Integral promotions are performed.
- // FIXME: Integral promotions for C++ are not complete.
- UsualUnaryConversions(Cond);
- }
- }
- } else {
- // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
- UsualUnaryConversions(Cond);
- }
-
- SwitchStmt *SS = new (Context) SwitchStmt(Cond);
+ SwitchStmt *SS = new (Context) SwitchStmt(cond.takeAs<Expr>());
getSwitchStack().push_back(SS);
return Owned(SS);
}
@@ -404,8 +378,103 @@
getSwitchStack().pop_back();
Expr *CondExpr = SS->getCond();
+ QualType CondTypeBeforePromotion =
+ GetTypeBeforeIntegralPromotion(CondExpr);
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()) {
+ 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);
+ }
+ }
+ } else {
+ // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
+ UsualUnaryConversions(CondExpr);
+ }
+ CondType = CondExpr->getType();
+ SS->setCond(CondExpr);
+
// C++ 6.4.2.p2:
// Integral promotions are performed (on the switch condition).
//
@@ -413,9 +482,6 @@
// type (before the promotion) doesn't make sense, even when it can
// be represented by the promoted type. Therefore we need to find
// the pre-promotion type of the switch condition.
- QualType CondTypeBeforePromotion =
- GetTypeBeforeIntegralPromotion(CondExpr);
-
if (!CondExpr->isTypeDependent()) {
if (!CondType->isIntegerType()) { // C99 6.8.4.2p1
Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer)
Added: cfe/trunk/test/FixIt/fixit-cxx0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit-cxx0x.cpp?rev=89655&view=auto
==============================================================================
--- cfe/trunk/test/FixIt/fixit-cxx0x.cpp (added)
+++ cfe/trunk/test/FixIt/fixit-cxx0x.cpp Mon Nov 23 07:46:08 2009
@@ -0,0 +1,14 @@
+/* RUN: clang-cc -std=c++0x -fixit %s -o - | clang-cc -x c++ -std=c++0x -
+ */
+
+/* This is a test of the various code modification hints that only
+ apply in C++0x. */
+struct A {
+ explicit operator int(); // expected-note{{conversion to integral type}}
+};
+
+void x() {
+ switch(A()) { // expected-error{{explicit conversion to}}
+ }
+}
+
Propchange: cfe/trunk/test/FixIt/fixit-cxx0x.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/FixIt/fixit-cxx0x.cpp
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/FixIt/fixit-cxx0x.cpp
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: cfe/trunk/test/SemaCXX/switch-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/switch-0x.cpp?rev=89655&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/switch-0x.cpp (added)
+++ cfe/trunk/test/SemaCXX/switch-0x.cpp Mon Nov 23 07:46:08 2009
@@ -0,0 +1,11 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s
+
+// PR5518
+struct A {
+ explicit operator int(); // expected-note{{conversion to integral type}}
+};
+
+void x() {
+ switch(A()) { // expected-error{{explicit conversion to}}
+ }
+}
Propchange: cfe/trunk/test/SemaCXX/switch-0x.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/SemaCXX/switch-0x.cpp
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/SemaCXX/switch-0x.cpp
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: cfe/trunk/test/SemaCXX/switch.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/switch.cpp?rev=89655&r1=89654&r2=89655&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/switch.cpp (original)
+++ cfe/trunk/test/SemaCXX/switch.cpp Mon Nov 23 07:46:08 2009
@@ -13,3 +13,23 @@
break;
}
}
+
+// PR5518
+struct A {
+ operator int(); // expected-note{{conversion to integral type}}
+};
+
+void x() {
+ switch(A()) {
+ }
+}
+
+enum E { e1, e2 };
+struct B : A {
+ operator E() const; // expected-note{{conversion to enumeration type}}
+};
+
+void x2() {
+ switch (B()) { // expected-error{{multiple conversions}}
+ }
+}
More information about the cfe-commits
mailing list