2007-08-25 14:57:03 +08:00
|
|
|
//===--- ParseDeclCXX.cpp - C++ Declaration Parsing -----------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-30 03:59:25 +08:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2007-08-25 14:57:03 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the C++ Declaration portions of the Parser interfaces.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2008-04-14 08:13:42 +08:00
|
|
|
#include "clang/Parse/Parser.h"
|
2009-01-29 13:15:15 +08:00
|
|
|
#include "clang/Parse/ParseDiagnostic.h"
|
2008-04-14 05:30:24 +08:00
|
|
|
#include "clang/Parse/DeclSpec.h"
|
2007-08-25 14:57:03 +08:00
|
|
|
#include "clang/Parse/Scope.h"
|
2008-11-26 06:21:31 +08:00
|
|
|
#include "AstGuard.h"
|
2008-12-18 09:12:00 +08:00
|
|
|
#include "ExtensionRAIIObject.h"
|
2007-08-25 14:57:03 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
/// ParseNamespace - We know that the current token is a namespace keyword. This
|
|
|
|
/// may either be a top level namespace or a block-level namespace alias.
|
|
|
|
///
|
|
|
|
/// namespace-definition: [C++ 7.3: basic.namespace]
|
|
|
|
/// named-namespace-definition
|
|
|
|
/// unnamed-namespace-definition
|
|
|
|
///
|
|
|
|
/// unnamed-namespace-definition:
|
|
|
|
/// 'namespace' attributes[opt] '{' namespace-body '}'
|
|
|
|
///
|
|
|
|
/// named-namespace-definition:
|
|
|
|
/// original-namespace-definition
|
|
|
|
/// extension-namespace-definition
|
|
|
|
///
|
|
|
|
/// original-namespace-definition:
|
|
|
|
/// 'namespace' identifier attributes[opt] '{' namespace-body '}'
|
|
|
|
///
|
|
|
|
/// extension-namespace-definition:
|
|
|
|
/// 'namespace' original-namespace-name '{' namespace-body '}'
|
|
|
|
///
|
|
|
|
/// namespace-alias-definition: [C++ 7.3.2: namespace.alias]
|
|
|
|
/// 'namespace' identifier '=' qualified-namespace-specifier ';'
|
|
|
|
///
|
2009-03-29 03:18:32 +08:00
|
|
|
Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context) {
|
2007-10-10 01:33:22 +08:00
|
|
|
assert(Tok.is(tok::kw_namespace) && "Not a namespace!");
|
2007-08-25 14:57:03 +08:00
|
|
|
SourceLocation NamespaceLoc = ConsumeToken(); // eat the 'namespace'.
|
|
|
|
|
|
|
|
SourceLocation IdentLoc;
|
|
|
|
IdentifierInfo *Ident = 0;
|
|
|
|
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::identifier)) {
|
2007-08-25 14:57:03 +08:00
|
|
|
Ident = Tok.getIdentifierInfo();
|
|
|
|
IdentLoc = ConsumeToken(); // eat the identifier.
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read label attributes, if present.
|
2009-03-29 03:18:32 +08:00
|
|
|
Action::AttrTy *AttrList = 0;
|
2007-10-10 01:33:22 +08:00
|
|
|
if (Tok.is(tok::kw___attribute))
|
2007-08-25 14:57:03 +08:00
|
|
|
// FIXME: save these somewhere.
|
|
|
|
AttrList = ParseAttributes();
|
|
|
|
|
2009-03-28 12:07:16 +08:00
|
|
|
if (Tok.is(tok::equal))
|
2007-08-25 14:57:03 +08:00
|
|
|
// FIXME: Verify no attributes were present.
|
2009-03-29 06:53:22 +08:00
|
|
|
return ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident);
|
2009-03-28 12:07:16 +08:00
|
|
|
|
2009-03-29 22:02:43 +08:00
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
|
|
|
Diag(Tok, Ident ? diag::err_expected_lbrace :
|
|
|
|
diag::err_expected_ident_lbrace);
|
|
|
|
return DeclPtrTy();
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation LBrace = ConsumeBrace();
|
2008-04-27 21:50:30 +08:00
|
|
|
|
2009-03-29 22:02:43 +08:00
|
|
|
// Enter a scope for the namespace.
|
|
|
|
ParseScope NamespaceScope(this, Scope::DeclScope);
|
2008-04-27 21:50:30 +08:00
|
|
|
|
2009-03-29 22:02:43 +08:00
|
|
|
DeclPtrTy NamespcDecl =
|
|
|
|
Actions.ActOnStartNamespaceDef(CurScope, IdentLoc, Ident, LBrace);
|
2008-04-27 21:50:30 +08:00
|
|
|
|
2009-03-29 22:02:43 +08:00
|
|
|
PrettyStackTraceActionsDecl CrashInfo(NamespcDecl, NamespaceLoc, Actions,
|
|
|
|
PP.getSourceManager(),
|
|
|
|
"parsing namespace");
|
|
|
|
|
|
|
|
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof))
|
|
|
|
ParseExternalDeclaration();
|
|
|
|
|
|
|
|
// Leave the namespace scope.
|
|
|
|
NamespaceScope.Exit();
|
2008-05-02 05:44:34 +08:00
|
|
|
|
2009-03-29 22:02:43 +08:00
|
|
|
SourceLocation RBrace = MatchRHSPunctuation(tok::r_brace, LBrace);
|
|
|
|
Actions.ActOnFinishNamespaceDef(NamespcDecl, RBrace);
|
2008-04-27 21:50:30 +08:00
|
|
|
|
2009-03-29 22:02:43 +08:00
|
|
|
return NamespcDecl;
|
2007-08-25 14:57:03 +08:00
|
|
|
}
|
2008-01-12 15:05:38 +08:00
|
|
|
|
2009-03-28 12:07:16 +08:00
|
|
|
/// ParseNamespaceAlias - Parse the part after the '=' in a namespace
|
|
|
|
/// alias definition.
|
|
|
|
///
|
2009-03-29 06:53:22 +08:00
|
|
|
Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
|
|
|
|
SourceLocation AliasLoc,
|
2009-03-29 03:18:32 +08:00
|
|
|
IdentifierInfo *Alias) {
|
2009-03-28 12:07:16 +08:00
|
|
|
assert(Tok.is(tok::equal) && "Not equal token");
|
|
|
|
|
|
|
|
ConsumeToken(); // eat the '='.
|
|
|
|
|
|
|
|
CXXScopeSpec SS;
|
|
|
|
// Parse (optional) nested-name-specifier.
|
|
|
|
ParseOptionalCXXScopeSpecifier(SS);
|
|
|
|
|
|
|
|
if (SS.isInvalid() || Tok.isNot(tok::identifier)) {
|
|
|
|
Diag(Tok, diag::err_expected_namespace_name);
|
|
|
|
// Skip to end of the definition and eat the ';'.
|
|
|
|
SkipUntil(tok::semi);
|
2009-03-29 03:18:32 +08:00
|
|
|
return DeclPtrTy();
|
2009-03-28 12:07:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parse identifier.
|
2009-03-29 06:53:22 +08:00
|
|
|
IdentifierInfo *Ident = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation IdentLoc = ConsumeToken();
|
2009-03-28 12:07:16 +08:00
|
|
|
|
|
|
|
// Eat the ';'.
|
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
|
|
|
|
"namespace name", tok::semi);
|
|
|
|
|
2009-03-29 06:53:22 +08:00
|
|
|
return Actions.ActOnNamespaceAliasDef(CurScope, NamespaceLoc, AliasLoc, Alias,
|
|
|
|
SS, IdentLoc, Ident);
|
2009-03-28 12:07:16 +08:00
|
|
|
}
|
|
|
|
|
2008-01-12 15:05:38 +08:00
|
|
|
/// ParseLinkage - We know that the current token is a string_literal
|
|
|
|
/// and just before that, that extern was seen.
|
|
|
|
///
|
|
|
|
/// linkage-specification: [C++ 7.5p2: dcl.link]
|
|
|
|
/// 'extern' string-literal '{' declaration-seq[opt] '}'
|
|
|
|
/// 'extern' string-literal declaration
|
|
|
|
///
|
2009-03-29 03:18:32 +08:00
|
|
|
Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) {
|
2008-11-22 00:10:08 +08:00
|
|
|
assert(Tok.is(tok::string_literal) && "Not a string literal!");
|
2008-01-12 15:05:38 +08:00
|
|
|
llvm::SmallVector<char, 8> LangBuffer;
|
|
|
|
// LangBuffer is guaranteed to be big enough.
|
|
|
|
LangBuffer.resize(Tok.getLength());
|
|
|
|
const char *LangBufPtr = &LangBuffer[0];
|
|
|
|
unsigned StrSize = PP.getSpelling(Tok, LangBufPtr);
|
|
|
|
|
|
|
|
SourceLocation Loc = ConsumeStringToken();
|
|
|
|
|
2009-01-06 03:45:36 +08:00
|
|
|
ParseScope LinkageScope(this, Scope::DeclScope);
|
2009-03-29 03:18:32 +08:00
|
|
|
DeclPtrTy LinkageSpec
|
2009-01-06 03:45:36 +08:00
|
|
|
= Actions.ActOnStartLinkageSpecification(CurScope,
|
|
|
|
/*FIXME: */SourceLocation(),
|
|
|
|
Loc, LangBufPtr, StrSize,
|
|
|
|
Tok.is(tok::l_brace)? Tok.getLocation()
|
|
|
|
: SourceLocation());
|
|
|
|
|
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
|
|
|
ParseDeclarationOrFunctionDefinition();
|
|
|
|
return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec,
|
|
|
|
SourceLocation());
|
2008-12-17 06:23:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation LBrace = ConsumeBrace();
|
|
|
|
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
|
2009-01-06 03:45:36 +08:00
|
|
|
ParseExternalDeclaration();
|
2008-12-17 06:23:02 +08:00
|
|
|
}
|
2008-01-12 15:05:38 +08:00
|
|
|
|
2008-12-17 06:23:02 +08:00
|
|
|
SourceLocation RBrace = MatchRHSPunctuation(tok::r_brace, LBrace);
|
2009-01-06 03:45:36 +08:00
|
|
|
return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec, RBrace);
|
2008-01-12 15:05:38 +08:00
|
|
|
}
|
2008-04-14 05:30:24 +08:00
|
|
|
|
2008-12-30 11:27:21 +08:00
|
|
|
/// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or
|
|
|
|
/// using-directive. Assumes that current token is 'using'.
|
2009-03-29 03:18:32 +08:00
|
|
|
Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context) {
|
2008-12-30 11:27:21 +08:00
|
|
|
assert(Tok.is(tok::kw_using) && "Not using token");
|
|
|
|
|
|
|
|
// Eat 'using'.
|
|
|
|
SourceLocation UsingLoc = ConsumeToken();
|
|
|
|
|
2009-01-06 14:55:51 +08:00
|
|
|
if (Tok.is(tok::kw_namespace))
|
2008-12-30 11:27:21 +08:00
|
|
|
// Next token after 'using' is 'namespace' so it must be using-directive
|
|
|
|
return ParseUsingDirective(Context, UsingLoc);
|
2009-01-06 14:55:51 +08:00
|
|
|
|
|
|
|
// Otherwise, it must be using-declaration.
|
|
|
|
return ParseUsingDeclaration(Context, UsingLoc);
|
2008-12-30 11:27:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseUsingDirective - Parse C++ using-directive, assumes
|
|
|
|
/// that current token is 'namespace' and 'using' was already parsed.
|
|
|
|
///
|
|
|
|
/// using-directive: [C++ 7.3.p4: namespace.udir]
|
|
|
|
/// 'using' 'namespace' ::[opt] nested-name-specifier[opt]
|
|
|
|
/// namespace-name ;
|
|
|
|
/// [GNU] using-directive:
|
|
|
|
/// 'using' 'namespace' ::[opt] nested-name-specifier[opt]
|
|
|
|
/// namespace-name attributes[opt] ;
|
|
|
|
///
|
2009-03-29 03:18:32 +08:00
|
|
|
Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context,
|
|
|
|
SourceLocation UsingLoc) {
|
2008-12-30 11:27:21 +08:00
|
|
|
assert(Tok.is(tok::kw_namespace) && "Not 'namespace' token");
|
|
|
|
|
|
|
|
// Eat 'namespace'.
|
|
|
|
SourceLocation NamespcLoc = ConsumeToken();
|
|
|
|
|
|
|
|
CXXScopeSpec SS;
|
|
|
|
// Parse (optional) nested-name-specifier.
|
2009-01-06 14:59:53 +08:00
|
|
|
ParseOptionalCXXScopeSpecifier(SS);
|
2008-12-30 11:27:21 +08:00
|
|
|
|
|
|
|
AttributeList *AttrList = 0;
|
|
|
|
IdentifierInfo *NamespcName = 0;
|
|
|
|
SourceLocation IdentLoc = SourceLocation();
|
|
|
|
|
|
|
|
// Parse namespace-name.
|
2009-01-06 15:27:21 +08:00
|
|
|
if (SS.isInvalid() || Tok.isNot(tok::identifier)) {
|
2008-12-30 11:27:21 +08:00
|
|
|
Diag(Tok, diag::err_expected_namespace_name);
|
|
|
|
// If there was invalid namespace name, skip to end of decl, and eat ';'.
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
// FIXME: Are there cases, when we would like to call ActOnUsingDirective?
|
2009-03-29 03:18:32 +08:00
|
|
|
return DeclPtrTy();
|
2008-12-30 11:27:21 +08:00
|
|
|
}
|
2009-01-06 15:27:21 +08:00
|
|
|
|
|
|
|
// Parse identifier.
|
|
|
|
NamespcName = Tok.getIdentifierInfo();
|
|
|
|
IdentLoc = ConsumeToken();
|
|
|
|
|
|
|
|
// Parse (optional) attributes (most likely GNU strong-using extension).
|
|
|
|
if (Tok.is(tok::kw___attribute))
|
|
|
|
AttrList = ParseAttributes();
|
|
|
|
|
|
|
|
// Eat ';'.
|
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
|
|
|
|
AttrList ? "attributes list" : "namespace name", tok::semi);
|
2008-12-30 11:27:21 +08:00
|
|
|
|
|
|
|
return Actions.ActOnUsingDirective(CurScope, UsingLoc, NamespcLoc, SS,
|
2009-01-06 15:27:21 +08:00
|
|
|
IdentLoc, NamespcName, AttrList);
|
2008-12-30 11:27:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseUsingDeclaration - Parse C++ using-declaration. Assumes that
|
|
|
|
/// 'using' was already seen.
|
|
|
|
///
|
|
|
|
/// using-declaration: [C++ 7.3.p3: namespace.udecl]
|
|
|
|
/// 'using' 'typename'[opt] ::[opt] nested-name-specifier
|
|
|
|
/// unqualified-id [TODO]
|
|
|
|
/// 'using' :: unqualified-id [TODO]
|
|
|
|
///
|
2009-03-29 03:18:32 +08:00
|
|
|
Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
|
|
|
|
SourceLocation UsingLoc) {
|
2008-12-30 11:27:21 +08:00
|
|
|
assert(false && "Not implemented");
|
|
|
|
// FIXME: Implement parsing.
|
2009-03-29 03:18:32 +08:00
|
|
|
return DeclPtrTy();
|
2008-12-30 11:27:21 +08:00
|
|
|
}
|
|
|
|
|
2009-03-12 00:27:10 +08:00
|
|
|
/// ParseStaticAssertDeclaration - Parse C++0x static_assert-declaratoion.
|
|
|
|
///
|
|
|
|
/// static_assert-declaration:
|
|
|
|
/// static_assert ( constant-expression , string-literal ) ;
|
|
|
|
///
|
2009-03-29 03:18:32 +08:00
|
|
|
Parser::DeclPtrTy Parser::ParseStaticAssertDeclaration() {
|
2009-03-12 00:27:10 +08:00
|
|
|
assert(Tok.is(tok::kw_static_assert) && "Not a static_assert declaration");
|
|
|
|
SourceLocation StaticAssertLoc = ConsumeToken();
|
|
|
|
|
|
|
|
if (Tok.isNot(tok::l_paren)) {
|
|
|
|
Diag(Tok, diag::err_expected_lparen);
|
2009-03-29 03:18:32 +08:00
|
|
|
return DeclPtrTy();
|
2009-03-12 00:27:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation LParenLoc = ConsumeParen();
|
|
|
|
|
|
|
|
OwningExprResult AssertExpr(ParseConstantExpression());
|
|
|
|
if (AssertExpr.isInvalid()) {
|
|
|
|
SkipUntil(tok::semi);
|
2009-03-29 03:18:32 +08:00
|
|
|
return DeclPtrTy();
|
2009-03-12 00:27:10 +08:00
|
|
|
}
|
|
|
|
|
2009-03-14 07:29:20 +08:00
|
|
|
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::semi))
|
2009-03-29 03:18:32 +08:00
|
|
|
return DeclPtrTy();
|
2009-03-14 07:29:20 +08:00
|
|
|
|
2009-03-12 00:27:10 +08:00
|
|
|
if (Tok.isNot(tok::string_literal)) {
|
|
|
|
Diag(Tok, diag::err_expected_string_literal);
|
|
|
|
SkipUntil(tok::semi);
|
2009-03-29 03:18:32 +08:00
|
|
|
return DeclPtrTy();
|
2009-03-12 00:27:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
OwningExprResult AssertMessage(ParseStringLiteralExpression());
|
|
|
|
if (AssertMessage.isInvalid())
|
2009-03-29 03:18:32 +08:00
|
|
|
return DeclPtrTy();
|
2009-03-12 00:27:10 +08:00
|
|
|
|
2009-03-16 02:44:04 +08:00
|
|
|
MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
2009-03-12 00:27:10 +08:00
|
|
|
|
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_static_assert);
|
|
|
|
|
2009-03-14 07:29:20 +08:00
|
|
|
return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc, move(AssertExpr),
|
2009-03-16 02:44:04 +08:00
|
|
|
move(AssertMessage));
|
2009-03-12 00:27:10 +08:00
|
|
|
}
|
|
|
|
|
2008-11-06 04:51:48 +08:00
|
|
|
/// ParseClassName - Parse a C++ class-name, which names a class. Note
|
|
|
|
/// that we only check that the result names a type; semantic analysis
|
|
|
|
/// will need to verify that the type names a class. The result is
|
2009-02-26 07:52:28 +08:00
|
|
|
/// either a type or NULL, depending on whether a type name was
|
2008-11-06 04:51:48 +08:00
|
|
|
/// found.
|
|
|
|
///
|
|
|
|
/// class-name: [C++ 9.1]
|
|
|
|
/// identifier
|
2009-02-26 07:52:28 +08:00
|
|
|
/// simple-template-id
|
2008-11-06 04:51:48 +08:00
|
|
|
///
|
2009-02-26 07:52:28 +08:00
|
|
|
Parser::TypeTy *Parser::ParseClassName(SourceLocation &EndLocation,
|
|
|
|
const CXXScopeSpec *SS) {
|
|
|
|
// Check whether we have a template-id that names a type.
|
|
|
|
if (Tok.is(tok::annot_template_id)) {
|
|
|
|
TemplateIdAnnotation *TemplateId
|
|
|
|
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
|
|
|
|
if (TemplateId->Kind == TNK_Class_template) {
|
|
|
|
if (AnnotateTemplateIdTokenAsType(SS))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
|
|
|
|
TypeTy *Type = Tok.getAnnotationValue();
|
|
|
|
EndLocation = Tok.getAnnotationEndLoc();
|
|
|
|
ConsumeToken();
|
|
|
|
return Type;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fall through to produce an error below.
|
|
|
|
}
|
|
|
|
|
2008-11-06 04:51:48 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_class_name);
|
2008-11-06 04:51:48 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have an identifier; check whether it is actually a type.
|
2009-02-05 01:00:24 +08:00
|
|
|
TypeTy *Type = Actions.getTypeName(*Tok.getIdentifierInfo(),
|
|
|
|
Tok.getLocation(), CurScope, SS);
|
2008-11-06 04:51:48 +08:00
|
|
|
if (!Type) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_class_name);
|
2008-11-06 04:51:48 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Consume the identifier.
|
2009-02-26 07:52:28 +08:00
|
|
|
EndLocation = ConsumeToken();
|
2008-11-06 04:51:48 +08:00
|
|
|
return Type;
|
|
|
|
}
|
|
|
|
|
2008-04-14 05:30:24 +08:00
|
|
|
/// ParseClassSpecifier - Parse a C++ class-specifier [C++ class] or
|
|
|
|
/// elaborated-type-specifier [C++ dcl.type.elab]; we can't tell which
|
|
|
|
/// until we reach the start of a definition or see a token that
|
|
|
|
/// cannot start a definition.
|
|
|
|
///
|
|
|
|
/// class-specifier: [C++ class]
|
|
|
|
/// class-head '{' member-specification[opt] '}'
|
|
|
|
/// class-head '{' member-specification[opt] '}' attributes[opt]
|
|
|
|
/// class-head:
|
|
|
|
/// class-key identifier[opt] base-clause[opt]
|
|
|
|
/// class-key nested-name-specifier identifier base-clause[opt]
|
|
|
|
/// class-key nested-name-specifier[opt] simple-template-id
|
|
|
|
/// base-clause[opt]
|
|
|
|
/// [GNU] class-key attributes[opt] identifier[opt] base-clause[opt]
|
|
|
|
/// [GNU] class-key attributes[opt] nested-name-specifier
|
|
|
|
/// identifier base-clause[opt]
|
|
|
|
/// [GNU] class-key attributes[opt] nested-name-specifier[opt]
|
|
|
|
/// simple-template-id base-clause[opt]
|
|
|
|
/// class-key:
|
|
|
|
/// 'class'
|
|
|
|
/// 'struct'
|
|
|
|
/// 'union'
|
|
|
|
///
|
|
|
|
/// elaborated-type-specifier: [C++ dcl.type.elab]
|
|
|
|
/// class-key ::[opt] nested-name-specifier[opt] identifier
|
|
|
|
/// class-key ::[opt] nested-name-specifier[opt] 'template'[opt]
|
|
|
|
/// simple-template-id
|
|
|
|
///
|
|
|
|
/// Note that the C++ class-specifier and elaborated-type-specifier,
|
|
|
|
/// together, subsume the C99 struct-or-union-specifier:
|
|
|
|
///
|
|
|
|
/// struct-or-union-specifier: [C99 6.7.2.1]
|
|
|
|
/// struct-or-union identifier[opt] '{' struct-contents '}'
|
|
|
|
/// struct-or-union identifier
|
|
|
|
/// [GNU] struct-or-union attributes[opt] identifier[opt] '{' struct-contents
|
|
|
|
/// '}' attributes[opt]
|
|
|
|
/// [GNU] struct-or-union attributes[opt] identifier
|
|
|
|
/// struct-or-union:
|
|
|
|
/// 'struct'
|
|
|
|
/// 'union'
|
2008-12-24 10:52:09 +08:00
|
|
|
void Parser::ParseClassSpecifier(DeclSpec &DS,
|
2009-03-26 06:00:53 +08:00
|
|
|
TemplateParameterLists *TemplateParams,
|
|
|
|
AccessSpecifier AS) {
|
2008-04-14 05:30:24 +08:00
|
|
|
assert((Tok.is(tok::kw_class) ||
|
|
|
|
Tok.is(tok::kw_struct) ||
|
|
|
|
Tok.is(tok::kw_union)) &&
|
|
|
|
"Not a class specifier");
|
|
|
|
DeclSpec::TST TagType =
|
|
|
|
Tok.is(tok::kw_class) ? DeclSpec::TST_class :
|
|
|
|
Tok.is(tok::kw_struct) ? DeclSpec::TST_struct :
|
|
|
|
DeclSpec::TST_union;
|
|
|
|
|
|
|
|
SourceLocation StartLoc = ConsumeToken();
|
|
|
|
|
|
|
|
AttributeList *Attr = 0;
|
|
|
|
// If attributes exist after tag, parse them.
|
|
|
|
if (Tok.is(tok::kw___attribute))
|
|
|
|
Attr = ParseAttributes();
|
|
|
|
|
2008-12-25 04:59:21 +08:00
|
|
|
// If declspecs exist after tag, parse them.
|
|
|
|
if (Tok.is(tok::kw___declspec) && PP.getLangOptions().Microsoft)
|
|
|
|
FuzzyParseMicrosoftDeclSpec();
|
|
|
|
|
2008-11-09 00:45:02 +08:00
|
|
|
// Parse the (optional) nested-name-specifier.
|
|
|
|
CXXScopeSpec SS;
|
Implement parsing of nested-name-specifiers that involve template-ids, e.g.,
std::vector<int>::allocator_type
When we parse a template-id that names a type, it will become either a
template-id annotation (which is a parsed representation of a
template-id that has not yet been through semantic analysis) or a
typename annotation (where semantic analysis has resolved the
template-id to an actual type), depending on the context. We only
produce a type in contexts where we know that we only need type
information, e.g., in a type specifier. Otherwise, we create a
template-id annotation that can later be "upgraded" by transforming it
into a typename annotation when the parser needs a type. This occurs,
for example, when we've parsed "std::vector<int>" above and then see
the '::' after it. However, it means that when writing something like
this:
template<> class Outer::Inner<int> { ... };
We have two tokens to represent Outer::Inner<int>: one token for the
nested name specifier Outer::, and one template-id annotation token
for Inner<int>, which will be passed to semantic analysis to define
the class template specialization.
Most of the churn in the template tests in this patch come from an
improvement in our error recovery from ill-formed template-ids.
llvm-svn: 65467
2009-02-26 03:37:18 +08:00
|
|
|
if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS))
|
|
|
|
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
|
2008-11-09 00:45:02 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident);
|
2009-02-18 07:15:12 +08:00
|
|
|
|
|
|
|
// Parse the (optional) class name or simple-template-id.
|
2008-04-14 05:30:24 +08:00
|
|
|
IdentifierInfo *Name = 0;
|
|
|
|
SourceLocation NameLoc;
|
Implement parsing of nested-name-specifiers that involve template-ids, e.g.,
std::vector<int>::allocator_type
When we parse a template-id that names a type, it will become either a
template-id annotation (which is a parsed representation of a
template-id that has not yet been through semantic analysis) or a
typename annotation (where semantic analysis has resolved the
template-id to an actual type), depending on the context. We only
produce a type in contexts where we know that we only need type
information, e.g., in a type specifier. Otherwise, we create a
template-id annotation that can later be "upgraded" by transforming it
into a typename annotation when the parser needs a type. This occurs,
for example, when we've parsed "std::vector<int>" above and then see
the '::' after it. However, it means that when writing something like
this:
template<> class Outer::Inner<int> { ... };
We have two tokens to represent Outer::Inner<int>: one token for the
nested name specifier Outer::, and one template-id annotation token
for Inner<int>, which will be passed to semantic analysis to define
the class template specialization.
Most of the churn in the template tests in this patch come from an
improvement in our error recovery from ill-formed template-ids.
llvm-svn: 65467
2009-02-26 03:37:18 +08:00
|
|
|
TemplateIdAnnotation *TemplateId = 0;
|
2008-04-14 05:30:24 +08:00
|
|
|
if (Tok.is(tok::identifier)) {
|
|
|
|
Name = Tok.getIdentifierInfo();
|
|
|
|
NameLoc = ConsumeToken();
|
Implement parsing of nested-name-specifiers that involve template-ids, e.g.,
std::vector<int>::allocator_type
When we parse a template-id that names a type, it will become either a
template-id annotation (which is a parsed representation of a
template-id that has not yet been through semantic analysis) or a
typename annotation (where semantic analysis has resolved the
template-id to an actual type), depending on the context. We only
produce a type in contexts where we know that we only need type
information, e.g., in a type specifier. Otherwise, we create a
template-id annotation that can later be "upgraded" by transforming it
into a typename annotation when the parser needs a type. This occurs,
for example, when we've parsed "std::vector<int>" above and then see
the '::' after it. However, it means that when writing something like
this:
template<> class Outer::Inner<int> { ... };
We have two tokens to represent Outer::Inner<int>: one token for the
nested name specifier Outer::, and one template-id annotation token
for Inner<int>, which will be passed to semantic analysis to define
the class template specialization.
Most of the churn in the template tests in this patch come from an
improvement in our error recovery from ill-formed template-ids.
llvm-svn: 65467
2009-02-26 03:37:18 +08:00
|
|
|
} else if (Tok.is(tok::annot_template_id)) {
|
|
|
|
TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
|
|
|
|
NameLoc = ConsumeToken();
|
2009-02-18 07:15:12 +08:00
|
|
|
|
Implement parsing of nested-name-specifiers that involve template-ids, e.g.,
std::vector<int>::allocator_type
When we parse a template-id that names a type, it will become either a
template-id annotation (which is a parsed representation of a
template-id that has not yet been through semantic analysis) or a
typename annotation (where semantic analysis has resolved the
template-id to an actual type), depending on the context. We only
produce a type in contexts where we know that we only need type
information, e.g., in a type specifier. Otherwise, we create a
template-id annotation that can later be "upgraded" by transforming it
into a typename annotation when the parser needs a type. This occurs,
for example, when we've parsed "std::vector<int>" above and then see
the '::' after it. However, it means that when writing something like
this:
template<> class Outer::Inner<int> { ... };
We have two tokens to represent Outer::Inner<int>: one token for the
nested name specifier Outer::, and one template-id annotation token
for Inner<int>, which will be passed to semantic analysis to define
the class template specialization.
Most of the churn in the template tests in this patch come from an
improvement in our error recovery from ill-formed template-ids.
llvm-svn: 65467
2009-02-26 03:37:18 +08:00
|
|
|
if (TemplateId->Kind != TNK_Class_template) {
|
|
|
|
// The template-name in the simple-template-id refers to
|
|
|
|
// something other than a class template. Give an appropriate
|
|
|
|
// error message and skip to the ';'.
|
|
|
|
SourceRange Range(NameLoc);
|
|
|
|
if (SS.isNotEmpty())
|
|
|
|
Range.setBegin(SS.getBeginLoc());
|
|
|
|
|
|
|
|
Diag(TemplateId->LAngleLoc, diag::err_template_spec_syntax_non_template)
|
|
|
|
<< Name << static_cast<int>(TemplateId->Kind) << Range;
|
2009-02-18 07:15:12 +08:00
|
|
|
|
Implement parsing of nested-name-specifiers that involve template-ids, e.g.,
std::vector<int>::allocator_type
When we parse a template-id that names a type, it will become either a
template-id annotation (which is a parsed representation of a
template-id that has not yet been through semantic analysis) or a
typename annotation (where semantic analysis has resolved the
template-id to an actual type), depending on the context. We only
produce a type in contexts where we know that we only need type
information, e.g., in a type specifier. Otherwise, we create a
template-id annotation that can later be "upgraded" by transforming it
into a typename annotation when the parser needs a type. This occurs,
for example, when we've parsed "std::vector<int>" above and then see
the '::' after it. However, it means that when writing something like
this:
template<> class Outer::Inner<int> { ... };
We have two tokens to represent Outer::Inner<int>: one token for the
nested name specifier Outer::, and one template-id annotation token
for Inner<int>, which will be passed to semantic analysis to define
the class template specialization.
Most of the churn in the template tests in this patch come from an
improvement in our error recovery from ill-formed template-ids.
llvm-svn: 65467
2009-02-26 03:37:18 +08:00
|
|
|
DS.SetTypeSpecError();
|
|
|
|
SkipUntil(tok::semi, false, true);
|
|
|
|
TemplateId->Destroy();
|
|
|
|
return;
|
2009-02-18 07:15:12 +08:00
|
|
|
}
|
2008-04-14 05:30:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// There are three options here. If we have 'struct foo;', then
|
|
|
|
// this is a forward declaration. If we have 'struct foo {...' or
|
Implement parsing of nested-name-specifiers that involve template-ids, e.g.,
std::vector<int>::allocator_type
When we parse a template-id that names a type, it will become either a
template-id annotation (which is a parsed representation of a
template-id that has not yet been through semantic analysis) or a
typename annotation (where semantic analysis has resolved the
template-id to an actual type), depending on the context. We only
produce a type in contexts where we know that we only need type
information, e.g., in a type specifier. Otherwise, we create a
template-id annotation that can later be "upgraded" by transforming it
into a typename annotation when the parser needs a type. This occurs,
for example, when we've parsed "std::vector<int>" above and then see
the '::' after it. However, it means that when writing something like
this:
template<> class Outer::Inner<int> { ... };
We have two tokens to represent Outer::Inner<int>: one token for the
nested name specifier Outer::, and one template-id annotation token
for Inner<int>, which will be passed to semantic analysis to define
the class template specialization.
Most of the churn in the template tests in this patch come from an
improvement in our error recovery from ill-formed template-ids.
llvm-svn: 65467
2009-02-26 03:37:18 +08:00
|
|
|
// 'struct foo :...' then this is a definition. Otherwise we have
|
2008-04-14 05:30:24 +08:00
|
|
|
// something like 'struct foo xyz', a reference.
|
|
|
|
Action::TagKind TK;
|
|
|
|
if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon)))
|
|
|
|
TK = Action::TK_Definition;
|
|
|
|
else if (Tok.is(tok::semi))
|
|
|
|
TK = Action::TK_Declaration;
|
|
|
|
else
|
|
|
|
TK = Action::TK_Reference;
|
|
|
|
|
Implement parsing of nested-name-specifiers that involve template-ids, e.g.,
std::vector<int>::allocator_type
When we parse a template-id that names a type, it will become either a
template-id annotation (which is a parsed representation of a
template-id that has not yet been through semantic analysis) or a
typename annotation (where semantic analysis has resolved the
template-id to an actual type), depending on the context. We only
produce a type in contexts where we know that we only need type
information, e.g., in a type specifier. Otherwise, we create a
template-id annotation that can later be "upgraded" by transforming it
into a typename annotation when the parser needs a type. This occurs,
for example, when we've parsed "std::vector<int>" above and then see
the '::' after it. However, it means that when writing something like
this:
template<> class Outer::Inner<int> { ... };
We have two tokens to represent Outer::Inner<int>: one token for the
nested name specifier Outer::, and one template-id annotation token
for Inner<int>, which will be passed to semantic analysis to define
the class template specialization.
Most of the churn in the template tests in this patch come from an
improvement in our error recovery from ill-formed template-ids.
llvm-svn: 65467
2009-02-26 03:37:18 +08:00
|
|
|
if (!Name && !TemplateId && TK != Action::TK_Definition) {
|
2008-04-14 05:30:24 +08:00
|
|
|
// We have a declaration or reference to an anonymous class.
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(StartLoc, diag::err_anon_type_definition)
|
|
|
|
<< DeclSpec::getSpecifierName(TagType);
|
2008-04-14 05:30:24 +08:00
|
|
|
|
|
|
|
// Skip the rest of this declarator, up until the comma or semicolon.
|
|
|
|
SkipUntil(tok::comma, true);
|
Implement parsing of nested-name-specifiers that involve template-ids, e.g.,
std::vector<int>::allocator_type
When we parse a template-id that names a type, it will become either a
template-id annotation (which is a parsed representation of a
template-id that has not yet been through semantic analysis) or a
typename annotation (where semantic analysis has resolved the
template-id to an actual type), depending on the context. We only
produce a type in contexts where we know that we only need type
information, e.g., in a type specifier. Otherwise, we create a
template-id annotation that can later be "upgraded" by transforming it
into a typename annotation when the parser needs a type. This occurs,
for example, when we've parsed "std::vector<int>" above and then see
the '::' after it. However, it means that when writing something like
this:
template<> class Outer::Inner<int> { ... };
We have two tokens to represent Outer::Inner<int>: one token for the
nested name specifier Outer::, and one template-id annotation token
for Inner<int>, which will be passed to semantic analysis to define
the class template specialization.
Most of the churn in the template tests in this patch come from an
improvement in our error recovery from ill-formed template-ids.
llvm-svn: 65467
2009-02-26 03:37:18 +08:00
|
|
|
|
|
|
|
if (TemplateId)
|
|
|
|
TemplateId->Destroy();
|
2008-04-14 05:30:24 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-02-07 06:42:48 +08:00
|
|
|
// Create the tag portion of the class or class template.
|
2009-03-25 08:13:59 +08:00
|
|
|
Action::DeclResult TagOrTempResult;
|
Implement parsing of nested-name-specifiers that involve template-ids, e.g.,
std::vector<int>::allocator_type
When we parse a template-id that names a type, it will become either a
template-id annotation (which is a parsed representation of a
template-id that has not yet been through semantic analysis) or a
typename annotation (where semantic analysis has resolved the
template-id to an actual type), depending on the context. We only
produce a type in contexts where we know that we only need type
information, e.g., in a type specifier. Otherwise, we create a
template-id annotation that can later be "upgraded" by transforming it
into a typename annotation when the parser needs a type. This occurs,
for example, when we've parsed "std::vector<int>" above and then see
the '::' after it. However, it means that when writing something like
this:
template<> class Outer::Inner<int> { ... };
We have two tokens to represent Outer::Inner<int>: one token for the
nested name specifier Outer::, and one template-id annotation token
for Inner<int>, which will be passed to semantic analysis to define
the class template specialization.
Most of the churn in the template tests in this patch come from an
improvement in our error recovery from ill-formed template-ids.
llvm-svn: 65467
2009-02-26 03:37:18 +08:00
|
|
|
if (TemplateId && TK != Action::TK_Reference) {
|
2009-02-18 07:15:12 +08:00
|
|
|
// Explicit specialization or class template partial
|
|
|
|
// specialization. Let semantic analysis decide.
|
Implement parsing of nested-name-specifiers that involve template-ids, e.g.,
std::vector<int>::allocator_type
When we parse a template-id that names a type, it will become either a
template-id annotation (which is a parsed representation of a
template-id that has not yet been through semantic analysis) or a
typename annotation (where semantic analysis has resolved the
template-id to an actual type), depending on the context. We only
produce a type in contexts where we know that we only need type
information, e.g., in a type specifier. Otherwise, we create a
template-id annotation that can later be "upgraded" by transforming it
into a typename annotation when the parser needs a type. This occurs,
for example, when we've parsed "std::vector<int>" above and then see
the '::' after it. However, it means that when writing something like
this:
template<> class Outer::Inner<int> { ... };
We have two tokens to represent Outer::Inner<int>: one token for the
nested name specifier Outer::, and one template-id annotation token
for Inner<int>, which will be passed to semantic analysis to define
the class template specialization.
Most of the churn in the template tests in this patch come from an
improvement in our error recovery from ill-formed template-ids.
llvm-svn: 65467
2009-02-26 03:37:18 +08:00
|
|
|
ASTTemplateArgsPtr TemplateArgsPtr(Actions,
|
|
|
|
TemplateId->getTemplateArgs(),
|
|
|
|
TemplateId->getTemplateArgIsType(),
|
|
|
|
TemplateId->NumArgs);
|
2009-03-25 08:13:59 +08:00
|
|
|
TagOrTempResult
|
2009-02-18 07:15:12 +08:00
|
|
|
= Actions.ActOnClassTemplateSpecialization(CurScope, TagType, TK,
|
Implement parsing of nested-name-specifiers that involve template-ids, e.g.,
std::vector<int>::allocator_type
When we parse a template-id that names a type, it will become either a
template-id annotation (which is a parsed representation of a
template-id that has not yet been through semantic analysis) or a
typename annotation (where semantic analysis has resolved the
template-id to an actual type), depending on the context. We only
produce a type in contexts where we know that we only need type
information, e.g., in a type specifier. Otherwise, we create a
template-id annotation that can later be "upgraded" by transforming it
into a typename annotation when the parser needs a type. This occurs,
for example, when we've parsed "std::vector<int>" above and then see
the '::' after it. However, it means that when writing something like
this:
template<> class Outer::Inner<int> { ... };
We have two tokens to represent Outer::Inner<int>: one token for the
nested name specifier Outer::, and one template-id annotation token
for Inner<int>, which will be passed to semantic analysis to define
the class template specialization.
Most of the churn in the template tests in this patch come from an
improvement in our error recovery from ill-formed template-ids.
llvm-svn: 65467
2009-02-26 03:37:18 +08:00
|
|
|
StartLoc, SS,
|
2009-03-31 06:58:21 +08:00
|
|
|
TemplateTy::make(TemplateId->Template),
|
Implement parsing of nested-name-specifiers that involve template-ids, e.g.,
std::vector<int>::allocator_type
When we parse a template-id that names a type, it will become either a
template-id annotation (which is a parsed representation of a
template-id that has not yet been through semantic analysis) or a
typename annotation (where semantic analysis has resolved the
template-id to an actual type), depending on the context. We only
produce a type in contexts where we know that we only need type
information, e.g., in a type specifier. Otherwise, we create a
template-id annotation that can later be "upgraded" by transforming it
into a typename annotation when the parser needs a type. This occurs,
for example, when we've parsed "std::vector<int>" above and then see
the '::' after it. However, it means that when writing something like
this:
template<> class Outer::Inner<int> { ... };
We have two tokens to represent Outer::Inner<int>: one token for the
nested name specifier Outer::, and one template-id annotation token
for Inner<int>, which will be passed to semantic analysis to define
the class template specialization.
Most of the churn in the template tests in this patch come from an
improvement in our error recovery from ill-formed template-ids.
llvm-svn: 65467
2009-02-26 03:37:18 +08:00
|
|
|
TemplateId->TemplateNameLoc,
|
|
|
|
TemplateId->LAngleLoc,
|
|
|
|
TemplateArgsPtr,
|
|
|
|
TemplateId->getTemplateArgLocations(),
|
|
|
|
TemplateId->RAngleLoc,
|
|
|
|
Attr,
|
2009-02-18 07:15:12 +08:00
|
|
|
Action::MultiTemplateParamsArg(Actions,
|
|
|
|
TemplateParams? &(*TemplateParams)[0] : 0,
|
|
|
|
TemplateParams? TemplateParams->size() : 0));
|
Implement parsing of nested-name-specifiers that involve template-ids, e.g.,
std::vector<int>::allocator_type
When we parse a template-id that names a type, it will become either a
template-id annotation (which is a parsed representation of a
template-id that has not yet been through semantic analysis) or a
typename annotation (where semantic analysis has resolved the
template-id to an actual type), depending on the context. We only
produce a type in contexts where we know that we only need type
information, e.g., in a type specifier. Otherwise, we create a
template-id annotation that can later be "upgraded" by transforming it
into a typename annotation when the parser needs a type. This occurs,
for example, when we've parsed "std::vector<int>" above and then see
the '::' after it. However, it means that when writing something like
this:
template<> class Outer::Inner<int> { ... };
We have two tokens to represent Outer::Inner<int>: one token for the
nested name specifier Outer::, and one template-id annotation token
for Inner<int>, which will be passed to semantic analysis to define
the class template specialization.
Most of the churn in the template tests in this patch come from an
improvement in our error recovery from ill-formed template-ids.
llvm-svn: 65467
2009-02-26 03:37:18 +08:00
|
|
|
TemplateId->Destroy();
|
|
|
|
} else if (TemplateParams && TK != Action::TK_Reference)
|
2009-03-25 08:13:59 +08:00
|
|
|
TagOrTempResult = Actions.ActOnClassTemplate(CurScope, TagType, TK,
|
|
|
|
StartLoc, SS, Name, NameLoc,
|
|
|
|
Attr,
|
2009-02-07 06:42:48 +08:00
|
|
|
Action::MultiTemplateParamsArg(Actions,
|
|
|
|
&(*TemplateParams)[0],
|
2009-03-26 08:52:18 +08:00
|
|
|
TemplateParams->size()),
|
|
|
|
AS);
|
2009-02-07 06:42:48 +08:00
|
|
|
else
|
2009-03-25 08:13:59 +08:00
|
|
|
TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, SS, Name,
|
2009-03-26 06:00:53 +08:00
|
|
|
NameLoc, Attr, AS);
|
2008-04-14 05:30:24 +08:00
|
|
|
|
|
|
|
// Parse the optional base clause (C++ only).
|
2009-02-17 06:07:16 +08:00
|
|
|
if (getLang().CPlusPlus && Tok.is(tok::colon))
|
2009-03-25 08:13:59 +08:00
|
|
|
ParseBaseClause(TagOrTempResult.get());
|
2008-04-14 05:30:24 +08:00
|
|
|
|
|
|
|
// If there is a body, parse it and inform the actions module.
|
|
|
|
if (Tok.is(tok::l_brace))
|
2008-07-01 18:37:29 +08:00
|
|
|
if (getLang().CPlusPlus)
|
2009-03-25 08:13:59 +08:00
|
|
|
ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get());
|
2008-07-01 18:37:29 +08:00
|
|
|
else
|
2009-03-25 08:13:59 +08:00
|
|
|
ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get());
|
2008-04-14 05:30:24 +08:00
|
|
|
else if (TK == Action::TK_Definition) {
|
|
|
|
// FIXME: Complain that we have a base-specifier list but no
|
|
|
|
// definition.
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_lbrace);
|
2008-04-14 05:30:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const char *PrevSpec = 0;
|
2009-03-25 08:13:59 +08:00
|
|
|
if (TagOrTempResult.isInvalid())
|
2009-02-07 06:42:48 +08:00
|
|
|
DS.SetTypeSpecError();
|
2009-03-25 08:13:59 +08:00
|
|
|
else if (DS.SetTypeSpecType(TagType, StartLoc, PrevSpec,
|
2009-03-29 03:18:32 +08:00
|
|
|
TagOrTempResult.get().getAs<void>()))
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
|
2008-04-14 05:30:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseBaseClause - Parse the base-clause of a C++ class [C++ class.derived].
|
|
|
|
///
|
|
|
|
/// base-clause : [C++ class.derived]
|
|
|
|
/// ':' base-specifier-list
|
|
|
|
/// base-specifier-list:
|
|
|
|
/// base-specifier '...'[opt]
|
|
|
|
/// base-specifier-list ',' base-specifier '...'[opt]
|
2009-03-29 03:18:32 +08:00
|
|
|
void Parser::ParseBaseClause(DeclPtrTy ClassDecl) {
|
2008-04-14 05:30:24 +08:00
|
|
|
assert(Tok.is(tok::colon) && "Not a base clause");
|
|
|
|
ConsumeToken();
|
|
|
|
|
2008-10-23 01:49:05 +08:00
|
|
|
// Build up an array of parsed base specifiers.
|
|
|
|
llvm::SmallVector<BaseTy *, 8> BaseInfo;
|
|
|
|
|
2008-04-14 05:30:24 +08:00
|
|
|
while (true) {
|
|
|
|
// Parse a base-specifier.
|
2008-10-23 01:49:05 +08:00
|
|
|
BaseResult Result = ParseBaseSpecifier(ClassDecl);
|
2009-01-27 06:44:13 +08:00
|
|
|
if (Result.isInvalid()) {
|
2008-04-14 05:30:24 +08:00
|
|
|
// Skip the rest of this base specifier, up until the comma or
|
|
|
|
// opening brace.
|
2008-10-23 01:49:05 +08:00
|
|
|
SkipUntil(tok::comma, tok::l_brace, true, true);
|
|
|
|
} else {
|
|
|
|
// Add this to our array of base specifiers.
|
2009-01-27 06:44:13 +08:00
|
|
|
BaseInfo.push_back(Result.get());
|
2008-04-14 05:30:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the next token is a comma, consume it and keep reading
|
|
|
|
// base-specifiers.
|
|
|
|
if (Tok.isNot(tok::comma)) break;
|
|
|
|
|
|
|
|
// Consume the comma.
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
2008-10-23 01:49:05 +08:00
|
|
|
|
|
|
|
// Attach the base specifiers
|
|
|
|
Actions.ActOnBaseSpecifiers(ClassDecl, &BaseInfo[0], BaseInfo.size());
|
2008-04-14 05:30:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseBaseSpecifier - Parse a C++ base-specifier. A base-specifier is
|
|
|
|
/// one entry in the base class list of a class specifier, for example:
|
|
|
|
/// class foo : public bar, virtual private baz {
|
|
|
|
/// 'public bar' and 'virtual private baz' are each base-specifiers.
|
|
|
|
///
|
|
|
|
/// base-specifier: [C++ class.derived]
|
|
|
|
/// ::[opt] nested-name-specifier[opt] class-name
|
|
|
|
/// 'virtual' access-specifier[opt] ::[opt] nested-name-specifier[opt]
|
|
|
|
/// class-name
|
|
|
|
/// access-specifier 'virtual'[opt] ::[opt] nested-name-specifier[opt]
|
|
|
|
/// class-name
|
2009-03-29 03:18:32 +08:00
|
|
|
Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) {
|
2008-04-14 05:30:24 +08:00
|
|
|
bool IsVirtual = false;
|
|
|
|
SourceLocation StartLoc = Tok.getLocation();
|
|
|
|
|
|
|
|
// Parse the 'virtual' keyword.
|
|
|
|
if (Tok.is(tok::kw_virtual)) {
|
|
|
|
ConsumeToken();
|
|
|
|
IsVirtual = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse an (optional) access specifier.
|
|
|
|
AccessSpecifier Access = getAccessSpecifierIfPresent();
|
|
|
|
if (Access)
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
// Parse the 'virtual' keyword (again!), in case it came after the
|
|
|
|
// access specifier.
|
|
|
|
if (Tok.is(tok::kw_virtual)) {
|
|
|
|
SourceLocation VirtualLoc = ConsumeToken();
|
|
|
|
if (IsVirtual) {
|
|
|
|
// Complain about duplicate 'virtual'
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(VirtualLoc, diag::err_dup_virtual)
|
|
|
|
<< SourceRange(VirtualLoc, VirtualLoc);
|
2008-04-14 05:30:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
IsVirtual = true;
|
|
|
|
}
|
|
|
|
|
2008-11-09 00:45:02 +08:00
|
|
|
// Parse optional '::' and optional nested-name-specifier.
|
|
|
|
CXXScopeSpec SS;
|
2009-01-06 14:59:53 +08:00
|
|
|
ParseOptionalCXXScopeSpecifier(SS);
|
2008-04-14 05:30:24 +08:00
|
|
|
|
|
|
|
// The location of the base class itself.
|
|
|
|
SourceLocation BaseLoc = Tok.getLocation();
|
2008-11-06 04:51:48 +08:00
|
|
|
|
|
|
|
// Parse the class-name.
|
2009-02-26 07:52:28 +08:00
|
|
|
SourceLocation EndLocation;
|
|
|
|
TypeTy *BaseType = ParseClassName(EndLocation, &SS);
|
2008-11-06 04:51:48 +08:00
|
|
|
if (!BaseType)
|
|
|
|
return true;
|
2008-04-14 05:30:24 +08:00
|
|
|
|
|
|
|
// Find the complete source range for the base-specifier.
|
2009-02-26 07:52:28 +08:00
|
|
|
SourceRange Range(StartLoc, EndLocation);
|
2008-04-14 05:30:24 +08:00
|
|
|
|
|
|
|
// Notify semantic analysis that we have parsed a complete
|
|
|
|
// base-specifier.
|
2008-11-26 06:21:31 +08:00
|
|
|
return Actions.ActOnBaseSpecifier(ClassDecl, Range, IsVirtual, Access,
|
|
|
|
BaseType, BaseLoc);
|
2008-04-14 05:30:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// getAccessSpecifierIfPresent - Determine whether the next token is
|
|
|
|
/// a C++ access-specifier.
|
|
|
|
///
|
|
|
|
/// access-specifier: [C++ class.derived]
|
|
|
|
/// 'private'
|
|
|
|
/// 'protected'
|
|
|
|
/// 'public'
|
2008-04-14 08:13:42 +08:00
|
|
|
AccessSpecifier Parser::getAccessSpecifierIfPresent() const
|
2008-04-14 05:30:24 +08:00
|
|
|
{
|
|
|
|
switch (Tok.getKind()) {
|
|
|
|
default: return AS_none;
|
|
|
|
case tok::kw_private: return AS_private;
|
|
|
|
case tok::kw_protected: return AS_protected;
|
|
|
|
case tok::kw_public: return AS_public;
|
|
|
|
}
|
|
|
|
}
|
2008-06-25 06:12:16 +08:00
|
|
|
|
|
|
|
/// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration.
|
|
|
|
///
|
|
|
|
/// member-declaration:
|
|
|
|
/// decl-specifier-seq[opt] member-declarator-list[opt] ';'
|
|
|
|
/// function-definition ';'[opt]
|
|
|
|
/// ::[opt] nested-name-specifier template[opt] unqualified-id ';'[TODO]
|
|
|
|
/// using-declaration [TODO]
|
2009-03-12 00:27:10 +08:00
|
|
|
/// [C++0x] static_assert-declaration
|
2009-03-26 08:52:18 +08:00
|
|
|
/// template-declaration
|
2008-12-18 09:12:00 +08:00
|
|
|
/// [GNU] '__extension__' member-declaration
|
2008-06-25 06:12:16 +08:00
|
|
|
///
|
|
|
|
/// member-declarator-list:
|
|
|
|
/// member-declarator
|
|
|
|
/// member-declarator-list ',' member-declarator
|
|
|
|
///
|
|
|
|
/// member-declarator:
|
|
|
|
/// declarator pure-specifier[opt]
|
|
|
|
/// declarator constant-initializer[opt]
|
|
|
|
/// identifier[opt] ':' constant-expression
|
|
|
|
///
|
|
|
|
/// pure-specifier: [TODO]
|
|
|
|
/// '= 0'
|
|
|
|
///
|
|
|
|
/// constant-initializer:
|
|
|
|
/// '=' constant-expression
|
|
|
|
///
|
2009-03-30 00:50:03 +08:00
|
|
|
void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) {
|
2009-03-12 00:27:10 +08:00
|
|
|
// static_assert-declaration
|
2009-03-30 00:50:03 +08:00
|
|
|
if (Tok.is(tok::kw_static_assert)) {
|
|
|
|
ParseStaticAssertDeclaration();
|
|
|
|
return;
|
|
|
|
}
|
2009-03-12 00:27:10 +08:00
|
|
|
|
2009-03-30 00:50:03 +08:00
|
|
|
if (Tok.is(tok::kw_template)) {
|
|
|
|
ParseTemplateDeclarationOrSpecialization(Declarator::MemberContext, AS);
|
|
|
|
return;
|
|
|
|
}
|
2009-03-26 08:52:18 +08:00
|
|
|
|
2008-12-18 09:12:00 +08:00
|
|
|
// Handle: member-declaration ::= '__extension__' member-declaration
|
|
|
|
if (Tok.is(tok::kw___extension__)) {
|
|
|
|
// __extension__ silences extension warnings in the subexpression.
|
|
|
|
ExtensionRAIIObject O(Diags); // Use RAII to do this.
|
|
|
|
ConsumeToken();
|
|
|
|
return ParseCXXClassMemberDeclaration(AS);
|
|
|
|
}
|
|
|
|
|
2008-06-25 06:12:16 +08:00
|
|
|
SourceLocation DSStart = Tok.getLocation();
|
|
|
|
// decl-specifier-seq:
|
|
|
|
// Parse the common declaration-specifiers piece.
|
|
|
|
DeclSpec DS;
|
2009-03-26 06:00:53 +08:00
|
|
|
ParseDeclarationSpecifiers(DS, 0, AS);
|
2008-06-25 06:12:16 +08:00
|
|
|
|
|
|
|
if (Tok.is(tok::semi)) {
|
|
|
|
ConsumeToken();
|
|
|
|
// C++ 9.2p7: The member-declarator-list can be omitted only after a
|
|
|
|
// class-specifier or an enum-specifier or in a friend declaration.
|
|
|
|
// FIXME: Friend declarations.
|
|
|
|
switch (DS.getTypeSpecType()) {
|
2009-03-30 00:50:03 +08:00
|
|
|
case DeclSpec::TST_struct:
|
|
|
|
case DeclSpec::TST_union:
|
|
|
|
case DeclSpec::TST_class:
|
|
|
|
case DeclSpec::TST_enum:
|
|
|
|
Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
|
|
|
|
return;
|
|
|
|
default:
|
|
|
|
Diag(DSStart, diag::err_no_declarators);
|
|
|
|
return;
|
2008-06-25 06:12:16 +08:00
|
|
|
}
|
|
|
|
}
|
2008-07-01 18:37:29 +08:00
|
|
|
|
2008-06-25 06:12:16 +08:00
|
|
|
Declarator DeclaratorInfo(DS, Declarator::MemberContext);
|
|
|
|
|
2008-06-28 16:10:48 +08:00
|
|
|
if (Tok.isNot(tok::colon)) {
|
|
|
|
// Parse the first declarator.
|
|
|
|
ParseDeclarator(DeclaratorInfo);
|
|
|
|
// Error parsing the declarator?
|
2008-11-18 06:58:34 +08:00
|
|
|
if (!DeclaratorInfo.hasName()) {
|
2008-06-28 16:10:48 +08:00
|
|
|
// If so, skip until the semi-colon or a }.
|
2008-06-25 06:12:16 +08:00
|
|
|
SkipUntil(tok::r_brace, true);
|
2008-06-28 16:10:48 +08:00
|
|
|
if (Tok.is(tok::semi))
|
|
|
|
ConsumeToken();
|
2009-03-30 00:50:03 +08:00
|
|
|
return;
|
2008-06-25 06:12:16 +08:00
|
|
|
}
|
|
|
|
|
2008-06-28 16:10:48 +08:00
|
|
|
// function-definition:
|
2008-11-05 12:29:56 +08:00
|
|
|
if (Tok.is(tok::l_brace)
|
|
|
|
|| (DeclaratorInfo.isFunctionDeclarator() && Tok.is(tok::colon))) {
|
2008-06-28 16:10:48 +08:00
|
|
|
if (!DeclaratorInfo.isFunctionDeclarator()) {
|
|
|
|
Diag(Tok, diag::err_func_def_no_params);
|
|
|
|
ConsumeBrace();
|
|
|
|
SkipUntil(tok::r_brace, true);
|
2009-03-30 00:50:03 +08:00
|
|
|
return;
|
2008-06-28 16:10:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
|
|
|
|
Diag(Tok, diag::err_function_declared_typedef);
|
|
|
|
// This recovery skips the entire function body. It would be nice
|
|
|
|
// to simply call ParseCXXInlineMethodDef() below, however Sema
|
|
|
|
// assumes the declarator represents a function, not a typedef.
|
|
|
|
ConsumeBrace();
|
|
|
|
SkipUntil(tok::r_brace, true);
|
2009-03-30 00:50:03 +08:00
|
|
|
return;
|
2008-06-28 16:10:48 +08:00
|
|
|
}
|
2008-06-25 06:12:16 +08:00
|
|
|
|
2009-03-30 00:50:03 +08:00
|
|
|
ParseCXXInlineMethodDef(AS, DeclaratorInfo);
|
|
|
|
return;
|
2008-06-28 16:10:48 +08:00
|
|
|
}
|
2008-06-25 06:12:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// member-declarator-list:
|
|
|
|
// member-declarator
|
|
|
|
// member-declarator-list ',' member-declarator
|
|
|
|
|
2009-03-30 00:50:03 +08:00
|
|
|
llvm::SmallVector<DeclPtrTy, 8> DeclsInGroup;
|
2008-12-10 04:22:58 +08:00
|
|
|
OwningExprResult BitfieldSize(Actions);
|
|
|
|
OwningExprResult Init(Actions);
|
2008-06-25 06:12:16 +08:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
|
|
|
// member-declarator:
|
|
|
|
// declarator pure-specifier[opt]
|
|
|
|
// declarator constant-initializer[opt]
|
|
|
|
// identifier[opt] ':' constant-expression
|
|
|
|
|
|
|
|
if (Tok.is(tok::colon)) {
|
|
|
|
ConsumeToken();
|
2008-12-09 21:15:23 +08:00
|
|
|
BitfieldSize = ParseConstantExpression();
|
|
|
|
if (BitfieldSize.isInvalid())
|
2008-06-25 06:12:16 +08:00
|
|
|
SkipUntil(tok::comma, true, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// pure-specifier:
|
|
|
|
// '= 0'
|
|
|
|
//
|
|
|
|
// constant-initializer:
|
|
|
|
// '=' constant-expression
|
|
|
|
|
|
|
|
if (Tok.is(tok::equal)) {
|
|
|
|
ConsumeToken();
|
2008-12-09 21:15:23 +08:00
|
|
|
Init = ParseInitializer();
|
|
|
|
if (Init.isInvalid())
|
2008-06-25 06:12:16 +08:00
|
|
|
SkipUntil(tok::comma, true, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If attributes exist after the declarator, parse them.
|
2009-02-10 02:23:29 +08:00
|
|
|
if (Tok.is(tok::kw___attribute)) {
|
|
|
|
SourceLocation Loc;
|
|
|
|
AttributeList *AttrList = ParseAttributes(&Loc);
|
|
|
|
DeclaratorInfo.AddAttributes(AttrList, Loc);
|
|
|
|
}
|
2008-06-25 06:12:16 +08:00
|
|
|
|
2008-07-01 18:37:29 +08:00
|
|
|
// NOTE: If Sema is the Action module and declarator is an instance field,
|
2009-03-30 00:50:03 +08:00
|
|
|
// this call will *not* return the created decl; It will return null.
|
2008-07-01 18:37:29 +08:00
|
|
|
// See Sema::ActOnCXXMemberDeclarator for details.
|
2009-03-30 00:50:03 +08:00
|
|
|
DeclPtrTy ThisDecl = Actions.ActOnCXXMemberDeclarator(CurScope, AS,
|
|
|
|
DeclaratorInfo,
|
|
|
|
BitfieldSize.release(),
|
|
|
|
Init.release());
|
|
|
|
if (ThisDecl)
|
|
|
|
DeclsInGroup.push_back(ThisDecl);
|
2008-06-25 06:12:16 +08:00
|
|
|
|
2008-12-17 05:30:33 +08:00
|
|
|
if (DeclaratorInfo.isFunctionDeclarator() &&
|
|
|
|
DeclaratorInfo.getDeclSpec().getStorageClassSpec()
|
|
|
|
!= DeclSpec::SCS_typedef) {
|
|
|
|
// We just declared a member function. If this member function
|
|
|
|
// has any default arguments, we'll need to parse them later.
|
|
|
|
LateParsedMethodDeclaration *LateMethod = 0;
|
|
|
|
DeclaratorChunk::FunctionTypeInfo &FTI
|
|
|
|
= DeclaratorInfo.getTypeObject(0).Fun;
|
|
|
|
for (unsigned ParamIdx = 0; ParamIdx < FTI.NumArgs; ++ParamIdx) {
|
|
|
|
if (LateMethod || FTI.ArgInfo[ParamIdx].DefaultArgTokens) {
|
|
|
|
if (!LateMethod) {
|
|
|
|
// Push this method onto the stack of late-parsed method
|
|
|
|
// declarations.
|
|
|
|
getCurTopClassStack().MethodDecls.push_back(
|
2009-03-30 00:50:03 +08:00
|
|
|
LateParsedMethodDeclaration(ThisDecl));
|
2008-12-17 05:30:33 +08:00
|
|
|
LateMethod = &getCurTopClassStack().MethodDecls.back();
|
|
|
|
|
|
|
|
// Add all of the parameters prior to this one (they don't
|
|
|
|
// have default arguments).
|
|
|
|
LateMethod->DefaultArgs.reserve(FTI.NumArgs);
|
|
|
|
for (unsigned I = 0; I < ParamIdx; ++I)
|
|
|
|
LateMethod->DefaultArgs.push_back(
|
|
|
|
LateParsedDefaultArgument(FTI.ArgInfo[ParamIdx].Param));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add this parameter to the list of parameters (it or may
|
|
|
|
// not have a default argument).
|
|
|
|
LateMethod->DefaultArgs.push_back(
|
|
|
|
LateParsedDefaultArgument(FTI.ArgInfo[ParamIdx].Param,
|
|
|
|
FTI.ArgInfo[ParamIdx].DefaultArgTokens));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-25 06:12:16 +08:00
|
|
|
// If we don't have a comma, it is either the end of the list (a ';')
|
|
|
|
// or an error, bail out.
|
|
|
|
if (Tok.isNot(tok::comma))
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Consume the comma.
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
// Parse the next declarator.
|
|
|
|
DeclaratorInfo.clear();
|
2008-12-10 04:22:58 +08:00
|
|
|
BitfieldSize = 0;
|
|
|
|
Init = 0;
|
2008-06-25 06:12:16 +08:00
|
|
|
|
|
|
|
// Attributes are only allowed on the second declarator.
|
2009-02-10 02:23:29 +08:00
|
|
|
if (Tok.is(tok::kw___attribute)) {
|
|
|
|
SourceLocation Loc;
|
|
|
|
AttributeList *AttrList = ParseAttributes(&Loc);
|
|
|
|
DeclaratorInfo.AddAttributes(AttrList, Loc);
|
|
|
|
}
|
2008-06-25 06:12:16 +08:00
|
|
|
|
2008-06-28 16:10:48 +08:00
|
|
|
if (Tok.isNot(tok::colon))
|
|
|
|
ParseDeclarator(DeclaratorInfo);
|
2008-06-25 06:12:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Tok.is(tok::semi)) {
|
|
|
|
ConsumeToken();
|
2009-03-30 00:50:03 +08:00
|
|
|
Actions.FinalizeDeclaratorGroup(CurScope, &DeclsInGroup[0],
|
|
|
|
DeclsInGroup.size());
|
|
|
|
return;
|
2008-06-25 06:12:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Diag(Tok, diag::err_expected_semi_decl_list);
|
|
|
|
// Skip to end of block or statement
|
|
|
|
SkipUntil(tok::r_brace, true, true);
|
|
|
|
if (Tok.is(tok::semi))
|
|
|
|
ConsumeToken();
|
2009-03-30 00:50:03 +08:00
|
|
|
return;
|
2008-06-25 06:12:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseCXXMemberSpecification - Parse the class definition.
|
|
|
|
///
|
|
|
|
/// member-specification:
|
|
|
|
/// member-declaration member-specification[opt]
|
|
|
|
/// access-specifier ':' member-specification[opt]
|
|
|
|
///
|
|
|
|
void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
|
2009-03-29 03:18:32 +08:00
|
|
|
unsigned TagType, DeclPtrTy TagDecl) {
|
2008-10-31 17:52:39 +08:00
|
|
|
assert((TagType == DeclSpec::TST_struct ||
|
2008-06-25 06:12:16 +08:00
|
|
|
TagType == DeclSpec::TST_union ||
|
2008-10-31 17:52:39 +08:00
|
|
|
TagType == DeclSpec::TST_class) && "Invalid TagType!");
|
2008-06-25 06:12:16 +08:00
|
|
|
|
2009-03-05 16:00:35 +08:00
|
|
|
PrettyStackTraceActionsDecl CrashInfo(TagDecl, RecordLoc, Actions,
|
|
|
|
PP.getSourceManager(),
|
|
|
|
"parsing struct/union/class body");
|
2009-03-05 10:25:03 +08:00
|
|
|
|
2008-06-25 06:12:16 +08:00
|
|
|
SourceLocation LBraceLoc = ConsumeBrace();
|
|
|
|
|
2009-01-10 06:42:13 +08:00
|
|
|
if (!CurScope->isClassScope() && // Not about to define a nested class.
|
2008-06-25 06:12:16 +08:00
|
|
|
CurScope->isInCXXInlineMethodScope()) {
|
|
|
|
// We will define a local class of an inline method.
|
|
|
|
// Push a new LexedMethodsForTopClass for its inline methods.
|
|
|
|
PushTopClassStack();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Enter a scope for the class.
|
2009-01-10 06:42:13 +08:00
|
|
|
ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope);
|
2008-06-25 06:12:16 +08:00
|
|
|
|
2009-02-07 06:42:48 +08:00
|
|
|
if (TagDecl)
|
|
|
|
Actions.ActOnTagStartDefinition(CurScope, TagDecl);
|
|
|
|
else {
|
|
|
|
SkipUntil(tok::r_brace, false, false);
|
|
|
|
return;
|
|
|
|
}
|
2008-06-25 06:12:16 +08:00
|
|
|
|
|
|
|
// C++ 11p3: Members of a class defined with the keyword class are private
|
|
|
|
// by default. Members of a class defined with the keywords struct or union
|
|
|
|
// are public by default.
|
|
|
|
AccessSpecifier CurAS;
|
|
|
|
if (TagType == DeclSpec::TST_class)
|
|
|
|
CurAS = AS_private;
|
|
|
|
else
|
|
|
|
CurAS = AS_public;
|
|
|
|
|
|
|
|
// While we still have something to read, read the member-declarations.
|
|
|
|
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
|
|
|
|
// Each iteration of this loop reads one member-declaration.
|
|
|
|
|
|
|
|
// Check for extraneous top-level semicolon.
|
|
|
|
if (Tok.is(tok::semi)) {
|
|
|
|
Diag(Tok, diag::ext_extra_struct_semi);
|
|
|
|
ConsumeToken();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
AccessSpecifier AS = getAccessSpecifierIfPresent();
|
|
|
|
if (AS != AS_none) {
|
|
|
|
// Current token is a C++ access specifier.
|
|
|
|
CurAS = AS;
|
|
|
|
ConsumeToken();
|
|
|
|
ExpectAndConsume(tok::colon, diag::err_expected_colon);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse all the comma separated declarators.
|
|
|
|
ParseCXXClassMemberDeclaration(CurAS);
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
|
|
|
|
|
|
|
|
AttributeList *AttrList = 0;
|
|
|
|
// If attributes exist after class contents, parse them.
|
|
|
|
if (Tok.is(tok::kw___attribute))
|
|
|
|
AttrList = ParseAttributes(); // FIXME: where should I put them?
|
|
|
|
|
|
|
|
Actions.ActOnFinishCXXMemberSpecification(CurScope, RecordLoc, TagDecl,
|
|
|
|
LBraceLoc, RBraceLoc);
|
|
|
|
|
|
|
|
// C++ 9.2p2: Within the class member-specification, the class is regarded as
|
|
|
|
// complete within function bodies, default arguments,
|
|
|
|
// exception-specifications, and constructor ctor-initializers (including
|
|
|
|
// such things in nested classes).
|
|
|
|
//
|
2008-12-17 05:30:33 +08:00
|
|
|
// FIXME: Only function bodies and constructor ctor-initializers are
|
|
|
|
// parsed correctly, fix the rest.
|
2009-01-10 06:42:13 +08:00
|
|
|
if (!CurScope->getParent()->isClassScope()) {
|
2008-06-25 06:12:16 +08:00
|
|
|
// We are not inside a nested class. This class and its nested classes
|
2008-12-17 05:30:33 +08:00
|
|
|
// are complete and we can parse the delayed portions of method
|
|
|
|
// declarations and the lexed inline method definitions.
|
|
|
|
ParseLexedMethodDeclarations();
|
2008-06-25 06:12:16 +08:00
|
|
|
ParseLexedMethodDefs();
|
|
|
|
|
|
|
|
// For a local class of inline method, pop the LexedMethodsForTopClass that
|
|
|
|
// was previously pushed.
|
|
|
|
|
2008-10-31 17:52:39 +08:00
|
|
|
assert((CurScope->isInCXXInlineMethodScope() ||
|
|
|
|
TopClassStacks.size() == 1) &&
|
2008-06-25 06:12:16 +08:00
|
|
|
"MethodLexers not getting popped properly!");
|
|
|
|
if (CurScope->isInCXXInlineMethodScope())
|
|
|
|
PopTopClassStack();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Leave the class scope.
|
2008-12-10 14:34:36 +08:00
|
|
|
ClassScope.Exit();
|
2008-06-25 06:12:16 +08:00
|
|
|
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
llvm-svn: 61940
2009-01-09 04:45:30 +08:00
|
|
|
Actions.ActOnTagFinishDefinition(CurScope, TagDecl);
|
2008-06-25 06:12:16 +08:00
|
|
|
}
|
2008-11-05 12:29:56 +08:00
|
|
|
|
|
|
|
/// ParseConstructorInitializer - Parse a C++ constructor initializer,
|
|
|
|
/// which explicitly initializes the members or base classes of a
|
|
|
|
/// class (C++ [class.base.init]). For example, the three initializers
|
|
|
|
/// after the ':' in the Derived constructor below:
|
|
|
|
///
|
|
|
|
/// @code
|
|
|
|
/// class Base { };
|
|
|
|
/// class Derived : Base {
|
|
|
|
/// int x;
|
|
|
|
/// float f;
|
|
|
|
/// public:
|
|
|
|
/// Derived(float f) : Base(), x(17), f(f) { }
|
|
|
|
/// };
|
|
|
|
/// @endcode
|
|
|
|
///
|
|
|
|
/// [C++] ctor-initializer:
|
|
|
|
/// ':' mem-initializer-list
|
|
|
|
///
|
|
|
|
/// [C++] mem-initializer-list:
|
|
|
|
/// mem-initializer
|
|
|
|
/// mem-initializer , mem-initializer-list
|
2009-03-29 03:18:32 +08:00
|
|
|
void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) {
|
2008-11-05 12:29:56 +08:00
|
|
|
assert(Tok.is(tok::colon) && "Constructor initializer always starts with ':'");
|
|
|
|
|
|
|
|
SourceLocation ColonLoc = ConsumeToken();
|
|
|
|
|
|
|
|
llvm::SmallVector<MemInitTy*, 4> MemInitializers;
|
|
|
|
|
|
|
|
do {
|
|
|
|
MemInitResult MemInit = ParseMemInitializer(ConstructorDecl);
|
2009-01-27 06:44:13 +08:00
|
|
|
if (!MemInit.isInvalid())
|
|
|
|
MemInitializers.push_back(MemInit.get());
|
2008-11-05 12:29:56 +08:00
|
|
|
|
|
|
|
if (Tok.is(tok::comma))
|
|
|
|
ConsumeToken();
|
|
|
|
else if (Tok.is(tok::l_brace))
|
|
|
|
break;
|
|
|
|
else {
|
|
|
|
// Skip over garbage, until we get to '{'. Don't eat the '{'.
|
|
|
|
SkipUntil(tok::l_brace, true, true);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (true);
|
|
|
|
|
|
|
|
Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc,
|
|
|
|
&MemInitializers[0], MemInitializers.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseMemInitializer - Parse a C++ member initializer, which is
|
|
|
|
/// part of a constructor initializer that explicitly initializes one
|
|
|
|
/// member or base class (C++ [class.base.init]). See
|
|
|
|
/// ParseConstructorInitializer for an example.
|
|
|
|
///
|
|
|
|
/// [C++] mem-initializer:
|
|
|
|
/// mem-initializer-id '(' expression-list[opt] ')'
|
|
|
|
///
|
|
|
|
/// [C++] mem-initializer-id:
|
|
|
|
/// '::'[opt] nested-name-specifier[opt] class-name
|
|
|
|
/// identifier
|
2009-03-29 03:18:32 +08:00
|
|
|
Parser::MemInitResult Parser::ParseMemInitializer(DeclPtrTy ConstructorDecl) {
|
2008-11-05 12:29:56 +08:00
|
|
|
// FIXME: parse '::'[opt] nested-name-specifier[opt]
|
|
|
|
|
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_member_or_base_name);
|
2008-11-05 12:29:56 +08:00
|
|
|
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.getIdentifierInfo();
|
|
|
|
SourceLocation IdLoc = ConsumeToken();
|
|
|
|
|
|
|
|
// Parse the '('.
|
|
|
|
if (Tok.isNot(tok::l_paren)) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_lparen);
|
2008-11-05 12:29:56 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
SourceLocation LParenLoc = ConsumeParen();
|
|
|
|
|
|
|
|
// Parse the optional expression-list.
|
2008-11-26 06:21:31 +08:00
|
|
|
ExprVector ArgExprs(Actions);
|
2008-11-05 12:29:56 +08:00
|
|
|
CommaLocsTy CommaLocs;
|
|
|
|
if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) {
|
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
|
|
|
|
2008-11-26 06:21:31 +08:00
|
|
|
return Actions.ActOnMemInitializer(ConstructorDecl, CurScope, II, IdLoc,
|
|
|
|
LParenLoc, ArgExprs.take(),
|
|
|
|
ArgExprs.size(), &CommaLocs[0], RParenLoc);
|
2008-11-05 12:29:56 +08:00
|
|
|
}
|
2008-11-25 11:22:00 +08:00
|
|
|
|
|
|
|
/// ParseExceptionSpecification - Parse a C++ exception-specification
|
|
|
|
/// (C++ [except.spec]).
|
|
|
|
///
|
2008-12-02 02:00:20 +08:00
|
|
|
/// exception-specification:
|
|
|
|
/// 'throw' '(' type-id-list [opt] ')'
|
|
|
|
/// [MS] 'throw' '(' '...' ')'
|
2008-11-25 11:22:00 +08:00
|
|
|
///
|
2008-12-02 02:00:20 +08:00
|
|
|
/// type-id-list:
|
|
|
|
/// type-id
|
|
|
|
/// type-id-list ',' type-id
|
2008-11-25 11:22:00 +08:00
|
|
|
///
|
2009-02-10 02:23:29 +08:00
|
|
|
bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc) {
|
2008-11-25 11:22:00 +08:00
|
|
|
assert(Tok.is(tok::kw_throw) && "expected throw");
|
|
|
|
|
|
|
|
SourceLocation ThrowLoc = ConsumeToken();
|
|
|
|
|
|
|
|
if (!Tok.is(tok::l_paren)) {
|
|
|
|
return Diag(Tok, diag::err_expected_lparen_after) << "throw";
|
|
|
|
}
|
|
|
|
SourceLocation LParenLoc = ConsumeParen();
|
|
|
|
|
2008-12-02 02:00:20 +08:00
|
|
|
// Parse throw(...), a Microsoft extension that means "this function
|
|
|
|
// can throw anything".
|
|
|
|
if (Tok.is(tok::ellipsis)) {
|
|
|
|
SourceLocation EllipsisLoc = ConsumeToken();
|
|
|
|
if (!getLang().Microsoft)
|
|
|
|
Diag(EllipsisLoc, diag::ext_ellipsis_exception_spec);
|
2009-02-10 02:23:29 +08:00
|
|
|
EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
2008-12-02 02:00:20 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-11-25 11:22:00 +08:00
|
|
|
// Parse the sequence of type-ids.
|
|
|
|
while (Tok.isNot(tok::r_paren)) {
|
|
|
|
ParseTypeName();
|
|
|
|
if (Tok.is(tok::comma))
|
|
|
|
ConsumeToken();
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-02-10 02:23:29 +08:00
|
|
|
EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
2008-11-25 11:22:00 +08:00
|
|
|
return false;
|
|
|
|
}
|