Implement support for C++ direct initializers that involve dependent
types or type-dependent expressions.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80143 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 369249b..ff16480 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -2443,6 +2443,8 @@
     return cast_or_null<Expr>(Exprs[Init]);
   }
 
+  Expr **getExprs() { return reinterpret_cast<Expr **>(Exprs); }
+  
   SourceLocation getLParenLoc() const { return LParenLoc; }
   SourceLocation getRParenLoc() const { return RParenLoc; }
 
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 0dbefe1..41a7fe6 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -2523,9 +2523,7 @@
     return;
   }
 
-  // FIXME: Need to handle dependent types and expressions here.
-
-  // We will treat direct-initialization as a copy-initialization:
+  // We will represent direct-initialization similarly to copy-initialization:
   //    int x(1);  -as-> int x = 1;
   //    ClassType x(a,b,c); -as-> ClassType x = ClassType(a,b,c);
   //
@@ -2535,6 +2533,24 @@
   // exactly form was it (like the CodeGen) can handle both cases without
   // special case code.
 
+  // If either the declaration has a dependent type or if any of the expressions
+  // is type-dependent, we represent the initialization via a ParenListExpr for
+  // later use during template instantiation.
+  if (VDecl->getType()->isDependentType() ||
+      Expr::hasAnyTypeDependentArguments((Expr **)Exprs.get(), Exprs.size())) {
+    // Let clients know that initialization was done with a direct initializer.
+    VDecl->setCXXDirectInitializer(true);
+    
+    // Store the initialization expressions as a ParenListExpr.
+    unsigned NumExprs = Exprs.size();
+    VDecl->setInit(Context, 
+                   new (Context) ParenListExpr(Context, LParenLoc,
+                                               (Expr **)Exprs.release(),
+                                               NumExprs, RParenLoc));
+    return;
+  }
+    
+
   // C++ 8.5p11:
   // The form of initialization (using parentheses or '=') is generally
   // insignificant, but does matter when the entity being initialized has a
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index bd25c8f..71fb368 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/DeclVisitor.h"
 #include "clang/AST/Expr.h"
+#include "clang/Lex/Preprocessor.h"
 #include "llvm/Support/Compiler.h"
 
 using namespace clang;
@@ -153,7 +154,31 @@
       = SemaRef.SubstExpr(D->getInit(), TemplateArgs);
     if (Init.isInvalid())
       Var->setInvalidDecl();
-    else
+    else if (ParenListExpr *PLE = dyn_cast<ParenListExpr>((Expr *)Init.get())) {
+      // FIXME: We're faking all of the comma locations, which is suboptimal. 
+      // Do we even need these comma locations?
+      llvm::SmallVector<SourceLocation, 4> FakeCommaLocs;
+      if (PLE->getNumExprs() > 0) {
+        FakeCommaLocs.reserve(PLE->getNumExprs() - 1);
+        for (unsigned I = 0, N = PLE->getNumExprs() - 1; I != N; ++I) {
+          Expr *E = PLE->getExpr(I)->Retain();
+          FakeCommaLocs.push_back(
+                                SemaRef.PP.getLocForEndOfToken(E->getLocEnd()));
+        }
+      }
+      
+      // Add the direct initializer to the declaration.
+      SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var),
+                                            PLE->getLParenLoc(), 
+                                            Sema::MultiExprArg(SemaRef,
+                                                       (void**)PLE->getExprs(),
+                                                           PLE->getNumExprs()),
+                                            FakeCommaLocs.data(),
+                                            PLE->getRParenLoc());
+      
+      // When Init is destroyed, it will destroy the instantiated ParenListExpr;
+      // we've explicitly retained all of its subexpressions already.
+    } else
       SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), move(Init),
                                    D->hasCXXDirectInitializer());
   } else if (!Var->isStaticDataMember() || Var->isOutOfLine())
diff --git a/test/SemaTemplate/instantiate-init.cpp b/test/SemaTemplate/instantiate-init.cpp
new file mode 100644
index 0000000..870b275
--- /dev/null
+++ b/test/SemaTemplate/instantiate-init.cpp
@@ -0,0 +1,28 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct X0 { // expected-note 4{{candidate}}
+  X0(int*, float*); // expected-note 4{{candidate}}
+};
+
+template<typename T, typename U>
+X0 f0(T t, U u) {
+  X0 x0(t, u); // expected-error{{no matching}}
+  return X0(t, u); // expected-error{{no matching}}
+}
+
+void test_f0(int *ip, float *fp, double *dp) {
+  f0(ip, fp);
+  f0(ip, dp); // expected-note{{instantiation}}
+}
+
+template<typename Ret, typename T, typename U>
+Ret f1(Ret *retty, T t, U u) {
+  Ret r0(t, u); // expected-error{{no matching}}
+  return Ret(t, u); // expected-error{{no matching}}
+}
+
+void test_f1(X0 *x0, int *ip, float *fp, double *dp) {
+  f1(x0, ip, fp);
+  f1(x0, ip, dp); // expected-note{{instantiation}}
+}
+