From: David Blaikie Date: Tue, 24 Jan 2012 06:03:59 +0000 (+0000) Subject: Support decltype in member initializers. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f211662199c87461f3b1475a549ab439c63ca83b;p=clang Support decltype in member initializers. This is the last piece of N3031 (decltype in weird places) - supporting the use of decltype in a class ctor's member-initializer-list to specify the base classes to initialize. Reviewed by Richard Smith. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148789 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index ecff2ec58d..28ae40444c 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3507,6 +3507,7 @@ public: CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, + const DeclSpec &DS, SourceLocation IdLoc, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, @@ -3518,6 +3519,7 @@ public: CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, + const DeclSpec &DS, SourceLocation IdLoc, Expr *InitList, SourceLocation EllipsisLoc); @@ -3527,6 +3529,7 @@ public: CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, + const DeclSpec &DS, SourceLocation IdLoc, const MultiInitializer &Init, SourceLocation EllipsisLoc); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 050b1b19c4..14c8955949 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -2414,15 +2414,28 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { TemplateTypeTy = getTypeAnnotation(Tok); } } - if (!TemplateTypeTy && Tok.isNot(tok::identifier)) { + // Uses of decltype will already have been converted to annot_decltype by + // ParseOptionalCXXScopeSpecifier at this point. + if (!TemplateTypeTy && Tok.isNot(tok::identifier) + && Tok.isNot(tok::annot_decltype)) { Diag(Tok, diag::err_expected_member_or_base_name); return true; } - // Get the identifier. This may be a member name or a class name, - // but we'll let the semantic analysis determine which it is. - IdentifierInfo *II = Tok.is(tok::identifier) ? Tok.getIdentifierInfo() : 0; - SourceLocation IdLoc = ConsumeToken(); + IdentifierInfo *II = 0; + DeclSpec DS(AttrFactory); + SourceLocation IdLoc = Tok.getLocation(); + if (Tok.is(tok::annot_decltype)) { + // Get the decltype expression, if there is one. + ParseDecltypeSpecifier(DS); + } else { + if (Tok.is(tok::identifier)) + // Get the identifier. This may be a member name or a class name, + // but we'll let the semantic analysis determine which it is. + II = Tok.getIdentifierInfo(); + ConsumeToken(); + } + // Parse the '('. if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) { @@ -2437,8 +2450,8 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { EllipsisLoc = ConsumeToken(); return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II, - TemplateTypeTy, IdLoc, InitList.take(), - EllipsisLoc); + TemplateTypeTy, DS, IdLoc, + InitList.take(), EllipsisLoc); } else if(Tok.is(tok::l_paren)) { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); @@ -2458,7 +2471,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { EllipsisLoc = ConsumeToken(); return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II, - TemplateTypeTy, IdLoc, + TemplateTypeTy, DS, IdLoc, T.getOpenLocation(), ArgExprs.take(), ArgExprs.size(), T.getCloseLocation(), EllipsisLoc); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index b706cdc9fb..3f8f585bb0 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1722,11 +1722,13 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, + const DeclSpec &DS, SourceLocation IdLoc, Expr *InitList, SourceLocation EllipsisLoc) { return BuildMemInitializer(ConstructorD, S, SS, MemberOrBase, TemplateTypeTy, - IdLoc, MultiInitializer(InitList), EllipsisLoc); + DS, IdLoc, MultiInitializer(InitList), + EllipsisLoc); } /// \brief Handle a C++ member initializer using parentheses syntax. @@ -1736,14 +1738,15 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, + const DeclSpec &DS, SourceLocation IdLoc, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc, SourceLocation EllipsisLoc) { return BuildMemInitializer(ConstructorD, S, SS, MemberOrBase, TemplateTypeTy, - IdLoc, MultiInitializer(LParenLoc, Args, NumArgs, - RParenLoc), + DS, IdLoc, MultiInitializer(LParenLoc, Args, + NumArgs, RParenLoc), EllipsisLoc); } @@ -1779,6 +1782,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD, CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, + const DeclSpec &DS, SourceLocation IdLoc, const MultiInitializer &Args, SourceLocation EllipsisLoc) { @@ -1831,6 +1835,8 @@ Sema::BuildMemInitializer(Decl *ConstructorD, if (TemplateTypeTy) { BaseType = GetTypeFromParser(TemplateTypeTy, &TInfo); + } else if (DS.getTypeSpecType() == TST_decltype) { + BaseType = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); } else { LookupResult R(*this, MemberOrBase, IdLoc, LookupOrdinaryName); LookupParsedName(R, S, &SS); diff --git a/test/SemaCXX/class-base-member-init.cpp b/test/SemaCXX/class-base-member-init.cpp index 9d030c28de..e84e57b747 100644 --- a/test/SemaCXX/class-base-member-init.cpp +++ b/test/SemaCXX/class-base-member-init.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s class S { public: @@ -74,3 +74,19 @@ namespace test4 { A(long _) : a(0), d(0) {} // expected-error {{initializing multiple members of union}} expected-note {{previous initialization is here}} }; } + +namespace test5 { + struct Base { + Base(int); + }; + struct A : Base { + A() : decltype(Base(1))(3) { + } + A(int) : Base(3), // expected-note {{previous initialization is here}} + decltype(Base(1))(2), // expected-error {{multiple initializations given for base 'decltype(test5::Base(1))' (aka 'test5::Base')}} + decltype(int())() { // expected-error {{constructor initializer 'decltype(int())' (aka 'int') does not name a class}} + } + A(float) : decltype(A())(3) { + } + }; +}