[cfe-commits] r147156 - in /cfe/trunk: include/clang/Sema/Initialization.h lib/Sema/SemaInit.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/cxx0x-initializer-constructor.cpp

Chad Rosier mcrosier at apple.com
Thu Dec 22 11:15:25 PST 2011


Hi Sebastian,
I'm seeing a warning that should probably be addressed:

clang/lib/Sema/SemaInit.cpp:5576:13: warning: enumeration value 'FK_ListConstructorOverloadFailed' not handled in switch [-Wswitch-enum]
    switch (Failure) {
            ^

 Chad

On Dec 22, 2011, at 10:58 AM, Sebastian Redl wrote:

> Author: cornedbee
> Date: Thu Dec 22 12:58:38 2011
> New Revision: 147156
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=147156&view=rev
> Log:
> Overloading for initializer list construction.
> 
> Modified:
>    cfe/trunk/include/clang/Sema/Initialization.h
>    cfe/trunk/lib/Sema/SemaInit.cpp
>    cfe/trunk/lib/Sema/SemaOverload.cpp
>    cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp
> 
> Modified: cfe/trunk/include/clang/Sema/Initialization.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=147156&r1=147155&r2=147156&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/Initialization.h (original)
> +++ cfe/trunk/include/clang/Sema/Initialization.h Thu Dec 22 12:58:38 2011
> @@ -643,8 +643,10 @@
>     FK_InitListBadDestinationType,
>     /// \brief Overloading for a user-defined conversion failed.
>     FK_UserConversionOverloadFailed,
> -    /// \brief Overloaded for initialization by constructor failed.
> +    /// \brief Overloading for initialization by constructor failed.
>     FK_ConstructorOverloadFailed,
> +    /// \brief Overloading for list-initialization by constructor failed.
> +    FK_ListConstructorOverloadFailed,
>     /// \brief Default-initialization of a 'const' object.
>     FK_DefaultInitOfConst,
>     /// \brief Initialization of an incomplete type.
> 
> Modified: cfe/trunk/lib/Sema/SemaInit.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=147156&r1=147155&r2=147156&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaInit.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaInit.cpp Thu Dec 22 12:58:38 2011
> @@ -2436,6 +2436,7 @@
>   case FK_ReferenceInitOverloadFailed:
>   case FK_UserConversionOverloadFailed:
>   case FK_ConstructorOverloadFailed:
> +  case FK_ListConstructorOverloadFailed:
>     return FailedOverloadResult == OR_Ambiguous;
>   }
> 
> @@ -2849,8 +2850,8 @@
>                                  Args, NumArgs, CandidateSet,
>                                  /*SuppressUserConversions*/ false);
>         Sequence.SetOverloadFailure(
> -                          InitializationSequence::FK_ConstructorOverloadFailed,
> -                          OR_Deleted);
> +                       InitializationSequence::FK_ListConstructorOverloadFailed,
> +                       OR_Deleted);
>       } else
>         Sequence.AddConstructorInitializationStep(DefaultConstructor,
>                                                 DefaultConstructor->getAccess(),
> @@ -2961,8 +2962,9 @@
>   OverloadCandidateSet::iterator Best;
>   if (OverloadingResult Result
>         = CandidateSet.BestViableFunction(S, DeclLoc, Best)) {
> -    Sequence.SetOverloadFailure(
> -                          InitializationSequence::FK_ConstructorOverloadFailed,
> +    Sequence.SetOverloadFailure(FromInitList ?
> +                      InitializationSequence::FK_ListConstructorOverloadFailed :
> +                      InitializationSequence::FK_ConstructorOverloadFailed,
>                                 Result);
>     return;
>   }
> @@ -5428,12 +5430,20 @@
>       << (DestType->isRecordType()) << DestType << Args[0]->getSourceRange();
>     break;
> 
> +  case FK_ListConstructorOverloadFailed:
>   case FK_ConstructorOverloadFailed: {
>     SourceRange ArgsRange;
>     if (NumArgs)
>       ArgsRange = SourceRange(Args[0]->getLocStart(),
>                               Args[NumArgs - 1]->getLocEnd());
> 
> +    if (Failure == FK_ListConstructorOverloadFailed) {
> +      assert(NumArgs == 1 && "List construction from other than 1 argument.");
> +      InitListExpr *InitList = cast<InitListExpr>(Args[0]);
> +      Args = InitList->getInits();
> +      NumArgs = InitList->getNumInits();
> +    }
> +
>     // FIXME: Using "DestType" for the entity we're printing is probably
>     // bad.
>     switch (FailedOverloadResult) {
> 
> Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=147156&r1=147155&r2=147156&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaOverload.cpp Thu Dec 22 12:58:38 2011
> @@ -824,6 +824,86 @@
>   return FD->isUnavailable() && !cast<Decl>(CurContext)->isUnavailable();
> }
> 
> +/// \brief Tries a user-defined conversion from From to ToType.
> +///
> +/// Produces an implicit conversion sequence for when a standard conversion
> +/// is not an option. See TryImplicitConversion for more information.
> +static ImplicitConversionSequence
> +TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
> +                         bool SuppressUserConversions,
> +                         bool AllowExplicit,
> +                         bool InOverloadResolution,
> +                         bool CStyle,
> +                         bool AllowObjCWritebackConversion) {
> +  ImplicitConversionSequence ICS;
> +
> +  if (SuppressUserConversions) {
> +    // We're not in the case above, so there is no conversion that
> +    // we can perform.
> +    ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
> +    return ICS;
> +  }
> +
> +  // Attempt user-defined conversion.
> +  OverloadCandidateSet Conversions(From->getExprLoc());
> +  OverloadingResult UserDefResult
> +    = IsUserDefinedConversion(S, From, ToType, ICS.UserDefined, Conversions,
> +                              AllowExplicit);
> +
> +  if (UserDefResult == OR_Success) {
> +    ICS.setUserDefined();
> +    // C++ [over.ics.user]p4:
> +    //   A conversion of an expression of class type to the same class
> +    //   type is given Exact Match rank, and a conversion of an
> +    //   expression of class type to a base class of that type is
> +    //   given Conversion rank, in spite of the fact that a copy
> +    //   constructor (i.e., a user-defined conversion function) is
> +    //   called for those cases.
> +    if (CXXConstructorDecl *Constructor
> +          = dyn_cast<CXXConstructorDecl>(ICS.UserDefined.ConversionFunction)) {
> +      QualType FromCanon
> +        = S.Context.getCanonicalType(From->getType().getUnqualifiedType());
> +      QualType ToCanon
> +        = S.Context.getCanonicalType(ToType).getUnqualifiedType();
> +      if (Constructor->isCopyConstructor() &&
> +          (FromCanon == ToCanon || S.IsDerivedFrom(FromCanon, ToCanon))) {
> +        // Turn this into a "standard" conversion sequence, so that it
> +        // gets ranked with standard conversion sequences.
> +        ICS.setStandard();
> +        ICS.Standard.setAsIdentityConversion();
> +        ICS.Standard.setFromType(From->getType());
> +        ICS.Standard.setAllToTypes(ToType);
> +        ICS.Standard.CopyConstructor = Constructor;
> +        if (ToCanon != FromCanon)
> +          ICS.Standard.Second = ICK_Derived_To_Base;
> +      }
> +    }
> +
> +    // C++ [over.best.ics]p4:
> +    //   However, when considering the argument of a user-defined
> +    //   conversion function that is a candidate by 13.3.1.3 when
> +    //   invoked for the copying of the temporary in the second step
> +    //   of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or
> +    //   13.3.1.6 in all cases, only standard conversion sequences and
> +    //   ellipsis conversion sequences are allowed.
> +    if (SuppressUserConversions && ICS.isUserDefined()) {
> +      ICS.setBad(BadConversionSequence::suppressed_user, From, ToType);
> +    }
> +  } else if (UserDefResult == OR_Ambiguous && !SuppressUserConversions) {
> +    ICS.setAmbiguous();
> +    ICS.Ambiguous.setFromType(From->getType());
> +    ICS.Ambiguous.setToType(ToType);
> +    for (OverloadCandidateSet::iterator Cand = Conversions.begin();
> +         Cand != Conversions.end(); ++Cand)
> +      if (Cand->Viable)
> +        ICS.Ambiguous.addConversion(Cand->Function);
> +  } else {
> +    ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
> +  }
> +
> +  return ICS;
> +}
> +
> /// TryImplicitConversion - Attempt to perform an implicit conversion
> /// from the given expression (Expr) to the given type (ToType). This
> /// function returns an implicit conversion sequence that can be used
> @@ -899,71 +979,9 @@
>     return ICS;
>   }
> 
> -  if (SuppressUserConversions) {
> -    // We're not in the case above, so there is no conversion that
> -    // we can perform.
> -    ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
> -    return ICS;
> -  }
> -
> -  // Attempt user-defined conversion.
> -  OverloadCandidateSet Conversions(From->getExprLoc());
> -  OverloadingResult UserDefResult
> -    = IsUserDefinedConversion(S, From, ToType, ICS.UserDefined, Conversions,
> -                              AllowExplicit);
> -
> -  if (UserDefResult == OR_Success) {
> -    ICS.setUserDefined();
> -    // C++ [over.ics.user]p4:
> -    //   A conversion of an expression of class type to the same class
> -    //   type is given Exact Match rank, and a conversion of an
> -    //   expression of class type to a base class of that type is
> -    //   given Conversion rank, in spite of the fact that a copy
> -    //   constructor (i.e., a user-defined conversion function) is
> -    //   called for those cases.
> -    if (CXXConstructorDecl *Constructor
> -          = dyn_cast<CXXConstructorDecl>(ICS.UserDefined.ConversionFunction)) {
> -      QualType FromCanon
> -        = S.Context.getCanonicalType(From->getType().getUnqualifiedType());
> -      QualType ToCanon
> -        = S.Context.getCanonicalType(ToType).getUnqualifiedType();
> -      if (Constructor->isCopyConstructor() &&
> -          (FromCanon == ToCanon || S.IsDerivedFrom(FromCanon, ToCanon))) {
> -        // Turn this into a "standard" conversion sequence, so that it
> -        // gets ranked with standard conversion sequences.
> -        ICS.setStandard();
> -        ICS.Standard.setAsIdentityConversion();
> -        ICS.Standard.setFromType(From->getType());
> -        ICS.Standard.setAllToTypes(ToType);
> -        ICS.Standard.CopyConstructor = Constructor;
> -        if (ToCanon != FromCanon)
> -          ICS.Standard.Second = ICK_Derived_To_Base;
> -      }
> -    }
> -
> -    // C++ [over.best.ics]p4:
> -    //   However, when considering the argument of a user-defined
> -    //   conversion function that is a candidate by 13.3.1.3 when
> -    //   invoked for the copying of the temporary in the second step
> -    //   of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or
> -    //   13.3.1.6 in all cases, only standard conversion sequences and
> -    //   ellipsis conversion sequences are allowed.
> -    if (SuppressUserConversions && ICS.isUserDefined()) {
> -      ICS.setBad(BadConversionSequence::suppressed_user, From, ToType);
> -    }
> -  } else if (UserDefResult == OR_Ambiguous && !SuppressUserConversions) {
> -    ICS.setAmbiguous();
> -    ICS.Ambiguous.setFromType(From->getType());
> -    ICS.Ambiguous.setToType(ToType);
> -    for (OverloadCandidateSet::iterator Cand = Conversions.begin();
> -         Cand != Conversions.end(); ++Cand)
> -      if (Cand->Viable)
> -        ICS.Ambiguous.addConversion(Cand->Function);
> -  } else {
> -    ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
> -  }
> -
> -  return ICS;
> +  return TryUserDefinedConversion(S, From, ToType, SuppressUserConversions,
> +                                  AllowExplicit, InOverloadResolution, CStyle,
> +                                  AllowObjCWritebackConversion);
> }
> 
> ImplicitConversionSequence
> @@ -2612,6 +2630,18 @@
>       // We're not going to find any constructors.
>     } else if (CXXRecordDecl *ToRecordDecl
>                  = dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) {
> +
> +      Expr **Args = &From;
> +      unsigned NumArgs = 1;
> +      bool ListInitializing = false;
> +      // If we're list-initializing, we pass the individual elements as
> +      // arguments, not the entire list.
> +      if (InitListExpr *InitList = dyn_cast<InitListExpr>(From)) {
> +        Args = InitList->getInits();
> +        NumArgs = InitList->getNumInits();
> +        ListInitializing = true;
> +      }
> +
>       DeclContext::lookup_iterator Con, ConEnd;
>       for (llvm::tie(Con, ConEnd) = S.LookupConstructors(ToRecordDecl);
>            Con != ConEnd; ++Con) {
> @@ -2628,28 +2658,33 @@
>         else
>           Constructor = cast<CXXConstructorDecl>(D);
> 
> -        if (!Constructor->isInvalidDecl() &&
> -            Constructor->isConvertingConstructor(AllowExplicit)) {
> +        bool Usable = !Constructor->isInvalidDecl();
> +        if (ListInitializing)
> +          Usable = Usable && (AllowExplicit || !Constructor->isExplicit());
> +        else
> +          Usable = Usable &&Constructor->isConvertingConstructor(AllowExplicit);
> +        if (Usable) {
>           if (ConstructorTmpl)
>             S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
>                                            /*ExplicitArgs*/ 0,
> -                                           &From, 1, CandidateSet,
> +                                           Args, NumArgs, CandidateSet,
>                                            /*SuppressUserConversions=*/
> -                                             !ConstructorsOnly);
> +                                           !ConstructorsOnly &&
> +                                             !ListInitializing);
>           else
>             // Allow one user-defined conversion when user specifies a
>             // From->ToType conversion via an static cast (c-style, etc).
>             S.AddOverloadCandidate(Constructor, FoundDecl,
> -                                   &From, 1, CandidateSet,
> +                                   Args, NumArgs, CandidateSet,
>                                    /*SuppressUserConversions=*/
> -                                     !ConstructorsOnly);
> +                                   !ConstructorsOnly && !ListInitializing);
>         }
>       }
>     }
>   }
> 
>   // Enumerate conversion functions, if we're allowed to.
> -  if (ConstructorsOnly) {
> +  if (ConstructorsOnly || isa<InitListExpr>(From)) {
>   } else if (S.RequireCompleteType(From->getLocStart(), From->getType(),
>                                    S.PDiag(0) << From->getSourceRange())) {
>     // No conversion functions from incomplete types.
> @@ -2705,11 +2740,16 @@
>       //   the argument of the constructor.
>       //
>       QualType ThisType = Constructor->getThisType(S.Context);
> -      if (Best->Conversions[0].isEllipsis())
> -        User.EllipsisConversion = true;
> -      else {
> -        User.Before = Best->Conversions[0].Standard;
> -        User.EllipsisConversion = false;
> +      if (isa<InitListExpr>(From)) {
> +        // Initializer lists don't have conversions as such.
> +        User.Before.setAsIdentityConversion();
> +      } else {
> +        if (Best->Conversions[0].isEllipsis())
> +          User.EllipsisConversion = true;
> +        else {
> +          User.Before = Best->Conversions[0].Standard;
> +          User.EllipsisConversion = false;
> +        }
>       }
>       User.HadMultipleCandidates = HadMultipleCandidates;
>       User.ConversionFunction = Constructor;
> @@ -3916,7 +3956,7 @@
>   //   conversion sequence is the worst conversion necessary to convert an
>   //   element of the list to X.
>   // FIXME: Recognize std::initializer_list.
> -  // FIXME: Arrays don't make sense until we can deal with references.
> +  // FIXME: Implement arrays.
>   if (ToType->isArrayType())
>     return Result;
> 
> @@ -3926,9 +3966,15 @@
>   //   conversion sequence is a user-defined conversion sequence. If multiple
>   //   constructors are viable but none is better than the others, the
>   //   implicit conversion sequence is a user-defined conversion sequence.
> -  // FIXME: Implement this.
> -  if (ToType->isRecordType() && !ToType->isAggregateType())
> +  if (ToType->isRecordType() && !ToType->isAggregateType()) {
> +    // This function can deal with initializer lists.
> +    Result = TryUserDefinedConversion(S, From, ToType, SuppressUserConversions,
> +                                      /*AllowExplicit=*/false,
> +                                      InOverloadResolution, /*CStyle=*/false,
> +                                      AllowObjCWritebackConversion);
> +    Result.setListInitializationSequence();
>     return Result;
> +  }
> 
>   // C++11 [over.ics.list]p4:
>   //   Otherwise, if the parameter has an aggregate type which can be
> 
> Modified: cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp?rev=147156&r1=147155&r2=147156&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp (original)
> +++ cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp Thu Dec 22 12:58:38 2011
> @@ -1,5 +1,8 @@
> // RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
> 
> +struct one { char c[1]; };
> +struct two { char c[2]; };
> +
> namespace objects {
> 
>   struct X1 { X1(int); };
> @@ -45,8 +48,8 @@
>     void takes_C(C);
>     takes_C({1, 1.0});
> 
> -    //C c;
> -    //c[{1, 1.0}]; needs overloading
> +    C c;
> +    c[{1, 1.0}];
> 
>     return {1, 1.0};
>   }
> @@ -56,11 +59,23 @@
>     (void) new C{1, 1.0};
>   }
> 
> -  struct B {
> -    B(C, int, C);
> +  struct B { // expected-note 2 {{candidate constructor}}
> +    B(C, int, C); // expected-note {{candidate constructor not viable: cannot convert initializer list argument to 'objects::C'}}
>   };
> 
>   void nested_init() {
> -    //B b{{1, 1.0}, 2, {3, 4}}; needs overloading
> +    B b1{{1, 1.0}, 2, {3, 4}};
> +    B b2{{1, 1.0, 4}, 2, {3, 4}}; // expected-error {{no matching constructor for initialization of 'objects::B'}}
> +  }
> +
> +  void overloaded_call() {
> +    one ov1(B); // expected-note {{not viable: cannot convert initializer list}}
> +    two ov1(C); // expected-note {{not viable: cannot convert initializer list}}
> +
> +    static_assert(sizeof(ov1({})) == sizeof(two), "bad overload");
> +    static_assert(sizeof(ov1({1, 2})) == sizeof(two), "bad overload");
> +    static_assert(sizeof(ov1({{1, 1.0}, 2, {3, 4}})) == sizeof(one), "bad overload");
> +
> +    ov1({1}); // expected-error {{no matching function}}
>   }
> }
> 
> 
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits




More information about the cfe-commits mailing list