[cfe-dev] Rudimentary 'auto' type deduction implementation

Douglas Gregor dgregor at apple.com
Mon Dec 20 22:21:29 PST 2010


On Dec 15, 2010, at 10:23 PM, Michael Price wrote:

> Hi Everyone,
> 
> Way back in August, I had a rudimentary implementation of the C++0x type deduction via the 'auto' type.  I never got around to adding the appropriate tests and then there was a major refactor of much of the Sema code that I think made my implementation seem out of place.  I've finally gotten around to looking at this again and would like the advice of those more experienced in the type system.
> 
> Also, I wasn't sure if I should attach my diff as a file or embed it inline, so I've done both.
> 
> Thanks ahead of time for your help!
> 
> 
> Index: include/clang/Sema/Sema.h
> ===================================================================
> --- include/clang/Sema/Sema.h    (revision 121900)
> +++ include/clang/Sema/Sema.h    (working copy)
> @@ -986,6 +986,13 @@
>    bool IsOverload(FunctionDecl *New, FunctionDecl *Old, bool IsForUsingDecl);
>  
>    bool TryImplicitConversion(InitializationSequence &Sequence,
> +                             QualType ToType,
> +                             Expr *From,
> +                             bool SuppressUserConversions,
> +                             bool AllowExplicit,
> +                             bool InOverloadResolution);
> +
> +  bool TryImplicitConversion(InitializationSequence &Sequence,
>                               const InitializedEntity &Entity,
>                               Expr *From,
>                               bool SuppressUserConversions,
> Index: include/clang/Sema/Initialization.h
> ===================================================================
> --- include/clang/Sema/Initialization.h    (revision 121900)
> +++ include/clang/Sema/Initialization.h    (working copy)
> @@ -552,6 +552,8 @@
>    
>    /// \brief Steps taken by this initialization.
>    llvm::SmallVector<Step, 4> Steps;
> +
> +  QualType DeducedType;
>    
>  public:
>    /// \brief Describes why initialization failed.
> Index: include/clang/AST/CanonicalType.h
> ===================================================================
> --- include/clang/AST/CanonicalType.h    (revision 121900)
> +++ include/clang/AST/CanonicalType.h    (working copy)
> @@ -277,6 +277,7 @@
>    LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnionType)
>    LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexIntegerType)
>    LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isNullPtrType)
> +  LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUndeducedAutoType)
>    LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDependentType)
>    LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isOverloadableType)
>    LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isArrayType)
> Index: include/clang/AST/Type.h
> ===================================================================
> --- include/clang/AST/Type.h    (revision 121900)
> +++ include/clang/AST/Type.h    (working copy)
> @@ -1176,6 +1176,7 @@
>    bool isObjCBuiltinType() const;               // 'id' or 'Class'
>    bool isTemplateTypeParmType() const;          // C++ template type parameter
>    bool isNullPtrType() const;                   // C++0x nullptr_t
> +  bool isUndeducedAutoType() const;                // C++0x yet to be deduced 'auto'
>  
>    enum ScalarTypeKind {
>      STK_Pointer,
> Index: lib/Sema/SemaInit.cpp
> ===================================================================
> --- lib/Sema/SemaInit.cpp    (revision 121900)
> +++ lib/Sema/SemaInit.cpp    (working copy)
> @@ -3094,12 +3094,6 @@
>    //   parenthesized list of expressions.
>    QualType DestType = Entity.getType();
>  
> -  if (DestType->isDependentType() ||
> -      Expr::hasAnyTypeDependentArguments(Args, NumArgs)) {
> -    SequenceKind = DependentSequence;
> -    return;
> -  }
> -
>    for (unsigned I = 0; I != NumArgs; ++I)
>      if (Args[I]->getObjectKind() == OK_ObjCProperty)
>        S.ConvertPropertyForRValue(Args[I]);
> @@ -3111,6 +3105,19 @@
>      if (!isa<InitListExpr>(Initializer))
>        SourceType = Initializer->getType();
>    }
> +
> +  if (S.getLangOptions().CPlusPlus0x) {
> +    if (DestType->isUndeducedAutoType() && !SourceType.isNull()) { // TODO: Can 'auto' be initialized with a list?
> +        DeducedType = SourceType;
> +        DestType = SourceType;
> +    }
> +  }

There's more to it than just copying the deduced type over. For one, there may not be a source type at this point, e.g., if we are attempting to direct-initialize with multiple arguments. Also, there's some matching that needs to be done.

  int x;
  auto *y = x; // should be an error

The process is like a restricted form of template argument deduction, but much simpler.

> +  if (DestType->isDependentType() ||
> +      Expr::hasAnyTypeDependentArguments(Args, NumArgs)) {
> +    SequenceKind = DependentSequence;
> +    return;
> +  }

Are we sure that it's safe to move this check down here? For example, did you verify that ConvertPropertyForRValue does the right thing for type-dependent expressions?

>    //     - If the initializer is a braced-init-list, the object is 
>    //       list-initialized (8.5.4).
> @@ -3183,7 +3190,7 @@
>           (Context.hasSameUnqualifiedType(SourceType, DestType) ||
>            S.IsDerivedFrom(SourceType, DestType))))
>        TryConstructorInitialization(S, Entity, Kind, Args, NumArgs, 
> -                                   Entity.getType(), *this);
> +                                   DestType, *this);
>      //     - Otherwise (i.e., for the remaining copy-initialization cases), 
>      //       user-defined conversion sequences that can convert from the source
>      //       type to the destination type or (when a conversion function is 
> @@ -3213,7 +3220,7 @@
>    //      conversions (Clause 4) will be used, if necessary, to convert the
>    //      initializer expression to the cv-unqualified version of the 
>    //      destination type; no user-defined conversions are considered.
> -  if (S.TryImplicitConversion(*this, Entity, Initializer,
> +  if (S.TryImplicitConversion(*this, DestType, Initializer,
>                                /*SuppressUserConversions*/ true,
>                                /*AllowExplicitConversions*/ false,
>                                /*InOverloadResolution*/ false))
> @@ -3548,6 +3555,10 @@
>      return ExprError();
>    }
>    
> +  if (ResultType && !DeducedType.isNull()) {
> +      *ResultType = DeducedType;
> +  }
> +
>    if (SequenceKind == DependentSequence) {
>      // If the declaration is a non-dependent, incomplete array type
>      // that has an initializer, then its type will be completed once
> @@ -3609,7 +3620,7 @@
>    // FIXME: Ugly hack around the fact that Entity.getType() is not
>    // the same as Entity.getDecl()->getType() in cases involving type merging,
>    //  and we want latter when it makes sense.
> -  if (ResultType)
> +  if (ResultType && DeducedType.isNull())
>      *ResultType = Entity.getDecl() ? Entity.getDecl()->getType() :
>                                       Entity.getType();
>  
> Index: lib/Sema/SemaOverload.cpp
> ===================================================================
> --- lib/Sema/SemaOverload.cpp    (revision 121900)
> +++ lib/Sema/SemaOverload.cpp    (working copy)
> @@ -834,23 +834,37 @@
>  }
>  
>  bool Sema::TryImplicitConversion(InitializationSequence &Sequence,
> -                                 const InitializedEntity &Entity,
> +                                 QualType ToType,
>                                   Expr *Initializer,
>                                   bool SuppressUserConversions,
>                                   bool AllowExplicitConversions,
>                                   bool InOverloadResolution) {
>    ImplicitConversionSequence ICS
> -    = clang::TryImplicitConversion(*this, Initializer, Entity.getType(),
> +    = clang::TryImplicitConversion(*this, Initializer, ToType,
>                                     SuppressUserConversions,
>                                     AllowExplicitConversions, 
>                                     InOverloadResolution);
>    if (ICS.isBad()) return true;
>  
>    // Perform the actual conversion.
> -  Sequence.AddConversionSequenceStep(ICS, Entity.getType());
> +  Sequence.AddConversionSequenceStep(ICS, ToType);
>    return false;
>  }
>  
> +    
> +bool Sema::TryImplicitConversion(InitializationSequence &Sequence,
> +                                 const InitializedEntity &Entity,
> +                                 Expr *Initializer,
> +                                 bool SuppressUserConversions,
> +                                 bool AllowExplicitConversions,
> +                                 bool InOverloadResolution) {
> +  return TryImplicitConversion(Sequence, Entity.getType(),
> +                               Initializer, SuppressUserConversions,
> +                               AllowExplicitConversions, InOverloadResolution);
> +}
> +    
> +    
> +    
>  /// PerformImplicitConversion - Perform an implicit conversion of the
>  /// expression From to the type ToType. Returns true if there was an
>  /// error, false otherwise. The expression From is replaced with the
> Index: lib/AST/Type.cpp
> ===================================================================
> --- lib/AST/Type.cpp    (revision 121900)
> +++ lib/AST/Type.cpp    (working copy)
> @@ -862,6 +862,12 @@
>    return false;
>  }
>  
> +bool Type::isUndeducedAutoType() const {
> +  if (const BuiltinType *BT = getAs<BuiltinType>())
> +    return BT->getKind() == BuiltinType::UndeducedAuto;
> +  return false;
> +}

Would this also work for reference-to-auto and pointer-to-auto cases?

There's one big thing missing here that I'd like to see addressed in any implementation of "auto": the AST should represent the fact that (1) auto was used in the declaration, and (2) what type was deduced for the "auto" keyword itself. For example, given

  int x;
  auto *xp = &x;

we want to know that the "auto" was deduced to "int".


	- Doug

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20101220/ec7f1ae4/attachment.html>


More information about the cfe-dev mailing list