[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