[cfe-commits] r62231 - in /cfe/trunk: include/clang/Basic/DiagnosticKinds.def lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaInit.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/condition.cpp www/cxx_status.html

Douglas Gregor dgregor at apple.com
Wed Jan 14 07:45:32 PST 2009


Author: dgregor
Date: Wed Jan 14 09:45:31 2009
New Revision: 62231

URL: http://llvm.org/viewvc/llvm-project?rev=62231&view=rev
Log:
Introduce support for C++0x explicit conversion operators (N2437)

Small cleanup in the handling of user-defined conversions. 

Also, implement an optimization when constructing a call. We avoid
recomputing implicit conversion sequences and instead use those
conversion sequences that we computed as part of overload resolution.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/SemaCXX/condition.cpp
    cfe/trunk/www/cxx_status.html

Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=62231&r1=62230&r2=62231&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jan 14 09:45:31 2009
@@ -1349,7 +1349,7 @@
 DIAG(err_type_defined_in_condition, ERROR,
      "types may not be defined in conditions")
 DIAG(err_typecheck_bool_condition, ERROR,
-    "expression must have bool type (or be convertible to bool) (%0 invalid)")
+     "value of type %0 is not contextually convertible to 'bool'")
 DIAG(err_expected_class_or_namespace, ERROR,
      "expected a class or namespace")
 DIAG(err_invalid_declarator_scope, ERROR,
@@ -1582,6 +1582,10 @@
 DIAG(warn_not_compound_assign, WARNING,
      "use of unary operator that may be intended as compound assignment (%0=)")
 
+// C++0x explicit conversion operators
+DIAG(warn_explicit_conversion_functions, WARNING,
+     "explicit conversion functions are a C++0x extension")
+
 // CHECK: printf format string errors
 DIAG(warn_printf_not_string_constant, WARNING,
      "format string is not a string literal (potentially insecure)")

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=62231&r1=62230&r2=62231&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Jan 14 09:45:31 2009
@@ -281,7 +281,8 @@
   virtual void ActOnParamUnparsedDefaultArgument(DeclTy *param, 
                                                  SourceLocation EqualLoc);
   virtual void ActOnParamDefaultArgumentError(DeclTy *param);
-  void AddInitializerToDecl(DeclTy *dcl, ExprArg init);
+  virtual void AddInitializerToDecl(DeclTy *dcl, ExprArg init);
+  void AddInitializerToDecl(DeclTy *dcl, ExprArg init, bool DirectInit);
   void ActOnUninitializedDecl(DeclTy *dcl);
   virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group);
 
@@ -390,7 +391,8 @@
                   OverloadedFunctionDecl::function_iterator &MatchedDecl);
   ImplicitConversionSequence 
   TryImplicitConversion(Expr* From, QualType ToType,
-                        bool SuppressUserConversions = false);
+                        bool SuppressUserConversions = false,
+                        bool AllowExplicit = false);
   bool IsStandardConversion(Expr *From, QualType ToType, 
                             StandardConversionSequence& SCS);
   bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType);
@@ -402,7 +404,8 @@
   bool CheckPointerConversion(Expr *From, QualType ToType);
   bool IsQualificationConversion(QualType FromType, QualType ToType);
   bool IsUserDefinedConversion(Expr *From, QualType ToType, 
-                               UserDefinedConversionSequence& User);
+                               UserDefinedConversionSequence& User,
+                               bool AllowExplicit = false);
 
   ImplicitConversionSequence::CompareKind 
   CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
@@ -430,6 +433,9 @@
   TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method);
   bool PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method);
 
+  ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From);
+  bool PerformContextuallyConvertToBool(Expr *&From);
+
   /// OverloadingResult - Capture the result of performing overload
   /// resolution.
   enum OverloadingResult {
@@ -459,7 +465,8 @@
   void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, 
                            Expr **Args, unsigned NumArgs,
                            OverloadCandidateSet& CandidateSet,
-                           bool IsAssignmentOperator = false);
+                           bool IsAssignmentOperator = false,
+                           unsigned NumContextualBoolArguments = 0);
   void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, 
                                     Expr **Args, unsigned NumArgs, 
                                     OverloadCandidateSet& CandidateSet);
@@ -497,7 +504,7 @@
   ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
                                       SourceLocation MemberLoc,
                                       IdentifierInfo &Member);
-                                           
+               
   /// Helpers for dealing with function parameters.
   bool CheckParmsForFunctionDef(FunctionDecl *FD);
   void CheckCXXDefaultArguments(FunctionDecl *FD);
@@ -1360,6 +1367,9 @@
   bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType);
 
   bool PerformImplicitConversion(Expr *&From, QualType ToType, 
+                                 const char *Flavor, bool AllowExplicit = false);
+  bool PerformImplicitConversion(Expr *&From, QualType ToType, 
+                                 const ImplicitConversionSequence& ICS,
                                  const char *Flavor);
   bool PerformImplicitConversion(Expr *&From, QualType ToType,
                                  const StandardConversionSequence& SCS,
@@ -1416,8 +1426,10 @@
   /// type checking declaration initializers (C99 6.7.8)
   friend class InitListChecker;
   bool CheckInitializerTypes(Expr *&simpleInit_or_initList, QualType &declType,
-                             SourceLocation InitLoc,DeclarationName InitEntity);
-  bool CheckSingleInitializer(Expr *&simpleInit, QualType declType);
+                             SourceLocation InitLoc,DeclarationName InitEntity,
+                             bool DirectInit);
+  bool CheckSingleInitializer(Expr *&simpleInit, QualType declType,
+                              bool DirectInit);
   bool CheckForConstantInitializer(Expr *e, QualType t);
   bool CheckArithmeticConstantExpression(const Expr* e);
   bool CheckAddressConstantExpression(const Expr* e);
@@ -1455,7 +1467,8 @@
 
   bool CheckReferenceInit(Expr *&simpleInit_or_initList, QualType &declType,
                           ImplicitConversionSequence *ICS = 0,
-                          bool SuppressUserConversions = false);
+                          bool SuppressUserConversions = false,
+                          bool AllowExplicit = false);
 
   /// CheckCastTypes - Check type constraints for casting between types.
   bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr);

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=62231&r1=62230&r2=62231&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Jan 14 09:45:31 2009
@@ -1120,13 +1120,22 @@
   return Anon;
 }
 
-bool Sema::CheckSingleInitializer(Expr *&Init, QualType DeclType) {  
+bool Sema::CheckSingleInitializer(Expr *&Init, QualType DeclType, 
+                                  bool DirectInit) {  
   // Get the type before calling CheckSingleAssignmentConstraints(), since
   // it can promote the expression.
   QualType InitType = Init->getType(); 
 
-  if (getLangOptions().CPlusPlus)
-    return PerformCopyInitialization(Init, DeclType, "initializing");
+  if (getLangOptions().CPlusPlus) {
+    // FIXME: I dislike this error message. A lot.
+    if (PerformImplicitConversion(Init, DeclType, "initializing", DirectInit))
+      return Diag(Init->getSourceRange().getBegin(),
+                  diag::err_typecheck_convert_incompatible)
+        << DeclType << Init->getType() << "initializing" 
+        << Init->getSourceRange();
+
+    return false;
+  }
 
   AssignConvertType ConvTy = CheckSingleAssignmentConstraints(DeclType, Init);
   return DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType,
@@ -1169,7 +1178,8 @@
 
 bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
                                  SourceLocation InitLoc,
-                                 DeclarationName InitEntity) {
+                                 DeclarationName InitEntity,
+                                 bool DirectInit) {
   if (DeclType->isDependentType() || Init->isTypeDependent())
     return false;
 
@@ -1178,7 +1188,7 @@
   //   (8.3.2), shall be initialized by an object, or function, of
   //   type T or by an object that can be converted into a T.
   if (DeclType->isReferenceType())
-    return CheckReferenceInit(Init, DeclType);
+    return CheckReferenceInit(Init, DeclType, 0, false, DirectInit);
 
   // C99 6.7.8p3: The type of the entity to be initialized shall be an array
   // of unknown size ("[]") or an object type that is not a variable array type.
@@ -1208,7 +1218,8 @@
         CXXConstructorDecl *Constructor 
           = PerformInitializationByConstructor(DeclType, &Init, 1,
                                                InitLoc, Init->getSourceRange(),
-                                               InitEntity, IK_Copy);
+                                               InitEntity, 
+                                               DirectInit? IK_Direct : IK_Copy);
         return Constructor == 0;
       }
 
@@ -1244,7 +1255,7 @@
       return Diag(Init->getLocStart(), diag::err_array_init_list_required)
         << Init->getSourceRange();
 
-    return CheckSingleInitializer(Init, DeclType);
+    return CheckSingleInitializer(Init, DeclType, DirectInit);
   } else if (getLangOptions().CPlusPlus) {
     // C++ [dcl.init]p14:
     //   [...] If the class is an aggregate (8.5.1), and the initializer
@@ -2366,6 +2377,13 @@
 }
 
 void Sema::AddInitializerToDecl(DeclTy *dcl, ExprArg init) {
+  AddInitializerToDecl(dcl, move(init), /*DirectInit=*/false);
+}
+
+/// AddInitializerToDecl - Adds the initializer Init to the
+/// declaration dcl. If DirectInit is true, this is C++ direct
+/// initialization rather than copy initialization.
+void Sema::AddInitializerToDecl(DeclTy *dcl, ExprArg init, bool DirectInit) {
   Decl *RealDecl = static_cast<Decl *>(dcl);
   Expr *Init = static_cast<Expr *>(init.release());
   assert(Init && "missing initializer");
@@ -2394,7 +2412,7 @@
       VDecl->setInvalidDecl();
     } else if (!VDecl->isInvalidDecl()) {
       if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(),
-                                VDecl->getDeclName()))
+                                VDecl->getDeclName(), DirectInit))
         VDecl->setInvalidDecl();
       
       // C++ 3.6.2p2, allow dynamic initialization of static initializers.
@@ -2408,7 +2426,7 @@
       Diag(VDecl->getLocation(), diag::warn_extern_init);
     if (!VDecl->isInvalidDecl())
       if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(),
-                                VDecl->getDeclName()))
+                                VDecl->getDeclName(), DirectInit))
         VDecl->setInvalidDecl();
     
     // C++ 3.6.2p2, allow dynamic initialization of static initializers.

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=62231&r1=62230&r2=62231&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Jan 14 09:45:31 2009
@@ -128,7 +128,8 @@
   Expr *DefaultArgPtr = DefaultArg.get();
   bool DefaultInitFailed = CheckInitializerTypes(DefaultArgPtr, ParamType,
                                                  EqualLoc,
-                                                 Param->getDeclName());
+                                                 Param->getDeclName(),
+                                                 /*DirectInit=*/false);
   if (DefaultArgPtr != DefaultArg.get()) {
     DefaultArg.take();
     DefaultArg.reset(DefaultArgPtr);
@@ -1299,6 +1300,12 @@
   R = Context.getFunctionType(ConvType, 0, 0, false, 
                               R->getAsFunctionTypeProto()->getTypeQuals());
 
+  // C++0x explicit conversion operators.
+  if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x)
+    Diag(D.getDeclSpec().getExplicitSpecLoc(), 
+         diag::warn_explicit_conversion_functions)
+      << SourceRange(D.getDeclSpec().getExplicitSpecLoc());
+
   return isInvalid;
 }
 
@@ -1538,7 +1545,7 @@
 
   assert(NumExprs == 1 && "Expected 1 expression");
   // Set the init expression, handles conversions.
-  AddInitializerToDecl(Dcl, ExprArg(*this, ExprTys[0]));
+  AddInitializerToDecl(Dcl, ExprArg(*this, ExprTys[0]), /*DirectInit=*/true);
 }
 
 /// PerformInitializationByConstructor - Perform initialization by
@@ -1677,10 +1684,13 @@
 ///
 /// When @p SuppressUserConversions, user-defined conversions are
 /// suppressed.
+/// When @p AllowExplicit, we also permit explicit user-defined
+/// conversion functions.
 bool 
 Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, 
                          ImplicitConversionSequence *ICS,
-                         bool SuppressUserConversions) {
+                         bool SuppressUserConversions,
+                         bool AllowExplicit) {
   assert(DeclType->isReferenceType() && "Reference init needs a reference");
 
   QualType T1 = DeclType->getAsReferenceType()->getPointeeType();
@@ -1780,7 +1790,8 @@
       // If the conversion function doesn't return a reference type,
       // it can't be considered for this conversion.
       // FIXME: This will change when we support rvalue references.
-      if (Conv->getConversionType()->isReferenceType())
+      if (Conv->getConversionType()->isReferenceType() &&
+          (AllowExplicit || !Conv->isExplicit()))
         AddConversionCandidate(Conv, Init, DeclType, CandidateSet);
     }
 

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=62231&r1=62230&r2=62231&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Jan 14 09:45:31 2009
@@ -1873,7 +1873,7 @@
   }
 
   if (CheckInitializerTypes(literalExpr, literalType, LParenLoc, 
-                            DeclarationName()))
+                            DeclarationName(), /*FIXME:DirectInit=*/false))
     return true;
 
   bool isFileScope = getCurFunctionOrMethodDecl() == 0;
@@ -3546,10 +3546,10 @@
         // We matched a built-in operator. Convert the arguments, then
         // break out so that we will build the appropriate built-in
         // operator node.
-        if (PerformCopyInitialization(lhs, Best->BuiltinTypes.ParamTypes[0],
-                                      "passing") ||
-            PerformCopyInitialization(rhs, Best->BuiltinTypes.ParamTypes[1],
-                                      "passing"))
+        if (PerformImplicitConversion(lhs, Best->BuiltinTypes.ParamTypes[0],
+                                      Best->Conversions[0], "passing") ||
+            PerformImplicitConversion(rhs, Best->BuiltinTypes.ParamTypes[1],
+                                      Best->Conversions[1], "passing"))
           return true;
 
         break;
@@ -3644,8 +3644,8 @@
         // We matched a built-in operator. Convert the arguments, then
         // break out so that we will build the appropriate built-in
         // operator node.
-        if (PerformCopyInitialization(Input, Best->BuiltinTypes.ParamTypes[0],
-                                      "passing"))
+        if (PerformImplicitConversion(Input, Best->BuiltinTypes.ParamTypes[0],
+                                      Best->Conversions[0], "passing"))
           return true;
 
         break;

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=62231&r1=62230&r2=62231&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Jan 14 09:45:31 2009
@@ -291,7 +291,8 @@
       // Object is direct-initialized.
       // FIXME: WHAT DeclarationName do we pass in here?
       if (CheckInitializerTypes(ConsArgs[0], AllocType, StartLoc,
-                                DeclarationName() /*AllocType.getAsString()*/))
+                                DeclarationName() /*AllocType.getAsString()*/,
+                                /*DirectInit=*/true))
         return true;
     } else {
       Diag(StartLoc, diag::err_builtin_direct_init_more_than_one_arg)
@@ -650,13 +651,7 @@
   // The value of a condition that is an expression is the value of the
   // expression, implicitly converted to bool.
   //
-  QualType Ty = CondExpr->getType(); // Save the type.
-  AssignConvertType
-    ConvTy = CheckSingleAssignmentConstraints(Context.BoolTy, CondExpr);
-  if (ConvTy == Incompatible)
-    return Diag(CondExpr->getLocStart(), diag::err_typecheck_bool_condition)
-      << Ty << CondExpr->getSourceRange();
-  return false;
+  return PerformContextuallyConvertToBool(CondExpr);
 }
 
 /// Helper function to determine whether this is the (deprecated) C++
@@ -694,12 +689,27 @@
 /// expression From to the type ToType. Returns true if there was an
 /// error, false otherwise. The expression From is replaced with the
 /// converted expression. Flavor is the kind of conversion we're
-/// performing, used in the error message.
+/// performing, used in the error message. If @p AllowExplicit,
+/// explicit user-defined conversions are permitted.
 bool 
 Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
-                                const char *Flavor)
+                                const char *Flavor, bool AllowExplicit)
 {
-  ImplicitConversionSequence ICS = TryImplicitConversion(From, ToType);
+  ImplicitConversionSequence ICS = TryImplicitConversion(From, ToType, false,
+                                                         AllowExplicit);
+  return PerformImplicitConversion(From, ToType, ICS, Flavor);
+}
+
+/// PerformImplicitConversion - Perform an implicit conversion of the
+/// expression From to the type ToType using the pre-computed implicit
+/// conversion sequence ICS. Returns true if there was an error, false
+/// otherwise. The expression From is replaced with the converted
+/// expression. Flavor is the kind of conversion we're performing,
+/// used in the error message.
+bool
+Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
+                                const ImplicitConversionSequence &ICS,
+                                const char* Flavor) {
   switch (ICS.ConversionKind) {
   case ImplicitConversionSequence::StandardConversion:
     if (PerformImplicitConversion(From, ToType, ICS.Standard, Flavor))
@@ -710,7 +720,8 @@
     // FIXME: This is, of course, wrong. We'll need to actually call
     // the constructor or conversion operator, and then cope with the
     // standard conversions.
-    ImpCastExprToType(From, ToType);
+    ImpCastExprToType(From, ToType.getNonReferenceType(), 
+                      ToType->isReferenceType());
     return false;
 
   case ImplicitConversionSequence::EllipsisConversion:
@@ -734,8 +745,7 @@
 bool 
 Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
                                 const StandardConversionSequence& SCS,
-                                const char *Flavor)
-{
+                                const char *Flavor) {
   // Overall FIXME: we are recomputing too many types here and doing
   // far too much extra work. What this means is that we need to keep
   // track of more information that is computed when we try the

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=62231&r1=62230&r2=62231&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Wed Jan 14 09:45:31 2009
@@ -193,7 +193,7 @@
       return;
     }
     Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer.
-    if (SemaRef->CheckSingleInitializer(expr, DeclType))
+    if (SemaRef->CheckSingleInitializer(expr, DeclType, false))
       hadError = true; // types weren't compatible.
     else if (savExpr != expr)
       // The type was promoted, update initializer list.

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=62231&r1=62230&r2=62231&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Jan 14 09:45:31 2009
@@ -361,15 +361,18 @@
 ///
 /// If @p SuppressUserConversions, then user-defined conversions are
 /// not permitted.
+/// If @p AllowExplicit, then explicit user-defined conversions are
+/// permitted.
 ImplicitConversionSequence
 Sema::TryImplicitConversion(Expr* From, QualType ToType,
-                            bool SuppressUserConversions)
+                            bool SuppressUserConversions,
+                            bool AllowExplict)
 {
   ImplicitConversionSequence ICS;
   if (IsStandardConversion(From, ToType, ICS.Standard))
     ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
   else if (!SuppressUserConversions &&
-           IsUserDefinedConversion(From, ToType, ICS.UserDefined)) {
+           IsUserDefinedConversion(From, ToType, ICS.UserDefined, AllowExplict)) {
     ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion;
     // C++ [over.ics.user]p4:
     //   A conversion of an expression of class type to the same class
@@ -1097,9 +1100,12 @@
 /// exists, User will contain the user-defined conversion sequence
 /// that performs such a conversion and this routine will return
 /// true. Otherwise, this routine returns false and User is
-/// unspecified.
+/// unspecified. AllowExplicit is true if the conversion should
+/// consider C++0x "explicit" conversion functions as well as
+/// non-explicit conversion functions (C++0x [class.conv.fct]p2).
 bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType, 
-                                   UserDefinedConversionSequence& User)
+                                   UserDefinedConversionSequence& User,
+                                   bool AllowExplicit)
 {
   OverloadCandidateSet CandidateSet;
   if (const CXXRecordType *ToRecordType 
@@ -1137,7 +1143,8 @@
            = Conversions->function_begin();
          Func != Conversions->function_end(); ++Func) {
       CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
-      AddConversionCandidate(Conv, From, ToType, CandidateSet);
+      if (AllowExplicit || !Conv->isExplicit())
+        AddConversionCandidate(Conv, From, ToType, CandidateSet);
     }
   }
 
@@ -1748,6 +1755,24 @@
   return false;
 }
 
+/// TryContextuallyConvertToBool - Attempt to contextually convert the
+/// expression From to bool (C++0x [conv]p3).
+ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) {
+  return TryImplicitConversion(From, Context.BoolTy, false, true);
+}
+
+/// PerformContextuallyConvertToBool - Perform a contextual conversion
+/// of the expression From to bool (C++0x [conv]p3).
+bool Sema::PerformContextuallyConvertToBool(Expr *&From) {
+  ImplicitConversionSequence ICS = TryContextuallyConvertToBool(From);
+  if (!PerformImplicitConversion(From, Context.BoolTy, ICS, "converting"))
+    return false;
+
+  return Diag(From->getSourceRange().getBegin(), 
+              diag::err_typecheck_bool_condition)
+    << From->getType() << From->getSourceRange();
+}
+
 /// 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
@@ -2201,11 +2226,14 @@
 /// of the built-in candidate, respectively. Args and NumArgs are the
 /// arguments being passed to the candidate. IsAssignmentOperator
 /// should be true when this built-in candidate is an assignment
-/// operator.
+/// operator. NumContextualBoolArguments is the number of arguments
+/// (at the beginning of the argument list) that will be contextually
+/// converted to bool.
 void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, 
                                Expr **Args, unsigned NumArgs,
                                OverloadCandidateSet& CandidateSet,
-                               bool IsAssignmentOperator) {
+                               bool IsAssignmentOperator,
+                               unsigned NumContextualBoolArguments) {
   // Add this candidate
   CandidateSet.push_back(OverloadCandidate());
   OverloadCandidate& Candidate = CandidateSet.back();
@@ -2233,9 +2261,15 @@
     // conversions, since that is the only way that initialization of
     // a reference to a non-class type can occur from something that
     // is not of the same type.
-    Candidate.Conversions[ArgIdx] 
-      = TryCopyInitialization(Args[ArgIdx], ParamTys[ArgIdx], 
-                              ArgIdx == 0 && IsAssignmentOperator);
+    if (ArgIdx < NumContextualBoolArguments) {
+      assert(ParamTys[ArgIdx] == Context.BoolTy && 
+             "Contextual conversion to bool requires bool type");
+      Candidate.Conversions[ArgIdx] = TryContextuallyConvertToBool(Args[ArgIdx]);
+    } else {
+      Candidate.Conversions[ArgIdx] 
+        = TryCopyInitialization(Args[ArgIdx], ParamTys[ArgIdx], 
+                                ArgIdx == 0 && IsAssignmentOperator);
+    }
     if (Candidate.Conversions[ArgIdx].ConversionKind 
         == ImplicitConversionSequence::BadConversion) {
       Candidate.Viable = false;
@@ -2309,7 +2343,8 @@
 
   BuiltinCandidateTypeSet(ASTContext &Context) : Context(Context) { }
 
-  void AddTypesConvertedFrom(QualType Ty, bool AllowUserConversions = true);
+  void AddTypesConvertedFrom(QualType Ty, bool AllowUserConversions,
+                             bool AllowExplicitConversions);
 
   /// pointer_begin - First pointer type found;
   iterator pointer_begin() { return PointerTypes.begin(); }
@@ -2358,9 +2393,15 @@
 
 /// AddTypesConvertedFrom - Add each of the types to which the type @p
 /// Ty can be implicit converted to the given set of @p Types. We're
-/// primarily interested in pointer types, enumeration types,
-void BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
-                                                    bool AllowUserConversions) {
+/// primarily interested in pointer types and enumeration types.
+/// AllowUserConversions is true if we should look at the conversion
+/// functions of a class type, and AllowExplicitConversions if we
+/// should also include the explicit conversion functions of a class
+/// type.
+void 
+BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
+                                               bool AllowUserConversions,
+                                               bool AllowExplicitConversions) {
   // Only deal with canonical types.
   Ty = Context.getCanonicalType(Ty);
 
@@ -2399,7 +2440,7 @@
 
         // Add the pointer type, recursively, so that we get all of
         // the indirect base classes, too.
-        AddTypesConvertedFrom(Context.getPointerType(BaseTy), false);
+        AddTypesConvertedFrom(Context.getPointerType(BaseTy), false, false);
       }
     }
   } else if (Ty->isEnumeralType()) {
@@ -2414,7 +2455,8 @@
              = Conversions->function_begin();
            Func != Conversions->function_end(); ++Func) {
         CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
-        AddTypesConvertedFrom(Conv->getConversionType(), false);
+        if (AllowExplicitConversions || !Conv->isExplicit())
+          AddTypesConvertedFrom(Conv->getConversionType(), false, false);
       }
     }
   }
@@ -2461,7 +2503,11 @@
       Op == OO_ArrowStar || Op == OO_PlusPlus || Op == OO_MinusMinus ||
       (Op == OO_Star && NumArgs == 1)) {
     for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
-      CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType());
+      CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType(),
+                                           true,
+                                           (Op == OO_Exclaim ||
+                                            Op == OO_AmpAmp ||
+                                            Op == OO_PipePipe));
   }
 
   bool isComparison = false;
@@ -2811,14 +2857,14 @@
       ParamTypes[0] = Context.getReferenceType(*Enum);
       ParamTypes[1] = *Enum;
       AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
-                          /*IsAssignmentOperator=*/true);
+                          /*IsAssignmentOperator=*/false);
 
       if (!Context.getCanonicalType(*Enum).isVolatileQualified()) {
         // volatile T& operator=(volatile T&, T)
         ParamTypes[0] = Context.getReferenceType((*Enum).withVolatile());
         ParamTypes[1] = *Enum;
         AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
-                            /*IsAssignmentOperator=*/true);
+                            /*IsAssignmentOperator=*/false);
       }
     }
     // Fall through.
@@ -2919,8 +2965,6 @@
         ParamTypes[1] = ArithmeticTypes[Right];
 
         // Add this built-in operator as a candidate (VQ is empty).
-        // FIXME: We should be caching these declarations somewhere,
-        // rather than re-building them every time.
         ParamTypes[0] = Context.getReferenceType(ArithmeticTypes[Left]);
         AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
 
@@ -2942,7 +2986,9 @@
     //        bool        operator&&(bool, bool);     [BELOW]
     //        bool        operator||(bool, bool);     [BELOW]
     QualType ParamTy = Context.BoolTy;
-    AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet);
+    AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet,
+                        /*IsAssignmentOperator=*/false,
+                        /*NumContextualBoolArguments=*/1);
     break;
   }
 
@@ -2956,7 +3002,9 @@
     //        bool        operator&&(bool, bool);
     //        bool        operator||(bool, bool);
     QualType ParamTypes[2] = { Context.BoolTy, Context.BoolTy };
-    AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet);
+    AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet,
+                        /*IsAssignmentOperator=*/false,
+                        /*NumContextualBoolArguments=*/2);
     break;
   }
 

Modified: cfe/trunk/test/SemaCXX/condition.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/condition.cpp?rev=62231&r1=62230&r2=62231&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/condition.cpp (original)
+++ cfe/trunk/test/SemaCXX/condition.cpp Wed Jan 14 09:45:31 2009
@@ -10,14 +10,14 @@
   while (int f()=0) ; // expected-error {{a function type is not allowed here}}
 
   struct S {} s;
-  if (s) ++x; // expected-error {{expression must have bool type (or be convertible to bool) ('struct S' invalid)}}
-  while (struct S x=s) ; // expected-error {{expression must have bool type (or be convertible to bool) ('struct S' invalid)}}
-  do ; while (s); // expected-error {{expression must have bool type (or be convertible to bool) ('struct S' invalid)}}
-  for (;s;) ; // expected-error {{expression must have bool type (or be convertible to bool) ('struct S' invalid)}}
+  if (s) ++x; // expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}}
+  while (struct S x=s) ; // expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}}
+  do ; while (s); // expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}}
+  for (;s;) ; // expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}}
   switch (s) {} // expected-error {{statement requires expression of integer type ('struct S' invalid)}}
 
-  while (struct S {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize 'x' with an rvalue of type 'int'}} expected-error {{expression must have bool type}}
-  while (struct {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize 'x' with an rvalue of type 'int'}} expected-error {{expression must have bool type}}
+  while (struct S {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize 'x' with an rvalue of type 'int'}} expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}}
+  while (struct {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize 'x' with an rvalue of type 'int'}} expected-error {{value of type 'struct <anonymous>' is not contextually convertible to 'bool'}}
   switch (enum {E} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{incompatible type}}
 
   if (int x=0) { // expected-note {{previous definition is here}}

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=62231&r1=62230&r2=62231&view=diff

==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Wed Jan 14 09:45:31 2009
@@ -1541,6 +1541,17 @@
 <tr><td>  D.4 [depr.string]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr><td>  D.5 [depr.c.headers]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr><td>E [extendid]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+  <td colspan="6" align="center" bgcolor="#ffffcc">C++0x Features</td>
+  <tr>
+  <td>Explicit conversion operators (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf">N2437</a>)</td>
+  <td class="complete" align="center">&#x2713;</td>
+  <td class="medium" align="center"></td>
+  <td class="advanced" align="center"></td>
+  <td class="broken"></td>
+  <td>No name mangling; ASTs don't contain calls to conversion operators</td>
+</tr>
+
 </table>
  
 </div>





More information about the cfe-commits mailing list