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

Michael Price michael.b.price.dev at gmail.com
Wed Dec 15 22:23:29 PST 2010


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

   //     - 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;
+}
+
 bool Type::isSpecifierType() const {
   // Note that this intentionally does not use the canonical type.
   switch (getTypeClass()) {
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20101215/95399c96/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: auto_type.diff
Type: application/octet-stream
Size: 8107 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20101215/95399c96/attachment.obj>


More information about the cfe-dev mailing list