]> granicus.if.org Git - clang/commitdiff
Fix parsing and processing initializer lists in return statements and as direct membe...
authorSebastian Redl <sebastian.redl@getdesigned.at>
Wed, 22 Feb 2012 10:50:08 +0000 (10:50 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Wed, 22 Feb 2012 10:50:08 +0000 (10:50 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151155 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticParseKinds.td
include/clang/Basic/DiagnosticSemaKinds.td
lib/Parse/ParseDeclCXX.cpp
lib/Parse/ParseStmt.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaStmt.cpp
test/SemaCXX/cxx0x-initializer-constructor.cpp
test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
test/SemaCXX/cxx0x-return-init-list.cpp

index 3eb12dee4768b29ee1be0be56c17b85940c17096..3fd7e90083a385f6b0a62332db34f6cb0f1df61f 100644 (file)
@@ -223,10 +223,8 @@ def ext_inline_namespace : ExtWarn<
 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">,
index 2f5ef02f76cf3df3beda5c022015ea66f8c92d8a..4e60edf37d436d2a5af449555703f0ff23103807 100644 (file)
@@ -5057,6 +5057,9 @@ def ext_return_has_expr : ExtWarn<
   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">>;
index 61ca84136e3d473b14e0225ebad881dc032fb874..cc8c0c45d255849dc7da5f2914edba74f816197a 100644 (file)
@@ -2012,7 +2012,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
       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 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
 ///
 ///   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 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
       return ExprResult();
     }
 
-    return ParseInitializer();
-  } else
-    return ExprError(Diag(Tok, diag::err_generalized_initializer_lists));
+  }
+  return ParseInitializer();
 }
 
 /// ParseCXXMemberSpecification - Parse the class definition.
index 54f1b51f7e9a7ca9f4bdd2faa5765ea11cf868c8..3537768eed15133d639aec1c8914608e7260c3fa 100644 (file)
@@ -1597,9 +1597,6 @@ StmtResult Parser::ParseReturnStatement(ParsedAttributes &attrs) {
       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())
index 22fb8cb7a83b6db0d7edf5c8828a9baf43755d49..c5215c016c5d2ca82eb8fb0a3882261529c7d588 100644 (file)
@@ -1640,12 +1640,17 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc,
   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;
index afbabacc73b5427b69beb9cab90dd7004c379e0c..a2dda0201ba3a5277b44bac7b1b504c339877ef5 100644 (file)
@@ -1961,7 +1961,26 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
   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 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
         }
       }
 
-      CheckImplicitConversions(RetValExp, ReturnLoc);
-      RetValExp = MaybeCreateExprWithCleanups(RetValExp);
+      if (RetValExp) {
+        CheckImplicitConversions(RetValExp, ReturnLoc);
+        RetValExp = MaybeCreateExprWithCleanups(RetValExp);
+      }
     }
 
     Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0);
index f7e89d3227ab0bed68445b92203b95b9a0302a24..2fd30614d14719e24aad4ac9b8f0de06bf7d32fb 100644 (file)
@@ -153,9 +153,9 @@ namespace objects {
     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 @@ namespace objects {
     (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}}
+  };
 }
index 6c299c7d8a1d2149f2b879642aff6fc1abe6f2dc..23b51515f9dd597caad091e70e032137d547fa34 100644 (file)
@@ -130,6 +130,7 @@ void dangle() {
 
 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();
 };
 
index b786922b71a8b523e3f99e85c5288341a96defab..b2cb3d37ce7750711aa4e2565bfee8bfadfe2ee3 100644 (file)
@@ -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);