]> granicus.if.org Git - clang/commitdiff
PR13293: Defer deduction of an auto type with a dependent declarator, such as "auto...
authorRichard Smith <richard-llvm@metafoo.co.uk>
Sun, 8 Jul 2012 04:13:07 +0000 (04:13 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Sun, 8 Jul 2012 04:13:07 +0000 (04:13 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159908 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaDecl.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaTemplateDeduction.cpp
test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp

index 99814911e095d57c0df6b2f48ecb770e143fba0a..f9a487270b8ecf907b228ba55626a1946ddf5263 100644 (file)
@@ -6335,7 +6335,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
   ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
 
   // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
-  if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) {
+  AutoType *Auto = 0;
+  if (TypeMayContainAuto &&
+      (Auto = VDecl->getType()->getContainedAutoType()) &&
+      !Auto->isDeduced()) {
     Expr *DeduceInit = Init;
     // Initializer could be a C++ direct-initializer. Deduction only works if it
     // contains exactly one expression.
index 8efd4655809a8287ad07026f38902dbd2824aaec..9657661a03775d33abcf32cd7d3c62ce1205763b 100644 (file)
@@ -1093,8 +1093,10 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
     }
   }
 
-  // C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
-  if (TypeMayContainAuto && AllocType->getContainedAutoType()) {
+  // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
+  AutoType *AT = 0;
+  if (TypeMayContainAuto &&
+      (AT = AllocType->getContainedAutoType()) && !AT->isDeduced()) {
     if (initStyle == CXXNewExpr::NoInit || NumInits == 0)
       return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
                        << AllocType << TypeRange);
@@ -1110,8 +1112,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
     }
     Expr *Deduce = Inits[0];
     TypeSourceInfo *DeducedType = 0;
-    if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) ==
-            DAR_Failed)
+    if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed)
       return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure)
                        << AllocType << Deduce->getType()
                        << TypeRange << Deduce->getSourceRange());
index f4618e2e7eb046ae20ac37f2b49389a70e3a7899..310d9b36cba22b99f61febc41c826500cc078a36 100644 (file)
@@ -3464,6 +3464,41 @@ namespace {
       return E;
     }
   };
+
+  /// Determine whether the specified type (which contains an 'auto' type
+  /// specifier) is dependent. This is not trivial, because the 'auto' specifier
+  /// itself claims to be type-dependent.
+  bool isDependentAutoType(QualType Ty) {
+    while (1) {
+      QualType Pointee = Ty->getPointeeType();
+      if (!Pointee.isNull()) {
+        Ty = Pointee;
+      } else if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>()){
+        if (MPT->getClass()->isDependentType())
+          return true;
+        Ty = MPT->getPointeeType();
+      } else if (const FunctionProtoType *FPT = Ty->getAs<FunctionProtoType>()){
+        for (FunctionProtoType::arg_type_iterator I = FPT->arg_type_begin(),
+                                                  E = FPT->arg_type_end();
+             I != E; ++I)
+          if ((*I)->isDependentType())
+            return true;
+        Ty = FPT->getResultType();
+      } else if (Ty->isDependentSizedArrayType()) {
+        return true;
+      } else if (const ArrayType *AT = Ty->getAsArrayTypeUnsafe()) {
+        Ty = AT->getElementType();
+      } else if (Ty->getAs<DependentSizedExtVectorType>()) {
+        return true;
+      } else if (const VectorType *VT = Ty->getAs<VectorType>()) {
+        Ty = VT->getElementType();
+      } else {
+        break;
+      }
+    }
+    assert(Ty->getAs<AutoType>() && "didn't find 'auto' in auto type");
+    return false;
+  }
 }
 
 /// \brief Deduce the type for an auto type-specifier (C++0x [dcl.spec.auto]p6)
@@ -3486,7 +3521,7 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
     Init = result.take();
   }
 
-  if (Init->isTypeDependent()) {
+  if (Init->isTypeDependent() || isDependentAutoType(Type->getType())) {
     Result = Type;
     return DAR_Succeeded;
   }
@@ -3517,10 +3552,10 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
 
   TemplateDeductionInfo Info(Context, Loc);
 
-  InitListExpr * InitList = dyn_cast<InitListExpr>(Init);
+  InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
   if (InitList) {
     for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
-      if (DeduceTemplateArgumentByListElement(*this, &TemplateParams, 
+      if (DeduceTemplateArgumentByListElement(*this, &TemplateParams,
                                               TemplArg,
                                               InitList->getInit(i),
                                               Info, Deduced, TDF))
@@ -3531,7 +3566,7 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
                                                   FuncParam, InitType, Init,
                                                   TDF))
       return DAR_Failed;
-    
+
     if (DeduceTemplateArgumentsByTypeMatch(*this, &TemplateParams, FuncParam,
                                            InitType, Info, Deduced, TDF))
       return DAR_Failed;
index 1daf02f6ea51d3bfa9bc1dadd99455c83144975b..f732255a8a4f1350ecd138eb6903e84ab565fe56 100644 (file)
@@ -49,3 +49,40 @@ void p3example() {
   same<__typeof(u), const int> uHasTypeConstInt;
   same<__typeof(y), double> yHasTypeDouble;
 }
+
+#if __cplusplus >= 201103L
+namespace PR13293 {
+  // Ensure that dependent declarators have their deduction delayed.
+  int f(char);
+  double f(short);
+  template<typename T> struct S {
+    static constexpr auto (*p)(T) = &f;
+  };
+
+  constexpr int (*f1)(char) = &f;
+  constexpr double (*f2)(short) = &f;
+  static_assert(S<char>::p == f1, "");
+  static_assert(S<short>::p == f2, "");
+
+  struct K { int n; };
+  template<typename T> struct U {
+    static constexpr auto (T::*p) = &K::n;
+  };
+  static_assert(U<K>::p == &K::n, "");
+
+  template<typename T>
+  using X = auto(int) -> auto(*)(T) -> auto(*)(char) -> long;
+  X<double> x;
+  template<typename T> struct V {
+    //static constexpr auto (*p)(int) -> auto(*)(T) -> auto(*)(char) = &x; // ill-formed
+    static constexpr auto (*(*(*p)(int))(T))(char) = &x; // ok
+  };
+  V<double> v;
+
+  int *g(double);
+  template<typename T> void h() {
+    new (auto(*)(T)) (&g);
+  }
+  template void h<double>();
+}
+#endif