[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