Fix parsing and processing initializer lists in return statements and as direct member initializers.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151155 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 3eb12de..3fd7e90 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -223,10 +223,8 @@
 def warn_cxx98_compat_inline_namespace : Warning<
   "inline namespaces are incompatible with C++98">,
   InGroup<CXX98Compat>, DefaultIgnore;
-def err_generalized_initializer_lists : Error<
-  "generalized initializer lists are a C++11 extension unsupported in Clang">;
 def ext_generalized_initializer_lists : ExtWarn<
-  "generalized initializer lists are a C++11 extension unsupported in Clang">,
+  "generalized initializer lists are a C++11 extension">,
   InGroup<CXX11>;
 def warn_cxx98_compat_generalized_initializer_lists : Warning<
   "generalized initializer lists are incompatible with C++98">,
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 2f5ef02..4e60edf 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5057,6 +5057,9 @@
   DefaultError, InGroup<ReturnType>;
 def ext_return_has_void_expr : Extension<
   "void %select{function|method}1 %0 should not return void expression">;
+def err_return_init_list : Error<
+  "%select{void function|void method|constructor|destructor}1 %0 "
+  "must not return a value">;
 def warn_noreturn_function_has_return_expr : Warning<
   "function %0 declared 'noreturn' should not return">,
   InGroup<DiagGroup<"invalid-noreturn">>;
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 61ca841..cc8c0c4 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -2012,7 +2012,7 @@
       if (Init.isInvalid())
         SkipUntil(tok::comma, true, true);
       else if (ThisDecl)
-        Actions.AddInitializerToDecl(ThisDecl, Init.get(), false,
+        Actions.AddInitializerToDecl(ThisDecl, Init.get(), EqualLoc.isInvalid(),
                                    DS.getTypeSpecType() == DeclSpec::TST_auto);      
     } else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static) {
       // No initializer.
@@ -2087,15 +2087,15 @@
 ///
 ///   pure-specifier:
 ///     '= 0'
-///  
+///
 ///   brace-or-equal-initializer:
 ///     '=' initializer-expression
-///     braced-init-list                       [TODO]
-///  
+///     braced-init-list
+///
 ///   initializer-clause:
 ///     assignment-expression
-///     braced-init-list                       [TODO]
-///  
+///     braced-init-list
+///
 ///   defaulted/deleted function-definition:                                                                                                                                                                                               
 ///     '=' 'default'
 ///     '=' 'delete'
@@ -2137,9 +2137,8 @@
       return ExprResult();
     }
 
-    return ParseInitializer();
-  } else
-    return ExprError(Diag(Tok, diag::err_generalized_initializer_lists));
+  }
+  return ParseInitializer();
 }
 
 /// ParseCXXMemberSpecification - Parse the class definition.
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 54f1b51..3537768 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -1597,9 +1597,6 @@
       return StmtError();
     }
 
-    // FIXME: This is a hack to allow something like C++0x's generalized
-    // initializer lists, but only enough of this feature to allow Clang to
-    // parse libstdc++ 4.5's headers.
     if (Tok.is(tok::l_brace) && getLang().CPlusPlus) {
       R = ParseInitializer();
       if (R.isUsable())
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 22fb8cb..c5215c0 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1640,12 +1640,17 @@
   ExprResult Init = InitExpr;
   if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) {
     if (isa<InitListExpr>(InitExpr) && isStdInitializerList(FD->getType(), 0)) {
-    Diag(FD->getLocation(), diag::warn_dangling_std_initializer_list)
+      Diag(FD->getLocation(), diag::warn_dangling_std_initializer_list)
         << /*at end of ctor*/1 << InitExpr->getSourceRange();
     }
-    // FIXME: if there is no EqualLoc, this is list-initialization.
-    Init = PerformCopyInitialization(
-      InitializedEntity::InitializeMember(FD), EqualLoc, InitExpr);
+    Expr **Inits = &InitExpr;
+    unsigned NumInits = 1;
+    InitializedEntity Entity = InitializedEntity::InitializeMember(FD);
+    InitializationKind Kind = EqualLoc.isInvalid()
+        ? InitializationKind::CreateDirectList(InitExpr->getLocStart())
+        : InitializationKind::CreateCopy(InitExpr->getLocStart(), EqualLoc);
+    InitializationSequence Seq(*this, Entity, Kind, Inits, NumInits);
+    Init = Seq.Perform(*this, Entity, Kind, MultiExprArg(Inits, NumInits));
     if (Init.isInvalid()) {
       FD->setInvalidDecl();
       return;
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index afbabac..a2dda02 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -1961,7 +1961,26 @@
   ReturnStmt *Result = 0;
   if (FnRetType->isVoidType()) {
     if (RetValExp) {
-      if (!RetValExp->isTypeDependent()) {
+      if (isa<InitListExpr>(RetValExp)) {
+        // We simply never allow init lists as the return value of void
+        // functions. This is compatible because this was never allowed before,
+        // so there's no legacy code to deal with.
+        NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
+        int FunctionKind = 0;
+        if (isa<ObjCMethodDecl>(CurDecl))
+          FunctionKind = 1;
+        else if (isa<CXXConstructorDecl>(CurDecl))
+          FunctionKind = 2;
+        else if (isa<CXXDestructorDecl>(CurDecl))
+          FunctionKind = 3;
+
+        Diag(ReturnLoc, diag::err_return_init_list)
+          << CurDecl->getDeclName() << FunctionKind
+          << RetValExp->getSourceRange();
+
+        // Drop the expression.
+        RetValExp = 0;
+      } else if (!RetValExp->isTypeDependent()) {
         // C99 6.8.6.4p1 (ext_ since GCC warns)
         unsigned D = diag::ext_return_has_expr;
         if (RetValExp->getType()->isVoidType())
@@ -1995,8 +2014,10 @@
         }
       }
 
-      CheckImplicitConversions(RetValExp, ReturnLoc);
-      RetValExp = MaybeCreateExprWithCleanups(RetValExp);
+      if (RetValExp) {
+        CheckImplicitConversions(RetValExp, ReturnLoc);
+        RetValExp = MaybeCreateExprWithCleanups(RetValExp);
+      }
     }
 
     Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0);
diff --git a/test/SemaCXX/cxx0x-initializer-constructor.cpp b/test/SemaCXX/cxx0x-initializer-constructor.cpp
index f7e89d3..2fd3061 100644
--- a/test/SemaCXX/cxx0x-initializer-constructor.cpp
+++ b/test/SemaCXX/cxx0x-initializer-constructor.cpp
@@ -153,9 +153,9 @@
     G(std::initializer_list<int>, T ...);  // expected-note 3 {{not viable}}
   };
 
-  struct H { // expected-note 6 {{not viable}}
+  struct H { // expected-note 8 {{not viable}}
     explicit H(int, int); // expected-note 3 {{not viable}}
-    H(int, void*); // expected-note 3 {{not viable}}
+    H(int, void*); // expected-note 4 {{not viable}}
   };
 
   void edge_cases() {
@@ -186,4 +186,11 @@
     (void) new H{1, 2};
     (void) H{1, 2};
   }
+
+  struct memberinit {
+    H h1{1, nullptr};
+    H h2 = {1, nullptr};
+    H h3{1, 1};
+    H h4 = {1, 1}; // expected-error {{no matching constructor}}
+  };
 }
diff --git a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
index 6c299c7..23b5151 100644
--- a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
+++ b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -130,6 +130,7 @@
 
 struct haslist1 {
   std::initializer_list<int> il = {1, 2, 3}; // expected-warning{{at the end of the constructor}}
+  std::initializer_list<int> jl{1, 2, 3}; // expected-warning{{at the end of the constructor}}
   haslist1();
 };
 
diff --git a/test/SemaCXX/cxx0x-return-init-list.cpp b/test/SemaCXX/cxx0x-return-init-list.cpp
index b786922..b2cb3d3 100644
--- a/test/SemaCXX/cxx0x-return-init-list.cpp
+++ b/test/SemaCXX/cxx0x-return-init-list.cpp
@@ -1,17 +1,15 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
-// This test checks for a teeny tiny subset of the functionality in
-// the C++11 generalized initializer lists feature, which happens to
-// be used in libstdc++ 4.5. We accept only this syntax so that Clang
-// can handle the libstdc++ 4.5 headers.
+// Test that a very basic variation of generalized initializer returns (that
+// required for libstdc++ 4.5) is supposed in C++98.
 
 int test0(int i) {
-  return { i }; // expected-warning{{generalized initializer lists are a C++11 extension unsupported in Clang}}
+  return { i }; // expected-warning{{generalized initializer lists are a C++11 extension}}
 }
 
 template<typename T, typename U>
 T test1(U u) {
-  return { u }; // expected-warning{{generalized initializer lists are a C++11 extension unsupported in Clang}}
+  return { u }; // expected-warning{{generalized initializer lists are a C++11 extension}}
 }
 
 template int test1(char);