]> granicus.if.org Git - clang/commitdiff
Factor the conversion from a switch condition to an integral or
authorDouglas Gregor <dgregor@apple.com>
Tue, 29 Jun 2010 23:17:37 +0000 (23:17 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 29 Jun 2010 23:17:37 +0000 (23:17 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@107222 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/Sema.h
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaStmt.cpp
test/Sema/complex-int.c

index f93a9492b2209d7b3df0bfbc3792dbc2594c0ce5..c771898d96d62f0f547762a6e4bbfbcdfb1dd36a 100644 (file)
@@ -1188,6 +1188,15 @@ public:
   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,
index 1801565ff09593a39471a3ff090c037f9ff9bac5..86d4d42ee0e32bf18a00e2a810898797278c9adf 100644 (file)
@@ -722,6 +722,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
   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)
index 317e8cd6d385e9b4e78e5c531a6ab60d4f389f87..af28d46b5fe77a1df9fe0dfde92717137b900e21 100644 (file)
@@ -3068,6 +3068,140 @@ bool Sema::PerformContextuallyConvertToObjCId(Expr *&From) {
   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
index 8e163ef245273d59bf880f744b00131de72d3e79..fed30e4e5604822518f98bcc19aa63ddf5fa18eb 100644 (file)
@@ -410,112 +410,6 @@ static QualType GetTypeBeforeIntegralPromotion(const Expr* expr) {
   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 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, ExprArg Cond,
     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)
index cb76a342c2d0e0c7dca0a3d573a705213305742a..bcd9939b29324ce81136da4f37d049f42c38fa97 100644 (file)
@@ -16,9 +16,13 @@ result = arr*brr;
 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() {