[cfe-commits] r151409 - in /cfe/trunk: include/clang/Sema/Initialization.h include/clang/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaInit.cpp lib/Sema/SemaOverload.cpp test/CXX/over/over.match/over.match.funcs/over.match.copy/p1.cpp test/SemaCXX/explicit.cpp

Douglas Gregor dgregor at apple.com
Fri Feb 24 15:56:31 PST 2012


Author: dgregor
Date: Fri Feb 24 17:56:31 2012
New Revision: 151409

URL: http://llvm.org/viewvc/llvm-project?rev=151409&view=rev
Log:
Implement C++11 [over.match.copy]p1b2, which allows the use of
explicit conversion functions to initialize the argument to a
copy/move constructor that itself is the subject of direct
initialization. Since we don't have that much context in overload
resolution, we end up threading more flags :(.

Fixes <rdar://problem/10903741> / PR10456. 

Added:
    cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.copy/p1.cpp
Modified:
    cfe/trunk/include/clang/Sema/Initialization.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/SemaCXX/explicit.cpp

Modified: cfe/trunk/include/clang/Sema/Initialization.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=151409&r1=151408&r2=151409&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Initialization.h (original)
+++ cfe/trunk/include/clang/Sema/Initialization.h Fri Feb 24 17:56:31 2012
@@ -365,17 +365,18 @@
 public:
   /// \brief The kind of initialization being performed.
   enum InitKind {
-    IK_Direct,     ///< Direct initialization
-    IK_DirectList, ///< Direct list-initialization
-    IK_Copy,       ///< Copy initialization
-    IK_Default,    ///< Default initialization
-    IK_Value       ///< Value initialization
+    IK_Direct,       ///< Direct initialization
+    IK_DirectList,   ///< Direct list-initialization
+    IK_Copy,         ///< Copy initialization
+    IK_Default,      ///< Default initialization
+    IK_Value         ///< Value initialization
   };
   
 private:
   /// \brief The context of the initialization.
   enum InitContext {
     IC_Normal,         ///< Normal context
+    IC_ExplicitConvs,  ///< Normal context, but allows explicit conversion funcs
     IC_Implicit,       ///< Implicit context (value initialization)
     IC_StaticCast,     ///< Static cast context
     IC_CStyleCast,     ///< C-style cast context
@@ -442,8 +443,11 @@
 
   /// \brief Create a copy initialization.
   static InitializationKind CreateCopy(SourceLocation InitLoc,
-                                       SourceLocation EqualLoc) {
-    return InitializationKind(IK_Copy, IC_Normal, InitLoc, EqualLoc, EqualLoc);
+                                       SourceLocation EqualLoc,
+                                       bool AllowExplicitConvs = false) {
+    return InitializationKind(IK_Copy, 
+                              AllowExplicitConvs? IC_ExplicitConvs : IC_Normal,
+                              InitLoc, EqualLoc, EqualLoc);
   }
   
   /// \brief Create a default initialization.
@@ -511,6 +515,12 @@
   ///        constructors.
   bool AllowExplicit() const { return !isCopyInit(); }
 
+  /// \brief Retrieve whether this initialization allows the use of explicit
+  /// conversion functions.
+  bool allowExplicitConversionFunctions() const {
+    return !isCopyInit() || Context == IC_ExplicitConvs;
+  }
+  
   /// \brief Retrieve the source range containing the locations of the open
   /// and closing parentheses for value and direct initializations.
   SourceRange getParenRange() const {

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=151409&r1=151408&r2=151409&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Feb 24 17:56:31 2012
@@ -1458,7 +1458,8 @@
   ExprResult PerformCopyInitialization(const InitializedEntity &Entity,
                                        SourceLocation EqualLoc,
                                        ExprResult Init,
-                                       bool TopLevelOfInitList = false);
+                                       bool TopLevelOfInitList = false,
+                                       bool AllowExplicit = false);
   ExprResult PerformObjectArgumentInitialization(Expr *From,
                                                  NestedNameSpecifier *Qualifier,
                                                  NamedDecl *FoundDecl,
@@ -1502,7 +1503,8 @@
                             Expr **Args, unsigned NumArgs,
                             OverloadCandidateSet& CandidateSet,
                             bool SuppressUserConversions = false,
-                            bool PartialOverloading = false);
+                            bool PartialOverloading = false,
+                            bool AllowExplicit = false);
   void AddFunctionCandidates(const UnresolvedSetImpl &Functions,
                              Expr **Args, unsigned NumArgs,
                              OverloadCandidateSet& CandidateSet,
@@ -3128,7 +3130,8 @@
   bool CompleteConstructorCall(CXXConstructorDecl *Constructor,
                                MultiExprArg ArgsPtr,
                                SourceLocation Loc,
-                               ASTOwningVector<Expr*> &ConvertedArgs);
+                               ASTOwningVector<Expr*> &ConvertedArgs,
+                               bool AllowExplicit = false);
 
   ParsedType getDestructorName(SourceLocation TildeLoc,
                                IdentifierInfo &II, SourceLocation NameLoc,
@@ -5911,7 +5914,8 @@
                               unsigned FirstProtoArg,
                               Expr **Args, unsigned NumArgs,
                               SmallVector<Expr *, 8> &AllArgs,
-                              VariadicCallType CallType = VariadicDoesNotApply);
+                              VariadicCallType CallType = VariadicDoesNotApply,
+                              bool AllowExplicit = false);
 
   // DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
   // will warn if the resulting type is not a POD type.

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=151409&r1=151408&r2=151409&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Feb 24 17:56:31 2012
@@ -9032,7 +9032,8 @@
 Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
                               MultiExprArg ArgsPtr,
                               SourceLocation Loc,                                    
-                              ASTOwningVector<Expr*> &ConvertedArgs) {
+                              ASTOwningVector<Expr*> &ConvertedArgs,
+                              bool AllowExplicit) {
   // FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall.
   unsigned NumArgs = ArgsPtr.size();
   Expr **Args = (Expr **)ArgsPtr.get();
@@ -9053,7 +9054,7 @@
   SmallVector<Expr *, 8> AllArgs;
   bool Invalid = GatherArgumentsForCall(Loc, Constructor,
                                         Proto, 0, Args, NumArgs, AllArgs, 
-                                        CallType);
+                                        CallType, AllowExplicit);
   ConvertedArgs.append(AllArgs.begin(), AllArgs.end());
 
   DiagnoseSentinelCalls(Constructor, Loc, AllArgs.data(), AllArgs.size());

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=151409&r1=151408&r2=151409&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Feb 24 17:56:31 2012
@@ -3248,7 +3248,8 @@
                                   unsigned FirstProtoArg,
                                   Expr **Args, unsigned NumArgs,
                                   SmallVector<Expr *, 8> &AllArgs,
-                                  VariadicCallType CallType) {
+                                  VariadicCallType CallType,
+                                  bool AllowExplicit) {
   unsigned NumArgsInProto = Proto->getNumArgs();
   unsigned NumArgsToCheck = NumArgs;
   bool Invalid = false;
@@ -3288,7 +3289,9 @@
                                                       Proto->isArgConsumed(i));
       ExprResult ArgE = PerformCopyInitialization(Entity,
                                                   SourceLocation(),
-                                                  Owned(Arg));
+                                                  Owned(Arg),
+                                                  /*TopLevelOfInitList=*/false,
+                                                  AllowExplicit);
       if (ArgE.isInvalid())
         return true;
 

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=151409&r1=151408&r2=151409&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Fri Feb 24 17:56:31 2012
@@ -2827,10 +2827,22 @@
                                        /*ExplicitArgs*/ 0,
                                        Args, NumArgs, CandidateSet,
                                        SuppressUserConversions);
-      else
+      else {
+        // C++ [over.match.copy]p1:
+        //   - When initializing a temporary to be bound to the first parameter 
+        //     of a constructor that takes a reference to possibly cv-qualified 
+        //     T as its first argument, called with a single argument in the 
+        //     context of direct-initialization, explicit conversion functions
+        //     are also considered.
+        bool AllowExplicitConv = AllowExplicit && !CopyInitializing && 
+                                 NumArgs == 1 &&
+                                 Constructor->isCopyOrMoveConstructor();
         S.AddOverloadCandidate(Constructor, FoundDecl,
                                Args, NumArgs, CandidateSet,
-                               SuppressUserConversions);
+                               SuppressUserConversions,
+                               /*PartialOverloading=*/false,
+                               /*AllowExplicit=*/AllowExplicitConv);
+      }
     }
   }
 
@@ -3122,8 +3134,8 @@
 static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
                                              const InitializedEntity &Entity,
                                              const InitializationKind &Kind,
-                                                          Expr *Initializer,
-                                                          bool AllowRValues,
+                                             Expr *Initializer,
+                                             bool AllowRValues,
                                              InitializationSequence &Sequence) {
   QualType DestType = Entity.getType();
   QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
@@ -3151,7 +3163,8 @@
   // Determine whether we are allowed to call explicit constructors or
   // explicit conversion operators.
   bool AllowExplicit = Kind.AllowExplicit();
-
+  bool AllowExplicitConvs = Kind.allowExplicitConversionFunctions();
+  
   const RecordType *T1RecordType = 0;
   if (AllowRValues && (T1RecordType = T1->getAs<RecordType>()) &&
       !S.RequireCompleteType(Kind.getLocation(), T1, 0)) {
@@ -3220,7 +3233,7 @@
       // FIXME: Do we need to make sure that we only consider conversion
       // candidates with reference-compatible results? That might be needed to
       // break recursion.
-      if ((AllowExplicit || !Conv->isExplicit()) &&
+      if ((AllowExplicitConvs || !Conv->isExplicit()) &&
           (AllowRValues || Conv->getConversionType()->isLValueReferenceType())){
         if (ConvTemplate)
           S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
@@ -4636,10 +4649,21 @@
 
   ExprResult CurInit = S.Owned((Expr *)0);
 
+  // C++ [over.match.copy]p1:
+  //   - When initializing a temporary to be bound to the first parameter 
+  //     of a constructor that takes a reference to possibly cv-qualified 
+  //     T as its first argument, called with a single argument in the 
+  //     context of direct-initialization, explicit conversion functions
+  //     are also considered.
+  bool AllowExplicitConv = Kind.AllowExplicit() && !Kind.isCopyInit() &&
+                           Args.size() == 1 && 
+                           Constructor->isCopyOrMoveConstructor();
+
   // Determine the arguments required to actually perform the constructor
   // call.
   if (S.CompleteConstructorCall(Constructor, move(Args),
-                                Loc, ConstructorArgs))
+                                Loc, ConstructorArgs,
+                                AllowExplicitConv))
     return ExprError();
 
 
@@ -6097,7 +6121,8 @@
 Sema::PerformCopyInitialization(const InitializedEntity &Entity,
                                 SourceLocation EqualLoc,
                                 ExprResult Init,
-                                bool TopLevelOfInitList) {
+                                bool TopLevelOfInitList,
+                                bool AllowExplicit) {
   if (Init.isInvalid())
     return ExprError();
 
@@ -6108,7 +6133,8 @@
     EqualLoc = InitE->getLocStart();
 
   InitializationKind Kind = InitializationKind::CreateCopy(InitE->getLocStart(),
-                                                           EqualLoc);
+                                                           EqualLoc,
+                                                           AllowExplicit);
   InitializationSequence Seq(*this, Entity, Kind, &InitE, 1);
   Init.release();
 

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=151409&r1=151408&r2=151409&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Feb 24 17:56:31 2012
@@ -4213,7 +4213,8 @@
 TryCopyInitialization(Sema &S, Expr *From, QualType ToType,
                       bool SuppressUserConversions,
                       bool InOverloadResolution,
-                      bool AllowObjCWritebackConversion);
+                      bool AllowObjCWritebackConversion,
+                      bool AllowExplicit = false);
 
 /// TryListConversion - Try to copy-initialize a value of type ToType from the
 /// initializer list From.
@@ -4413,7 +4414,8 @@
 TryCopyInitialization(Sema &S, Expr *From, QualType ToType,
                       bool SuppressUserConversions,
                       bool InOverloadResolution,
-                      bool AllowObjCWritebackConversion) {
+                      bool AllowObjCWritebackConversion,
+                      bool AllowExplicit) {
   if (InitListExpr *FromInitList = dyn_cast<InitListExpr>(From))
     return TryListConversion(S, FromInitList, ToType, SuppressUserConversions,
                              InOverloadResolution,AllowObjCWritebackConversion);
@@ -4422,7 +4424,7 @@
     return TryReferenceInit(S, From, ToType,
                             /*FIXME:*/From->getLocStart(),
                             SuppressUserConversions,
-                            /*AllowExplicit=*/false);
+                            AllowExplicit);
 
   return TryImplicitConversion(S, From, ToType,
                                SuppressUserConversions,
@@ -5103,7 +5105,8 @@
                            Expr **Args, unsigned NumArgs,
                            OverloadCandidateSet& CandidateSet,
                            bool SuppressUserConversions,
-                           bool PartialOverloading) {
+                           bool PartialOverloading,
+                           bool AllowExplicit) {
   const FunctionProtoType* Proto
     = dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
   assert(Proto && "Functions without a prototype cannot be overloaded");
@@ -5204,7 +5207,8 @@
                                 SuppressUserConversions,
                                 /*InOverloadResolution=*/true,
                                 /*AllowObjCWritebackConversion=*/
-                                  getLangOptions().ObjCAutoRefCount);
+                                  getLangOptions().ObjCAutoRefCount,
+                                AllowExplicit);
       if (Candidate.Conversions[ArgIdx].isBad()) {
         Candidate.Viable = false;
         Candidate.FailureKind = ovl_fail_bad_conversion;

Added: cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.copy/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.copy/p1.cpp?rev=151409&view=auto
==============================================================================
--- cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.copy/p1.cpp (added)
+++ cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.copy/p1.cpp Fri Feb 24 17:56:31 2012
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -verify
+
+namespace ExplicitConv {
+  struct X { }; // expected-note 2{{candidate constructor}}
+
+  struct Y {
+    explicit operator X() const;
+  };
+
+  void test(const Y& y) {
+    X x(static_cast<X>(y));
+    X x2((X)y);
+    X x3 = y; // expected-error{{no viable conversion from 'const ExplicitConv::Y' to 'ExplicitConv::X'}}
+  }
+}

Modified: cfe/trunk/test/SemaCXX/explicit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/explicit.cpp?rev=151409&r1=151408&r2=151409&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/explicit.cpp (original)
+++ cfe/trunk/test/SemaCXX/explicit.cpp Fri Feb 24 17:56:31 2012
@@ -43,16 +43,8 @@
     class Y { }; // expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y &' for 1st argument}} \
 					          expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y &&' for 1st argument}} \
                     expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y &' for 1st argument}} \
-                    expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y' for 1st argument}} \
-					expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y' for 1st argument}} \
-					expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y' for 1st argument}} \
-					expected-note {{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}} \
-					expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y' for 1st argument}} \
-					expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y' for 1st argument}} \
-					expected-note {{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}} \
-					expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y' for 1st argument}} \
-          expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y &&' for 1st argument}} \
-					expected-note {{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}}
+          expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y &&' for 1st argument}}
+
     struct Z {
       explicit operator Y() const;
       explicit operator int() const;
@@ -61,10 +53,9 @@
     Z z;
     // 13.3.1.4p1 & 8.5p16:
     Y y2 = z; // expected-error {{no viable conversion from 'Conversion::Z' to 'Conversion::Y'}}
-    // FIXME: These are well-formed per C++0x 13.3.1.4p1 (see DR899).
-    Y y3 = (Y)z; // expected-error {{no matching conversion for C-style cast from 'Conversion::Z' to 'Conversion::Y'}}
-    Y y4 = Y(z); // expected-error {{no matching conversion for functional-style cast from 'Conversion::Z' to 'Conversion::Y'}}
-    Y y5 = static_cast<Y>(z); // expected-error {{no matching conversion for static_cast from 'Conversion::Z' to 'Conversion::Y'}}
+    Y y3 = (Y)z;
+    Y y4 = Y(z);
+    Y y5 = static_cast<Y>(z);
     // 13.3.1.5p1 & 8.5p16:
     int i1 = (int)z;
     int i2 = int(z);





More information about the cfe-commits mailing list