From: Sebastian Redl Date: Wed, 22 Feb 2012 10:50:08 +0000 (+0000) Subject: Fix parsing and processing initializer lists in return statements and as direct membe... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=33deb35535aebe81bed0eaf5c14f3032276a086e;p=clang 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 3eb12dee47..3fd7e90083 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -223,10 +223,8 @@ def ext_inline_namespace : ExtWarn< def warn_cxx98_compat_inline_namespace : Warning< "inline namespaces are incompatible with C++98">, InGroup, 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; 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 2f5ef02f76..4e60edf37d 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -5057,6 +5057,9 @@ def ext_return_has_expr : ExtWarn< DefaultError, InGroup; 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>; diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 61ca84136e..cc8c0c45d2 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -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. diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 54f1b51f7e..3537768eed 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -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()) diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 22fb8cb7a8..c5215c016c 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1640,12 +1640,17 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc, ExprResult Init = InitExpr; if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) { if (isa(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 afbabacc73..a2dda0201b 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -1961,7 +1961,26 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { ReturnStmt *Result = 0; if (FnRetType->isVoidType()) { if (RetValExp) { - if (!RetValExp->isTypeDependent()) { + if (isa(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(CurDecl)) + FunctionKind = 1; + else if (isa(CurDecl)) + FunctionKind = 2; + else if (isa(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); diff --git a/test/SemaCXX/cxx0x-initializer-constructor.cpp b/test/SemaCXX/cxx0x-initializer-constructor.cpp index f7e89d3227..2fd30614d1 100644 --- a/test/SemaCXX/cxx0x-initializer-constructor.cpp +++ b/test/SemaCXX/cxx0x-initializer-constructor.cpp @@ -153,9 +153,9 @@ namespace objects { G(std::initializer_list, 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}} + }; } diff --git a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp index 6c299c7d8a..23b51515f9 100644 --- a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp +++ b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -130,6 +130,7 @@ void dangle() { struct haslist1 { std::initializer_list il = {1, 2, 3}; // expected-warning{{at the end of the constructor}} + std::initializer_list 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 b786922b71..b2cb3d37ce 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 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);