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.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-06-27 08:27:47 +08:00
|
|
|
#include "clang/Basic/OperatorKinds.h"
|
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"
|
2009-11-11 03:49:08 +08:00
|
|
|
#include "clang/Parse/Template.h"
|
2009-12-10 08:21:05 +08:00
|
|
|
#include "RAIIObjectsForParser.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 '}'
|
2009-09-09 23:08:12 +08:00
|
|
|
///
|
2007-08-25 14:57:03 +08:00
|
|
|
/// namespace-alias-definition: [C++ 7.3.2: namespace.alias]
|
|
|
|
/// 'namespace' identifier '=' qualified-namespace-specifier ';'
|
|
|
|
///
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context,
|
|
|
|
SourceLocation &DeclEnd) {
|
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'.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-19 03:03:04 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
|
|
|
Actions.CodeCompleteNamespaceDecl(CurScope);
|
2010-05-25 13:58:43 +08:00
|
|
|
ConsumeCodeCompletionToken();
|
2009-09-19 03:03:04 +08:00
|
|
|
}
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2007-08-25 14:57:03 +08:00
|
|
|
SourceLocation IdentLoc;
|
|
|
|
IdentifierInfo *Ident = 0;
|
2009-06-18 03:49:00 +08:00
|
|
|
|
|
|
|
Token attrTok;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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.
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-25 14:57:03 +08:00
|
|
|
// Read label attributes, if present.
|
2010-02-11 10:19:13 +08:00
|
|
|
llvm::OwningPtr<AttributeList> AttrList;
|
2009-06-18 03:49:00 +08:00
|
|
|
if (Tok.is(tok::kw___attribute)) {
|
|
|
|
attrTok = Tok;
|
|
|
|
|
2007-08-25 14:57:03 +08:00
|
|
|
// FIXME: save these somewhere.
|
2010-02-11 10:19:13 +08:00
|
|
|
AttrList.reset(ParseGNUAttributes());
|
2009-06-18 03:49:00 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-18 03:49:00 +08:00
|
|
|
if (Tok.is(tok::equal)) {
|
|
|
|
if (AttrList)
|
|
|
|
Diag(attrTok, diag::err_unexpected_namespace_attributes_alias);
|
|
|
|
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
return ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident, DeclEnd);
|
2009-06-18 03:49:00 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-29 22:02:43 +08:00
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
2009-09-09 23:08:12 +08:00
|
|
|
Diag(Tok, Ident ? diag::err_expected_lbrace :
|
2009-03-29 22:02:43 +08:00
|
|
|
diag::err_expected_ident_lbrace);
|
|
|
|
return DeclPtrTy();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-29 22:02:43 +08:00
|
|
|
SourceLocation LBrace = ConsumeBrace();
|
2008-04-27 21:50:30 +08:00
|
|
|
|
2010-05-14 13:08:22 +08:00
|
|
|
if (CurScope->isClassScope() || CurScope->isTemplateParamScope() ||
|
|
|
|
CurScope->isInObjcMethodScope() || CurScope->getBlockParent() ||
|
|
|
|
CurScope->getFnParent()) {
|
|
|
|
Diag(LBrace, diag::err_namespace_nonnamespace_scope);
|
|
|
|
SkipUntil(tok::r_brace, false);
|
|
|
|
return DeclPtrTy();
|
|
|
|
}
|
|
|
|
|
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 =
|
2010-02-11 10:19:13 +08:00
|
|
|
Actions.ActOnStartNamespaceDef(CurScope, IdentLoc, Ident, LBrace,
|
|
|
|
AttrList.get());
|
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");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-21 16:43:09 +08:00
|
|
|
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
|
|
|
|
CXX0XAttributeList Attr;
|
|
|
|
if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
|
|
|
|
Attr = ParseCXX0XAttributes();
|
|
|
|
ParseExternalDeclaration(Attr);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-29 22:02:43 +08:00
|
|
|
// Leave the namespace scope.
|
|
|
|
NamespaceScope.Exit();
|
2008-05-02 05:44:34 +08:00
|
|
|
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBrace);
|
|
|
|
Actions.ActOnFinishNamespaceDef(NamespcDecl, RBraceLoc);
|
2008-04-27 21:50:30 +08:00
|
|
|
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
DeclEnd = RBraceLoc;
|
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,
|
2009-09-09 23:08:12 +08:00
|
|
|
SourceLocation AliasLoc,
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
IdentifierInfo *Alias,
|
|
|
|
SourceLocation &DeclEnd) {
|
2009-03-28 12:07:16 +08:00
|
|
|
assert(Tok.is(tok::equal) && "Not equal token");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-28 12:07:16 +08:00
|
|
|
ConsumeToken(); // eat the '='.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-19 03:03:04 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
|
|
|
Actions.CodeCompleteNamespaceAliasDecl(CurScope);
|
2010-05-25 13:58:43 +08:00
|
|
|
ConsumeCodeCompletionToken();
|
2009-09-19 03:03:04 +08:00
|
|
|
}
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2009-03-28 12:07:16 +08:00
|
|
|
CXXScopeSpec SS;
|
|
|
|
// Parse (optional) nested-name-specifier.
|
2009-12-07 09:38:03 +08:00
|
|
|
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
|
2009-03-28 12:07:16 +08:00
|
|
|
|
|
|
|
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-09-09 23:08:12 +08:00
|
|
|
|
2009-03-28 12:07:16 +08:00
|
|
|
// Eat the ';'.
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
DeclEnd = Tok.getLocation();
|
2009-06-14 08:07:48 +08:00
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_namespace_name,
|
|
|
|
"", tok::semi);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
return Actions.ActOnNamespaceAliasDef(CurScope, NamespaceLoc, AliasLoc, Alias,
|
2009-03-29 06:53:22 +08:00
|
|
|
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-12-10 05:39:38 +08:00
|
|
|
Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS,
|
|
|
|
unsigned Context) {
|
2008-11-22 00:10:08 +08:00
|
|
|
assert(Tok.is(tok::string_literal) && "Not a string literal!");
|
2010-03-13 18:17:05 +08:00
|
|
|
llvm::SmallString<8> LangBuffer;
|
2008-01-12 15:05:38 +08:00
|
|
|
// LangBuffer is guaranteed to be big enough.
|
2010-03-17 06:30:13 +08:00
|
|
|
bool Invalid = false;
|
|
|
|
llvm::StringRef Lang = PP.getSpelling(Tok, LangBuffer, &Invalid);
|
|
|
|
if (Invalid)
|
|
|
|
return DeclPtrTy();
|
2008-01-12 15:05:38 +08:00
|
|
|
|
|
|
|
SourceLocation Loc = ConsumeStringToken();
|
|
|
|
|
2009-01-06 03:45:36 +08:00
|
|
|
ParseScope LinkageScope(this, Scope::DeclScope);
|
2009-09-09 23:08:12 +08:00
|
|
|
DeclPtrTy LinkageSpec
|
|
|
|
= Actions.ActOnStartLinkageSpecification(CurScope,
|
2009-01-06 03:45:36 +08:00
|
|
|
/*FIXME: */SourceLocation(),
|
2010-05-03 21:08:54 +08:00
|
|
|
Loc, Lang,
|
2009-09-09 23:08:12 +08:00
|
|
|
Tok.is(tok::l_brace)? Tok.getLocation()
|
2009-01-06 03:45:36 +08:00
|
|
|
: SourceLocation());
|
|
|
|
|
2009-11-21 16:43:09 +08:00
|
|
|
CXX0XAttributeList Attr;
|
|
|
|
if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
|
|
|
|
Attr = ParseCXX0XAttributes();
|
|
|
|
}
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2009-01-06 03:45:36 +08:00
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
2009-12-10 05:39:38 +08:00
|
|
|
ParseDeclarationOrFunctionDefinition(DS, Attr.AttrList);
|
2009-09-09 23:08:12 +08:00
|
|
|
return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec,
|
2009-01-06 03:45:36 +08:00
|
|
|
SourceLocation());
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2008-12-17 06:23:02 +08:00
|
|
|
|
2010-02-07 16:38:28 +08:00
|
|
|
DS.abort();
|
|
|
|
|
2009-11-21 16:43:09 +08:00
|
|
|
if (Attr.HasAttr)
|
|
|
|
Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
|
|
|
|
<< Attr.Range;
|
|
|
|
|
2008-12-17 06:23:02 +08:00
|
|
|
SourceLocation LBrace = ConsumeBrace();
|
|
|
|
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
|
2009-11-21 16:43:09 +08:00
|
|
|
CXX0XAttributeList Attr;
|
|
|
|
if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
|
|
|
|
Attr = ParseCXX0XAttributes();
|
|
|
|
ParseExternalDeclaration(Attr);
|
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'.
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
|
2009-11-21 16:43:09 +08:00
|
|
|
SourceLocation &DeclEnd,
|
|
|
|
CXX0XAttributeList Attr) {
|
2008-12-30 11:27:21 +08:00
|
|
|
assert(Tok.is(tok::kw_using) && "Not using token");
|
|
|
|
|
|
|
|
// Eat 'using'.
|
|
|
|
SourceLocation UsingLoc = ConsumeToken();
|
|
|
|
|
2009-09-19 03:03:04 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
|
|
|
Actions.CodeCompleteUsing(CurScope);
|
2010-05-25 13:58:43 +08:00
|
|
|
ConsumeCodeCompletionToken();
|
2009-09-19 03:03:04 +08:00
|
|
|
}
|
2010-03-13 18:17:05 +08:00
|
|
|
|
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
|
2009-11-21 16:43:09 +08:00
|
|
|
return ParseUsingDirective(Context, UsingLoc, DeclEnd, Attr.AttrList);
|
|
|
|
|
|
|
|
if (Attr.HasAttr)
|
|
|
|
Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
|
|
|
|
<< Attr.Range;
|
2009-01-06 14:55:51 +08:00
|
|
|
|
|
|
|
// Otherwise, it must be using-declaration.
|
2009-11-21 16:43:09 +08:00
|
|
|
// Ignore illegal attributes (the caller should already have issued an error.
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
return ParseUsingDeclaration(Context, UsingLoc, DeclEnd);
|
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,
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
SourceLocation UsingLoc,
|
2009-11-21 16:43:09 +08:00
|
|
|
SourceLocation &DeclEnd,
|
|
|
|
AttributeList *Attr) {
|
2008-12-30 11:27:21 +08:00
|
|
|
assert(Tok.is(tok::kw_namespace) && "Not 'namespace' token");
|
|
|
|
|
|
|
|
// Eat 'namespace'.
|
|
|
|
SourceLocation NamespcLoc = ConsumeToken();
|
|
|
|
|
2009-09-19 03:03:04 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
|
|
|
Actions.CodeCompleteUsingDirective(CurScope);
|
2010-05-25 13:58:43 +08:00
|
|
|
ConsumeCodeCompletionToken();
|
2009-09-19 03:03:04 +08:00
|
|
|
}
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2008-12-30 11:27:21 +08:00
|
|
|
CXXScopeSpec SS;
|
|
|
|
// Parse (optional) nested-name-specifier.
|
2009-12-07 09:38:03 +08:00
|
|
|
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
|
2008-12-30 11:27:21 +08:00
|
|
|
|
|
|
|
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-09-09 23:08:12 +08:00
|
|
|
|
2009-01-06 15:27:21 +08:00
|
|
|
// Parse identifier.
|
|
|
|
NamespcName = Tok.getIdentifierInfo();
|
|
|
|
IdentLoc = ConsumeToken();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-01-06 15:27:21 +08:00
|
|
|
// Parse (optional) attributes (most likely GNU strong-using extension).
|
2009-11-21 16:43:09 +08:00
|
|
|
bool GNUAttr = false;
|
|
|
|
if (Tok.is(tok::kw___attribute)) {
|
|
|
|
GNUAttr = true;
|
|
|
|
Attr = addAttributeLists(Attr, ParseGNUAttributes());
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-01-06 15:27:21 +08:00
|
|
|
// Eat ';'.
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
DeclEnd = Tok.getLocation();
|
2009-06-14 08:07:48 +08:00
|
|
|
ExpectAndConsume(tok::semi,
|
2009-11-21 16:43:09 +08:00
|
|
|
GNUAttr ? diag::err_expected_semi_after_attribute_list :
|
2009-06-14 08:07:48 +08:00
|
|
|
diag::err_expected_semi_after_namespace_name, "", tok::semi);
|
2008-12-30 11:27:21 +08:00
|
|
|
|
|
|
|
return Actions.ActOnUsingDirective(CurScope, UsingLoc, NamespcLoc, SS,
|
2009-11-21 16:43:09 +08:00
|
|
|
IdentLoc, NamespcName, Attr);
|
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
|
2009-06-20 08:51:54 +08:00
|
|
|
/// unqualified-id
|
|
|
|
/// 'using' :: unqualified-id
|
2008-12-30 11:27:21 +08:00
|
|
|
///
|
2009-03-29 03:18:32 +08:00
|
|
|
Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
SourceLocation UsingLoc,
|
2009-08-30 03:54:19 +08:00
|
|
|
SourceLocation &DeclEnd,
|
|
|
|
AccessSpecifier AS) {
|
2009-06-20 08:51:54 +08:00
|
|
|
CXXScopeSpec SS;
|
2009-11-18 10:36:19 +08:00
|
|
|
SourceLocation TypenameLoc;
|
2009-06-20 08:51:54 +08:00
|
|
|
bool IsTypeName;
|
|
|
|
|
|
|
|
// Ignore optional 'typename'.
|
2009-11-05 00:30:06 +08:00
|
|
|
// FIXME: This is wrong; we should parse this as a typename-specifier.
|
2009-06-20 08:51:54 +08:00
|
|
|
if (Tok.is(tok::kw_typename)) {
|
2009-11-18 10:36:19 +08:00
|
|
|
TypenameLoc = Tok.getLocation();
|
2009-06-20 08:51:54 +08:00
|
|
|
ConsumeToken();
|
|
|
|
IsTypeName = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
IsTypeName = false;
|
|
|
|
|
|
|
|
// Parse nested-name-specifier.
|
2009-12-07 09:38:03 +08:00
|
|
|
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
|
2009-06-20 08:51:54 +08:00
|
|
|
|
|
|
|
// Check nested-name specifier.
|
|
|
|
if (SS.isInvalid()) {
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
return DeclPtrTy();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-03-13 18:17:05 +08:00
|
|
|
// Parse the unqualified-id. We allow parsing of both constructor and
|
2009-11-05 00:30:06 +08:00
|
|
|
// destructor names and allow the action module to diagnose any semantic
|
|
|
|
// errors.
|
|
|
|
UnqualifiedId Name;
|
2010-03-13 18:17:05 +08:00
|
|
|
if (ParseUnqualifiedId(SS,
|
2009-11-05 00:30:06 +08:00
|
|
|
/*EnteringContext=*/false,
|
|
|
|
/*AllowDestructorName=*/true,
|
2010-03-13 18:17:05 +08:00
|
|
|
/*AllowConstructorName=*/true,
|
|
|
|
/*ObjectType=*/0,
|
2009-11-05 00:30:06 +08:00
|
|
|
Name)) {
|
2009-06-20 08:51:54 +08:00
|
|
|
SkipUntil(tok::semi);
|
|
|
|
return DeclPtrTy();
|
|
|
|
}
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2009-06-20 08:51:54 +08:00
|
|
|
// Parse (optional) attributes (most likely GNU strong-using extension).
|
2010-02-11 10:19:13 +08:00
|
|
|
llvm::OwningPtr<AttributeList> AttrList;
|
2009-06-20 08:51:54 +08:00
|
|
|
if (Tok.is(tok::kw___attribute))
|
2010-02-11 10:19:13 +08:00
|
|
|
AttrList.reset(ParseGNUAttributes());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 08:51:54 +08:00
|
|
|
// Eat ';'.
|
|
|
|
DeclEnd = Tok.getLocation();
|
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
|
2010-03-13 18:17:05 +08:00
|
|
|
AttrList ? "attributes list" : "using declaration",
|
2009-11-05 00:30:06 +08:00
|
|
|
tok::semi);
|
2009-06-20 08:51:54 +08:00
|
|
|
|
2009-12-11 10:10:03 +08:00
|
|
|
return Actions.ActOnUsingDeclaration(CurScope, AS, true, UsingLoc, SS, Name,
|
2010-02-11 10:19:13 +08:00
|
|
|
AttrList.get(), IsTypeName, TypenameLoc);
|
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 ) ;
|
|
|
|
///
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
Parser::DeclPtrTy Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
|
2009-03-12 00:27:10 +08:00
|
|
|
assert(Tok.is(tok::kw_static_assert) && "Not a static_assert declaration");
|
|
|
|
SourceLocation StaticAssertLoc = ConsumeToken();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-12 00:27:10 +08:00
|
|
|
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
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-12 00:27:10 +08:00
|
|
|
SourceLocation LParenLoc = ConsumeParen();
|
2009-06-20 07:52:42 +08:00
|
|
|
|
2009-03-12 00:27:10 +08:00
|
|
|
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-09-09 23:08:12 +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
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-12 00:27:10 +08:00
|
|
|
OwningExprResult AssertMessage(ParseStringLiteralExpression());
|
2009-09-09 23:08:12 +08:00
|
|
|
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-09-09 23:08:12 +08:00
|
|
|
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
DeclEnd = Tok.getLocation();
|
2009-03-12 00:27:10 +08:00
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_static_assert);
|
|
|
|
|
2009-09-09 23:08:12 +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
|
|
|
}
|
|
|
|
|
2009-06-25 01:47:40 +08:00
|
|
|
/// ParseDecltypeSpecifier - Parse a C++0x decltype specifier.
|
|
|
|
///
|
|
|
|
/// 'decltype' ( expression )
|
|
|
|
///
|
|
|
|
void Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
|
|
|
|
assert(Tok.is(tok::kw_decltype) && "Not a decltype specifier");
|
|
|
|
|
|
|
|
SourceLocation StartLoc = ConsumeToken();
|
|
|
|
SourceLocation LParenLoc = Tok.getLocation();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
|
2009-06-25 01:47:40 +08:00
|
|
|
"decltype")) {
|
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-25 01:47:40 +08:00
|
|
|
// Parse the expression
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-25 01:47:40 +08:00
|
|
|
// C++0x [dcl.type.simple]p4:
|
|
|
|
// The operand of the decltype specifier is an unevaluated operand.
|
|
|
|
EnterExpressionEvaluationContext Unevaluated(Actions,
|
|
|
|
Action::Unevaluated);
|
|
|
|
OwningExprResult Result = ParseExpression();
|
|
|
|
if (Result.isInvalid()) {
|
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-25 01:47:40 +08:00
|
|
|
// Match the ')'
|
|
|
|
SourceLocation RParenLoc;
|
|
|
|
if (Tok.is(tok::r_paren))
|
|
|
|
RParenLoc = ConsumeParen();
|
|
|
|
else
|
|
|
|
MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-25 01:47:40 +08:00
|
|
|
if (RParenLoc.isInvalid())
|
|
|
|
return;
|
|
|
|
|
|
|
|
const char *PrevSpec = 0;
|
2009-08-04 04:12:06 +08:00
|
|
|
unsigned DiagID;
|
2009-06-25 01:47:40 +08:00
|
|
|
// Check for duplicate type specifiers (e.g. "int decltype(a)").
|
2009-09-09 23:08:12 +08:00
|
|
|
if (DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec,
|
2009-08-04 04:12:06 +08:00
|
|
|
DiagID, Result.release()))
|
|
|
|
Diag(StartLoc, DiagID) << PrevSpec;
|
2009-06-25 01:47:40 +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
|
2009-09-09 23:08:12 +08:00
|
|
|
///
|
2009-04-02 05:51:26 +08:00
|
|
|
Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
|
2010-04-09 00:38:48 +08:00
|
|
|
CXXScopeSpec *SS) {
|
2009-02-26 07:52:28 +08:00
|
|
|
// Check whether we have a template-id that names a type.
|
|
|
|
if (Tok.is(tok::annot_template_id)) {
|
2009-09-09 23:08:12 +08:00
|
|
|
TemplateIdAnnotation *TemplateId
|
2009-02-26 07:52:28 +08:00
|
|
|
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
|
2010-01-13 01:52:59 +08:00
|
|
|
if (TemplateId->Kind == TNK_Type_template ||
|
|
|
|
TemplateId->Kind == TNK_Dependent_template_name) {
|
2009-04-02 05:51:26 +08:00
|
|
|
AnnotateTemplateIdTokenAsType(SS);
|
2009-02-26 07:52:28 +08:00
|
|
|
|
|
|
|
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
|
|
|
|
TypeTy *Type = Tok.getAnnotationValue();
|
|
|
|
EndLocation = Tok.getAnnotationEndLoc();
|
|
|
|
ConsumeToken();
|
2009-04-02 05:51:26 +08:00
|
|
|
|
|
|
|
if (Type)
|
|
|
|
return Type;
|
|
|
|
return true;
|
2009-02-26 07:52:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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);
|
2009-04-02 05:51:26 +08:00
|
|
|
return true;
|
2008-11-06 04:51:48 +08:00
|
|
|
}
|
|
|
|
|
2010-01-13 05:28:44 +08:00
|
|
|
IdentifierInfo *Id = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation IdLoc = ConsumeToken();
|
|
|
|
|
|
|
|
if (Tok.is(tok::less)) {
|
|
|
|
// It looks the user intended to write a template-id here, but the
|
|
|
|
// template-name was wrong. Try to fix that.
|
|
|
|
TemplateNameKind TNK = TNK_Type_template;
|
|
|
|
TemplateTy Template;
|
|
|
|
if (!Actions.DiagnoseUnknownTemplateName(*Id, IdLoc, CurScope,
|
|
|
|
SS, Template, TNK)) {
|
|
|
|
Diag(IdLoc, diag::err_unknown_template_name)
|
|
|
|
<< Id;
|
|
|
|
}
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2010-01-13 05:28:44 +08:00
|
|
|
if (!Template)
|
|
|
|
return true;
|
|
|
|
|
2010-03-13 18:17:05 +08:00
|
|
|
// Form the template name
|
2010-01-13 05:28:44 +08:00
|
|
|
UnqualifiedId TemplateName;
|
|
|
|
TemplateName.setIdentifier(Id, IdLoc);
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2010-01-13 05:28:44 +08:00
|
|
|
// Parse the full template-id, then turn it into a type.
|
|
|
|
if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName,
|
|
|
|
SourceLocation(), true))
|
|
|
|
return true;
|
|
|
|
if (TNK == TNK_Dependent_template_name)
|
|
|
|
AnnotateTemplateIdTokenAsType(SS);
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2010-01-13 05:28:44 +08:00
|
|
|
// If we didn't end up with a typename token, there's nothing more we
|
|
|
|
// can do.
|
|
|
|
if (Tok.isNot(tok::annot_typename))
|
|
|
|
return true;
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2010-01-13 05:28:44 +08:00
|
|
|
// Retrieve the type from the annotation token, consume that token, and
|
|
|
|
// return.
|
|
|
|
EndLocation = Tok.getAnnotationEndLoc();
|
|
|
|
TypeTy *Type = Tok.getAnnotationValue();
|
|
|
|
ConsumeToken();
|
|
|
|
return Type;
|
|
|
|
}
|
|
|
|
|
2008-11-06 04:51:48 +08:00
|
|
|
// We have an identifier; check whether it is actually a type.
|
2010-01-13 05:28:44 +08:00
|
|
|
TypeTy *Type = Actions.getTypeName(*Id, IdLoc, CurScope, SS, true);
|
2010-03-13 18:17:05 +08:00
|
|
|
if (!Type) {
|
2010-02-17 03:09:40 +08:00
|
|
|
Diag(IdLoc, diag::err_expected_class_name);
|
2009-04-02 05:51:26 +08:00
|
|
|
return true;
|
2008-11-06 04:51:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Consume the identifier.
|
2010-01-13 05:28:44 +08:00
|
|
|
EndLocation = IdLoc;
|
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
|
2010-02-04 05:21:43 +08:00
|
|
|
/// cannot start a definition. If SuppressDeclarations is true, we do know.
|
2008-04-14 05:30:24 +08:00
|
|
|
///
|
|
|
|
/// 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]
|
2009-09-09 23:08:12 +08:00
|
|
|
/// [GNU] class-key attributes[opt] nested-name-specifier
|
2008-04-14 05:30:24 +08:00
|
|
|
/// identifier base-clause[opt]
|
2009-09-09 23:08:12 +08:00
|
|
|
/// [GNU] class-key attributes[opt] nested-name-specifier[opt]
|
2008-04-14 05:30:24 +08:00
|
|
|
/// simple-template-id base-clause[opt]
|
|
|
|
/// class-key:
|
|
|
|
/// 'class'
|
|
|
|
/// 'struct'
|
|
|
|
/// 'union'
|
|
|
|
///
|
|
|
|
/// elaborated-type-specifier: [C++ dcl.type.elab]
|
2009-09-09 23:08:12 +08:00
|
|
|
/// class-key ::[opt] nested-name-specifier[opt] identifier
|
|
|
|
/// class-key ::[opt] nested-name-specifier[opt] 'template'[opt]
|
|
|
|
/// simple-template-id
|
2008-04-14 05:30:24 +08:00
|
|
|
///
|
|
|
|
/// 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'
|
2009-04-13 05:49:30 +08:00
|
|
|
void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|
|
|
SourceLocation StartLoc, DeclSpec &DS,
|
2009-05-13 07:25:50 +08:00
|
|
|
const ParsedTemplateInfo &TemplateInfo,
|
2010-02-04 05:21:43 +08:00
|
|
|
AccessSpecifier AS, bool SuppressDeclarations){
|
2009-04-13 05:49:30 +08:00
|
|
|
DeclSpec::TST TagType;
|
|
|
|
if (TagTokKind == tok::kw_struct)
|
|
|
|
TagType = DeclSpec::TST_struct;
|
|
|
|
else if (TagTokKind == tok::kw_class)
|
|
|
|
TagType = DeclSpec::TST_class;
|
|
|
|
else {
|
|
|
|
assert(TagTokKind == tok::kw_union && "Not a class specifier");
|
|
|
|
TagType = DeclSpec::TST_union;
|
|
|
|
}
|
2008-04-14 05:30:24 +08:00
|
|
|
|
2009-09-18 23:37:17 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
|
|
|
// Code completion for a struct, class, or union name.
|
|
|
|
Actions.CodeCompleteTag(CurScope, TagType);
|
2010-05-25 13:58:43 +08:00
|
|
|
ConsumeCodeCompletionToken();
|
2009-09-18 23:37:17 +08:00
|
|
|
}
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2009-11-21 16:43:09 +08:00
|
|
|
AttributeList *AttrList = 0;
|
2008-04-14 05:30:24 +08:00
|
|
|
// If attributes exist after tag, parse them.
|
|
|
|
if (Tok.is(tok::kw___attribute))
|
2009-11-21 16:43:09 +08:00
|
|
|
AttrList = ParseGNUAttributes();
|
2008-04-14 05:30:24 +08:00
|
|
|
|
2008-12-25 04:59:21 +08:00
|
|
|
// If declspecs exist after tag, parse them.
|
2009-06-09 07:27:34 +08:00
|
|
|
if (Tok.is(tok::kw___declspec))
|
2009-11-21 16:43:09 +08:00
|
|
|
AttrList = ParseMicrosoftDeclSpec(AttrList);
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2009-11-21 16:43:09 +08:00
|
|
|
// If C++0x attributes exist here, parse them.
|
|
|
|
// FIXME: Are we consistent with the ordering of parsing of different
|
|
|
|
// styles of attributes?
|
|
|
|
if (isCXX0XAttributeSpecifier())
|
|
|
|
AttrList = addAttributeLists(AttrList, ParseCXX0XAttributes().AttrList);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-04 13:53:02 +08:00
|
|
|
if (TagType == DeclSpec::TST_struct && Tok.is(tok::kw___is_pod)) {
|
|
|
|
// GNU libstdc++ 4.2 uses __is_pod as the name of a struct template, but
|
|
|
|
// __is_pod is a keyword in GCC >= 4.3. Therefore, when we see the
|
2009-09-09 23:08:12 +08:00
|
|
|
// token sequence "struct __is_pod", make __is_pod into a normal
|
2009-09-04 13:53:02 +08:00
|
|
|
// identifier rather than a keyword, to allow libstdc++ 4.2 to work
|
|
|
|
// properly.
|
|
|
|
Tok.getIdentifierInfo()->setTokenID(tok::identifier);
|
|
|
|
Tok.setKind(tok::identifier);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TagType == DeclSpec::TST_struct && Tok.is(tok::kw___is_empty)) {
|
|
|
|
// GNU libstdc++ 4.2 uses __is_empty as the name of a struct template, but
|
|
|
|
// __is_empty is a keyword in GCC >= 4.3. Therefore, when we see the
|
2009-09-09 23:08:12 +08:00
|
|
|
// token sequence "struct __is_empty", make __is_empty into a normal
|
2009-09-04 13:53:02 +08:00
|
|
|
// identifier rather than a keyword, to allow libstdc++ 4.2 to work
|
|
|
|
// properly.
|
|
|
|
Tok.getIdentifierInfo()->setTokenID(tok::identifier);
|
|
|
|
Tok.setKind(tok::identifier);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-11-09 00:45:02 +08:00
|
|
|
// Parse the (optional) nested-name-specifier.
|
2009-12-12 19:40:51 +08:00
|
|
|
CXXScopeSpec &SS = DS.getTypeSpecScope();
|
2009-12-10 08:32:41 +08:00
|
|
|
if (getLang().CPlusPlus) {
|
|
|
|
// "FOO : BAR" is not a potential typo for "FOO::BAR".
|
|
|
|
ColonProtectionRAIIObject X(*this);
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2010-02-26 16:45:28 +08:00
|
|
|
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true);
|
|
|
|
if (SS.isSet())
|
2009-12-10 08:32:41 +08:00
|
|
|
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
|
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
}
|
2009-02-18 07:15:12 +08:00
|
|
|
|
2009-10-31 05:46:58 +08:00
|
|
|
TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
|
|
|
|
|
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();
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2009-10-31 05:46:58 +08:00
|
|
|
if (Tok.is(tok::less)) {
|
2010-03-13 18:17:05 +08:00
|
|
|
// The name was supposed to refer to a template, but didn't.
|
2009-10-31 05:46:58 +08:00
|
|
|
// Eat the template argument list and try to continue parsing this as
|
|
|
|
// a class (or template thereof).
|
|
|
|
TemplateArgList TemplateArgs;
|
|
|
|
SourceLocation LAngleLoc, RAngleLoc;
|
2010-03-13 18:17:05 +08:00
|
|
|
if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, &SS,
|
2009-10-31 05:46:58 +08:00
|
|
|
true, LAngleLoc,
|
2009-11-11 03:49:08 +08:00
|
|
|
TemplateArgs, RAngleLoc)) {
|
2009-10-31 05:46:58 +08:00
|
|
|
// We couldn't parse the template argument list at all, so don't
|
|
|
|
// try to give any location information for the list.
|
|
|
|
LAngleLoc = RAngleLoc = SourceLocation();
|
|
|
|
}
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2009-10-31 05:46:58 +08:00
|
|
|
Diag(NameLoc, diag::err_explicit_spec_non_template)
|
2009-10-31 06:09:44 +08:00
|
|
|
<< (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
|
2009-10-31 05:46:58 +08:00
|
|
|
<< (TagType == DeclSpec::TST_class? 0
|
|
|
|
: TagType == DeclSpec::TST_struct? 1
|
|
|
|
: 2)
|
|
|
|
<< Name
|
|
|
|
<< SourceRange(LAngleLoc, RAngleLoc);
|
2010-03-13 18:17:05 +08:00
|
|
|
|
|
|
|
// Strip off the last template parameter list if it was empty, since
|
2009-10-31 06:09:44 +08:00
|
|
|
// we've removed its template argument list.
|
|
|
|
if (TemplateParams && TemplateInfo.LastParameterListWasEmpty) {
|
|
|
|
if (TemplateParams && TemplateParams->size() > 1) {
|
|
|
|
TemplateParams->pop_back();
|
|
|
|
} else {
|
|
|
|
TemplateParams = 0;
|
2010-03-13 18:17:05 +08:00
|
|
|
const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind
|
2009-10-31 06:09:44 +08:00
|
|
|
= ParsedTemplateInfo::NonTemplate;
|
|
|
|
}
|
|
|
|
} else if (TemplateInfo.Kind
|
|
|
|
== ParsedTemplateInfo::ExplicitInstantiation) {
|
|
|
|
// Pretend this is just a forward declaration.
|
2009-10-31 05:46:58 +08:00
|
|
|
TemplateParams = 0;
|
2010-03-13 18:17:05 +08:00
|
|
|
const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind
|
2009-10-31 05:46:58 +08:00
|
|
|
= ParsedTemplateInfo::NonTemplate;
|
2010-03-13 18:17:05 +08:00
|
|
|
const_cast<ParsedTemplateInfo&>(TemplateInfo).TemplateLoc
|
2009-10-31 06:09:44 +08:00
|
|
|
= SourceLocation();
|
|
|
|
const_cast<ParsedTemplateInfo&>(TemplateInfo).ExternLoc
|
|
|
|
= SourceLocation();
|
2009-10-31 05:46:58 +08:00
|
|
|
}
|
2010-03-13 18:17:05 +08:00
|
|
|
|
|
|
|
|
2009-10-31 05:46:58 +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
|
|
|
} else if (Tok.is(tok::annot_template_id)) {
|
|
|
|
TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
|
|
|
|
NameLoc = ConsumeToken();
|
2009-02-18 07:15:12 +08:00
|
|
|
|
2009-03-31 08:43:58 +08:00
|
|
|
if (TemplateId->Kind != TNK_Type_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
|
|
|
// 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-09-09 23:08: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
|
|
|
}
|
|
|
|
|
2009-08-06 10:15:43 +08:00
|
|
|
// There are four options here. If we have 'struct foo;', then this
|
|
|
|
// is either a forward declaration or a friend declaration, which
|
|
|
|
// have to be treated differently. 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.
|
2010-02-04 05:21:43 +08:00
|
|
|
// However, in some contexts, things look like declarations but are just
|
|
|
|
// references, e.g.
|
|
|
|
// new struct s;
|
|
|
|
// or
|
|
|
|
// &T::operator struct s;
|
|
|
|
// For these, SuppressDeclarations is true.
|
2009-07-31 10:45:11 +08:00
|
|
|
Action::TagUseKind TUK;
|
2010-02-04 05:21:43 +08:00
|
|
|
if (SuppressDeclarations)
|
|
|
|
TUK = Action::TUK_Reference;
|
|
|
|
else if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon))){
|
2009-09-26 14:47:28 +08:00
|
|
|
if (DS.isFriendSpecified()) {
|
|
|
|
// C++ [class.friend]p2:
|
|
|
|
// A class shall not be defined in a friend declaration.
|
|
|
|
Diag(Tok.getLocation(), diag::err_friend_decl_defines_class)
|
|
|
|
<< SourceRange(DS.getFriendSpecLoc());
|
|
|
|
|
|
|
|
// Skip everything up to the semicolon, so that this looks like a proper
|
|
|
|
// friend class (or template thereof) declaration.
|
|
|
|
SkipUntil(tok::semi, true, true);
|
|
|
|
TUK = Action::TUK_Friend;
|
|
|
|
} else {
|
|
|
|
// Okay, this is a class definition.
|
|
|
|
TUK = Action::TUK_Definition;
|
|
|
|
}
|
|
|
|
} else if (Tok.is(tok::semi))
|
2009-08-06 10:15:43 +08:00
|
|
|
TUK = DS.isFriendSpecified() ? Action::TUK_Friend : Action::TUK_Declaration;
|
2008-04-14 05:30:24 +08:00
|
|
|
else
|
2009-07-31 10:45:11 +08:00
|
|
|
TUK = Action::TUK_Reference;
|
2008-04-14 05:30:24 +08:00
|
|
|
|
2009-07-31 10:45:11 +08:00
|
|
|
if (!Name && !TemplateId && TUK != Action::TUK_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
|
|
|
|
|
|
|
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-09-11 12:59:25 +08:00
|
|
|
Action::DeclResult TagOrTempResult = true; // invalid
|
|
|
|
Action::TypeResult TypeResult = true; // invalid
|
2009-05-13 07:25:50 +08:00
|
|
|
|
When we parse a tag specifier, keep track of whether that tag
specifier resulted in the creation of a new TagDecl node, which
happens either when the tag specifier was a definition or when the tag
specifier was the first declaration of that tag type. This information
has several uses, the first of which is implemented in this commit:
1) In C++, one is not allowed to define tag types within a type
specifier (e.g., static_cast<struct S { int x; } *>(0) is
ill-formed) or within the result or parameter types of a
function. We now diagnose this.
2) We can extend DeclGroups to contain information about any tags
that are declared/defined within the declaration specifiers of a
variable, e.g.,
struct Point { int x, y, z; } p;
This will help improve AST printing and template instantiation,
among other things.
3) For C99, we can keep track of whether a tag type is defined
within the type of a parameter, to properly cope with cases like,
e.g.,
int bar(struct T2 { int x; } y) {
struct T2 z;
}
We can also do similar things wherever there is a type specifier,
e.g., to keep track of where the definition of S occurs in this
legal C99 code:
(struct S { int x, y; } *)0
llvm-svn: 72555
2009-05-29 07:31:59 +08:00
|
|
|
bool Owned = false;
|
2009-09-04 09:14:41 +08:00
|
|
|
if (TemplateId) {
|
2009-05-13 07:25:50 +08:00
|
|
|
// Explicit specialization, class template partial specialization,
|
|
|
|
// or explicit instantiation.
|
2009-09-09 23:08:12 +08:00
|
|
|
ASTTemplateArgsPtr TemplateArgsPtr(Actions,
|
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->getTemplateArgs(),
|
|
|
|
TemplateId->NumArgs);
|
2009-05-13 07:25:50 +08:00
|
|
|
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
|
2009-07-31 10:45:11 +08:00
|
|
|
TUK == Action::TUK_Declaration) {
|
2009-05-13 07:25:50 +08:00
|
|
|
// This is an explicit instantiation of a class template.
|
|
|
|
TagOrTempResult
|
2009-09-09 23:08:12 +08:00
|
|
|
= Actions.ActOnExplicitInstantiation(CurScope,
|
2009-09-04 14:33:52 +08:00
|
|
|
TemplateInfo.ExternLoc,
|
2009-09-09 23:08:12 +08:00
|
|
|
TemplateInfo.TemplateLoc,
|
2009-05-13 07:25:50 +08:00
|
|
|
TagType,
|
2009-09-09 23:08:12 +08:00
|
|
|
StartLoc,
|
2009-05-13 07:25:50 +08:00
|
|
|
SS,
|
2009-09-09 23:08:12 +08:00
|
|
|
TemplateTy::make(TemplateId->Template),
|
|
|
|
TemplateId->TemplateNameLoc,
|
|
|
|
TemplateId->LAngleLoc,
|
2009-05-13 07:25:50 +08:00
|
|
|
TemplateArgsPtr,
|
2009-09-09 23:08:12 +08:00
|
|
|
TemplateId->RAngleLoc,
|
2009-11-21 16:43:09 +08:00
|
|
|
AttrList);
|
2010-04-14 08:24:33 +08:00
|
|
|
|
|
|
|
// Friend template-ids are treated as references unless
|
|
|
|
// they have template headers, in which case they're ill-formed
|
|
|
|
// (FIXME: "template <class T> friend class A<T>::B<int>;").
|
|
|
|
// We diagnose this error in ActOnClassTemplateSpecialization.
|
|
|
|
} else if (TUK == Action::TUK_Reference ||
|
|
|
|
(TUK == Action::TUK_Friend &&
|
|
|
|
TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) {
|
2009-09-11 12:59:25 +08:00
|
|
|
TypeResult
|
2009-09-09 01:47:29 +08:00
|
|
|
= Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
|
|
|
|
TemplateId->TemplateNameLoc,
|
|
|
|
TemplateId->LAngleLoc,
|
|
|
|
TemplateArgsPtr,
|
|
|
|
TemplateId->RAngleLoc);
|
|
|
|
|
2009-09-11 12:59:25 +08:00
|
|
|
TypeResult = Actions.ActOnTagTemplateIdType(TypeResult, TUK,
|
|
|
|
TagType, StartLoc);
|
2009-05-13 07:25:50 +08:00
|
|
|
} else {
|
|
|
|
// This is an explicit specialization or a class template
|
|
|
|
// partial specialization.
|
|
|
|
TemplateParameterLists FakedParamLists;
|
|
|
|
|
|
|
|
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
|
|
|
|
// This looks like an explicit instantiation, because we have
|
|
|
|
// something like
|
|
|
|
//
|
|
|
|
// template class Foo<X>
|
|
|
|
//
|
2009-05-14 08:28:11 +08:00
|
|
|
// but it actually has a definition. Most likely, this was
|
2009-05-13 07:25:50 +08:00
|
|
|
// meant to be an explicit specialization, but the user forgot
|
|
|
|
// the '<>' after 'template'.
|
2009-07-31 10:45:11 +08:00
|
|
|
assert(TUK == Action::TUK_Definition && "Expected a definition here");
|
2009-05-13 07:25:50 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
SourceLocation LAngleLoc
|
2009-05-13 07:25:50 +08:00
|
|
|
= PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
|
2009-09-09 23:08:12 +08:00
|
|
|
Diag(TemplateId->TemplateNameLoc,
|
2009-05-13 07:25:50 +08:00
|
|
|
diag::err_explicit_instantiation_with_definition)
|
|
|
|
<< SourceRange(TemplateInfo.TemplateLoc)
|
2010-04-01 01:46:05 +08:00
|
|
|
<< FixItHint::CreateInsertion(LAngleLoc, "<>");
|
2009-05-13 07:25:50 +08:00
|
|
|
|
|
|
|
// Create a fake template parameter list that contains only
|
|
|
|
// "template<>", so that we treat this construct as a class
|
|
|
|
// template specialization.
|
|
|
|
FakedParamLists.push_back(
|
2009-09-09 23:08:12 +08:00
|
|
|
Actions.ActOnTemplateParameterList(0, SourceLocation(),
|
2009-05-13 07:25:50 +08:00
|
|
|
TemplateInfo.TemplateLoc,
|
2009-09-09 23:08:12 +08:00
|
|
|
LAngleLoc,
|
|
|
|
0, 0,
|
2009-05-13 07:25:50 +08:00
|
|
|
LAngleLoc));
|
|
|
|
TemplateParams = &FakedParamLists;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build the class template specialization.
|
|
|
|
TagOrTempResult
|
2009-07-31 10:45:11 +08:00
|
|
|
= Actions.ActOnClassTemplateSpecialization(CurScope, TagType, TUK,
|
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-09-09 23:08:12 +08:00
|
|
|
TemplateTy::make(TemplateId->Template),
|
|
|
|
TemplateId->TemplateNameLoc,
|
|
|
|
TemplateId->LAngleLoc,
|
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
|
|
|
TemplateArgsPtr,
|
2009-09-09 23:08:12 +08:00
|
|
|
TemplateId->RAngleLoc,
|
2009-11-21 16:43:09 +08:00
|
|
|
AttrList,
|
2009-09-09 23:08:12 +08:00
|
|
|
Action::MultiTemplateParamsArg(Actions,
|
2009-02-18 07:15:12 +08:00
|
|
|
TemplateParams? &(*TemplateParams)[0] : 0,
|
|
|
|
TemplateParams? TemplateParams->size() : 0));
|
2009-05-13 07:25:50 +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
|
|
|
TemplateId->Destroy();
|
2009-05-14 08:28:11 +08:00
|
|
|
} else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
|
2009-07-31 10:45:11 +08:00
|
|
|
TUK == Action::TUK_Declaration) {
|
2009-05-14 08:28:11 +08:00
|
|
|
// Explicit instantiation of a member of a class template
|
|
|
|
// specialization, e.g.,
|
|
|
|
//
|
|
|
|
// template struct Outer<int>::Inner;
|
|
|
|
//
|
|
|
|
TagOrTempResult
|
2009-09-09 23:08:12 +08:00
|
|
|
= Actions.ActOnExplicitInstantiation(CurScope,
|
2009-09-04 14:33:52 +08:00
|
|
|
TemplateInfo.ExternLoc,
|
2009-09-09 23:08:12 +08:00
|
|
|
TemplateInfo.TemplateLoc,
|
|
|
|
TagType, StartLoc, SS, Name,
|
2009-11-21 16:43:09 +08:00
|
|
|
NameLoc, AttrList);
|
2009-05-14 08:28:11 +08:00
|
|
|
} else {
|
|
|
|
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
|
2009-07-31 10:45:11 +08:00
|
|
|
TUK == Action::TUK_Definition) {
|
2009-05-14 08:28:11 +08:00
|
|
|
// FIXME: Diagnose this particular error.
|
|
|
|
}
|
|
|
|
|
2009-09-11 12:59:25 +08:00
|
|
|
bool IsDependent = false;
|
|
|
|
|
2009-05-14 08:28:11 +08:00
|
|
|
// Declaration or definition of a class type
|
2009-09-09 23:08:12 +08:00
|
|
|
TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TUK, StartLoc, SS,
|
2009-11-21 16:43:09 +08:00
|
|
|
Name, NameLoc, AttrList, AS,
|
2009-09-09 23:08:12 +08:00
|
|
|
Action::MultiTemplateParamsArg(Actions,
|
2009-07-23 07:48:44 +08:00
|
|
|
TemplateParams? &(*TemplateParams)[0] : 0,
|
|
|
|
TemplateParams? TemplateParams->size() : 0),
|
2009-09-11 12:59:25 +08:00
|
|
|
Owned, IsDependent);
|
|
|
|
|
|
|
|
// If ActOnTag said the type was dependent, try again with the
|
|
|
|
// less common call.
|
|
|
|
if (IsDependent)
|
|
|
|
TypeResult = Actions.ActOnDependentTag(CurScope, TagType, TUK,
|
2010-03-13 18:17:05 +08:00
|
|
|
SS, Name, StartLoc, NameLoc);
|
2009-05-14 08:28:11 +08:00
|
|
|
}
|
2008-04-14 05:30:24 +08:00
|
|
|
|
|
|
|
// If there is a body, parse it and inform the actions module.
|
2009-12-20 05:48:58 +08:00
|
|
|
if (TUK == Action::TUK_Definition) {
|
|
|
|
assert(Tok.is(tok::l_brace) ||
|
|
|
|
(getLang().CPlusPlus && Tok.is(tok::colon)));
|
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
|
|
|
}
|
|
|
|
|
2009-09-11 12:59:25 +08:00
|
|
|
void *Result;
|
|
|
|
if (!TypeResult.isInvalid()) {
|
|
|
|
TagType = DeclSpec::TST_typename;
|
|
|
|
Result = TypeResult.get();
|
|
|
|
Owned = false;
|
|
|
|
} else if (!TagOrTempResult.isInvalid()) {
|
|
|
|
Result = TagOrTempResult.get().getAs<void>();
|
|
|
|
} else {
|
2009-02-07 06:42:48 +08:00
|
|
|
DS.SetTypeSpecError();
|
2009-05-12 06:27:47 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-04 04:12:06 +08:00
|
|
|
const char *PrevSpec = 0;
|
|
|
|
unsigned DiagID;
|
2009-09-11 12:59:25 +08:00
|
|
|
|
2010-01-26 00:33:23 +08:00
|
|
|
// FIXME: The DeclSpec should keep the locations of both the keyword and the
|
|
|
|
// name (if there is one).
|
|
|
|
SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc;
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2010-01-26 00:33:23 +08:00
|
|
|
if (DS.SetTypeSpecType(TagType, TSTLoc, PrevSpec, DiagID,
|
2009-09-11 12:59:25 +08:00
|
|
|
Result, Owned))
|
2009-08-04 04:12:06 +08:00
|
|
|
Diag(StartLoc, DiagID) << PrevSpec;
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2010-02-02 09:23:29 +08:00
|
|
|
// At this point, we've successfully parsed a class-specifier in 'definition'
|
|
|
|
// form (e.g. "struct foo { int x; }". While we could just return here, we're
|
|
|
|
// going to look at what comes after it to improve error recovery. If an
|
|
|
|
// impossible token occurs next, we assume that the programmer forgot a ; at
|
|
|
|
// the end of the declaration and recover that way.
|
|
|
|
//
|
|
|
|
// This switch enumerates the valid "follow" set for definition.
|
|
|
|
if (TUK == Action::TUK_Definition) {
|
2010-03-01 02:18:36 +08:00
|
|
|
bool ExpectedSemi = true;
|
2010-02-02 09:23:29 +08:00
|
|
|
switch (Tok.getKind()) {
|
2010-03-01 02:18:36 +08:00
|
|
|
default: break;
|
2010-02-02 09:23:29 +08:00
|
|
|
case tok::semi: // struct foo {...} ;
|
2010-02-03 01:32:27 +08:00
|
|
|
case tok::star: // struct foo {...} * P;
|
|
|
|
case tok::amp: // struct foo {...} & R = ...
|
|
|
|
case tok::identifier: // struct foo {...} V ;
|
|
|
|
case tok::r_paren: //(struct foo {...} ) {4}
|
|
|
|
case tok::annot_cxxscope: // struct foo {...} a:: b;
|
|
|
|
case tok::annot_typename: // struct foo {...} a ::b;
|
|
|
|
case tok::annot_template_id: // struct foo {...} a<int> ::b;
|
2010-02-04 04:41:24 +08:00
|
|
|
case tok::l_paren: // struct foo {...} ( x);
|
2010-02-03 09:45:03 +08:00
|
|
|
case tok::comma: // __builtin_offsetof(struct foo{...} ,
|
2010-03-01 02:18:36 +08:00
|
|
|
ExpectedSemi = false;
|
|
|
|
break;
|
|
|
|
// Type qualifiers
|
|
|
|
case tok::kw_const: // struct foo {...} const x;
|
|
|
|
case tok::kw_volatile: // struct foo {...} volatile x;
|
|
|
|
case tok::kw_restrict: // struct foo {...} restrict x;
|
|
|
|
case tok::kw_inline: // struct foo {...} inline foo() {};
|
2010-02-03 01:32:27 +08:00
|
|
|
// Storage-class specifiers
|
|
|
|
case tok::kw_static: // struct foo {...} static x;
|
|
|
|
case tok::kw_extern: // struct foo {...} extern x;
|
|
|
|
case tok::kw_typedef: // struct foo {...} typedef x;
|
|
|
|
case tok::kw_register: // struct foo {...} register x;
|
|
|
|
case tok::kw_auto: // struct foo {...} auto x;
|
2010-05-18 02:19:56 +08:00
|
|
|
case tok::kw_mutable: // struct foo {...} mutable x;
|
2010-03-01 02:18:36 +08:00
|
|
|
// As shown above, type qualifiers and storage class specifiers absolutely
|
|
|
|
// can occur after class specifiers according to the grammar. However,
|
|
|
|
// almost noone actually writes code like this. If we see one of these,
|
|
|
|
// it is much more likely that someone missed a semi colon and the
|
|
|
|
// type/storage class specifier we're seeing is part of the *next*
|
|
|
|
// intended declaration, as in:
|
|
|
|
//
|
|
|
|
// struct foo { ... }
|
|
|
|
// typedef int X;
|
|
|
|
//
|
|
|
|
// We'd really like to emit a missing semicolon error instead of emitting
|
|
|
|
// an error on the 'int' saying that you can't have two type specifiers in
|
|
|
|
// the same declaration of X. Because of this, we look ahead past this
|
|
|
|
// token to see if it's a type specifier. If so, we know the code is
|
|
|
|
// otherwise invalid, so we can produce the expected semi error.
|
|
|
|
if (!isKnownToBeTypeSpecifier(NextToken()))
|
|
|
|
ExpectedSemi = false;
|
2010-02-02 09:23:29 +08:00
|
|
|
break;
|
2010-03-13 18:17:05 +08:00
|
|
|
|
|
|
|
case tok::r_brace: // struct bar { struct foo {...} }
|
2010-02-02 09:23:29 +08:00
|
|
|
// Missing ';' at end of struct is accepted as an extension in C mode.
|
2010-03-01 02:18:36 +08:00
|
|
|
if (!getLang().CPlusPlus)
|
|
|
|
ExpectedSemi = false;
|
|
|
|
break;
|
|
|
|
}
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2010-03-01 02:18:36 +08:00
|
|
|
if (ExpectedSemi) {
|
2010-02-02 09:23:29 +08:00
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
|
|
|
|
TagType == DeclSpec::TST_class ? "class"
|
|
|
|
: TagType == DeclSpec::TST_struct? "struct" : "union");
|
|
|
|
// Push this token back into the preprocessor and change our current token
|
|
|
|
// to ';' so that the rest of the code recovers as though there were an
|
|
|
|
// ';' after the definition.
|
|
|
|
PP.EnterToken(Tok);
|
2010-03-13 18:17:05 +08:00
|
|
|
Tok.setKind(tok::semi);
|
2010-02-02 09:23:29 +08:00
|
|
|
}
|
|
|
|
}
|
2008-04-14 05:30:24 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
/// ParseBaseClause - Parse the base-clause of a C++ class [C++ class.derived].
|
2008-04-14 05:30:24 +08:00
|
|
|
///
|
|
|
|
/// 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;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-14 05:30:24 +08:00
|
|
|
// Consume the comma.
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
2008-10-23 01:49:05 +08:00
|
|
|
|
|
|
|
// Attach the base specifiers
|
2009-05-21 17:52:38 +08:00
|
|
|
Actions.ActOnBaseSpecifiers(ClassDecl, BaseInfo.data(), 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();
|
2010-01-23 08:46:32 +08:00
|
|
|
if (Access != AS_none)
|
2008-04-14 05:30:24 +08:00
|
|
|
ConsumeToken();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-14 05:30:24 +08:00
|
|
|
// 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)
|
2010-04-01 01:46:05 +08:00
|
|
|
<< FixItHint::CreateRemoval(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;
|
2010-03-13 18:17:05 +08:00
|
|
|
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0,
|
2010-03-02 08:25:00 +08:00
|
|
|
/*EnteringContext=*/false);
|
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;
|
2009-04-02 05:51:26 +08:00
|
|
|
TypeResult BaseType = ParseClassName(EndLocation, &SS);
|
|
|
|
if (BaseType.isInvalid())
|
2008-11-06 04:51:48 +08:00
|
|
|
return true;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
// Find the complete source range for the base-specifier.
|
2009-02-26 07:52:28 +08:00
|
|
|
SourceRange Range(StartLoc, EndLocation);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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,
|
2009-04-02 05:51:26 +08:00
|
|
|
BaseType.get(), 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'
|
2009-09-09 23:08:12 +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
|
|
|
|
2009-07-23 05:45:50 +08:00
|
|
|
void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo,
|
|
|
|
DeclPtrTy ThisDecl) {
|
|
|
|
// We just declared a member function. If this member function
|
|
|
|
// has any default arguments, we'll need to parse them later.
|
|
|
|
LateParsedMethodDeclaration *LateMethod = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
DeclaratorChunk::FunctionTypeInfo &FTI
|
2009-07-23 05:45:50 +08:00
|
|
|
= 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.
|
|
|
|
getCurrentClass().MethodDecls.push_back(
|
|
|
|
LateParsedMethodDeclaration(ThisDecl));
|
|
|
|
LateMethod = &getCurrentClass().MethodDecls.back();
|
2009-08-22 08:34:47 +08:00
|
|
|
LateMethod->TemplateScope = CurScope->isTemplateParamScope();
|
2009-07-23 05:45:50 +08:00
|
|
|
|
|
|
|
// 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(
|
2010-03-02 09:29:43 +08:00
|
|
|
LateParsedDefaultArgument(FTI.ArgInfo[I].Param));
|
2009-07-23 05:45:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
/// 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
|
|
|
|
///
|
2009-04-13 01:16:29 +08:00
|
|
|
/// pure-specifier:
|
2008-06-25 06:12:16 +08:00
|
|
|
/// '= 0'
|
|
|
|
///
|
|
|
|
/// constant-initializer:
|
|
|
|
/// '=' constant-expression
|
|
|
|
///
|
2009-08-21 06:52:58 +08:00
|
|
|
void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
|
|
|
const ParsedTemplateInfo &TemplateInfo) {
|
2009-12-11 10:10:03 +08:00
|
|
|
// Access declarations.
|
|
|
|
if (!TemplateInfo.Kind &&
|
|
|
|
(Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) &&
|
2010-02-26 16:45:28 +08:00
|
|
|
!TryAnnotateCXXScopeToken() &&
|
2009-12-11 10:10:03 +08:00
|
|
|
Tok.is(tok::annot_cxxscope)) {
|
|
|
|
bool isAccessDecl = false;
|
|
|
|
if (NextToken().is(tok::identifier))
|
|
|
|
isAccessDecl = GetLookAheadToken(2).is(tok::semi);
|
|
|
|
else
|
|
|
|
isAccessDecl = NextToken().is(tok::kw_operator);
|
|
|
|
|
|
|
|
if (isAccessDecl) {
|
|
|
|
// Collect the scope specifier token we annotated earlier.
|
|
|
|
CXXScopeSpec SS;
|
|
|
|
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType*/ 0, false);
|
|
|
|
|
|
|
|
// Try to parse an unqualified-id.
|
|
|
|
UnqualifiedId Name;
|
|
|
|
if (ParseUnqualifiedId(SS, false, true, true, /*ObjectType*/ 0, Name)) {
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: recover from mistakenly-qualified operator declarations.
|
|
|
|
if (ExpectAndConsume(tok::semi,
|
|
|
|
diag::err_expected_semi_after,
|
|
|
|
"access declaration",
|
|
|
|
tok::semi))
|
|
|
|
return;
|
|
|
|
|
|
|
|
Actions.ActOnUsingDeclaration(CurScope, AS,
|
|
|
|
false, SourceLocation(),
|
|
|
|
SS, Name,
|
|
|
|
/* AttrList */ 0,
|
|
|
|
/* IsTypeName */ false,
|
|
|
|
SourceLocation());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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)) {
|
2009-08-21 06:52:58 +08:00
|
|
|
// FIXME: Check for templates
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
SourceLocation DeclEnd;
|
|
|
|
ParseStaticAssertDeclaration(DeclEnd);
|
2009-03-30 00:50:03 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-30 00:50:03 +08:00
|
|
|
if (Tok.is(tok::kw_template)) {
|
2009-09-09 23:08:12 +08:00
|
|
|
assert(!TemplateInfo.TemplateParams &&
|
2009-08-21 06:52:58 +08:00
|
|
|
"Nested template improperly parsed?");
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
SourceLocation DeclEnd;
|
2009-09-09 23:08:12 +08:00
|
|
|
ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd,
|
2009-05-13 07:25:50 +08:00
|
|
|
AS);
|
2009-03-30 00:50:03 +08:00
|
|
|
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();
|
2009-08-21 06:52:58 +08:00
|
|
|
return ParseCXXClassMemberDeclaration(AS, TemplateInfo);
|
2008-12-18 09:12:00 +08:00
|
|
|
}
|
2009-06-20 08:51:54 +08:00
|
|
|
|
2010-02-02 09:23:29 +08:00
|
|
|
// Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it
|
|
|
|
// is a bitfield.
|
2009-12-10 09:59:24 +08:00
|
|
|
ColonProtectionRAIIObject X(*this);
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2009-11-21 16:43:09 +08:00
|
|
|
CXX0XAttributeList AttrList;
|
|
|
|
// Optional C++0x attribute-specifier
|
2009-12-10 09:59:24 +08:00
|
|
|
if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
|
2009-11-21 16:43:09 +08:00
|
|
|
AttrList = ParseCXX0XAttributes();
|
|
|
|
|
2009-06-20 08:51:54 +08:00
|
|
|
if (Tok.is(tok::kw_using)) {
|
2009-08-21 06:52:58 +08:00
|
|
|
// FIXME: Check for template aliases
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2009-11-21 16:43:09 +08:00
|
|
|
if (AttrList.HasAttr)
|
|
|
|
Diag(AttrList.Range.getBegin(), diag::err_attributes_not_allowed)
|
|
|
|
<< AttrList.Range;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 08:51:54 +08:00
|
|
|
// Eat 'using'.
|
|
|
|
SourceLocation UsingLoc = ConsumeToken();
|
|
|
|
|
|
|
|
if (Tok.is(tok::kw_namespace)) {
|
|
|
|
Diag(UsingLoc, diag::err_using_namespace_in_class);
|
|
|
|
SkipUntil(tok::semi, true, true);
|
2010-02-02 08:43:15 +08:00
|
|
|
} else {
|
2009-06-20 08:51:54 +08:00
|
|
|
SourceLocation DeclEnd;
|
|
|
|
// Otherwise, it must be using-declaration.
|
2009-08-30 03:54:19 +08:00
|
|
|
ParseUsingDeclaration(Declarator::MemberContext, UsingLoc, DeclEnd, AS);
|
2009-06-20 08:51:54 +08:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-06-25 06:12:16 +08:00
|
|
|
SourceLocation DSStart = Tok.getLocation();
|
|
|
|
// decl-specifier-seq:
|
|
|
|
// Parse the common declaration-specifiers piece.
|
2009-11-04 10:18:39 +08:00
|
|
|
ParsingDeclSpec DS(*this);
|
2009-11-21 16:43:09 +08:00
|
|
|
DS.AddAttributes(AttrList.AttrList);
|
2009-08-21 06:52:58 +08:00
|
|
|
ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class);
|
2008-06-25 06:12:16 +08:00
|
|
|
|
2009-09-17 06:47:08 +08:00
|
|
|
Action::MultiTemplateParamsArg TemplateParams(Actions,
|
|
|
|
TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0,
|
|
|
|
TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0);
|
|
|
|
|
2008-06-25 06:12:16 +08:00
|
|
|
if (Tok.is(tok::semi)) {
|
|
|
|
ConsumeToken();
|
2010-05-22 04:45:30 +08:00
|
|
|
Actions.ParsedFreeStandingDeclSpec(CurScope, AS, DS);
|
2009-08-06 10:15:43 +08:00
|
|
|
return;
|
2008-06-25 06:12:16 +08:00
|
|
|
}
|
2008-07-01 18:37:29 +08:00
|
|
|
|
2009-11-04 10:18:39 +08:00
|
|
|
ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext);
|
2008-06-25 06:12:16 +08:00
|
|
|
|
2008-06-28 16:10:48 +08:00
|
|
|
if (Tok.isNot(tok::colon)) {
|
2009-12-10 09:59:24 +08:00
|
|
|
// Don't parse FOO:BAR as if it were a typo for FOO::BAR.
|
|
|
|
ColonProtectionRAIIObject X(*this);
|
|
|
|
|
2008-06-28 16:10:48 +08:00
|
|
|
// 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
|
|
|
}
|
|
|
|
|
2009-11-26 06:58:06 +08:00
|
|
|
// If attributes exist after the declarator, but before an '{', parse them.
|
|
|
|
if (Tok.is(tok::kw___attribute)) {
|
|
|
|
SourceLocation Loc;
|
|
|
|
AttributeList *AttrList = ParseGNUAttributes(&Loc);
|
|
|
|
DeclaratorInfo.AddAttributes(AttrList, Loc);
|
|
|
|
}
|
|
|
|
|
2008-06-28 16:10:48 +08:00
|
|
|
// function-definition:
|
2008-11-05 12:29:56 +08:00
|
|
|
if (Tok.is(tok::l_brace)
|
2009-04-27 04:35:05 +08:00
|
|
|
|| (DeclaratorInfo.isFunctionDeclarator() &&
|
|
|
|
(Tok.is(tok::colon) || Tok.is(tok::kw_try)))) {
|
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-08-21 06:52:58 +08:00
|
|
|
ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
// 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);
|
2009-04-13 01:16:29 +08:00
|
|
|
bool Deleted = false;
|
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);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-25 06:12:16 +08:00
|
|
|
// pure-specifier:
|
|
|
|
// '= 0'
|
|
|
|
//
|
|
|
|
// constant-initializer:
|
|
|
|
// '=' constant-expression
|
2009-04-13 01:16:29 +08:00
|
|
|
//
|
|
|
|
// defaulted/deleted function-definition:
|
|
|
|
// '=' 'default' [TODO]
|
|
|
|
// '=' 'delete'
|
2008-06-25 06:12:16 +08:00
|
|
|
|
|
|
|
if (Tok.is(tok::equal)) {
|
|
|
|
ConsumeToken();
|
2009-04-13 01:16:29 +08:00
|
|
|
if (getLang().CPlusPlus0x && Tok.is(tok::kw_delete)) {
|
|
|
|
ConsumeToken();
|
|
|
|
Deleted = true;
|
|
|
|
} else {
|
|
|
|
Init = ParseInitializer();
|
|
|
|
if (Init.isInvalid())
|
|
|
|
SkipUntil(tok::comma, true, true);
|
|
|
|
}
|
2008-06-25 06:12:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If attributes exist after the declarator, parse them.
|
2009-02-10 02:23:29 +08:00
|
|
|
if (Tok.is(tok::kw___attribute)) {
|
|
|
|
SourceLocation Loc;
|
2009-11-21 16:43:09 +08:00
|
|
|
AttributeList *AttrList = ParseGNUAttributes(&Loc);
|
2009-02-10 02:23:29 +08:00
|
|
|
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-08-06 10:15:43 +08:00
|
|
|
|
|
|
|
DeclPtrTy ThisDecl;
|
|
|
|
if (DS.isFriendSpecified()) {
|
2009-09-12 05:02:39 +08:00
|
|
|
// TODO: handle initializers, bitfields, 'delete'
|
|
|
|
ThisDecl = Actions.ActOnFriendFunctionDecl(CurScope, DeclaratorInfo,
|
|
|
|
/*IsDefinition*/ false,
|
|
|
|
move(TemplateParams));
|
2009-08-21 06:52:58 +08:00
|
|
|
} else {
|
2009-08-06 10:15:43 +08:00
|
|
|
ThisDecl = Actions.ActOnCXXMemberDeclarator(CurScope, AS,
|
|
|
|
DeclaratorInfo,
|
2009-08-21 06:52:58 +08:00
|
|
|
move(TemplateParams),
|
2009-08-06 10:15:43 +08:00
|
|
|
BitfieldSize.release(),
|
|
|
|
Init.release(),
|
2009-11-25 07:38:44 +08:00
|
|
|
/*IsDefinition*/Deleted,
|
2009-08-06 10:15:43 +08:00
|
|
|
Deleted);
|
2009-08-21 06:52:58 +08:00
|
|
|
}
|
2009-03-30 00:50:03 +08:00
|
|
|
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() &&
|
2009-09-09 23:08:12 +08:00
|
|
|
DeclaratorInfo.getDeclSpec().getStorageClassSpec()
|
2008-12-17 05:30:33 +08:00
|
|
|
!= DeclSpec::SCS_typedef) {
|
2009-07-23 05:45:50 +08:00
|
|
|
HandleMemberFunctionDefaultArgs(DeclaratorInfo, ThisDecl);
|
2008-12-17 05:30:33 +08:00
|
|
|
}
|
|
|
|
|
2009-11-04 10:18:39 +08:00
|
|
|
DeclaratorInfo.complete(ThisDecl);
|
|
|
|
|
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;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-25 06:12:16 +08:00
|
|
|
// Consume the comma.
|
|
|
|
ConsumeToken();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-25 06:12:16 +08:00
|
|
|
// Parse the next declarator.
|
|
|
|
DeclaratorInfo.clear();
|
2008-12-10 04:22:58 +08:00
|
|
|
BitfieldSize = 0;
|
|
|
|
Init = 0;
|
2009-04-13 01:16:29 +08:00
|
|
|
Deleted = false;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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;
|
2009-11-21 16:43:09 +08:00
|
|
|
AttributeList *AttrList = ParseGNUAttributes(&Loc);
|
2009-02-10 02:23:29 +08:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2010-02-02 08:43:15 +08:00
|
|
|
if (ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list)) {
|
|
|
|
// Skip to end of block or statement.
|
|
|
|
SkipUntil(tok::r_brace, true, true);
|
|
|
|
// If we stopped at a ';', eat it.
|
|
|
|
if (Tok.is(tok::semi)) ConsumeToken();
|
2009-03-30 00:50:03 +08:00
|
|
|
return;
|
2008-06-25 06:12:16 +08:00
|
|
|
}
|
|
|
|
|
2010-02-02 08:43:15 +08:00
|
|
|
Actions.FinalizeDeclaratorGroup(CurScope, DS, DeclsInGroup.data(),
|
|
|
|
DeclsInGroup.size());
|
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-09-09 23:08:12 +08:00
|
|
|
|
2010-01-17 04:52:59 +08:00
|
|
|
// Determine whether this is a non-nested class. Note that local
|
|
|
|
// classes are *not* considered to be nested classes.
|
|
|
|
bool NonNestedClass = true;
|
|
|
|
if (!ClassStack.empty()) {
|
|
|
|
for (const Scope *S = CurScope; S; S = S->getParent()) {
|
|
|
|
if (S->isClassScope()) {
|
|
|
|
// We're inside a class scope, so this is a nested class.
|
|
|
|
NonNestedClass = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((S->getFlags() & Scope::FnScope)) {
|
|
|
|
// If we're in a function or function template declared in the
|
|
|
|
// body of a class, then this is a local class rather than a
|
|
|
|
// nested class.
|
|
|
|
const Scope *Parent = S->getParent();
|
|
|
|
if (Parent->isTemplateParamScope())
|
|
|
|
Parent = Parent->getParent();
|
|
|
|
if (Parent->isClassScope())
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-06-25 06:12:16 +08:00
|
|
|
|
|
|
|
// 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-05-28 07:11:45 +08:00
|
|
|
// Note that we are parsing a new (potentially-nested) class definition.
|
2010-01-17 04:52:59 +08:00
|
|
|
ParsingClassDefinition ParsingDef(*this, TagDecl, NonNestedClass);
|
2009-05-28 07:11:45 +08:00
|
|
|
|
2009-02-07 06:42:48 +08:00
|
|
|
if (TagDecl)
|
|
|
|
Actions.ActOnTagStartDefinition(CurScope, TagDecl);
|
2009-12-20 05:48:58 +08:00
|
|
|
|
|
|
|
if (Tok.is(tok::colon)) {
|
|
|
|
ParseBaseClause(TagDecl);
|
|
|
|
|
|
|
|
if (!Tok.is(tok::l_brace)) {
|
|
|
|
Diag(Tok, diag::err_expected_lbrace_after_base_specifiers);
|
2010-03-17 08:38:33 +08:00
|
|
|
|
|
|
|
if (TagDecl)
|
|
|
|
Actions.ActOnTagDefinitionError(CurScope, TagDecl);
|
2009-12-20 05:48:58 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(Tok.is(tok::l_brace));
|
|
|
|
|
|
|
|
SourceLocation LBraceLoc = ConsumeBrace();
|
|
|
|
|
2010-05-28 16:11:17 +08:00
|
|
|
if (TagDecl)
|
|
|
|
Actions.ActOnStartCXXMemberDeclarations(CurScope, TagDecl, LBraceLoc);
|
2009-12-20 15:58:13 +08:00
|
|
|
|
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.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-25 06:12:16 +08:00
|
|
|
// Check for extraneous top-level semicolon.
|
|
|
|
if (Tok.is(tok::semi)) {
|
2009-11-06 14:40:12 +08:00
|
|
|
Diag(Tok, diag::ext_extra_struct_semi)
|
2010-04-01 01:46:05 +08:00
|
|
|
<< FixItHint::CreateRemoval(Tok.getLocation());
|
2008-06-25 06:12:16 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-08-21 06:52:58 +08:00
|
|
|
// FIXME: Make sure we don't have a template here.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-25 06:12:16 +08:00
|
|
|
// Parse all the comma separated declarators.
|
|
|
|
ParseCXXClassMemberDeclaration(CurAS);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-25 06:12:16 +08:00
|
|
|
SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-25 06:12:16 +08:00
|
|
|
// If attributes exist after class contents, parse them.
|
2010-02-11 10:19:13 +08:00
|
|
|
llvm::OwningPtr<AttributeList> AttrList;
|
2008-06-25 06:12:16 +08:00
|
|
|
if (Tok.is(tok::kw___attribute))
|
2010-03-29 22:42:08 +08:00
|
|
|
AttrList.reset(ParseGNUAttributes());
|
2008-06-25 06:12:16 +08:00
|
|
|
|
2010-05-28 16:11:17 +08:00
|
|
|
if (TagDecl)
|
|
|
|
Actions.ActOnFinishCXXMemberSpecification(CurScope, RecordLoc, TagDecl,
|
|
|
|
LBraceLoc, RBraceLoc,
|
|
|
|
AttrList.get());
|
2008-06-25 06:12:16 +08:00
|
|
|
|
|
|
|
// 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.
|
2010-01-17 04:52:59 +08:00
|
|
|
if (NonNestedClass) {
|
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.
|
2009-05-28 07:11:45 +08:00
|
|
|
ParseLexedMethodDeclarations(getCurrentClass());
|
|
|
|
ParseLexedMethodDefs(getCurrentClass());
|
2008-06-25 06:12:16 +08:00
|
|
|
}
|
|
|
|
|
2010-05-28 16:11:17 +08:00
|
|
|
if (TagDecl)
|
|
|
|
Actions.ActOnTagFinishDefinition(CurScope, TagDecl, RBraceLoc);
|
2010-03-17 08:38:33 +08:00
|
|
|
|
2008-06-25 06:12:16 +08:00
|
|
|
// Leave the class scope.
|
2009-05-28 07:11:45 +08:00
|
|
|
ParsingDef.Pop();
|
2008-12-10 14:34:36 +08:00
|
|
|
ClassScope.Exit();
|
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
|
|
|
|
///
|
2009-09-09 23:08:12 +08:00
|
|
|
/// [C++] ctor-initializer:
|
|
|
|
/// ':' mem-initializer-list
|
2008-11-05 12:29:56 +08:00
|
|
|
///
|
2009-09-09 23:08:12 +08:00
|
|
|
/// [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();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-11-05 12:29:56 +08:00
|
|
|
llvm::SmallVector<MemInitTy*, 4> MemInitializers;
|
Rework base and member initialization in constructors, with several
(necessarily simultaneous) changes:
- CXXBaseOrMemberInitializer now contains only a single initializer
rather than a set of initialiation arguments + a constructor. The
single initializer covers all aspects of initialization, including
constructor calls as necessary but also cleanup of temporaries
created by the initializer (which we never handled
before!).
- Rework + simplify code generation for CXXBaseOrMemberInitializers,
since we can now just emit the initializer as an initializer.
- Switched base and member initialization over to the new
initialization code (InitializationSequence), so that it
- Improved diagnostics for the new initialization code when
initializing bases and members, to match the diagnostics produced
by the previous (special-purpose) code.
- Simplify the representation of type-checked constructor initializers in
templates; instead of keeping the fully-type-checked AST, which is
rather hard to undo at template instantiation time, throw away the
type-checked AST and store the raw expressions in the AST. This
simplifies instantiation, but loses a little but of information in
the AST.
- When type-checking implicit base or member initializers within a
dependent context, don't add the generated initializers into the
AST, because they'll look like they were explicit.
- Record in CXXConstructExpr when the constructor call is to
initialize a base class, so that CodeGen does not have to infer it
from context. This ensures that we call the right kind of
constructor.
There are also a few "opportunity" fixes here that were needed to not
regress, for example:
- Diagnose default-initialization of a const-qualified class that
does not have a user-declared default constructor. We had this
diagnostic specifically for bases and members, but missed it for
variables. That's fixed now.
- When defining the implicit constructors, destructor, and
copy-assignment operator, set the CurContext to that constructor
when we're defining the body.
llvm-svn: 94952
2010-01-31 17:12:51 +08:00
|
|
|
bool AnyErrors = false;
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2008-11-05 12:29:56 +08:00
|
|
|
do {
|
|
|
|
MemInitResult MemInit = ParseMemInitializer(ConstructorDecl);
|
2009-01-27 06:44:13 +08:00
|
|
|
if (!MemInit.isInvalid())
|
|
|
|
MemInitializers.push_back(MemInit.get());
|
Rework base and member initialization in constructors, with several
(necessarily simultaneous) changes:
- CXXBaseOrMemberInitializer now contains only a single initializer
rather than a set of initialiation arguments + a constructor. The
single initializer covers all aspects of initialization, including
constructor calls as necessary but also cleanup of temporaries
created by the initializer (which we never handled
before!).
- Rework + simplify code generation for CXXBaseOrMemberInitializers,
since we can now just emit the initializer as an initializer.
- Switched base and member initialization over to the new
initialization code (InitializationSequence), so that it
- Improved diagnostics for the new initialization code when
initializing bases and members, to match the diagnostics produced
by the previous (special-purpose) code.
- Simplify the representation of type-checked constructor initializers in
templates; instead of keeping the fully-type-checked AST, which is
rather hard to undo at template instantiation time, throw away the
type-checked AST and store the raw expressions in the AST. This
simplifies instantiation, but loses a little but of information in
the AST.
- When type-checking implicit base or member initializers within a
dependent context, don't add the generated initializers into the
AST, because they'll look like they were explicit.
- Record in CXXConstructExpr when the constructor call is to
initialize a base class, so that CodeGen does not have to infer it
from context. This ensures that we call the right kind of
constructor.
There are also a few "opportunity" fixes here that were needed to not
regress, for example:
- Diagnose default-initialization of a const-qualified class that
does not have a user-declared default constructor. We had this
diagnostic specifically for bases and members, but missed it for
variables. That's fixed now.
- When defining the implicit constructors, destructor, and
copy-assignment operator, set the CurContext to that constructor
when we're defining the body.
llvm-svn: 94952
2010-01-31 17:12:51 +08:00
|
|
|
else
|
|
|
|
AnyErrors = true;
|
2010-03-13 18:17:05 +08:00
|
|
|
|
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 '{'.
|
2009-04-27 04:35:05 +08:00
|
|
|
Diag(Tok.getLocation(), diag::err_expected_lbrace_or_comma);
|
2008-11-05 12:29:56 +08:00
|
|
|
SkipUntil(tok::l_brace, true, true);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (true);
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc,
|
Rework base and member initialization in constructors, with several
(necessarily simultaneous) changes:
- CXXBaseOrMemberInitializer now contains only a single initializer
rather than a set of initialiation arguments + a constructor. The
single initializer covers all aspects of initialization, including
constructor calls as necessary but also cleanup of temporaries
created by the initializer (which we never handled
before!).
- Rework + simplify code generation for CXXBaseOrMemberInitializers,
since we can now just emit the initializer as an initializer.
- Switched base and member initialization over to the new
initialization code (InitializationSequence), so that it
- Improved diagnostics for the new initialization code when
initializing bases and members, to match the diagnostics produced
by the previous (special-purpose) code.
- Simplify the representation of type-checked constructor initializers in
templates; instead of keeping the fully-type-checked AST, which is
rather hard to undo at template instantiation time, throw away the
type-checked AST and store the raw expressions in the AST. This
simplifies instantiation, but loses a little but of information in
the AST.
- When type-checking implicit base or member initializers within a
dependent context, don't add the generated initializers into the
AST, because they'll look like they were explicit.
- Record in CXXConstructExpr when the constructor call is to
initialize a base class, so that CodeGen does not have to infer it
from context. This ensures that we call the right kind of
constructor.
There are also a few "opportunity" fixes here that were needed to not
regress, for example:
- Diagnose default-initialization of a const-qualified class that
does not have a user-declared default constructor. We had this
diagnostic specifically for bases and members, but missed it for
variables. That's fixed now.
- When defining the implicit constructors, destructor, and
copy-assignment operator, set the CurContext to that constructor
when we're defining the body.
llvm-svn: 94952
2010-01-31 17:12:51 +08:00
|
|
|
MemInitializers.data(), MemInitializers.size(),
|
|
|
|
AnyErrors);
|
2008-11-05 12:29:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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] ')'
|
2009-09-09 23:08:12 +08:00
|
|
|
///
|
2008-11-05 12:29:56 +08:00
|
|
|
/// [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) {
|
2009-07-01 07:26:25 +08:00
|
|
|
// parse '::'[opt] nested-name-specifier[opt]
|
|
|
|
CXXScopeSpec SS;
|
2009-09-03 06:59:36 +08:00
|
|
|
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
|
2009-07-02 03:21:19 +08:00
|
|
|
TypeTy *TemplateTypeTy = 0;
|
|
|
|
if (Tok.is(tok::annot_template_id)) {
|
|
|
|
TemplateIdAnnotation *TemplateId
|
|
|
|
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
|
2010-01-13 01:52:59 +08:00
|
|
|
if (TemplateId->Kind == TNK_Type_template ||
|
|
|
|
TemplateId->Kind == TNK_Dependent_template_name) {
|
2009-07-02 03:21:19 +08:00
|
|
|
AnnotateTemplateIdTokenAsType(&SS);
|
|
|
|
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
|
|
|
|
TemplateTypeTy = Tok.getAnnotationValue();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!TemplateTypeTy && 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;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-11-05 12:29:56 +08:00
|
|
|
// Get the identifier. This may be a member name or a class name,
|
|
|
|
// but we'll let the semantic analysis determine which it is.
|
2009-07-02 03:21:19 +08:00
|
|
|
IdentifierInfo *II = Tok.is(tok::identifier) ? Tok.getIdentifierInfo() : 0;
|
2008-11-05 12:29:56 +08:00
|
|
|
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);
|
|
|
|
|
2009-07-02 03:21:19 +08:00
|
|
|
return Actions.ActOnMemInitializer(ConstructorDecl, CurScope, SS, II,
|
|
|
|
TemplateTypeTy, IdLoc,
|
2008-11-26 06:21:31 +08:00
|
|
|
LParenLoc, ArgExprs.take(),
|
2009-05-21 17:52:38 +08:00
|
|
|
ArgExprs.size(), CommaLocs.data(),
|
|
|
|
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' '(' '...' ')'
|
2009-09-09 23:08:12 +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-04-30 01:30:04 +08:00
|
|
|
bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc,
|
2009-05-30 02:02:33 +08:00
|
|
|
llvm::SmallVector<TypeTy*, 2>
|
|
|
|
&Exceptions,
|
|
|
|
llvm::SmallVector<SourceRange, 2>
|
|
|
|
&Ranges,
|
2009-04-30 01:30:04 +08:00
|
|
|
bool &hasAnyExceptionSpec) {
|
2008-11-25 11:22:00 +08:00
|
|
|
assert(Tok.is(tok::kw_throw) && "expected throw");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-11-25 11:22:00 +08:00
|
|
|
SourceLocation ThrowLoc = ConsumeToken();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-11-25 11:22:00 +08:00
|
|
|
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)) {
|
2009-04-30 01:30:04 +08:00
|
|
|
hasAnyExceptionSpec = true;
|
2008-12-02 02:00:20 +08:00
|
|
|
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.
|
2009-05-30 02:02:33 +08:00
|
|
|
SourceRange Range;
|
2008-11-25 11:22:00 +08:00
|
|
|
while (Tok.isNot(tok::r_paren)) {
|
2009-05-30 02:02:33 +08:00
|
|
|
TypeResult Res(ParseTypeName(&Range));
|
|
|
|
if (!Res.isInvalid()) {
|
2009-04-30 01:30:04 +08:00
|
|
|
Exceptions.push_back(Res.get());
|
2009-05-30 02:02:33 +08:00
|
|
|
Ranges.push_back(Range);
|
|
|
|
}
|
2008-11-25 11:22:00 +08:00
|
|
|
if (Tok.is(tok::comma))
|
|
|
|
ConsumeToken();
|
2009-04-30 01:30:04 +08:00
|
|
|
else
|
2008-11-25 11:22:00 +08:00
|
|
|
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;
|
|
|
|
}
|
2009-05-28 07:11:45 +08:00
|
|
|
|
|
|
|
/// \brief We have just started parsing the definition of a new class,
|
|
|
|
/// so push that class onto our stack of classes that is currently
|
|
|
|
/// being parsed.
|
2010-01-17 04:52:59 +08:00
|
|
|
void Parser::PushParsingClass(DeclPtrTy ClassDecl, bool NonNestedClass) {
|
|
|
|
assert((NonNestedClass || !ClassStack.empty()) &&
|
2009-05-28 07:11:45 +08:00
|
|
|
"Nested class without outer class");
|
2010-01-17 04:52:59 +08:00
|
|
|
ClassStack.push(new ParsingClass(ClassDecl, NonNestedClass));
|
2009-05-28 07:11:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Deallocate the given parsed class and all of its nested
|
|
|
|
/// classes.
|
|
|
|
void Parser::DeallocateParsedClasses(Parser::ParsingClass *Class) {
|
|
|
|
for (unsigned I = 0, N = Class->NestedClasses.size(); I != N; ++I)
|
|
|
|
DeallocateParsedClasses(Class->NestedClasses[I]);
|
|
|
|
delete Class;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Pop the top class of the stack of classes that are
|
|
|
|
/// currently being parsed.
|
|
|
|
///
|
|
|
|
/// This routine should be called when we have finished parsing the
|
|
|
|
/// definition of a class, but have not yet popped the Scope
|
|
|
|
/// associated with the class's definition.
|
|
|
|
///
|
|
|
|
/// \returns true if the class we've popped is a top-level class,
|
|
|
|
/// false otherwise.
|
|
|
|
void Parser::PopParsingClass() {
|
|
|
|
assert(!ClassStack.empty() && "Mismatched push/pop for class parsing");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-28 07:11:45 +08:00
|
|
|
ParsingClass *Victim = ClassStack.top();
|
|
|
|
ClassStack.pop();
|
|
|
|
if (Victim->TopLevelClass) {
|
|
|
|
// Deallocate all of the nested classes of this class,
|
|
|
|
// recursively: we don't need to keep any of this information.
|
|
|
|
DeallocateParsedClasses(Victim);
|
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2009-05-28 07:11:45 +08:00
|
|
|
assert(!ClassStack.empty() && "Missing top-level class?");
|
|
|
|
|
|
|
|
if (Victim->MethodDecls.empty() && Victim->MethodDefs.empty() &&
|
|
|
|
Victim->NestedClasses.empty()) {
|
|
|
|
// The victim is a nested class, but we will not need to perform
|
|
|
|
// any processing after the definition of this class since it has
|
|
|
|
// no members whose handling was delayed. Therefore, we can just
|
|
|
|
// remove this nested class.
|
|
|
|
delete Victim;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This nested class has some members that will need to be processed
|
|
|
|
// after the top-level class is completely defined. Therefore, add
|
|
|
|
// it to the list of nested classes within its parent.
|
|
|
|
assert(CurScope->isClassScope() && "Nested class outside of class scope?");
|
|
|
|
ClassStack.top()->NestedClasses.push_back(Victim);
|
|
|
|
Victim->TemplateScope = CurScope->getParent()->isTemplateParamScope();
|
|
|
|
}
|
2009-11-21 16:43:09 +08:00
|
|
|
|
|
|
|
/// ParseCXX0XAttributes - Parse a C++0x attribute-specifier. Currently only
|
|
|
|
/// parses standard attributes.
|
|
|
|
///
|
|
|
|
/// [C++0x] attribute-specifier:
|
|
|
|
/// '[' '[' attribute-list ']' ']'
|
|
|
|
///
|
|
|
|
/// [C++0x] attribute-list:
|
|
|
|
/// attribute[opt]
|
|
|
|
/// attribute-list ',' attribute[opt]
|
|
|
|
///
|
|
|
|
/// [C++0x] attribute:
|
|
|
|
/// attribute-token attribute-argument-clause[opt]
|
|
|
|
///
|
|
|
|
/// [C++0x] attribute-token:
|
|
|
|
/// identifier
|
|
|
|
/// attribute-scoped-token
|
|
|
|
///
|
|
|
|
/// [C++0x] attribute-scoped-token:
|
|
|
|
/// attribute-namespace '::' identifier
|
|
|
|
///
|
|
|
|
/// [C++0x] attribute-namespace:
|
|
|
|
/// identifier
|
|
|
|
///
|
|
|
|
/// [C++0x] attribute-argument-clause:
|
|
|
|
/// '(' balanced-token-seq ')'
|
|
|
|
///
|
|
|
|
/// [C++0x] balanced-token-seq:
|
|
|
|
/// balanced-token
|
|
|
|
/// balanced-token-seq balanced-token
|
|
|
|
///
|
|
|
|
/// [C++0x] balanced-token:
|
|
|
|
/// '(' balanced-token-seq ')'
|
|
|
|
/// '[' balanced-token-seq ']'
|
|
|
|
/// '{' balanced-token-seq '}'
|
|
|
|
/// any token but '(', ')', '[', ']', '{', or '}'
|
|
|
|
CXX0XAttributeList Parser::ParseCXX0XAttributes(SourceLocation *EndLoc) {
|
|
|
|
assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square)
|
|
|
|
&& "Not a C++0x attribute list");
|
|
|
|
|
|
|
|
SourceLocation StartLoc = Tok.getLocation(), Loc;
|
|
|
|
AttributeList *CurrAttr = 0;
|
|
|
|
|
|
|
|
ConsumeBracket();
|
|
|
|
ConsumeBracket();
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2009-11-21 16:43:09 +08:00
|
|
|
if (Tok.is(tok::comma)) {
|
|
|
|
Diag(Tok.getLocation(), diag::err_expected_ident);
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
|
|
|
|
|
|
|
while (Tok.is(tok::identifier) || Tok.is(tok::comma)) {
|
|
|
|
// attribute not present
|
|
|
|
if (Tok.is(tok::comma)) {
|
|
|
|
ConsumeToken();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
IdentifierInfo *ScopeName = 0, *AttrName = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation ScopeLoc, AttrLoc = ConsumeToken();
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2009-11-21 16:43:09 +08:00
|
|
|
// scoped attribute
|
|
|
|
if (Tok.is(tok::coloncolon)) {
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
if (!Tok.is(tok::identifier)) {
|
|
|
|
Diag(Tok.getLocation(), diag::err_expected_ident);
|
|
|
|
SkipUntil(tok::r_square, tok::comma, true, true);
|
|
|
|
continue;
|
|
|
|
}
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2009-11-21 16:43:09 +08:00
|
|
|
ScopeName = AttrName;
|
|
|
|
ScopeLoc = AttrLoc;
|
|
|
|
|
|
|
|
AttrName = Tok.getIdentifierInfo();
|
|
|
|
AttrLoc = ConsumeToken();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AttrParsed = false;
|
|
|
|
// No scoped names are supported; ideally we could put all non-standard
|
|
|
|
// attributes into namespaces.
|
|
|
|
if (!ScopeName) {
|
|
|
|
switch(AttributeList::getKind(AttrName))
|
|
|
|
{
|
|
|
|
// No arguments
|
2009-11-25 12:20:27 +08:00
|
|
|
case AttributeList::AT_base_check:
|
|
|
|
case AttributeList::AT_carries_dependency:
|
2009-11-21 16:43:09 +08:00
|
|
|
case AttributeList::AT_final:
|
2009-11-25 12:20:27 +08:00
|
|
|
case AttributeList::AT_hiding:
|
|
|
|
case AttributeList::AT_noreturn:
|
|
|
|
case AttributeList::AT_override: {
|
2009-11-21 16:43:09 +08:00
|
|
|
if (Tok.is(tok::l_paren)) {
|
|
|
|
Diag(Tok.getLocation(), diag::err_cxx0x_attribute_forbids_arguments)
|
|
|
|
<< AttrName->getName();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
CurrAttr = new AttributeList(AttrName, AttrLoc, 0, AttrLoc, 0,
|
|
|
|
SourceLocation(), 0, 0, CurrAttr, false,
|
|
|
|
true);
|
|
|
|
AttrParsed = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// One argument; must be a type-id or assignment-expression
|
|
|
|
case AttributeList::AT_aligned: {
|
|
|
|
if (Tok.isNot(tok::l_paren)) {
|
|
|
|
Diag(Tok.getLocation(), diag::err_cxx0x_attribute_requires_arguments)
|
|
|
|
<< AttrName->getName();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
SourceLocation ParamLoc = ConsumeParen();
|
|
|
|
|
|
|
|
OwningExprResult ArgExpr = ParseCXX0XAlignArgument(ParamLoc);
|
|
|
|
|
|
|
|
MatchRHSPunctuation(tok::r_paren, ParamLoc);
|
|
|
|
|
|
|
|
ExprVector ArgExprs(Actions);
|
|
|
|
ArgExprs.push_back(ArgExpr.release());
|
|
|
|
CurrAttr = new AttributeList(AttrName, AttrLoc, 0, AttrLoc,
|
|
|
|
0, ParamLoc, ArgExprs.take(), 1, CurrAttr,
|
|
|
|
false, true);
|
|
|
|
|
|
|
|
AttrParsed = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Silence warnings
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip the entire parameter clause, if any
|
|
|
|
if (!AttrParsed && Tok.is(tok::l_paren)) {
|
|
|
|
ConsumeParen();
|
|
|
|
// SkipUntil maintains the balancedness of tokens.
|
|
|
|
SkipUntil(tok::r_paren, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare))
|
|
|
|
SkipUntil(tok::r_square, false);
|
|
|
|
Loc = Tok.getLocation();
|
|
|
|
if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare))
|
|
|
|
SkipUntil(tok::r_square, false);
|
|
|
|
|
|
|
|
CXX0XAttributeList Attr (CurrAttr, SourceRange(StartLoc, Loc), true);
|
|
|
|
return Attr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseCXX0XAlignArgument - Parse the argument to C++0x's [[align]]
|
|
|
|
/// attribute.
|
|
|
|
///
|
|
|
|
/// FIXME: Simply returns an alignof() expression if the argument is a
|
|
|
|
/// type. Ideally, the type should be propagated directly into Sema.
|
|
|
|
///
|
|
|
|
/// [C++0x] 'align' '(' type-id ')'
|
|
|
|
/// [C++0x] 'align' '(' assignment-expression ')'
|
|
|
|
Parser::OwningExprResult Parser::ParseCXX0XAlignArgument(SourceLocation Start) {
|
|
|
|
if (isTypeIdInParens()) {
|
|
|
|
EnterExpressionEvaluationContext Unevaluated(Actions,
|
|
|
|
Action::Unevaluated);
|
|
|
|
SourceLocation TypeLoc = Tok.getLocation();
|
|
|
|
TypeTy *Ty = ParseTypeName().get();
|
|
|
|
SourceRange TypeRange(Start, Tok.getLocation());
|
|
|
|
return Actions.ActOnSizeOfAlignOfExpr(TypeLoc, false, true, Ty,
|
|
|
|
TypeRange);
|
|
|
|
} else
|
|
|
|
return ParseConstantExpression();
|
|
|
|
}
|