2007-08-25 14:57:03 +08:00
|
|
|
//===--- ParseDeclCXX.cpp - C++ Declaration Parsing -----------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-30 03:59:25 +08:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2007-08-25 14:57:03 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the C++ Declaration portions of the Parser interfaces.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2008-04-14 08:13:42 +08:00
|
|
|
#include "clang/Parse/Parser.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "RAIIObjectsForParser.h"
|
2014-01-15 17:15:43 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2014-03-04 18:05:20 +08:00
|
|
|
#include "clang/AST/DeclTemplate.h"
|
2014-04-01 01:32:39 +08:00
|
|
|
#include "clang/Basic/Attributes.h"
|
2013-02-09 06:30:41 +08:00
|
|
|
#include "clang/Basic/CharInfo.h"
|
2014-04-01 01:32:39 +08:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/Basic/OperatorKinds.h"
|
2009-01-29 13:15:15 +08:00
|
|
|
#include "clang/Parse/ParseDiagnostic.h"
|
2010-08-21 02:27:03 +08:00
|
|
|
#include "clang/Sema/DeclSpec.h"
|
|
|
|
#include "clang/Sema/ParsedTemplate.h"
|
2010-08-27 07:41:50 +08:00
|
|
|
#include "clang/Sema/PrettyDeclStackTrace.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/Sema/Scope.h"
|
2012-09-25 15:32:39 +08:00
|
|
|
#include "clang/Sema/SemaDiagnostic.h"
|
2012-02-04 21:45:25 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
2007-08-25 14:57:03 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
/// ParseNamespace - We know that the current token is a namespace keyword. This
|
2010-08-28 07:12:46 +08:00
|
|
|
/// may either be a top level namespace or a block-level namespace alias. If
|
|
|
|
/// there was an inline keyword, it has already been parsed.
|
2007-08-25 14:57:03 +08:00
|
|
|
///
|
|
|
|
/// namespace-definition: [C++ 7.3: basic.namespace]
|
|
|
|
/// named-namespace-definition
|
|
|
|
/// unnamed-namespace-definition
|
|
|
|
///
|
|
|
|
/// unnamed-namespace-definition:
|
2010-08-28 07:12:46 +08:00
|
|
|
/// 'inline'[opt] 'namespace' attributes[opt] '{' namespace-body '}'
|
2007-08-25 14:57:03 +08:00
|
|
|
///
|
|
|
|
/// named-namespace-definition:
|
|
|
|
/// original-namespace-definition
|
|
|
|
/// extension-namespace-definition
|
|
|
|
///
|
|
|
|
/// original-namespace-definition:
|
2010-08-28 07:12:46 +08:00
|
|
|
/// 'inline'[opt] 'namespace' identifier attributes[opt]
|
|
|
|
/// '{' namespace-body '}'
|
2007-08-25 14:57:03 +08:00
|
|
|
///
|
|
|
|
/// extension-namespace-definition:
|
2010-08-28 07:12:46 +08:00
|
|
|
/// 'inline'[opt] '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 ';'
|
|
|
|
///
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Parser::ParseNamespace(unsigned Context,
|
2010-08-28 07:12:46 +08:00
|
|
|
SourceLocation &DeclEnd,
|
|
|
|
SourceLocation InlineLoc) {
|
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'.
|
2011-08-23 01:59:19 +08:00
|
|
|
ObjCDeclContextSwitch ObjCDC(*this);
|
2011-08-22 23:54:49 +08:00
|
|
|
|
2009-09-19 03:03:04 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteNamespaceDecl(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
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;
|
2014-05-21 14:02:52 +08:00
|
|
|
IdentifierInfo *Ident = nullptr;
|
2011-05-27 04:11:09 +08:00
|
|
|
std::vector<SourceLocation> ExtraIdentLoc;
|
|
|
|
std::vector<IdentifierInfo*> ExtraIdent;
|
|
|
|
std::vector<SourceLocation> ExtraNamespaceLoc;
|
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.
|
2011-05-27 04:11:09 +08:00
|
|
|
while (Tok.is(tok::coloncolon) && NextToken().is(tok::identifier)) {
|
|
|
|
ExtraNamespaceLoc.push_back(ConsumeToken());
|
|
|
|
ExtraIdent.push_back(Tok.getIdentifierInfo());
|
|
|
|
ExtraIdentLoc.push_back(ConsumeToken());
|
|
|
|
}
|
2007-08-25 14:57:03 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-25 14:57:03 +08:00
|
|
|
// Read label attributes, if present.
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributes attrs(AttrFactory);
|
2009-06-18 03:49:00 +08:00
|
|
|
if (Tok.is(tok::kw___attribute)) {
|
|
|
|
attrTok = Tok;
|
2010-12-24 10:08:15 +08:00
|
|
|
ParseGNUAttributes(attrs);
|
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)) {
|
2014-05-21 14:02:52 +08:00
|
|
|
if (!Ident) {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::identifier;
|
2012-10-28 07:44:27 +08:00
|
|
|
// Skip to end of the definition and eat the ';'.
|
|
|
|
SkipUntil(tok::semi);
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2012-10-28 07:44:27 +08:00
|
|
|
}
|
2010-12-24 10:08:15 +08:00
|
|
|
if (!attrs.empty())
|
2009-06-18 03:49:00 +08:00
|
|
|
Diag(attrTok, diag::err_unexpected_namespace_attributes_alias);
|
2010-08-28 07:12:46 +08:00
|
|
|
if (InlineLoc.isValid())
|
|
|
|
Diag(InlineLoc, diag::err_inline_namespace_alias)
|
|
|
|
<< FixItHint::CreateRemoval(InlineLoc);
|
2011-08-23 01:59:19 +08:00
|
|
|
return ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident, DeclEnd);
|
2009-06-18 03:49:00 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-05-27 04:11:09 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_brace);
|
|
|
|
if (T.consumeOpen()) {
|
2011-05-27 04:11:09 +08:00
|
|
|
if (!ExtraIdent.empty()) {
|
|
|
|
Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
|
|
|
|
<< SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
|
|
|
|
}
|
2013-12-24 17:48:30 +08:00
|
|
|
|
|
|
|
if (Ident)
|
|
|
|
Diag(Tok, diag::err_expected) << tok::l_brace;
|
|
|
|
else
|
|
|
|
Diag(Tok, diag::err_expected_either) << tok::identifier << tok::l_brace;
|
|
|
|
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2009-03-29 22:02:43 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-03 01:43:08 +08:00
|
|
|
if (getCurScope()->isClassScope() || getCurScope()->isTemplateParamScope() ||
|
|
|
|
getCurScope()->isInObjcMethodScope() || getCurScope()->getBlockParent() ||
|
|
|
|
getCurScope()->getFnParent()) {
|
2011-05-27 04:11:09 +08:00
|
|
|
if (!ExtraIdent.empty()) {
|
|
|
|
Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
|
|
|
|
<< SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
|
|
|
|
}
|
2011-10-13 00:37:45 +08:00
|
|
|
Diag(T.getOpenLocation(), diag::err_namespace_nonnamespace_scope);
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace);
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2010-05-14 13:08:22 +08:00
|
|
|
}
|
|
|
|
|
2011-05-27 04:11:09 +08:00
|
|
|
if (!ExtraIdent.empty()) {
|
|
|
|
TentativeParsingAction TPA(*this);
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace, StopBeforeMatch);
|
2011-05-27 04:11:09 +08:00
|
|
|
Token rBraceToken = Tok;
|
|
|
|
TPA.Revert();
|
|
|
|
|
|
|
|
if (!rBraceToken.is(tok::r_brace)) {
|
|
|
|
Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
|
|
|
|
<< SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
|
|
|
|
} else {
|
2011-05-27 05:32:30 +08:00
|
|
|
std::string NamespaceFix;
|
2011-05-27 04:11:09 +08:00
|
|
|
for (std::vector<IdentifierInfo*>::iterator I = ExtraIdent.begin(),
|
|
|
|
E = ExtraIdent.end(); I != E; ++I) {
|
|
|
|
NamespaceFix += " { namespace ";
|
|
|
|
NamespaceFix += (*I)->getName();
|
|
|
|
}
|
2011-05-27 05:32:30 +08:00
|
|
|
|
2011-05-27 04:11:09 +08:00
|
|
|
std::string RBraces;
|
2011-05-27 05:32:30 +08:00
|
|
|
for (unsigned i = 0, e = ExtraIdent.size(); i != e; ++i)
|
2011-05-27 04:11:09 +08:00
|
|
|
RBraces += "} ";
|
2011-05-27 05:32:30 +08:00
|
|
|
|
2011-05-27 04:11:09 +08:00
|
|
|
Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
|
|
|
|
<< FixItHint::CreateReplacement(SourceRange(ExtraNamespaceLoc.front(),
|
|
|
|
ExtraIdentLoc.back()),
|
|
|
|
NamespaceFix)
|
|
|
|
<< FixItHint::CreateInsertion(rBraceToken.getLocation(), RBraces);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-31 08:36:45 +08:00
|
|
|
// If we're still good, complain about inline namespaces in non-C++0x now.
|
2011-10-15 13:09:34 +08:00
|
|
|
if (InlineLoc.isValid())
|
2013-01-02 19:42:31 +08:00
|
|
|
Diag(InlineLoc, getLangOpts().CPlusPlus11 ?
|
2011-10-15 13:09:34 +08:00
|
|
|
diag::warn_cxx98_compat_inline_namespace : diag::ext_inline_namespace);
|
2010-08-31 08:36:45 +08:00
|
|
|
|
2009-03-29 22:02:43 +08:00
|
|
|
// Enter a scope for the namespace.
|
|
|
|
ParseScope NamespaceScope(this, Scope::DeclScope);
|
2008-04-27 21:50:30 +08:00
|
|
|
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *NamespcDecl =
|
2011-03-08 20:38:20 +08:00
|
|
|
Actions.ActOnStartNamespaceDef(getCurScope(), InlineLoc, NamespaceLoc,
|
2011-10-13 00:37:45 +08:00
|
|
|
IdentLoc, Ident, T.getOpenLocation(),
|
|
|
|
attrs.getList());
|
2008-04-27 21:50:30 +08:00
|
|
|
|
2010-08-27 07:41:50 +08:00
|
|
|
PrettyDeclStackTraceEntry CrashInfo(Actions, NamespcDecl, NamespaceLoc,
|
|
|
|
"parsing namespace");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-05-27 04:11:09 +08:00
|
|
|
// Parse the contents of the namespace. This includes parsing recovery on
|
|
|
|
// any improperly nested namespaces.
|
|
|
|
ParseInnerNamespace(ExtraIdentLoc, ExtraIdent, ExtraNamespaceLoc, 0,
|
2011-10-13 00:37:45 +08:00
|
|
|
InlineLoc, attrs, T);
|
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
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
DeclEnd = T.getCloseLocation();
|
|
|
|
Actions.ActOnFinishNamespaceDef(NamespcDecl, DeclEnd);
|
2008-04-27 21:50:30 +08:00
|
|
|
|
2009-03-29 22:02:43 +08:00
|
|
|
return NamespcDecl;
|
2007-08-25 14:57:03 +08:00
|
|
|
}
|
2008-01-12 15:05:38 +08:00
|
|
|
|
2011-05-27 04:11:09 +08:00
|
|
|
/// ParseInnerNamespace - Parse the contents of a namespace.
|
|
|
|
void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc,
|
|
|
|
std::vector<IdentifierInfo*>& Ident,
|
|
|
|
std::vector<SourceLocation>& NamespaceLoc,
|
|
|
|
unsigned int index, SourceLocation& InlineLoc,
|
|
|
|
ParsedAttributes& attrs,
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker &Tracker) {
|
2011-05-27 04:11:09 +08:00
|
|
|
if (index == Ident.size()) {
|
2013-11-23 12:06:09 +08:00
|
|
|
while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
|
2011-05-27 04:11:09 +08:00
|
|
|
ParsedAttributesWithRange attrs(AttrFactory);
|
2013-01-02 20:01:23 +08:00
|
|
|
MaybeParseCXX11Attributes(attrs);
|
2011-05-27 04:11:09 +08:00
|
|
|
MaybeParseMicrosoftAttributes(attrs);
|
|
|
|
ParseExternalDeclaration(attrs);
|
|
|
|
}
|
2011-10-13 00:37:45 +08:00
|
|
|
|
|
|
|
// The caller is what called check -- we are simply calling
|
|
|
|
// the close for it.
|
|
|
|
Tracker.consumeClose();
|
2011-05-27 04:11:09 +08:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse improperly nested namespaces.
|
|
|
|
ParseScope NamespaceScope(this, Scope::DeclScope);
|
|
|
|
Decl *NamespcDecl =
|
|
|
|
Actions.ActOnStartNamespaceDef(getCurScope(), SourceLocation(),
|
|
|
|
NamespaceLoc[index], IdentLoc[index],
|
2011-10-13 00:37:45 +08:00
|
|
|
Ident[index], Tracker.getOpenLocation(),
|
|
|
|
attrs.getList());
|
2011-05-27 04:11:09 +08:00
|
|
|
|
|
|
|
ParseInnerNamespace(IdentLoc, Ident, NamespaceLoc, ++index, InlineLoc,
|
2011-10-13 00:37:45 +08:00
|
|
|
attrs, Tracker);
|
2011-05-27 04:11:09 +08:00
|
|
|
|
|
|
|
NamespaceScope.Exit();
|
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
Actions.ActOnFinishNamespaceDef(NamespcDecl, Tracker.getCloseLocation());
|
2011-05-27 04:11:09 +08:00
|
|
|
}
|
|
|
|
|
2009-03-28 12:07:16 +08:00
|
|
|
/// ParseNamespaceAlias - Parse the part after the '=' in a namespace
|
|
|
|
/// alias definition.
|
|
|
|
///
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
|
2011-03-24 19:26:52 +08:00
|
|
|
SourceLocation AliasLoc,
|
|
|
|
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)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteNamespaceAliasDecl(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
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.
|
2011-11-08 01:33:42 +08:00
|
|
|
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/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);
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
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();
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after_namespace_name))
|
|
|
|
SkipUntil(tok::semi);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-03 01:43:08 +08:00
|
|
|
return Actions.ActOnNamespaceAliasDef(getCurScope(), 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
|
|
|
|
///
|
2010-11-10 04:15:55 +08:00
|
|
|
Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
|
2014-02-18 07:25:27 +08:00
|
|
|
assert(isTokenStringLiteral() && "Not a string literal!");
|
|
|
|
ExprResult Lang = ParseStringLiteralExpression(false);
|
2008-01-12 15:05:38 +08:00
|
|
|
|
2009-01-06 03:45:36 +08:00
|
|
|
ParseScope LinkageScope(this, Scope::DeclScope);
|
2014-02-18 07:25:27 +08:00
|
|
|
Decl *LinkageSpec =
|
|
|
|
Lang.isInvalid()
|
2014-05-21 14:02:52 +08:00
|
|
|
? nullptr
|
2014-02-18 07:25:27 +08:00
|
|
|
: Actions.ActOnStartLinkageSpecification(
|
2014-05-29 18:55:11 +08:00
|
|
|
getCurScope(), DS.getSourceRange().getBegin(), Lang.get(),
|
2014-02-18 07:25:27 +08:00
|
|
|
Tok.is(tok::l_brace) ? Tok.getLocation() : SourceLocation());
|
2009-01-06 03:45:36 +08:00
|
|
|
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributesWithRange attrs(AttrFactory);
|
2013-01-02 20:01:23 +08:00
|
|
|
MaybeParseCXX11Attributes(attrs);
|
2010-12-24 10:08:15 +08:00
|
|
|
MaybeParseMicrosoftAttributes(attrs);
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2009-01-06 03:45:36 +08:00
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
2011-05-02 00:25:54 +08:00
|
|
|
// Reset the source range in DS, as the leading "extern"
|
|
|
|
// does not really belong to the inner declaration ...
|
|
|
|
DS.SetRangeStart(SourceLocation());
|
|
|
|
DS.SetRangeEnd(SourceLocation());
|
|
|
|
// ... but anyway remember that such an "extern" was seen.
|
2010-07-31 00:47:02 +08:00
|
|
|
DS.setExternInLinkageSpec(true);
|
2010-12-24 10:08:15 +08:00
|
|
|
ParseExternalDeclaration(attrs, &DS);
|
2014-02-18 07:25:27 +08:00
|
|
|
return LinkageSpec ? Actions.ActOnFinishLinkageSpecification(
|
|
|
|
getCurScope(), LinkageSpec, SourceLocation())
|
2014-05-21 14:02:52 +08:00
|
|
|
: nullptr;
|
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();
|
|
|
|
|
2010-12-24 10:08:15 +08:00
|
|
|
ProhibitAttributes(attrs);
|
2009-11-21 16:43:09 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_brace);
|
|
|
|
T.consumeOpen();
|
2014-03-02 13:58:18 +08:00
|
|
|
|
|
|
|
unsigned NestedModules = 0;
|
|
|
|
while (true) {
|
|
|
|
switch (Tok.getKind()) {
|
|
|
|
case tok::annot_module_begin:
|
|
|
|
++NestedModules;
|
|
|
|
ParseTopLevelDecl();
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case tok::annot_module_end:
|
|
|
|
if (!NestedModules)
|
|
|
|
break;
|
|
|
|
--NestedModules;
|
|
|
|
ParseTopLevelDecl();
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case tok::annot_module_include:
|
|
|
|
ParseTopLevelDecl();
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case tok::eof:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::r_brace:
|
|
|
|
if (!NestedModules)
|
|
|
|
break;
|
|
|
|
// Fall through.
|
|
|
|
default:
|
|
|
|
ParsedAttributesWithRange attrs(AttrFactory);
|
|
|
|
MaybeParseCXX11Attributes(attrs);
|
|
|
|
MaybeParseMicrosoftAttributes(attrs);
|
|
|
|
ParseExternalDeclaration(attrs);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
2008-12-17 06:23:02 +08:00
|
|
|
}
|
2008-01-12 15:05:38 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2014-02-18 07:25:27 +08:00
|
|
|
return LinkageSpec ? Actions.ActOnFinishLinkageSpecification(
|
|
|
|
getCurScope(), LinkageSpec, T.getCloseLocation())
|
2014-05-21 14:02:52 +08:00
|
|
|
: nullptr;
|
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'.
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
|
2010-11-10 10:40:36 +08:00
|
|
|
const ParsedTemplateInfo &TemplateInfo,
|
|
|
|
SourceLocation &DeclEnd,
|
2011-07-02 03:46:12 +08:00
|
|
|
ParsedAttributesWithRange &attrs,
|
|
|
|
Decl **OwnedType) {
|
2008-12-30 11:27:21 +08:00
|
|
|
assert(Tok.is(tok::kw_using) && "Not using token");
|
2011-08-23 01:59:19 +08:00
|
|
|
ObjCDeclContextSwitch ObjCDC(*this);
|
|
|
|
|
2008-12-30 11:27:21 +08:00
|
|
|
// Eat 'using'.
|
|
|
|
SourceLocation UsingLoc = ConsumeToken();
|
|
|
|
|
2009-09-19 03:03:04 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteUsing(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2009-09-19 03:03:04 +08:00
|
|
|
}
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2010-11-10 10:40:36 +08:00
|
|
|
// 'using namespace' means this is a using-directive.
|
|
|
|
if (Tok.is(tok::kw_namespace)) {
|
|
|
|
// Template parameters are always an error here.
|
|
|
|
if (TemplateInfo.Kind) {
|
|
|
|
SourceRange R = TemplateInfo.getSourceRange();
|
|
|
|
Diag(UsingLoc, diag::err_templated_using_directive)
|
|
|
|
<< R << FixItHint::CreateRemoval(R);
|
|
|
|
}
|
|
|
|
|
2011-08-23 01:59:19 +08:00
|
|
|
return ParseUsingDirective(Context, UsingLoc, DeclEnd, attrs);
|
2010-11-10 10:40:36 +08:00
|
|
|
}
|
2009-11-21 16:43:09 +08:00
|
|
|
|
2011-04-15 22:24:37 +08:00
|
|
|
// Otherwise, it must be a using-declaration or an alias-declaration.
|
2010-11-10 10:40:36 +08:00
|
|
|
|
|
|
|
// Using declarations can't have attributes.
|
2010-12-24 10:08:15 +08:00
|
|
|
ProhibitAttributes(attrs);
|
2009-01-06 14:55:51 +08:00
|
|
|
|
2011-08-23 01:59:19 +08:00
|
|
|
return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd,
|
2011-08-22 23:54:49 +08:00
|
|
|
AS_none, OwnedType);
|
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] ;
|
|
|
|
///
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Parser::ParseUsingDirective(unsigned Context,
|
2010-11-10 10:40:36 +08:00
|
|
|
SourceLocation UsingLoc,
|
|
|
|
SourceLocation &DeclEnd,
|
2010-12-24 10:08:15 +08:00
|
|
|
ParsedAttributes &attrs) {
|
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)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteUsingDirective(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
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.
|
2011-11-08 01:33:42 +08:00
|
|
|
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
|
2008-12-30 11:27:21 +08:00
|
|
|
|
2014-05-21 14:02:52 +08:00
|
|
|
IdentifierInfo *NamespcName = nullptr;
|
2008-12-30 11:27:21 +08:00
|
|
|
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?
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
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;
|
2010-12-24 10:08:15 +08:00
|
|
|
ParseGNUAttributes(attrs);
|
2009-11-21 16:43:09 +08:00
|
|
|
}
|
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();
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::semi,
|
|
|
|
GNUAttr ? diag::err_expected_semi_after_attribute_list
|
|
|
|
: diag::err_expected_semi_after_namespace_name))
|
|
|
|
SkipUntil(tok::semi);
|
2008-12-30 11:27:21 +08:00
|
|
|
|
2010-07-03 01:43:08 +08:00
|
|
|
return Actions.ActOnUsingDirective(getCurScope(), UsingLoc, NamespcLoc, SS,
|
2010-12-24 10:08:15 +08:00
|
|
|
IdentLoc, NamespcName, attrs.getList());
|
2008-12-30 11:27:21 +08:00
|
|
|
}
|
|
|
|
|
2011-04-15 22:24:37 +08:00
|
|
|
/// ParseUsingDeclaration - Parse C++ using-declaration or alias-declaration.
|
|
|
|
/// Assumes that 'using' was already seen.
|
2008-12-30 11:27:21 +08:00
|
|
|
///
|
|
|
|
/// 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
|
|
|
///
|
2013-01-29 18:02:16 +08:00
|
|
|
/// alias-declaration: C++11 [dcl.dcl]p1
|
|
|
|
/// 'using' identifier attribute-specifier-seq[opt] = type-id ;
|
2011-04-15 22:24:37 +08:00
|
|
|
///
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Parser::ParseUsingDeclaration(unsigned Context,
|
2010-11-10 10:40:36 +08:00
|
|
|
const ParsedTemplateInfo &TemplateInfo,
|
|
|
|
SourceLocation UsingLoc,
|
|
|
|
SourceLocation &DeclEnd,
|
2011-07-02 03:46:12 +08:00
|
|
|
AccessSpecifier AS,
|
|
|
|
Decl **OwnedType) {
|
2009-06-20 08:51:54 +08:00
|
|
|
CXXScopeSpec SS;
|
2009-11-18 10:36:19 +08:00
|
|
|
SourceLocation TypenameLoc;
|
2013-07-22 18:54:09 +08:00
|
|
|
bool HasTypenameKeyword = false;
|
2012-06-23 13:07:58 +08:00
|
|
|
|
2013-10-15 09:34:54 +08:00
|
|
|
// Check for misplaced attributes before the identifier in an
|
|
|
|
// alias-declaration.
|
|
|
|
ParsedAttributesWithRange MisplacedAttrs(AttrFactory);
|
|
|
|
MaybeParseCXX11Attributes(MisplacedAttrs);
|
2009-06-20 08:51:54 +08:00
|
|
|
|
|
|
|
// Ignore optional 'typename'.
|
2009-11-05 00:30:06 +08:00
|
|
|
// FIXME: This is wrong; we should parse this as a typename-specifier.
|
2014-01-10 19:19:30 +08:00
|
|
|
if (TryConsumeToken(tok::kw_typename, TypenameLoc))
|
2013-07-22 18:54:09 +08:00
|
|
|
HasTypenameKeyword = true;
|
2009-06-20 08:51:54 +08:00
|
|
|
|
2014-09-26 08:28:20 +08:00
|
|
|
if (Tok.is(tok::kw___super)) {
|
|
|
|
Diag(Tok.getLocation(), diag::err_super_in_using_declaration);
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2009-06-20 08:51:54 +08:00
|
|
|
// Parse nested-name-specifier.
|
2014-05-21 14:02:52 +08:00
|
|
|
IdentifierInfo *LastII = nullptr;
|
2013-03-26 09:15:19 +08:00
|
|
|
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false,
|
2014-05-21 14:02:52 +08:00
|
|
|
/*MayBePseudoDtor=*/nullptr,
|
|
|
|
/*IsTypename=*/false,
|
2013-03-26 09:15:19 +08:00
|
|
|
/*LastII=*/&LastII);
|
2009-06-20 08:51:54 +08:00
|
|
|
|
|
|
|
// Check nested-name specifier.
|
|
|
|
if (SS.isInvalid()) {
|
|
|
|
SkipUntil(tok::semi);
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2009-06-20 08:51:54 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2013-03-26 09:15:19 +08:00
|
|
|
SourceLocation TemplateKWLoc;
|
|
|
|
UnqualifiedId Name;
|
|
|
|
|
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.
|
2013-03-26 09:15:19 +08:00
|
|
|
//
|
|
|
|
// C++11 [class.qual]p2:
|
|
|
|
// [...] in a using-declaration that is a member-declaration, if the name
|
|
|
|
// specified after the nested-name-specifier is the same as the identifier
|
|
|
|
// or the simple-template-id's template-name in the last component of the
|
|
|
|
// nested-name-specifier, the name is [...] considered to name the
|
|
|
|
// constructor.
|
|
|
|
if (getLangOpts().CPlusPlus11 && Context == Declarator::MemberContext &&
|
|
|
|
Tok.is(tok::identifier) && NextToken().is(tok::semi) &&
|
|
|
|
SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() &&
|
|
|
|
!SS.getScopeRep()->getAsNamespace() &&
|
|
|
|
!SS.getScopeRep()->getAsNamespaceAlias()) {
|
|
|
|
SourceLocation IdLoc = ConsumeToken();
|
|
|
|
ParsedType Type = Actions.getInheritingConstructorName(SS, IdLoc, *LastII);
|
|
|
|
Name.setConstructorName(Type, IdLoc, IdLoc);
|
|
|
|
} else if (ParseUnqualifiedId(SS, /*EnteringContext=*/ false,
|
|
|
|
/*AllowDestructorName=*/ true,
|
|
|
|
/*AllowConstructorName=*/ true, ParsedType(),
|
|
|
|
TemplateKWLoc, Name)) {
|
2009-06-20 08:51:54 +08:00
|
|
|
SkipUntil(tok::semi);
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2009-06-20 08:51:54 +08:00
|
|
|
}
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2013-10-15 09:34:54 +08:00
|
|
|
ParsedAttributesWithRange Attrs(AttrFactory);
|
2013-10-24 09:21:09 +08:00
|
|
|
MaybeParseGNUAttributes(Attrs);
|
2013-02-21 03:22:51 +08:00
|
|
|
MaybeParseCXX11Attributes(Attrs);
|
2011-04-15 22:24:37 +08:00
|
|
|
|
|
|
|
// Maybe this is an alias-declaration.
|
|
|
|
TypeResult TypeAlias;
|
2013-10-15 09:34:54 +08:00
|
|
|
bool IsAliasDecl = Tok.is(tok::equal);
|
2011-04-15 22:24:37 +08:00
|
|
|
if (IsAliasDecl) {
|
2013-10-15 09:34:54 +08:00
|
|
|
// If we had any misplaced attributes from earlier, this is where they
|
|
|
|
// should have been written.
|
|
|
|
if (MisplacedAttrs.Range.isValid()) {
|
|
|
|
Diag(MisplacedAttrs.Range.getBegin(), diag::err_attributes_not_allowed)
|
|
|
|
<< FixItHint::CreateInsertionFromRange(
|
|
|
|
Tok.getLocation(),
|
|
|
|
CharSourceRange::getTokenRange(MisplacedAttrs.Range))
|
|
|
|
<< FixItHint::CreateRemoval(MisplacedAttrs.Range);
|
|
|
|
Attrs.takeAllFrom(MisplacedAttrs);
|
|
|
|
}
|
|
|
|
|
2011-04-15 22:24:37 +08:00
|
|
|
ConsumeToken();
|
|
|
|
|
2013-01-02 19:42:31 +08:00
|
|
|
Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ?
|
2011-10-15 13:09:34 +08:00
|
|
|
diag::warn_cxx98_compat_alias_declaration :
|
|
|
|
diag::ext_alias_declaration);
|
2011-04-15 22:24:37 +08:00
|
|
|
|
2011-05-06 05:57:07 +08:00
|
|
|
// Type alias templates cannot be specialized.
|
|
|
|
int SpecKind = -1;
|
2011-05-06 06:36:10 +08:00
|
|
|
if (TemplateInfo.Kind == ParsedTemplateInfo::Template &&
|
|
|
|
Name.getKind() == UnqualifiedId::IK_TemplateId)
|
2011-05-06 05:57:07 +08:00
|
|
|
SpecKind = 0;
|
|
|
|
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization)
|
|
|
|
SpecKind = 1;
|
|
|
|
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
|
|
|
|
SpecKind = 2;
|
|
|
|
if (SpecKind != -1) {
|
|
|
|
SourceRange Range;
|
|
|
|
if (SpecKind == 0)
|
|
|
|
Range = SourceRange(Name.TemplateId->LAngleLoc,
|
|
|
|
Name.TemplateId->RAngleLoc);
|
|
|
|
else
|
|
|
|
Range = TemplateInfo.getSourceRange();
|
|
|
|
Diag(Range.getBegin(), diag::err_alias_declaration_specialization)
|
|
|
|
<< SpecKind << Range;
|
|
|
|
SkipUntil(tok::semi);
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2011-05-06 05:57:07 +08:00
|
|
|
}
|
|
|
|
|
2011-04-15 22:24:37 +08:00
|
|
|
// Name must be an identifier.
|
|
|
|
if (Name.getKind() != UnqualifiedId::IK_Identifier) {
|
|
|
|
Diag(Name.StartLocation, diag::err_alias_declaration_not_identifier);
|
|
|
|
// No removal fixit: can't recover from this.
|
|
|
|
SkipUntil(tok::semi);
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2013-07-22 18:54:09 +08:00
|
|
|
} else if (HasTypenameKeyword)
|
2011-04-15 22:24:37 +08:00
|
|
|
Diag(TypenameLoc, diag::err_alias_declaration_not_identifier)
|
|
|
|
<< FixItHint::CreateRemoval(SourceRange(TypenameLoc,
|
|
|
|
SS.isNotEmpty() ? SS.getEndLoc() : TypenameLoc));
|
|
|
|
else if (SS.isNotEmpty())
|
|
|
|
Diag(SS.getBeginLoc(), diag::err_alias_declaration_not_identifier)
|
|
|
|
<< FixItHint::CreateRemoval(SS.getRange());
|
|
|
|
|
2014-05-21 14:02:52 +08:00
|
|
|
TypeAlias = ParseTypeName(nullptr, TemplateInfo.Kind ?
|
2011-05-06 05:57:07 +08:00
|
|
|
Declarator::AliasTemplateContext :
|
2013-02-21 03:22:51 +08:00
|
|
|
Declarator::AliasDeclContext, AS, OwnedType,
|
|
|
|
&Attrs);
|
2012-06-23 13:07:58 +08:00
|
|
|
} else {
|
|
|
|
// C++11 attributes are not allowed on a using-declaration, but GNU ones
|
|
|
|
// are.
|
2013-10-15 09:34:54 +08:00
|
|
|
ProhibitAttributes(MisplacedAttrs);
|
2013-02-21 03:22:51 +08:00
|
|
|
ProhibitAttributes(Attrs);
|
2012-06-23 13:07:58 +08:00
|
|
|
|
2011-04-15 22:24:37 +08:00
|
|
|
// Parse (optional) attributes (most likely GNU strong-using extension).
|
2013-02-21 03:22:51 +08:00
|
|
|
MaybeParseGNUAttributes(Attrs);
|
2012-06-23 13:07:58 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 08:51:54 +08:00
|
|
|
// Eat ';'.
|
|
|
|
DeclEnd = Tok.getLocation();
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::semi, diag::err_expected_after,
|
|
|
|
!Attrs.empty() ? "attributes list"
|
|
|
|
: IsAliasDecl ? "alias declaration"
|
|
|
|
: "using declaration"))
|
|
|
|
SkipUntil(tok::semi);
|
2009-06-20 08:51:54 +08:00
|
|
|
|
2010-11-10 10:40:36 +08:00
|
|
|
// Diagnose an attempt to declare a templated using-declaration.
|
2013-01-29 18:02:16 +08:00
|
|
|
// In C++11, alias-declarations can be templates:
|
2011-04-15 22:24:37 +08:00
|
|
|
// template <...> using id = type;
|
2011-05-06 05:57:07 +08:00
|
|
|
if (TemplateInfo.Kind && !IsAliasDecl) {
|
2010-11-10 10:40:36 +08:00
|
|
|
SourceRange R = TemplateInfo.getSourceRange();
|
|
|
|
Diag(UsingLoc, diag::err_templated_using_declaration)
|
|
|
|
<< R << FixItHint::CreateRemoval(R);
|
|
|
|
|
|
|
|
// Unfortunately, we have to bail out instead of recovering by
|
|
|
|
// ignoring the parameters, just in case the nested name specifier
|
|
|
|
// depends on the parameters.
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2010-11-10 10:40:36 +08:00
|
|
|
}
|
|
|
|
|
2011-09-26 22:30:28 +08:00
|
|
|
// "typename" keyword is allowed for identifiers only,
|
|
|
|
// because it may be a type definition.
|
2013-07-22 18:54:09 +08:00
|
|
|
if (HasTypenameKeyword && Name.getKind() != UnqualifiedId::IK_Identifier) {
|
2011-09-26 22:30:28 +08:00
|
|
|
Diag(Name.getSourceRange().getBegin(), diag::err_typename_identifiers_only)
|
|
|
|
<< FixItHint::CreateRemoval(SourceRange(TypenameLoc));
|
2013-07-22 18:54:09 +08:00
|
|
|
// Proceed parsing, but reset the HasTypenameKeyword flag.
|
|
|
|
HasTypenameKeyword = false;
|
2011-09-26 22:30:28 +08:00
|
|
|
}
|
|
|
|
|
2011-05-06 05:57:07 +08:00
|
|
|
if (IsAliasDecl) {
|
|
|
|
TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
|
2012-08-24 07:38:35 +08:00
|
|
|
MultiTemplateParamsArg TemplateParamsArg(
|
2014-05-21 14:02:52 +08:00
|
|
|
TemplateParams ? TemplateParams->data() : nullptr,
|
2011-05-06 05:57:07 +08:00
|
|
|
TemplateParams ? TemplateParams->size() : 0);
|
|
|
|
return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg,
|
2013-02-21 03:22:51 +08:00
|
|
|
UsingLoc, Name, Attrs.getList(),
|
|
|
|
TypeAlias);
|
2011-05-06 05:57:07 +08:00
|
|
|
}
|
2011-04-15 22:24:37 +08:00
|
|
|
|
2013-07-22 18:54:09 +08:00
|
|
|
return Actions.ActOnUsingDeclaration(getCurScope(), AS,
|
|
|
|
/* HasUsingKeyword */ true, UsingLoc,
|
|
|
|
SS, Name, Attrs.getList(),
|
|
|
|
HasTypenameKeyword, TypenameLoc);
|
2008-12-30 11:27:21 +08:00
|
|
|
}
|
|
|
|
|
2011-12-24 01:00:35 +08:00
|
|
|
/// ParseStaticAssertDeclaration - Parse C++0x or C11 static_assert-declaration.
|
2009-03-12 00:27:10 +08:00
|
|
|
///
|
2011-04-15 08:35:57 +08:00
|
|
|
/// [C++0x] static_assert-declaration:
|
|
|
|
/// static_assert ( constant-expression , string-literal ) ;
|
|
|
|
///
|
2011-12-24 01:00:35 +08:00
|
|
|
/// [C11] static_assert-declaration:
|
2011-04-15 08:35:57 +08:00
|
|
|
/// _Static_assert ( constant-expression , string-literal ) ;
|
2009-03-12 00:27:10 +08:00
|
|
|
///
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
|
2011-04-15 08:35:57 +08:00
|
|
|
assert((Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert)) &&
|
|
|
|
"Not a static_assert declaration");
|
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (Tok.is(tok::kw__Static_assert) && !getLangOpts().C11)
|
2011-12-24 01:00:35 +08:00
|
|
|
Diag(Tok, diag::ext_c11_static_assert);
|
2011-10-18 07:06:20 +08:00
|
|
|
if (Tok.is(tok::kw_static_assert))
|
|
|
|
Diag(Tok, diag::warn_cxx98_compat_static_assert);
|
2011-04-15 08:35:57 +08:00
|
|
|
|
2009-03-12 00:27:10 +08:00
|
|
|
SourceLocation StaticAssertLoc = ConsumeToken();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
if (T.consumeOpen()) {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::l_paren;
|
2012-09-14 03:12:50 +08:00
|
|
|
SkipMalformedDecl();
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2009-03-12 00:27:10 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult AssertExpr(ParseConstantExpression());
|
2009-03-12 00:27:10 +08:00
|
|
|
if (AssertExpr.isInvalid()) {
|
2012-09-14 03:12:50 +08:00
|
|
|
SkipMalformedDecl();
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2009-03-12 00:27:10 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-06-21 03:57:12 +08:00
|
|
|
ExprResult AssertMessage;
|
|
|
|
if (Tok.is(tok::r_paren)) {
|
|
|
|
Diag(Tok, getLangOpts().CPlusPlus1z
|
2014-08-19 23:55:55 +08:00
|
|
|
? diag::warn_cxx14_compat_static_assert_no_message
|
2014-06-21 03:57:12 +08:00
|
|
|
: diag::ext_static_assert_no_message)
|
|
|
|
<< (getLangOpts().CPlusPlus1z
|
|
|
|
? FixItHint()
|
|
|
|
: FixItHint::CreateInsertion(Tok.getLocation(), ", \"\""));
|
|
|
|
} else {
|
|
|
|
if (ExpectAndConsume(tok::comma)) {
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
return nullptr;
|
|
|
|
}
|
2009-03-14 07:29:20 +08:00
|
|
|
|
2014-06-21 03:57:12 +08:00
|
|
|
if (!isTokenStringLiteral()) {
|
|
|
|
Diag(Tok, diag::err_expected_string_literal)
|
|
|
|
<< /*Source='static_assert'*/1;
|
|
|
|
SkipMalformedDecl();
|
|
|
|
return nullptr;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-06-21 03:57:12 +08:00
|
|
|
AssertMessage = ParseStringLiteralExpression();
|
|
|
|
if (AssertMessage.isInvalid()) {
|
|
|
|
SkipMalformedDecl();
|
|
|
|
return nullptr;
|
|
|
|
}
|
2012-03-06 11:21:47 +08:00
|
|
|
}
|
2009-03-12 00:27:10 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
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();
|
2010-09-07 23:23:11 +08:00
|
|
|
ExpectAndConsumeSemi(diag::err_expected_semi_after_static_assert);
|
2009-03-12 00:27:10 +08:00
|
|
|
|
2010-08-24 07:25:46 +08:00
|
|
|
return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc,
|
2014-05-29 18:55:11 +08:00
|
|
|
AssertExpr.get(),
|
|
|
|
AssertMessage.get(),
|
2011-10-13 00:37:45 +08:00
|
|
|
T.getCloseLocation());
|
2009-03-12 00:27:10 +08:00
|
|
|
}
|
|
|
|
|
2013-04-27 00:15:35 +08:00
|
|
|
/// ParseDecltypeSpecifier - Parse a C++11 decltype specifier.
|
2009-06-25 01:47:40 +08:00
|
|
|
///
|
|
|
|
/// 'decltype' ( expression )
|
2013-04-27 00:15:35 +08:00
|
|
|
/// 'decltype' ( 'auto' ) [C++1y]
|
2009-06-25 01:47:40 +08:00
|
|
|
///
|
2011-12-04 13:04:18 +08:00
|
|
|
SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
|
|
|
|
assert((Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype))
|
|
|
|
&& "Not a decltype specifier");
|
|
|
|
|
|
|
|
ExprResult Result;
|
|
|
|
SourceLocation StartLoc = Tok.getLocation();
|
|
|
|
SourceLocation EndLoc;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-12-04 13:04:18 +08:00
|
|
|
if (Tok.is(tok::annot_decltype)) {
|
|
|
|
Result = getExprAnnotation(Tok);
|
|
|
|
EndLoc = Tok.getAnnotationEndLoc();
|
|
|
|
ConsumeToken();
|
|
|
|
if (Result.isInvalid()) {
|
|
|
|
DS.SetTypeSpecError();
|
|
|
|
return EndLoc;
|
|
|
|
}
|
|
|
|
} else {
|
2012-02-25 06:30:04 +08:00
|
|
|
if (Tok.getIdentifierInfo()->isStr("decltype"))
|
|
|
|
Diag(Tok, diag::warn_cxx98_compat_decltype);
|
2012-02-25 02:10:23 +08:00
|
|
|
|
2011-12-04 13:04:18 +08:00
|
|
|
ConsumeToken();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-12-04 13:04:18 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
if (T.expectAndConsume(diag::err_expected_lparen_after,
|
|
|
|
"decltype", tok::r_paren)) {
|
|
|
|
DS.SetTypeSpecError();
|
|
|
|
return T.getOpenLocation() == Tok.getLocation() ?
|
|
|
|
StartLoc : T.getOpenLocation();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2013-04-27 00:15:35 +08:00
|
|
|
// Check for C++1y 'decltype(auto)'.
|
|
|
|
if (Tok.is(tok::kw_auto)) {
|
|
|
|
// No need to disambiguate here: an expression can't start with 'auto',
|
|
|
|
// because the typename-specifier in a function-style cast operation can't
|
|
|
|
// be 'auto'.
|
|
|
|
Diag(Tok.getLocation(),
|
2014-08-19 23:55:55 +08:00
|
|
|
getLangOpts().CPlusPlus14
|
2013-04-27 00:15:35 +08:00
|
|
|
? diag::warn_cxx11_compat_decltype_auto_type_specifier
|
|
|
|
: diag::ext_decltype_auto_type_specifier);
|
|
|
|
ConsumeToken();
|
|
|
|
} else {
|
|
|
|
// Parse the expression
|
|
|
|
|
|
|
|
// C++11 [dcl.type.simple]p4:
|
|
|
|
// The operand of the decltype specifier is an unevaluated operand.
|
|
|
|
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
|
2014-05-21 14:02:52 +08:00
|
|
|
nullptr,/*IsDecltype=*/true);
|
2013-04-27 00:15:35 +08:00
|
|
|
Result = ParseExpression();
|
|
|
|
if (Result.isInvalid()) {
|
|
|
|
DS.SetTypeSpecError();
|
2013-11-18 16:17:37 +08:00
|
|
|
if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch)) {
|
2013-04-27 00:15:35 +08:00
|
|
|
EndLoc = ConsumeParen();
|
2012-10-27 06:53:44 +08:00
|
|
|
} else {
|
2013-04-27 00:15:35 +08:00
|
|
|
if (PP.isBacktrackEnabled() && Tok.is(tok::semi)) {
|
|
|
|
// Backtrack to get the location of the last token before the semi.
|
|
|
|
PP.RevertCachedTokens(2);
|
|
|
|
ConsumeToken(); // the semi.
|
|
|
|
EndLoc = ConsumeAnyToken();
|
|
|
|
assert(Tok.is(tok::semi));
|
|
|
|
} else {
|
|
|
|
EndLoc = Tok.getLocation();
|
|
|
|
}
|
2012-10-27 06:53:44 +08:00
|
|
|
}
|
2013-04-27 00:15:35 +08:00
|
|
|
return EndLoc;
|
2012-10-27 06:53:44 +08:00
|
|
|
}
|
2013-04-27 00:15:35 +08:00
|
|
|
|
2014-05-29 18:55:11 +08:00
|
|
|
Result = Actions.ActOnDecltypeExpression(Result.get());
|
2011-12-04 13:04:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Match the ')'
|
|
|
|
T.consumeClose();
|
|
|
|
if (T.getCloseLocation().isInvalid()) {
|
|
|
|
DS.SetTypeSpecError();
|
|
|
|
// FIXME: this should return the location of the last token
|
|
|
|
// that was consumed (by "consumeClose()")
|
|
|
|
return T.getCloseLocation();
|
|
|
|
}
|
|
|
|
|
2012-02-22 10:04:18 +08:00
|
|
|
if (Result.isInvalid()) {
|
|
|
|
DS.SetTypeSpecError();
|
|
|
|
return T.getCloseLocation();
|
|
|
|
}
|
|
|
|
|
2011-12-04 13:04:18 +08:00
|
|
|
EndLoc = T.getCloseLocation();
|
|
|
|
}
|
2013-04-27 00:15:35 +08:00
|
|
|
assert(!Result.isInvalid());
|
2009-06-25 01:47:40 +08:00
|
|
|
|
2014-05-21 14:02:52 +08:00
|
|
|
const char *PrevSpec = nullptr;
|
2009-08-04 04:12:06 +08:00
|
|
|
unsigned DiagID;
|
2014-01-15 17:15:43 +08:00
|
|
|
const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy();
|
2009-06-25 01:47:40 +08:00
|
|
|
// Check for duplicate type specifiers (e.g. "int decltype(a)").
|
2013-04-27 00:15:35 +08:00
|
|
|
if (Result.get()
|
|
|
|
? DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec,
|
2014-05-29 18:55:11 +08:00
|
|
|
DiagID, Result.get(), Policy)
|
2013-04-27 00:15:35 +08:00
|
|
|
: DS.SetTypeSpecType(DeclSpec::TST_decltype_auto, StartLoc, PrevSpec,
|
2014-01-15 17:15:43 +08:00
|
|
|
DiagID, Policy)) {
|
2009-08-04 04:12:06 +08:00
|
|
|
Diag(StartLoc, DiagID) << PrevSpec;
|
2011-12-04 13:04:18 +08:00
|
|
|
DS.SetTypeSpecError();
|
|
|
|
}
|
|
|
|
return EndLoc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec& DS,
|
|
|
|
SourceLocation StartLoc,
|
|
|
|
SourceLocation EndLoc) {
|
|
|
|
// make sure we have a token we can turn into an annotation token
|
|
|
|
if (PP.isBacktrackEnabled())
|
|
|
|
PP.RevertCachedTokens(1);
|
|
|
|
else
|
|
|
|
PP.EnterToken(Tok);
|
|
|
|
|
|
|
|
Tok.setKind(tok::annot_decltype);
|
2013-04-27 00:15:35 +08:00
|
|
|
setExprAnnotation(Tok,
|
|
|
|
DS.getTypeSpecType() == TST_decltype ? DS.getRepAsExpr() :
|
|
|
|
DS.getTypeSpecType() == TST_decltype_auto ? ExprResult() :
|
|
|
|
ExprError());
|
2011-12-04 13:04:18 +08:00
|
|
|
Tok.setAnnotationEndLoc(EndLoc);
|
|
|
|
Tok.setLocation(StartLoc);
|
|
|
|
PP.AnnotateCachedTokens(Tok);
|
2009-06-25 01:47:40 +08:00
|
|
|
}
|
|
|
|
|
2011-05-19 13:37:45 +08:00
|
|
|
void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) {
|
|
|
|
assert(Tok.is(tok::kw___underlying_type) &&
|
|
|
|
"Not an underlying type specifier");
|
|
|
|
|
|
|
|
SourceLocation StartLoc = ConsumeToken();
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
if (T.expectAndConsume(diag::err_expected_lparen_after,
|
|
|
|
"__underlying_type", tok::r_paren)) {
|
2011-05-19 13:37:45 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeResult Result = ParseTypeName();
|
|
|
|
if (Result.isInvalid()) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2011-05-19 13:37:45 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Match the ')'
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
|
|
|
if (T.getCloseLocation().isInvalid())
|
2011-05-19 13:37:45 +08:00
|
|
|
return;
|
|
|
|
|
2014-05-21 14:02:52 +08:00
|
|
|
const char *PrevSpec = nullptr;
|
2011-05-19 13:37:45 +08:00
|
|
|
unsigned DiagID;
|
2011-05-25 06:41:36 +08:00
|
|
|
if (DS.SetTypeSpecType(DeclSpec::TST_underlyingType, StartLoc, PrevSpec,
|
2014-05-29 18:55:11 +08:00
|
|
|
DiagID, Result.get(),
|
2014-01-15 17:15:43 +08:00
|
|
|
Actions.getASTContext().getPrintingPolicy()))
|
2011-05-19 13:37:45 +08:00
|
|
|
Diag(StartLoc, DiagID) << PrevSpec;
|
2013-07-07 02:54:58 +08:00
|
|
|
DS.setTypeofParensRange(T.getRange());
|
2011-05-19 13:37:45 +08:00
|
|
|
}
|
|
|
|
|
2011-10-25 23:01:20 +08:00
|
|
|
/// ParseBaseTypeSpecifier - Parse a C++ base-type-specifier which is either a
|
|
|
|
/// class name or decltype-specifier. 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 either a type or null, depending on whether a type
|
|
|
|
/// name was found.
|
2008-11-06 04:51:48 +08:00
|
|
|
///
|
2013-02-20 07:47:15 +08:00
|
|
|
/// base-type-specifier: [C++11 class.derived]
|
2011-10-25 23:01:20 +08:00
|
|
|
/// class-or-decltype
|
2013-02-20 07:47:15 +08:00
|
|
|
/// class-or-decltype: [C++11 class.derived]
|
2011-10-25 23:01:20 +08:00
|
|
|
/// nested-name-specifier[opt] class-name
|
|
|
|
/// decltype-specifier
|
2013-02-20 07:47:15 +08:00
|
|
|
/// class-name: [C++ class.name]
|
2008-11-06 04:51:48 +08:00
|
|
|
/// identifier
|
2009-02-26 07:52:28 +08:00
|
|
|
/// simple-template-id
|
2009-09-09 23:08:12 +08:00
|
|
|
///
|
2013-02-20 07:47:15 +08:00
|
|
|
/// In C++98, instead of base-type-specifier, we have:
|
|
|
|
///
|
|
|
|
/// ::[opt] nested-name-specifier[opt] class-name
|
2014-10-31 14:57:07 +08:00
|
|
|
TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
|
|
|
|
SourceLocation &EndLocation) {
|
2011-10-26 02:46:41 +08:00
|
|
|
// Ignore attempts to use typename
|
|
|
|
if (Tok.is(tok::kw_typename)) {
|
|
|
|
Diag(Tok, diag::err_expected_class_name_not_template)
|
|
|
|
<< FixItHint::CreateRemoval(Tok.getLocation());
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
|
|
|
|
2011-10-26 02:17:58 +08:00
|
|
|
// Parse optional nested-name-specifier
|
|
|
|
CXXScopeSpec SS;
|
|
|
|
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
|
|
|
|
|
|
|
|
BaseLoc = Tok.getLocation();
|
|
|
|
|
2011-10-26 01:10:12 +08:00
|
|
|
// Parse decltype-specifier
|
2011-12-04 13:04:18 +08:00
|
|
|
// tok == kw_decltype is just error recovery, it can only happen when SS
|
|
|
|
// isn't empty
|
|
|
|
if (Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) {
|
2011-10-26 02:17:58 +08:00
|
|
|
if (SS.isNotEmpty())
|
|
|
|
Diag(SS.getBeginLoc(), diag::err_unexpected_scope_on_base_decltype)
|
|
|
|
<< FixItHint::CreateRemoval(SS.getRange());
|
2011-10-26 01:10:12 +08:00
|
|
|
// Fake up a Declarator to use with ActOnTypeName.
|
|
|
|
DeclSpec DS(AttrFactory);
|
|
|
|
|
2011-12-08 12:53:15 +08:00
|
|
|
EndLocation = ParseDecltypeSpecifier(DS);
|
2011-10-26 01:10:12 +08:00
|
|
|
|
|
|
|
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
|
|
|
|
return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
|
|
|
|
}
|
|
|
|
|
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)) {
|
2011-06-22 14:09:49 +08:00
|
|
|
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
|
2010-01-13 01:52:59 +08:00
|
|
|
if (TemplateId->Kind == TNK_Type_template ||
|
|
|
|
TemplateId->Kind == TNK_Dependent_template_name) {
|
2011-03-02 08:47:37 +08:00
|
|
|
AnnotateTemplateIdTokenAsType();
|
2009-02-26 07:52:28 +08:00
|
|
|
|
|
|
|
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType Type = getTypeAnnotation(Tok);
|
2009-02-26 07:52:28 +08:00
|
|
|
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;
|
2010-07-03 01:43:08 +08:00
|
|
|
if (!Actions.DiagnoseUnknownTemplateName(*Id, IdLoc, getCurScope(),
|
2011-03-02 08:47:37 +08:00
|
|
|
&SS, Template, TNK)) {
|
2010-01-13 05:28:44 +08:00
|
|
|
Diag(IdLoc, diag::err_unknown_template_name)
|
|
|
|
<< Id;
|
|
|
|
}
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2013-08-10 13:54:47 +08:00
|
|
|
if (!Template) {
|
|
|
|
TemplateArgList TemplateArgs;
|
|
|
|
SourceLocation LAngleLoc, RAngleLoc;
|
|
|
|
ParseTemplateIdAfterTemplateName(TemplateTy(), IdLoc, SS,
|
|
|
|
true, LAngleLoc, TemplateArgs, RAngleLoc);
|
2010-01-13 05:28:44 +08:00
|
|
|
return true;
|
2013-08-10 13:54:47 +08:00
|
|
|
}
|
2010-01-13 05:28:44 +08:00
|
|
|
|
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.
|
2012-01-27 17:46:47 +08:00
|
|
|
if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(),
|
|
|
|
TemplateName, true))
|
2010-01-13 05:28:44 +08:00
|
|
|
return true;
|
|
|
|
if (TNK == TNK_Dependent_template_name)
|
2011-03-02 08:47:37 +08:00
|
|
|
AnnotateTemplateIdTokenAsType();
|
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();
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType Type = getTypeAnnotation(Tok);
|
2010-01-13 05:28:44 +08:00
|
|
|
ConsumeToken();
|
|
|
|
return Type;
|
|
|
|
}
|
|
|
|
|
2008-11-06 04:51:48 +08:00
|
|
|
// We have an identifier; check whether it is actually a type.
|
2014-05-21 14:02:52 +08:00
|
|
|
IdentifierInfo *CorrectedII = nullptr;
|
2011-03-02 08:47:37 +08:00
|
|
|
ParsedType Type = Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, true,
|
2011-03-02 02:12:44 +08:00
|
|
|
false, ParsedType(),
|
2012-01-27 16:46:19 +08:00
|
|
|
/*IsCtorOrDtorName=*/false,
|
2012-06-23 07:37:05 +08:00
|
|
|
/*NonTrivialTypeSourceInfo=*/true,
|
|
|
|
&CorrectedII);
|
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;
|
2010-07-27 00:56:01 +08:00
|
|
|
|
|
|
|
// Fake up a Declarator to use with ActOnTypeName.
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2010-07-27 00:56:01 +08:00
|
|
|
DS.SetRangeStart(IdLoc);
|
|
|
|
DS.SetRangeEnd(EndLocation);
|
2011-03-02 08:47:37 +08:00
|
|
|
DS.getTypeSpecScope() = SS;
|
2010-07-27 00:56:01 +08:00
|
|
|
|
2014-05-21 14:02:52 +08:00
|
|
|
const char *PrevSpec = nullptr;
|
2010-07-27 00:56:01 +08:00
|
|
|
unsigned DiagID;
|
2014-01-15 17:15:43 +08:00
|
|
|
DS.SetTypeSpecType(TST_typename, IdLoc, PrevSpec, DiagID, Type,
|
|
|
|
Actions.getASTContext().getPrintingPolicy());
|
2010-07-27 00:56:01 +08:00
|
|
|
|
|
|
|
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
|
|
|
|
return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
|
2008-11-06 04:51:48 +08:00
|
|
|
}
|
|
|
|
|
2012-05-23 05:28:12 +08:00
|
|
|
void Parser::ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs) {
|
|
|
|
while (Tok.is(tok::kw___single_inheritance) ||
|
|
|
|
Tok.is(tok::kw___multiple_inheritance) ||
|
|
|
|
Tok.is(tok::kw___virtual_inheritance)) {
|
|
|
|
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation AttrNameLoc = ConsumeToken();
|
2014-05-21 14:02:52 +08:00
|
|
|
attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
|
2013-12-19 07:44:18 +08:00
|
|
|
AttributeList::AS_Keyword);
|
2012-05-23 05:28:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-26 05:37:02 +08:00
|
|
|
/// Determine whether the following tokens are valid after a type-specifier
|
|
|
|
/// which could be a standalone declaration. This will conservatively return
|
|
|
|
/// true if there's any doubt, and is appropriate for insert-';' fixits.
|
2012-07-03 03:14:01 +08:00
|
|
|
bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
|
2012-06-26 05:37:02 +08:00
|
|
|
// This switch enumerates the valid "follow" set for type-specifiers.
|
|
|
|
switch (Tok.getKind()) {
|
|
|
|
default: break;
|
|
|
|
case tok::semi: // struct foo {...} ;
|
|
|
|
case tok::star: // struct foo {...} * P;
|
|
|
|
case tok::amp: // struct foo {...} & R = ...
|
2013-01-19 11:48:05 +08:00
|
|
|
case tok::ampamp: // struct foo {...} && R = ...
|
2012-06-26 05:37:02 +08:00
|
|
|
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;
|
|
|
|
case tok::l_paren: // struct foo {...} ( x);
|
|
|
|
case tok::comma: // __builtin_offsetof(struct foo{...} ,
|
2013-01-19 11:48:05 +08:00
|
|
|
case tok::kw_operator: // struct foo operator ++() {...}
|
2013-11-25 04:24:54 +08:00
|
|
|
case tok::kw___declspec: // struct foo {...} __declspec(...)
|
2014-08-13 10:13:15 +08:00
|
|
|
case tok::l_square: // void f(struct f [ 3])
|
|
|
|
case tok::ellipsis: // void f(struct f ... [Ns])
|
2014-08-16 16:29:27 +08:00
|
|
|
// FIXME: we should emit semantic diagnostic when declaration
|
|
|
|
// attribute is in type attribute position.
|
|
|
|
case tok::kw___attribute: // struct foo __attribute__((used)) x;
|
2012-06-26 05:37:02 +08:00
|
|
|
return true;
|
2012-07-03 03:14:01 +08:00
|
|
|
case tok::colon:
|
|
|
|
return CouldBeBitfield; // enum E { ... } : 2;
|
2012-06-26 05:37:02 +08:00
|
|
|
// 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;
|
2014-08-13 10:13:15 +08:00
|
|
|
case tok::kw__Atomic: // struct foo {...} _Atomic x;
|
2013-01-19 11:48:05 +08:00
|
|
|
// Function specifiers
|
|
|
|
// Note, no 'explicit'. An explicit function must be either a conversion
|
|
|
|
// operator or a constructor. Either way, it can't have a return type.
|
|
|
|
case tok::kw_inline: // struct foo inline f();
|
|
|
|
case tok::kw_virtual: // struct foo virtual f();
|
|
|
|
case tok::kw_friend: // struct foo friend f();
|
2012-06-26 05:37:02 +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;
|
|
|
|
case tok::kw_mutable: // struct foo {...} mutable x;
|
2013-01-19 11:48:05 +08:00
|
|
|
case tok::kw_thread_local: // struct foo {...} thread_local x;
|
2012-06-26 05:37:02 +08:00
|
|
|
case tok::kw_constexpr: // struct foo {...} constexpr x;
|
|
|
|
// As shown above, type qualifiers and storage class specifiers absolutely
|
|
|
|
// can occur after class specifiers according to the grammar. However,
|
|
|
|
// almost no one 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()))
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
case tok::r_brace: // struct bar { struct foo {...} }
|
|
|
|
// Missing ';' at end of struct is accepted as an extension in C mode.
|
|
|
|
if (!getLangOpts().CPlusPlus)
|
|
|
|
return true;
|
|
|
|
break;
|
2013-01-29 12:13:32 +08:00
|
|
|
case tok::greater:
|
|
|
|
// template<class T = class X>
|
|
|
|
return getLangOpts().CPlusPlus;
|
2012-06-26 05:37:02 +08:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
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
|
2012-03-12 15:56:15 +08:00
|
|
|
/// cannot start a definition.
|
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,
|
2011-11-08 01:33:42 +08:00
|
|
|
AccessSpecifier AS,
|
2012-11-27 06:54:45 +08:00
|
|
|
bool EnteringContext, DeclSpecContext DSC,
|
2012-12-21 03:22:21 +08:00
|
|
|
ParsedAttributesWithRange &Attributes) {
|
2012-09-01 06:18:20 +08:00
|
|
|
DeclSpec::TST TagType;
|
|
|
|
if (TagTokKind == tok::kw_struct)
|
|
|
|
TagType = DeclSpec::TST_struct;
|
|
|
|
else if (TagTokKind == tok::kw___interface)
|
|
|
|
TagType = DeclSpec::TST_interface;
|
|
|
|
else if (TagTokKind == tok::kw_class)
|
|
|
|
TagType = DeclSpec::TST_class;
|
|
|
|
else {
|
2009-04-13 05:49:30 +08:00
|
|
|
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.
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteTag(getCurScope(), TagType);
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2009-09-18 23:37:17 +08:00
|
|
|
}
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2010-06-28 16:39:25 +08:00
|
|
|
// C++03 [temp.explicit] 14.7.2/8:
|
|
|
|
// The usual access checking rules do not apply to names used to specify
|
|
|
|
// explicit instantiations.
|
|
|
|
//
|
|
|
|
// As an extension we do not perform access checking on the names used to
|
|
|
|
// specify explicit specializations either. This is important to allow
|
|
|
|
// specializing traits classes for private types.
|
2012-05-07 14:16:58 +08:00
|
|
|
//
|
|
|
|
// Note that we don't suppress if this turns out to be an elaborated
|
|
|
|
// type specifier.
|
|
|
|
bool shouldDelayDiagsInTag =
|
|
|
|
(TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation ||
|
|
|
|
TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization);
|
|
|
|
SuppressAccessChecks diagsFromTag(*this, shouldDelayDiagsInTag);
|
2010-06-28 16:39:25 +08:00
|
|
|
|
2012-06-23 13:07:58 +08:00
|
|
|
ParsedAttributesWithRange attrs(AttrFactory);
|
2008-04-14 05:30:24 +08:00
|
|
|
// If attributes exist after tag, parse them.
|
2013-10-24 09:21:09 +08:00
|
|
|
MaybeParseGNUAttributes(attrs);
|
2008-04-14 05:30:24 +08:00
|
|
|
|
2008-12-25 04:59:21 +08:00
|
|
|
// If declspecs exist after tag, parse them.
|
2010-08-06 01:13:11 +08:00
|
|
|
while (Tok.is(tok::kw___declspec))
|
2010-12-24 10:08:15 +08:00
|
|
|
ParseMicrosoftDeclSpec(attrs);
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2012-05-23 05:28:12 +08:00
|
|
|
// Parse inheritance specifiers.
|
|
|
|
if (Tok.is(tok::kw___single_inheritance) ||
|
|
|
|
Tok.is(tok::kw___multiple_inheritance) ||
|
|
|
|
Tok.is(tok::kw___virtual_inheritance))
|
2013-10-24 09:21:09 +08:00
|
|
|
ParseMicrosoftInheritanceClassAttributes(attrs);
|
2012-05-23 05:28:12 +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?
|
2013-01-02 20:01:23 +08:00
|
|
|
MaybeParseCXX11Attributes(attrs);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2013-01-08 00:57:11 +08:00
|
|
|
// Source location used by FIXIT to insert misplaced
|
|
|
|
// C++11 attributes
|
|
|
|
SourceLocation AttrFixitLoc = Tok.getLocation();
|
|
|
|
|
2014-09-23 12:09:56 +08:00
|
|
|
if (TagType == DeclSpec::TST_struct &&
|
|
|
|
!Tok.is(tok::identifier) &&
|
|
|
|
Tok.getIdentifierInfo() &&
|
2014-09-24 11:28:54 +08:00
|
|
|
(Tok.is(tok::kw___is_abstract) ||
|
|
|
|
Tok.is(tok::kw___is_arithmetic) ||
|
|
|
|
Tok.is(tok::kw___is_array) ||
|
|
|
|
Tok.is(tok::kw___is_base_of) ||
|
|
|
|
Tok.is(tok::kw___is_class) ||
|
|
|
|
Tok.is(tok::kw___is_complete_type) ||
|
|
|
|
Tok.is(tok::kw___is_compound) ||
|
|
|
|
Tok.is(tok::kw___is_const) ||
|
|
|
|
Tok.is(tok::kw___is_constructible) ||
|
2014-09-23 12:09:56 +08:00
|
|
|
Tok.is(tok::kw___is_convertible) ||
|
2014-09-24 11:28:54 +08:00
|
|
|
Tok.is(tok::kw___is_convertible_to) ||
|
|
|
|
Tok.is(tok::kw___is_destructible) ||
|
2014-09-23 12:09:56 +08:00
|
|
|
Tok.is(tok::kw___is_empty) ||
|
2014-09-24 11:28:54 +08:00
|
|
|
Tok.is(tok::kw___is_enum) ||
|
2014-09-23 12:09:56 +08:00
|
|
|
Tok.is(tok::kw___is_floating_point) ||
|
2014-09-24 11:28:54 +08:00
|
|
|
Tok.is(tok::kw___is_final) ||
|
2014-09-23 12:09:56 +08:00
|
|
|
Tok.is(tok::kw___is_function) ||
|
|
|
|
Tok.is(tok::kw___is_fundamental) ||
|
|
|
|
Tok.is(tok::kw___is_integral) ||
|
2014-09-24 11:28:54 +08:00
|
|
|
Tok.is(tok::kw___is_interface_class) ||
|
|
|
|
Tok.is(tok::kw___is_literal) ||
|
|
|
|
Tok.is(tok::kw___is_lvalue_expr) ||
|
|
|
|
Tok.is(tok::kw___is_lvalue_reference) ||
|
2014-09-23 12:09:56 +08:00
|
|
|
Tok.is(tok::kw___is_member_function_pointer) ||
|
2014-09-24 11:28:54 +08:00
|
|
|
Tok.is(tok::kw___is_member_object_pointer) ||
|
2014-09-23 12:09:56 +08:00
|
|
|
Tok.is(tok::kw___is_member_pointer) ||
|
2014-09-24 11:28:54 +08:00
|
|
|
Tok.is(tok::kw___is_nothrow_assignable) ||
|
|
|
|
Tok.is(tok::kw___is_nothrow_constructible) ||
|
|
|
|
Tok.is(tok::kw___is_nothrow_destructible) ||
|
|
|
|
Tok.is(tok::kw___is_object) ||
|
2014-09-23 12:09:56 +08:00
|
|
|
Tok.is(tok::kw___is_pod) ||
|
|
|
|
Tok.is(tok::kw___is_pointer) ||
|
2014-09-24 11:28:54 +08:00
|
|
|
Tok.is(tok::kw___is_polymorphic) ||
|
|
|
|
Tok.is(tok::kw___is_reference) ||
|
|
|
|
Tok.is(tok::kw___is_rvalue_expr) ||
|
|
|
|
Tok.is(tok::kw___is_rvalue_reference) ||
|
2014-09-23 12:09:56 +08:00
|
|
|
Tok.is(tok::kw___is_same) ||
|
|
|
|
Tok.is(tok::kw___is_scalar) ||
|
2014-09-24 11:28:54 +08:00
|
|
|
Tok.is(tok::kw___is_sealed) ||
|
2014-09-23 12:09:56 +08:00
|
|
|
Tok.is(tok::kw___is_signed) ||
|
2014-09-24 11:28:54 +08:00
|
|
|
Tok.is(tok::kw___is_standard_layout) ||
|
|
|
|
Tok.is(tok::kw___is_trivial) ||
|
|
|
|
Tok.is(tok::kw___is_trivially_assignable) ||
|
|
|
|
Tok.is(tok::kw___is_trivially_constructible) ||
|
|
|
|
Tok.is(tok::kw___is_trivially_copyable) ||
|
|
|
|
Tok.is(tok::kw___is_union) ||
|
2014-09-23 12:09:56 +08:00
|
|
|
Tok.is(tok::kw___is_unsigned) ||
|
2014-09-24 11:28:54 +08:00
|
|
|
Tok.is(tok::kw___is_void) ||
|
|
|
|
Tok.is(tok::kw___is_volatile)))
|
2014-09-23 12:09:56 +08:00
|
|
|
// GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the
|
|
|
|
// name of struct templates, but some are keywords in GCC >= 4.3
|
|
|
|
// and Clang. Therefore, when we see the token sequence "struct
|
|
|
|
// X", make X into a normal identifier rather than a keyword, to
|
|
|
|
// allow libstdc++ 4.2 and libc++ to work properly.
|
|
|
|
TryKeywordIdentFallback(true);
|
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();
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus) {
|
2014-07-16 13:16:52 +08:00
|
|
|
// "FOO : BAR" is not a potential typo for "FOO::BAR". In this context it
|
|
|
|
// is a base-specifier-list.
|
2009-12-10 08:32:41 +08:00
|
|
|
ColonProtectionRAIIObject X(*this);
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2011-11-08 01:33:42 +08:00
|
|
|
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
|
2010-07-30 14:26:29 +08:00
|
|
|
DS.SetTypeSpecError();
|
2010-02-26 16:45:28 +08:00
|
|
|
if (SS.isSet())
|
2009-12-10 08:32:41 +08:00
|
|
|
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::identifier;
|
2009-12-10 08:32:41 +08:00
|
|
|
}
|
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.
|
2014-05-21 14:02:52 +08:00
|
|
|
IdentifierInfo *Name = nullptr;
|
2008-04-14 05:30:24 +08:00
|
|
|
SourceLocation NameLoc;
|
2014-05-21 14:02:52 +08:00
|
|
|
TemplateIdAnnotation *TemplateId = nullptr;
|
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
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (Tok.is(tok::less) && getLangOpts().CPlusPlus) {
|
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;
|
2011-03-02 08:47:37 +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)
|
2014-01-06 20:54:41 +08:00
|
|
|
<< (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
|
|
|
|
<< TagTokKind << Name << SourceRange(LAngleLoc, RAngleLoc);
|
2012-09-01 06:18:20 +08:00
|
|
|
|
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 {
|
2014-05-21 14:02:52 +08:00
|
|
|
TemplateParams = nullptr;
|
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.
|
2014-05-21 14:02:52 +08:00
|
|
|
TemplateParams = nullptr;
|
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
|
|
|
}
|
|
|
|
}
|
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)) {
|
2011-06-22 14:09:49 +08:00
|
|
|
TemplateId = takeTemplateIdAnnotation(Tok);
|
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
|
|
|
NameLoc = ConsumeToken();
|
2009-02-18 07:15:12 +08:00
|
|
|
|
2011-03-02 08:47:37 +08:00
|
|
|
if (TemplateId->Kind != TNK_Type_template &&
|
|
|
|
TemplateId->Kind != TNK_Dependent_template_name) {
|
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());
|
|
|
|
|
2013-12-04 08:28:23 +08:00
|
|
|
// FIXME: Name may be null here.
|
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
|
|
|
Diag(TemplateId->LAngleLoc, diag::err_template_spec_syntax_non_template)
|
2013-06-20 06:25:01 +08:00
|
|
|
<< TemplateId->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();
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::semi, StopBeforeMatch);
|
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
|
|
|
return;
|
2009-02-18 07:15:12 +08:00
|
|
|
}
|
2008-04-14 05:30:24 +08:00
|
|
|
}
|
|
|
|
|
2012-03-12 16:56:40 +08:00
|
|
|
// There are four options here.
|
|
|
|
// - If we are in a trailing return type, this is always just a reference,
|
|
|
|
// and we must not try to parse a definition. For instance,
|
|
|
|
// [] () -> struct S { };
|
|
|
|
// does not define a type.
|
|
|
|
// - If we have 'struct foo {...', 'struct foo :...',
|
|
|
|
// 'struct foo final :' or 'struct foo final {', then this is a definition.
|
|
|
|
// - If we have 'struct foo;', then this is either a forward declaration
|
|
|
|
// or a friend declaration, which have to be treated differently.
|
|
|
|
// - Otherwise we have something like 'struct foo xyz', a reference.
|
2012-11-27 06:54:45 +08:00
|
|
|
//
|
|
|
|
// We also detect these erroneous cases to provide better diagnostic for
|
|
|
|
// C++11 attributes parsing.
|
|
|
|
// - attributes follow class name:
|
|
|
|
// struct foo [[]] {};
|
|
|
|
// - attributes appear before or after 'final':
|
|
|
|
// struct foo [[]] final [[]] {};
|
|
|
|
//
|
2012-03-12 15:56:15 +08:00
|
|
|
// However, in type-specifier-seq's, things look like declarations but are
|
|
|
|
// just references, e.g.
|
|
|
|
// new struct s;
|
2010-02-04 05:21:43 +08:00
|
|
|
// or
|
2012-03-12 15:56:15 +08:00
|
|
|
// &T::operator struct s;
|
2014-01-08 08:56:48 +08:00
|
|
|
// For these, DSC is DSC_type_specifier or DSC_alias_declaration.
|
2012-11-27 06:54:45 +08:00
|
|
|
|
|
|
|
// If there are attributes after class name, parse them.
|
2013-01-02 20:01:23 +08:00
|
|
|
MaybeParseCXX11Attributes(Attributes);
|
2012-11-27 06:54:45 +08:00
|
|
|
|
2014-01-15 17:15:43 +08:00
|
|
|
const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy();
|
2010-08-27 07:41:50 +08:00
|
|
|
Sema::TagUseKind TUK;
|
2012-03-12 16:56:40 +08:00
|
|
|
if (DSC == DSC_trailing)
|
|
|
|
TUK = Sema::TUK_Reference;
|
|
|
|
else if (Tok.is(tok::l_brace) ||
|
|
|
|
(getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
|
2013-01-02 20:01:23 +08:00
|
|
|
(isCXX11FinalKeyword() &&
|
2012-03-12 23:39:49 +08:00
|
|
|
(NextToken().is(tok::l_brace) || NextToken().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.
|
2012-01-10 09:33:14 +08:00
|
|
|
Diag(Tok.getLocation(), diag::err_friend_decl_defines_type)
|
2009-09-26 14:47:28 +08:00
|
|
|
<< SourceRange(DS.getFriendSpecLoc());
|
|
|
|
|
|
|
|
// Skip everything up to the semicolon, so that this looks like a proper
|
|
|
|
// friend class (or template thereof) declaration.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::semi, StopBeforeMatch);
|
2010-08-27 07:41:50 +08:00
|
|
|
TUK = Sema::TUK_Friend;
|
2009-09-26 14:47:28 +08:00
|
|
|
} else {
|
|
|
|
// Okay, this is a class definition.
|
2010-08-27 07:41:50 +08:00
|
|
|
TUK = Sema::TUK_Definition;
|
2009-09-26 14:47:28 +08:00
|
|
|
}
|
2013-02-22 14:46:23 +08:00
|
|
|
} else if (isCXX11FinalKeyword() && (NextToken().is(tok::l_square) ||
|
|
|
|
NextToken().is(tok::kw_alignas))) {
|
2012-11-27 06:54:45 +08:00
|
|
|
// We can't tell if this is a definition or reference
|
|
|
|
// until we skipped the 'final' and C++11 attribute specifiers.
|
|
|
|
TentativeParsingAction PA(*this);
|
|
|
|
|
|
|
|
// Skip the 'final' keyword.
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
// Skip C++11 attribute specifiers.
|
|
|
|
while (true) {
|
|
|
|
if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) {
|
|
|
|
ConsumeBracket();
|
2013-11-18 16:17:37 +08:00
|
|
|
if (!SkipUntil(tok::r_square, StopAtSemi))
|
2012-11-27 06:54:45 +08:00
|
|
|
break;
|
2013-02-22 14:46:23 +08:00
|
|
|
} else if (Tok.is(tok::kw_alignas) && NextToken().is(tok::l_paren)) {
|
2012-11-27 06:54:45 +08:00
|
|
|
ConsumeToken();
|
|
|
|
ConsumeParen();
|
2013-11-18 16:17:37 +08:00
|
|
|
if (!SkipUntil(tok::r_paren, StopAtSemi))
|
2012-11-27 06:54:45 +08:00
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Tok.is(tok::l_brace) || Tok.is(tok::colon))
|
|
|
|
TUK = Sema::TUK_Definition;
|
|
|
|
else
|
|
|
|
TUK = Sema::TUK_Reference;
|
|
|
|
|
|
|
|
PA.Revert();
|
2014-01-08 08:56:48 +08:00
|
|
|
} else if (!isTypeSpecifier(DSC) &&
|
2012-06-26 05:37:02 +08:00
|
|
|
(Tok.is(tok::semi) ||
|
2012-07-03 03:14:01 +08:00
|
|
|
(Tok.isAtStartOfLine() && !isValidAfterTypeSpecifier(false)))) {
|
2010-08-27 07:41:50 +08:00
|
|
|
TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration;
|
2012-09-01 06:18:20 +08:00
|
|
|
if (Tok.isNot(tok::semi)) {
|
2014-01-15 17:15:43 +08:00
|
|
|
const PrintingPolicy &PPol = Actions.getASTContext().getPrintingPolicy();
|
2012-09-01 06:18:20 +08:00
|
|
|
// A semicolon was missing after this declaration. Diagnose and recover.
|
2014-01-01 11:08:43 +08:00
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_after,
|
2014-01-15 17:15:43 +08:00
|
|
|
DeclSpec::getSpecifierName(TagType, PPol));
|
2012-09-01 06:18:20 +08:00
|
|
|
PP.EnterToken(Tok);
|
|
|
|
Tok.setKind(tok::semi);
|
|
|
|
}
|
2012-06-26 05:37:02 +08:00
|
|
|
} else
|
2010-08-27 07:41:50 +08:00
|
|
|
TUK = Sema::TUK_Reference;
|
2008-04-14 05:30:24 +08:00
|
|
|
|
2012-11-27 06:54:45 +08:00
|
|
|
// Forbid misplaced attributes. In cases of a reference, we pass attributes
|
|
|
|
// to caller to handle.
|
2013-01-08 00:57:11 +08:00
|
|
|
if (TUK != Sema::TUK_Reference) {
|
|
|
|
// If this is not a reference, then the only possible
|
|
|
|
// valid place for C++11 attributes to appear here
|
|
|
|
// is between class-key and class-name. If there are
|
|
|
|
// any attributes after class-name, we try a fixit to move
|
|
|
|
// them to the right place.
|
|
|
|
SourceRange AttrRange = Attributes.Range;
|
|
|
|
if (AttrRange.isValid()) {
|
|
|
|
Diag(AttrRange.getBegin(), diag::err_attributes_not_allowed)
|
|
|
|
<< AttrRange
|
|
|
|
<< FixItHint::CreateInsertionFromRange(AttrFixitLoc,
|
|
|
|
CharSourceRange(AttrRange, true))
|
|
|
|
<< FixItHint::CreateRemoval(AttrRange);
|
|
|
|
|
|
|
|
// Recover by adding misplaced attributes to the attribute list
|
|
|
|
// of the class so they can be applied on the class later.
|
|
|
|
attrs.takeAllFrom(Attributes);
|
|
|
|
}
|
|
|
|
}
|
2012-11-27 06:54:45 +08:00
|
|
|
|
2012-05-07 14:16:58 +08:00
|
|
|
// If this is an elaborated type specifier, and we delayed
|
|
|
|
// diagnostics before, just merge them into the current pool.
|
|
|
|
if (shouldDelayDiagsInTag) {
|
|
|
|
diagsFromTag.done();
|
|
|
|
if (TUK == Sema::TUK_Reference)
|
|
|
|
diagsFromTag.redelay();
|
|
|
|
}
|
|
|
|
|
2010-07-30 14:26:29 +08:00
|
|
|
if (!Name && !TemplateId && (DS.getTypeSpecType() == DeclSpec::TST_error ||
|
2010-08-27 07:41:50 +08:00
|
|
|
TUK != Sema::TUK_Definition)) {
|
2010-07-30 14:26:29 +08:00
|
|
|
if (DS.getTypeSpecType() != DeclSpec::TST_error) {
|
|
|
|
// We have a declaration or reference to an anonymous class.
|
|
|
|
Diag(StartLoc, diag::err_anon_type_definition)
|
2014-01-15 17:15:43 +08:00
|
|
|
<< DeclSpec::getSpecifierName(TagType, Policy);
|
2010-07-30 14:26:29 +08:00
|
|
|
}
|
2008-04-14 05:30:24 +08:00
|
|
|
|
2013-12-05 09:36:53 +08:00
|
|
|
// If we are parsing a definition and stop at a base-clause, continue on
|
|
|
|
// until the semicolon. Continuing from the comma will just trick us into
|
|
|
|
// thinking we are seeing a variable declaration.
|
|
|
|
if (TUK == Sema::TUK_Definition && Tok.is(tok::colon))
|
|
|
|
SkipUntil(tok::semi, StopBeforeMatch);
|
|
|
|
else
|
|
|
|
SkipUntil(tok::comma, StopAtSemi);
|
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.
|
2010-08-21 17:40:31 +08:00
|
|
|
DeclResult TagOrTempResult = true; // invalid
|
|
|
|
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.
|
2012-08-24 07:38:35 +08:00
|
|
|
ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
|
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->NumArgs);
|
2009-05-13 07:25:50 +08:00
|
|
|
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
|
2010-08-27 07:41:50 +08:00
|
|
|
TUK == Sema::TUK_Declaration) {
|
2009-05-13 07:25:50 +08:00
|
|
|
// This is an explicit instantiation of a class template.
|
2012-06-23 13:07:58 +08:00
|
|
|
ProhibitAttributes(attrs);
|
|
|
|
|
2009-05-13 07:25:50 +08:00
|
|
|
TagOrTempResult
|
2010-07-03 01:43:08 +08:00
|
|
|
= Actions.ActOnExplicitInstantiation(getCurScope(),
|
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,
|
2010-08-23 15:28:44 +08:00
|
|
|
TemplateId->Template,
|
2009-09-09 23:08:12 +08:00
|
|
|
TemplateId->TemplateNameLoc,
|
|
|
|
TemplateId->LAngleLoc,
|
2009-05-13 07:25:50 +08:00
|
|
|
TemplateArgsPtr,
|
2009-09-09 23:08:12 +08:00
|
|
|
TemplateId->RAngleLoc,
|
2010-12-24 10:08:15 +08:00
|
|
|
attrs.getList());
|
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.
|
2010-08-27 07:41:50 +08:00
|
|
|
} else if (TUK == Sema::TUK_Reference ||
|
|
|
|
(TUK == Sema::TUK_Friend &&
|
2010-04-14 08:24:33 +08:00
|
|
|
TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) {
|
2012-06-23 13:07:58 +08:00
|
|
|
ProhibitAttributes(attrs);
|
2012-02-06 22:41:24 +08:00
|
|
|
TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType, StartLoc,
|
2011-03-02 08:47:37 +08:00
|
|
|
TemplateId->SS,
|
2012-02-06 22:41:24 +08:00
|
|
|
TemplateId->TemplateKWLoc,
|
2011-03-02 08:47:37 +08:00
|
|
|
TemplateId->Template,
|
|
|
|
TemplateId->TemplateNameLoc,
|
|
|
|
TemplateId->LAngleLoc,
|
|
|
|
TemplateArgsPtr,
|
2012-02-06 22:41:24 +08:00
|
|
|
TemplateId->RAngleLoc);
|
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'.
|
2013-11-09 03:03:29 +08:00
|
|
|
// It this is friend declaration however, since it cannot have a
|
|
|
|
// template header, it is most likely that the user meant to
|
|
|
|
// remove the 'template' keyword.
|
2013-06-22 21:56:11 +08:00
|
|
|
assert((TUK == Sema::TUK_Definition || TUK == Sema::TUK_Friend) &&
|
2013-11-09 03:03:29 +08:00
|
|
|
"Expected a definition here");
|
|
|
|
|
|
|
|
if (TUK == Sema::TUK_Friend) {
|
|
|
|
Diag(DS.getFriendSpecLoc(), diag::err_friend_explicit_instantiation);
|
2014-05-21 14:02:52 +08:00
|
|
|
TemplateParams = nullptr;
|
2013-11-09 03:03:29 +08:00
|
|
|
} else {
|
|
|
|
SourceLocation LAngleLoc =
|
|
|
|
PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
|
|
|
|
Diag(TemplateId->TemplateNameLoc,
|
|
|
|
diag::err_explicit_instantiation_with_definition)
|
|
|
|
<< SourceRange(TemplateInfo.TemplateLoc)
|
|
|
|
<< FixItHint::CreateInsertion(LAngleLoc, "<>");
|
|
|
|
|
|
|
|
// Create a fake template parameter list that contains only
|
|
|
|
// "template<>", so that we treat this construct as a class
|
|
|
|
// template specialization.
|
|
|
|
FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
|
2014-05-21 14:02:52 +08:00
|
|
|
0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, nullptr,
|
|
|
|
0, LAngleLoc));
|
2013-11-09 03:03:29 +08:00
|
|
|
TemplateParams = &FakedParamLists;
|
|
|
|
}
|
2009-05-13 07:25:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Build the class template specialization.
|
2014-04-17 11:29:33 +08:00
|
|
|
TagOrTempResult = Actions.ActOnClassTemplateSpecialization(
|
|
|
|
getCurScope(), TagType, TUK, StartLoc, DS.getModulePrivateSpecLoc(),
|
|
|
|
*TemplateId, attrs.getList(),
|
2014-05-21 14:02:52 +08:00
|
|
|
MultiTemplateParamsArg(TemplateParams ? &(*TemplateParams)[0]
|
|
|
|
: nullptr,
|
2014-04-17 11:29:33 +08:00
|
|
|
TemplateParams ? TemplateParams->size() : 0));
|
2009-05-13 07:25:50 +08:00
|
|
|
}
|
2009-05-14 08:28:11 +08:00
|
|
|
} else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
|
2010-08-27 07:41:50 +08:00
|
|
|
TUK == Sema::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;
|
|
|
|
//
|
2012-06-23 13:07:58 +08:00
|
|
|
ProhibitAttributes(attrs);
|
|
|
|
|
2009-05-14 08:28:11 +08:00
|
|
|
TagOrTempResult
|
2010-07-03 01:43:08 +08:00
|
|
|
= Actions.ActOnExplicitInstantiation(getCurScope(),
|
2009-09-04 14:33:52 +08:00
|
|
|
TemplateInfo.ExternLoc,
|
2009-09-09 23:08:12 +08:00
|
|
|
TemplateInfo.TemplateLoc,
|
|
|
|
TagType, StartLoc, SS, Name,
|
2010-12-24 10:08:15 +08:00
|
|
|
NameLoc, attrs.getList());
|
2010-10-19 09:40:49 +08:00
|
|
|
} else if (TUK == Sema::TUK_Friend &&
|
|
|
|
TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) {
|
2012-06-23 13:07:58 +08:00
|
|
|
ProhibitAttributes(attrs);
|
|
|
|
|
2010-10-19 09:40:49 +08:00
|
|
|
TagOrTempResult =
|
|
|
|
Actions.ActOnTemplatedFriendTag(getCurScope(), DS.getFriendSpecLoc(),
|
|
|
|
TagType, StartLoc, SS,
|
2010-12-24 10:08:15 +08:00
|
|
|
Name, NameLoc, attrs.getList(),
|
2012-08-24 07:38:35 +08:00
|
|
|
MultiTemplateParamsArg(
|
2014-05-21 14:02:52 +08:00
|
|
|
TemplateParams? &(*TemplateParams)[0]
|
|
|
|
: nullptr,
|
2010-10-19 09:40:49 +08:00
|
|
|
TemplateParams? TemplateParams->size() : 0));
|
2009-05-14 08:28:11 +08:00
|
|
|
} else {
|
2012-06-23 13:07:58 +08:00
|
|
|
if (TUK != Sema::TUK_Declaration && TUK != Sema::TUK_Definition)
|
|
|
|
ProhibitAttributes(attrs);
|
2013-11-09 03:03:29 +08:00
|
|
|
|
2013-06-21 08:08:46 +08:00
|
|
|
if (TUK == Sema::TUK_Definition &&
|
|
|
|
TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
|
|
|
|
// If the declarator-id is not a template-id, issue a diagnostic and
|
|
|
|
// recover by ignoring the 'template' keyword.
|
|
|
|
Diag(Tok, diag::err_template_defn_explicit_instantiation)
|
|
|
|
<< 1 << FixItHint::CreateRemoval(TemplateInfo.TemplateLoc);
|
2014-05-21 14:02:52 +08:00
|
|
|
TemplateParams = nullptr;
|
2013-06-21 08:08:46 +08:00
|
|
|
}
|
2012-06-23 13:07:58 +08:00
|
|
|
|
2009-09-11 12:59:25 +08:00
|
|
|
bool IsDependent = false;
|
|
|
|
|
2010-10-20 02:40:57 +08:00
|
|
|
// Don't pass down template parameter lists if this is just a tag
|
|
|
|
// reference. For example, we don't need the template parameters here:
|
|
|
|
// template <class T> class A *makeA(T t);
|
|
|
|
MultiTemplateParamsArg TParams;
|
|
|
|
if (TUK != Sema::TUK_Reference && TemplateParams)
|
|
|
|
TParams =
|
|
|
|
MultiTemplateParamsArg(&(*TemplateParams)[0], TemplateParams->size());
|
|
|
|
|
2009-05-14 08:28:11 +08:00
|
|
|
// Declaration or definition of a class type
|
2010-10-19 09:40:49 +08:00
|
|
|
TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc,
|
2010-12-24 10:08:15 +08:00
|
|
|
SS, Name, NameLoc, attrs.getList(), AS,
|
2011-09-10 03:05:14 +08:00
|
|
|
DS.getModulePrivateSpecLoc(),
|
2012-01-10 09:33:14 +08:00
|
|
|
TParams, Owned, IsDependent,
|
|
|
|
SourceLocation(), false,
|
2014-01-08 08:56:48 +08:00
|
|
|
clang::TypeResult(),
|
|
|
|
DSC == DSC_type_specifier);
|
2009-09-11 12:59:25 +08:00
|
|
|
|
|
|
|
// If ActOnTag said the type was dependent, try again with the
|
|
|
|
// less common call.
|
2010-10-19 09:40:49 +08:00
|
|
|
if (IsDependent) {
|
|
|
|
assert(TUK == Sema::TUK_Reference || TUK == Sema::TUK_Friend);
|
2010-07-03 01:43:08 +08:00
|
|
|
TypeResult = Actions.ActOnDependentTag(getCurScope(), TagType, TUK,
|
2010-03-13 18:17:05 +08:00
|
|
|
SS, Name, StartLoc, NameLoc);
|
2010-10-19 09:40:49 +08:00
|
|
|
}
|
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.
|
2010-08-27 07:41:50 +08:00
|
|
|
if (TUK == Sema::TUK_Definition) {
|
2009-12-20 05:48:58 +08:00
|
|
|
assert(Tok.is(tok::l_brace) ||
|
2012-03-11 15:00:24 +08:00
|
|
|
(getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
|
2013-01-02 20:01:23 +08:00
|
|
|
isCXX11FinalKeyword());
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus)
|
2013-01-08 00:57:11 +08:00
|
|
|
ParseCXXMemberSpecification(StartLoc, AttrFixitLoc, attrs, 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
|
|
|
}
|
|
|
|
|
2014-05-21 14:02:52 +08:00
|
|
|
const char *PrevSpec = nullptr;
|
2010-08-24 13:47:05 +08:00
|
|
|
unsigned DiagID;
|
|
|
|
bool Result;
|
2009-09-11 12:59:25 +08:00
|
|
|
if (!TypeResult.isInvalid()) {
|
2011-03-17 04:16:18 +08:00
|
|
|
Result = DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc,
|
|
|
|
NameLoc.isValid() ? NameLoc : StartLoc,
|
2014-01-15 17:15:43 +08:00
|
|
|
PrevSpec, DiagID, TypeResult.get(), Policy);
|
2009-09-11 12:59:25 +08:00
|
|
|
} else if (!TagOrTempResult.isInvalid()) {
|
2011-03-17 04:16:18 +08:00
|
|
|
Result = DS.SetTypeSpecType(TagType, StartLoc,
|
|
|
|
NameLoc.isValid() ? NameLoc : StartLoc,
|
2014-01-15 17:15:43 +08:00
|
|
|
PrevSpec, DiagID, TagOrTempResult.get(), Owned,
|
|
|
|
Policy);
|
2009-09-11 12:59:25 +08:00
|
|
|
} 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
|
|
|
|
2010-08-24 13:47:05 +08:00
|
|
|
if (Result)
|
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.
|
|
|
|
//
|
2012-06-26 05:37:02 +08:00
|
|
|
// Also enforce C++ [temp]p3:
|
|
|
|
// In a template-declaration which defines a class, no declarator
|
|
|
|
// is permitted.
|
2014-08-13 10:13:15 +08:00
|
|
|
//
|
|
|
|
// After a type-specifier, we don't expect a semicolon. This only happens in
|
|
|
|
// C, since definitions are not permitted in this context in C++.
|
2012-09-01 06:18:20 +08:00
|
|
|
if (TUK == Sema::TUK_Definition &&
|
2014-08-13 10:13:15 +08:00
|
|
|
(getLangOpts().CPlusPlus || !isTypeSpecifier(DSC)) &&
|
2012-09-01 06:18:20 +08:00
|
|
|
(TemplateInfo.Kind || !isValidAfterTypeSpecifier(false))) {
|
2012-12-18 04:10:43 +08:00
|
|
|
if (Tok.isNot(tok::semi)) {
|
2014-01-15 17:15:43 +08:00
|
|
|
const PrintingPolicy &PPol = Actions.getASTContext().getPrintingPolicy();
|
2014-01-01 11:08:43 +08:00
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_after,
|
2014-01-15 17:15:43 +08:00
|
|
|
DeclSpec::getSpecifierName(TagType, PPol));
|
2012-12-18 04:10:43 +08:00
|
|
|
// 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);
|
|
|
|
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]
|
2010-08-21 17:40:31 +08:00
|
|
|
void Parser::ParseBaseClause(Decl *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.
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<CXXBaseSpecifier *, 8> BaseInfo;
|
2008-10-23 01:49:05 +08:00
|
|
|
|
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.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::comma, tok::l_brace, StopAtSemi | StopBeforeMatch);
|
2008-10-23 01:49:05 +08:00
|
|
|
} 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.
|
2014-01-10 19:19:30 +08:00
|
|
|
if (!TryConsumeToken(tok::comma))
|
|
|
|
break;
|
2008-04-14 05:30:24 +08:00
|
|
|
}
|
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]
|
2013-02-20 07:47:15 +08:00
|
|
|
/// attribute-specifier-seq[opt] base-type-specifier
|
|
|
|
/// attribute-specifier-seq[opt] 'virtual' access-specifier[opt]
|
|
|
|
/// base-type-specifier
|
|
|
|
/// attribute-specifier-seq[opt] access-specifier 'virtual'[opt]
|
|
|
|
/// base-type-specifier
|
2014-10-31 14:57:07 +08:00
|
|
|
BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
|
2008-04-14 05:30:24 +08:00
|
|
|
bool IsVirtual = false;
|
|
|
|
SourceLocation StartLoc = Tok.getLocation();
|
|
|
|
|
2013-02-20 07:47:15 +08:00
|
|
|
ParsedAttributesWithRange Attributes(AttrFactory);
|
|
|
|
MaybeParseCXX11Attributes(Attributes);
|
|
|
|
|
2008-04-14 05:30:24 +08:00
|
|
|
// Parse the 'virtual' keyword.
|
2014-01-10 19:19:30 +08:00
|
|
|
if (TryConsumeToken(tok::kw_virtual))
|
2008-04-14 05:30:24 +08:00
|
|
|
IsVirtual = true;
|
|
|
|
|
2013-02-20 07:47:15 +08:00
|
|
|
CheckMisplacedCXX11Attribute(Attributes, StartLoc);
|
|
|
|
|
2008-04-14 05:30:24 +08:00
|
|
|
// 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
|
|
|
|
2013-02-20 07:47:15 +08:00
|
|
|
CheckMisplacedCXX11Attribute(Attributes, StartLoc);
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-02-20 07:47:15 +08:00
|
|
|
CheckMisplacedCXX11Attribute(Attributes, StartLoc);
|
|
|
|
|
2008-11-06 04:51:48 +08:00
|
|
|
// Parse the class-name.
|
2009-02-26 07:52:28 +08:00
|
|
|
SourceLocation EndLocation;
|
2011-10-26 01:10:12 +08:00
|
|
|
SourceLocation BaseLoc;
|
|
|
|
TypeResult BaseType = ParseBaseTypeSpecifier(BaseLoc, EndLocation);
|
2009-04-02 05:51:26 +08:00
|
|
|
if (BaseType.isInvalid())
|
2008-11-06 04:51:48 +08:00
|
|
|
return true;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-01-04 06:36:02 +08:00
|
|
|
// Parse the optional ellipsis (for a pack expansion). The ellipsis is
|
|
|
|
// actually part of the base-specifier-list grammar productions, but we
|
|
|
|
// parse it here for convenience.
|
|
|
|
SourceLocation EllipsisLoc;
|
2014-01-10 19:19:30 +08:00
|
|
|
TryConsumeToken(tok::ellipsis, EllipsisLoc);
|
|
|
|
|
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.
|
2013-02-20 07:47:15 +08:00
|
|
|
return Actions.ActOnBaseSpecifier(ClassDecl, Range, Attributes, IsVirtual,
|
|
|
|
Access, BaseType.get(), BaseLoc,
|
|
|
|
EllipsisLoc);
|
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
|
|
|
|
2012-04-17 02:27:27 +08:00
|
|
|
/// \brief If the given declarator has any parts for which parsing has to be
|
2012-05-03 06:22:32 +08:00
|
|
|
/// delayed, e.g., default arguments, create a late-parsed method declaration
|
|
|
|
/// record to handle the parsing at the end of the class definition.
|
2012-04-17 02:27:27 +08:00
|
|
|
void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo,
|
|
|
|
Decl *ThisDecl) {
|
2009-07-23 05:45:50 +08:00
|
|
|
// We just declared a member function. If this member function
|
2012-05-03 06:22:32 +08:00
|
|
|
// has any default arguments, we'll need to parse them later.
|
2014-05-21 14:02:52 +08:00
|
|
|
LateParsedMethodDeclaration *LateMethod = nullptr;
|
2009-09-09 23:08:12 +08:00
|
|
|
DeclaratorChunk::FunctionTypeInfo &FTI
|
2010-12-11 00:29:40 +08:00
|
|
|
= DeclaratorInfo.getFunctionTypeInfo();
|
2012-04-17 02:27:27 +08:00
|
|
|
|
2014-02-27 06:27:52 +08:00
|
|
|
for (unsigned ParamIdx = 0; ParamIdx < FTI.NumParams; ++ParamIdx) {
|
|
|
|
if (LateMethod || FTI.Params[ParamIdx].DefaultArgTokens) {
|
2009-07-23 05:45:50 +08:00
|
|
|
if (!LateMethod) {
|
|
|
|
// Push this method onto the stack of late-parsed method
|
|
|
|
// declarations.
|
2010-10-13 00:25:54 +08:00
|
|
|
LateMethod = new LateParsedMethodDeclaration(this, ThisDecl);
|
|
|
|
getCurrentClass().LateParsedDeclarations.push_back(LateMethod);
|
2010-07-03 01:43:08 +08:00
|
|
|
LateMethod->TemplateScope = getCurScope()->isTemplateParamScope();
|
2009-07-23 05:45:50 +08:00
|
|
|
|
|
|
|
// Add all of the parameters prior to this one (they don't
|
|
|
|
// have default arguments).
|
2014-02-27 06:27:52 +08:00
|
|
|
LateMethod->DefaultArgs.reserve(FTI.NumParams);
|
2009-07-23 05:45:50 +08:00
|
|
|
for (unsigned I = 0; I < ParamIdx; ++I)
|
|
|
|
LateMethod->DefaultArgs.push_back(
|
2014-02-27 06:27:52 +08:00
|
|
|
LateParsedDefaultArgument(FTI.Params[I].Param));
|
2009-07-23 05:45:50 +08:00
|
|
|
}
|
|
|
|
|
2012-04-17 02:27:27 +08:00
|
|
|
// Add this parameter to the list of parameters (it may or may
|
2009-07-23 05:45:50 +08:00
|
|
|
// not have a default argument).
|
2014-02-27 06:27:52 +08:00
|
|
|
LateMethod->DefaultArgs.push_back(LateParsedDefaultArgument(
|
|
|
|
FTI.Params[ParamIdx].Param, FTI.Params[ParamIdx].DefaultArgTokens));
|
2009-07-23 05:45:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-02 20:01:23 +08:00
|
|
|
/// isCXX11VirtSpecifier - Determine whether the given token is a C++11
|
2011-01-17 07:56:42 +08:00
|
|
|
/// virt-specifier.
|
|
|
|
///
|
|
|
|
/// virt-specifier:
|
|
|
|
/// override
|
|
|
|
/// final
|
2013-01-02 20:01:23 +08:00
|
|
|
VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const {
|
2014-01-09 08:13:52 +08:00
|
|
|
if (!getLangOpts().CPlusPlus || Tok.isNot(tok::identifier))
|
2011-01-23 00:56:46 +08:00
|
|
|
return VirtSpecifiers::VS_None;
|
|
|
|
|
2014-01-09 08:13:52 +08:00
|
|
|
IdentifierInfo *II = Tok.getIdentifierInfo();
|
2011-01-20 11:47:08 +08:00
|
|
|
|
2014-01-09 08:13:52 +08:00
|
|
|
// Initialize the contextual keywords.
|
|
|
|
if (!Ident_final) {
|
|
|
|
Ident_final = &PP.getIdentifierTable().get("final");
|
|
|
|
if (getLangOpts().MicrosoftExt)
|
|
|
|
Ident_sealed = &PP.getIdentifierTable().get("sealed");
|
|
|
|
Ident_override = &PP.getIdentifierTable().get("override");
|
|
|
|
}
|
2011-01-17 07:56:42 +08:00
|
|
|
|
2014-01-09 08:13:52 +08:00
|
|
|
if (II == Ident_override)
|
|
|
|
return VirtSpecifiers::VS_Override;
|
2013-10-18 08:33:31 +08:00
|
|
|
|
2014-01-09 08:13:52 +08:00
|
|
|
if (II == Ident_sealed)
|
|
|
|
return VirtSpecifiers::VS_Sealed;
|
|
|
|
|
|
|
|
if (II == Ident_final)
|
|
|
|
return VirtSpecifiers::VS_Final;
|
2011-01-17 11:05:47 +08:00
|
|
|
|
|
|
|
return VirtSpecifiers::VS_None;
|
2011-01-17 07:56:42 +08:00
|
|
|
}
|
|
|
|
|
2013-01-02 20:01:23 +08:00
|
|
|
/// ParseOptionalCXX11VirtSpecifierSeq - Parse a virt-specifier-seq.
|
2011-01-17 07:56:42 +08:00
|
|
|
///
|
|
|
|
/// virt-specifier-seq:
|
|
|
|
/// virt-specifier
|
|
|
|
/// virt-specifier-seq virt-specifier
|
2013-01-02 20:01:23 +08:00
|
|
|
void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS,
|
2014-08-12 08:22:39 +08:00
|
|
|
bool IsInterface,
|
|
|
|
SourceLocation FriendLoc) {
|
2011-01-17 11:05:47 +08:00
|
|
|
while (true) {
|
2013-01-02 20:01:23 +08:00
|
|
|
VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier();
|
2011-01-17 11:05:47 +08:00
|
|
|
if (Specifier == VirtSpecifiers::VS_None)
|
|
|
|
return;
|
|
|
|
|
2014-08-12 08:22:39 +08:00
|
|
|
if (FriendLoc.isValid()) {
|
|
|
|
Diag(Tok.getLocation(), diag::err_friend_decl_spec)
|
|
|
|
<< VirtSpecifiers::getSpecifierName(Specifier)
|
|
|
|
<< FixItHint::CreateRemoval(Tok.getLocation())
|
|
|
|
<< SourceRange(FriendLoc, FriendLoc);
|
|
|
|
ConsumeToken();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-01-17 11:05:47 +08:00
|
|
|
// C++ [class.mem]p8:
|
|
|
|
// A virt-specifier-seq shall contain at most one of each virt-specifier.
|
2014-05-21 14:02:52 +08:00
|
|
|
const char *PrevSpec = nullptr;
|
2011-01-22 23:58:16 +08:00
|
|
|
if (VS.SetSpecifier(Specifier, Tok.getLocation(), PrevSpec))
|
2011-01-17 11:05:47 +08:00
|
|
|
Diag(Tok.getLocation(), diag::err_duplicate_virt_specifier)
|
|
|
|
<< PrevSpec
|
|
|
|
<< FixItHint::CreateRemoval(Tok.getLocation());
|
|
|
|
|
2013-10-18 08:33:31 +08:00
|
|
|
if (IsInterface && (Specifier == VirtSpecifiers::VS_Final ||
|
|
|
|
Specifier == VirtSpecifiers::VS_Sealed)) {
|
2012-09-25 15:32:39 +08:00
|
|
|
Diag(Tok.getLocation(), diag::err_override_control_interface)
|
|
|
|
<< VirtSpecifiers::getSpecifierName(Specifier);
|
2013-10-18 08:33:31 +08:00
|
|
|
} else if (Specifier == VirtSpecifiers::VS_Sealed) {
|
|
|
|
Diag(Tok.getLocation(), diag::ext_ms_sealed_keyword);
|
2012-09-25 15:32:39 +08:00
|
|
|
} else {
|
2013-10-18 08:33:31 +08:00
|
|
|
Diag(Tok.getLocation(),
|
|
|
|
getLangOpts().CPlusPlus11
|
|
|
|
? diag::warn_cxx98_compat_override_control_keyword
|
|
|
|
: diag::ext_override_control_keyword)
|
|
|
|
<< VirtSpecifiers::getSpecifierName(Specifier);
|
2012-09-25 15:32:39 +08:00
|
|
|
}
|
2011-01-17 11:05:47 +08:00
|
|
|
ConsumeToken();
|
|
|
|
}
|
2011-01-17 07:56:42 +08:00
|
|
|
}
|
|
|
|
|
2013-01-02 20:01:23 +08:00
|
|
|
/// isCXX11FinalKeyword - Determine whether the next token is a C++11
|
2014-01-09 08:13:52 +08:00
|
|
|
/// 'final' or Microsoft 'sealed' contextual keyword.
|
2013-01-02 20:01:23 +08:00
|
|
|
bool Parser::isCXX11FinalKeyword() const {
|
2014-01-09 08:13:52 +08:00
|
|
|
VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier();
|
|
|
|
return Specifier == VirtSpecifiers::VS_Final ||
|
|
|
|
Specifier == VirtSpecifiers::VS_Sealed;
|
2011-01-23 00:56:46 +08:00
|
|
|
}
|
|
|
|
|
2014-01-24 07:53:27 +08:00
|
|
|
/// \brief Parse a C++ member-declarator up to, but not including, the optional
|
|
|
|
/// brace-or-equal-initializer or pure-specifier.
|
|
|
|
void Parser::ParseCXXMemberDeclaratorBeforeInitializer(
|
|
|
|
Declarator &DeclaratorInfo, VirtSpecifiers &VS, ExprResult &BitfieldSize,
|
|
|
|
LateParsedAttrList &LateParsedAttrs) {
|
|
|
|
// member-declarator:
|
|
|
|
// declarator pure-specifier[opt]
|
|
|
|
// declarator brace-or-equal-initializer[opt]
|
|
|
|
// identifier[opt] ':' constant-expression
|
2014-07-16 13:16:52 +08:00
|
|
|
if (Tok.isNot(tok::colon))
|
2014-01-24 07:53:27 +08:00
|
|
|
ParseDeclarator(DeclaratorInfo);
|
2014-08-12 08:22:39 +08:00
|
|
|
else
|
|
|
|
DeclaratorInfo.SetIdentifier(nullptr, Tok.getLocation());
|
2014-01-24 07:53:27 +08:00
|
|
|
|
|
|
|
if (!DeclaratorInfo.isFunctionDeclarator() && TryConsumeToken(tok::colon)) {
|
2014-08-12 08:22:39 +08:00
|
|
|
assert(DeclaratorInfo.isPastIdentifier() &&
|
|
|
|
"don't know where identifier would go yet?");
|
2014-01-24 07:53:27 +08:00
|
|
|
BitfieldSize = ParseConstantExpression();
|
|
|
|
if (BitfieldSize.isInvalid())
|
|
|
|
SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
|
|
|
|
} else
|
2014-08-12 08:22:39 +08:00
|
|
|
ParseOptionalCXX11VirtSpecifierSeq(
|
|
|
|
VS, getCurrentClass().IsInterface,
|
|
|
|
DeclaratorInfo.getDeclSpec().getFriendSpecLoc());
|
2014-01-24 07:53:27 +08:00
|
|
|
|
|
|
|
// If a simple-asm-expr is present, parse it.
|
|
|
|
if (Tok.is(tok::kw_asm)) {
|
|
|
|
SourceLocation Loc;
|
|
|
|
ExprResult AsmLabel(ParseSimpleAsm(&Loc));
|
|
|
|
if (AsmLabel.isInvalid())
|
|
|
|
SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
|
|
|
|
|
2014-05-29 18:55:11 +08:00
|
|
|
DeclaratorInfo.setAsmLabel(AsmLabel.get());
|
2014-01-24 07:53:27 +08:00
|
|
|
DeclaratorInfo.SetRangeEnd(Loc);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If attributes exist after the declarator, but before an '{', parse them.
|
|
|
|
MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
|
2014-01-25 06:34:35 +08:00
|
|
|
|
|
|
|
// For compatibility with code written to older Clang, also accept a
|
|
|
|
// virt-specifier *after* the GNU attributes.
|
2014-08-05 01:03:51 +08:00
|
|
|
if (BitfieldSize.isUnset() && VS.isUnset()) {
|
2014-08-12 08:22:39 +08:00
|
|
|
ParseOptionalCXX11VirtSpecifierSeq(
|
|
|
|
VS, getCurrentClass().IsInterface,
|
|
|
|
DeclaratorInfo.getDeclSpec().getFriendSpecLoc());
|
2014-08-05 01:03:51 +08:00
|
|
|
if (!VS.isUnset()) {
|
|
|
|
// If we saw any GNU-style attributes that are known to GCC followed by a
|
|
|
|
// virt-specifier, issue a GCC-compat warning.
|
|
|
|
const AttributeList *Attr = DeclaratorInfo.getAttributes();
|
|
|
|
while (Attr) {
|
|
|
|
if (Attr->isKnownToGCC() && !Attr->isCXX11Attribute())
|
|
|
|
Diag(Attr->getLoc(), diag::warn_gcc_attribute_location);
|
|
|
|
Attr = Attr->getNext();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-01-24 07:53:27 +08:00
|
|
|
}
|
|
|
|
|
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:
|
2011-01-17 07:56:42 +08:00
|
|
|
/// declarator virt-specifier-seq[opt] pure-specifier[opt]
|
2008-06-25 06:12:16 +08:00
|
|
|
/// declarator constant-initializer[opt]
|
2011-06-12 01:19:42 +08:00
|
|
|
/// [C++11] declarator brace-or-equal-initializer[opt]
|
2008-06-25 06:12:16 +08:00
|
|
|
/// identifier[opt] ':' constant-expression
|
|
|
|
///
|
2011-01-17 07:56:42 +08:00
|
|
|
/// virt-specifier-seq:
|
|
|
|
/// virt-specifier
|
|
|
|
/// virt-specifier-seq virt-specifier
|
|
|
|
///
|
|
|
|
/// virt-specifier:
|
|
|
|
/// override
|
|
|
|
/// final
|
2013-10-18 08:33:31 +08:00
|
|
|
/// [MS] sealed
|
2011-01-17 07:56:42 +08:00
|
|
|
///
|
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,
|
2011-10-13 17:41:32 +08:00
|
|
|
AttributeList *AccessAttrs,
|
2010-07-16 16:13:16 +08:00
|
|
|
const ParsedTemplateInfo &TemplateInfo,
|
|
|
|
ParsingDeclRAIIObject *TemplateDiags) {
|
2011-04-15 01:21:19 +08:00
|
|
|
if (Tok.is(tok::at)) {
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().ObjC1 && NextToken().isObjCAtKeyword(tok::objc_defs))
|
2011-04-15 01:21:19 +08:00
|
|
|
Diag(Tok, diag::err_at_defs_cxx);
|
|
|
|
else
|
|
|
|
Diag(Tok, diag::err_at_in_class);
|
2013-11-09 12:52:51 +08:00
|
|
|
|
2011-04-15 01:21:19 +08:00
|
|
|
ConsumeToken();
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace, StopAtSemi);
|
2011-04-15 01:21:19 +08:00
|
|
|
return;
|
|
|
|
}
|
2013-11-09 12:52:51 +08:00
|
|
|
|
2014-07-16 13:16:52 +08:00
|
|
|
// Turn on colon protection early, while parsing declspec, although there is
|
|
|
|
// nothing to protect there. It prevents from false errors if error recovery
|
|
|
|
// incorrectly determines where the declspec ends, as in the example:
|
|
|
|
// struct A { enum class B { C }; };
|
|
|
|
// const int C = 4;
|
|
|
|
// struct D { A::B : C; };
|
|
|
|
ColonProtectionRAIIObject X(*this);
|
|
|
|
|
2009-12-11 10:10:03 +08:00
|
|
|
// Access declarations.
|
2012-05-09 16:23:23 +08:00
|
|
|
bool MalformedTypeSpec = false;
|
2009-12-11 10:10:03 +08:00
|
|
|
if (!TemplateInfo.Kind &&
|
2014-09-26 08:28:20 +08:00
|
|
|
(Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
|
|
|
|
Tok.is(tok::kw___super))) {
|
2012-05-09 16:23:23 +08:00
|
|
|
if (TryAnnotateCXXScopeToken())
|
|
|
|
MalformedTypeSpec = true;
|
|
|
|
|
|
|
|
bool isAccessDecl;
|
|
|
|
if (Tok.isNot(tok::annot_cxxscope))
|
|
|
|
isAccessDecl = false;
|
|
|
|
else if (NextToken().is(tok::identifier))
|
2009-12-11 10:10:03 +08:00
|
|
|
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;
|
2011-11-08 01:33:42 +08:00
|
|
|
ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
|
|
|
|
/*EnteringContext=*/false);
|
2009-12-11 10:10:03 +08:00
|
|
|
|
2014-09-10 08:59:37 +08:00
|
|
|
if (SS.isInvalid()) {
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-12-11 10:10:03 +08:00
|
|
|
// Try to parse an unqualified-id.
|
2012-01-27 17:46:47 +08:00
|
|
|
SourceLocation TemplateKWLoc;
|
2009-12-11 10:10:03 +08:00
|
|
|
UnqualifiedId Name;
|
2012-01-27 17:46:47 +08:00
|
|
|
if (ParseUnqualifiedId(SS, false, true, true, ParsedType(),
|
|
|
|
TemplateKWLoc, Name)) {
|
2009-12-11 10:10:03 +08:00
|
|
|
SkipUntil(tok::semi);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: recover from mistakenly-qualified operator declarations.
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::semi, diag::err_expected_after,
|
|
|
|
"access declaration")) {
|
|
|
|
SkipUntil(tok::semi);
|
2009-12-11 10:10:03 +08:00
|
|
|
return;
|
2014-01-01 11:08:43 +08:00
|
|
|
}
|
2009-12-11 10:10:03 +08:00
|
|
|
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.ActOnUsingDeclaration(getCurScope(), AS,
|
2013-07-22 18:54:09 +08:00
|
|
|
/* HasUsingKeyword */ false,
|
|
|
|
SourceLocation(),
|
2009-12-11 10:10:03 +08:00
|
|
|
SS, Name,
|
2014-05-21 14:02:52 +08:00
|
|
|
/* AttrList */ nullptr,
|
2013-07-22 18:54:09 +08:00
|
|
|
/* HasTypenameKeyword */ false,
|
2009-12-11 10:10:03 +08:00
|
|
|
SourceLocation());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-05 04:28:35 +08:00
|
|
|
// static_assert-declaration. A templated static_assert declaration is
|
|
|
|
// diagnosed in Parser::ParseSingleDeclarationAfterTemplate.
|
|
|
|
if (!TemplateInfo.Kind &&
|
|
|
|
(Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert))) {
|
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,
|
2011-10-13 17:41:32 +08:00
|
|
|
AS, AccessAttrs);
|
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();
|
2011-10-13 17:41:32 +08:00
|
|
|
return ParseCXXClassMemberDeclaration(AS, AccessAttrs,
|
|
|
|
TemplateInfo, TemplateDiags);
|
2008-12-18 09:12:00 +08:00
|
|
|
}
|
2009-06-20 08:51:54 +08:00
|
|
|
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributesWithRange attrs(AttrFactory);
|
2012-11-29 07:17:40 +08:00
|
|
|
ParsedAttributesWithRange FnAttrs(AttrFactory);
|
2013-01-02 20:01:23 +08:00
|
|
|
// Optional C++11 attribute-specifier
|
|
|
|
MaybeParseCXX11Attributes(attrs);
|
2012-11-29 07:17:40 +08:00
|
|
|
// We need to keep these attributes for future diagnostic
|
|
|
|
// before they are taken over by declaration specifier.
|
|
|
|
FnAttrs.addAll(attrs.getList());
|
|
|
|
FnAttrs.Range = attrs.Range;
|
|
|
|
|
2010-12-24 10:08:15 +08:00
|
|
|
MaybeParseMicrosoftAttributes(attrs);
|
2009-11-21 16:43:09 +08:00
|
|
|
|
2009-06-20 08:51:54 +08:00
|
|
|
if (Tok.is(tok::kw_using)) {
|
2010-12-24 10:08:15 +08:00
|
|
|
ProhibitAttributes(attrs);
|
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);
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::semi, StopBeforeMatch);
|
2010-02-02 08:43:15 +08:00
|
|
|
} else {
|
2009-06-20 08:51:54 +08:00
|
|
|
SourceLocation DeclEnd;
|
2011-05-06 05:57:07 +08:00
|
|
|
// Otherwise, it must be a using-declaration or an alias-declaration.
|
2010-11-10 10:40:36 +08:00
|
|
|
ParseUsingDeclaration(Declarator::MemberContext, TemplateInfo,
|
|
|
|
UsingLoc, DeclEnd, AS);
|
2009-06-20 08:51:54 +08:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-03-03 06:12:59 +08:00
|
|
|
// Hold late-parsed attributes so we can attach a Decl to them later.
|
|
|
|
LateParsedAttrList CommonLateParsedAttrs;
|
|
|
|
|
2008-06-25 06:12:16 +08:00
|
|
|
// decl-specifier-seq:
|
|
|
|
// Parse the common declaration-specifiers piece.
|
2010-07-16 16:13:16 +08:00
|
|
|
ParsingDeclSpec DS(*this, TemplateDiags);
|
2010-12-24 10:08:15 +08:00
|
|
|
DS.takeAttributesFrom(attrs);
|
2012-05-09 16:23:23 +08:00
|
|
|
if (MalformedTypeSpec)
|
|
|
|
DS.SetTypeSpecError();
|
2014-01-24 07:53:27 +08:00
|
|
|
|
2014-07-16 13:16:52 +08:00
|
|
|
ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class,
|
|
|
|
&CommonLateParsedAttrs);
|
|
|
|
|
|
|
|
// Turn off colon protection that was set for declspec.
|
|
|
|
X.restore();
|
2008-06-25 06:12:16 +08:00
|
|
|
|
2013-11-20 06:47:36 +08:00
|
|
|
// If we had a free-standing type definition with a missing semicolon, we
|
|
|
|
// may get this far before the problem becomes obvious.
|
|
|
|
if (DS.hasTagDefinition() &&
|
|
|
|
TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate &&
|
|
|
|
DiagnoseMissingSemiAfterTagDefinition(DS, AS, DSC_class,
|
|
|
|
&CommonLateParsedAttrs))
|
|
|
|
return;
|
|
|
|
|
2012-08-24 07:38:35 +08:00
|
|
|
MultiTemplateParamsArg TemplateParams(
|
2014-05-21 14:02:52 +08:00
|
|
|
TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data()
|
|
|
|
: nullptr,
|
2009-09-17 06:47:08 +08:00
|
|
|
TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0);
|
|
|
|
|
2013-12-31 07:29:50 +08:00
|
|
|
if (TryConsumeToken(tok::semi)) {
|
2012-11-29 07:17:40 +08:00
|
|
|
if (DS.isFriendSpecified())
|
|
|
|
ProhibitAttributes(FnAttrs);
|
|
|
|
|
2010-08-21 17:40:31 +08:00
|
|
|
Decl *TheDecl =
|
2011-05-04 02:35:10 +08:00
|
|
|
Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS, TemplateParams);
|
2010-07-16 16:13:16 +08:00
|
|
|
DS.complete(TheDecl);
|
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);
|
2011-01-28 14:07:34 +08:00
|
|
|
VirtSpecifiers VS;
|
2008-06-25 06:12:16 +08:00
|
|
|
|
2011-09-09 01:42:22 +08:00
|
|
|
// Hold late-parsed attributes so we can attach a Decl to them later.
|
|
|
|
LateParsedAttrList LateParsedAttrs;
|
|
|
|
|
2011-10-18 01:09:53 +08:00
|
|
|
SourceLocation EqualLoc;
|
|
|
|
bool HasInitializer = false;
|
|
|
|
ExprResult Init;
|
2009-12-10 09:59:24 +08:00
|
|
|
|
2014-01-24 07:53:27 +08:00
|
|
|
SmallVector<Decl *, 8> DeclsInGroup;
|
|
|
|
ExprResult BitfieldSize;
|
|
|
|
bool ExpectSemi = true;
|
2008-06-25 06:12:16 +08:00
|
|
|
|
2014-01-24 07:53:27 +08:00
|
|
|
// Parse the first declarator.
|
|
|
|
ParseCXXMemberDeclaratorBeforeInitializer(DeclaratorInfo, VS, BitfieldSize,
|
|
|
|
LateParsedAttrs);
|
2011-01-28 14:07:34 +08:00
|
|
|
|
2014-01-24 07:53:27 +08:00
|
|
|
// If this has neither a name nor a bit width, something has gone seriously
|
|
|
|
// wrong. Skip until the semi-colon or }.
|
2014-01-25 06:34:35 +08:00
|
|
|
if (!DeclaratorInfo.hasName() && BitfieldSize.isUnset()) {
|
2014-01-24 07:53:27 +08:00
|
|
|
// If so, skip until the semi-colon or a }.
|
|
|
|
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
|
|
|
|
TryConsumeToken(tok::semi);
|
|
|
|
return;
|
|
|
|
}
|
2009-11-26 06:58:06 +08:00
|
|
|
|
2014-01-24 07:53:27 +08:00
|
|
|
// Check for a member function definition.
|
2014-01-25 06:34:35 +08:00
|
|
|
if (BitfieldSize.isUnset()) {
|
2014-01-24 07:53:27 +08:00
|
|
|
// MSVC permits pure specifier on inline functions defined at class scope.
|
2011-05-11 10:14:46 +08:00
|
|
|
// Hence check for =0 before checking for function definition.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().MicrosoftExt && Tok.is(tok::equal) &&
|
2014-01-24 07:53:27 +08:00
|
|
|
DeclaratorInfo.isFunctionDeclarator() &&
|
2011-05-11 10:14:46 +08:00
|
|
|
NextToken().is(tok::numeric_constant)) {
|
2011-10-18 01:09:53 +08:00
|
|
|
EqualLoc = ConsumeToken();
|
2011-05-11 10:14:46 +08:00
|
|
|
Init = ParseInitializer();
|
|
|
|
if (Init.isInvalid())
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
|
2011-10-18 01:09:53 +08:00
|
|
|
else
|
|
|
|
HasInitializer = true;
|
2011-05-11 10:14:46 +08:00
|
|
|
}
|
|
|
|
|
2011-11-08 04:56:01 +08:00
|
|
|
FunctionDefinitionKind DefinitionKind = FDK_Declaration;
|
2008-06-28 16:10:48 +08:00
|
|
|
// function-definition:
|
2011-06-12 01:19:42 +08:00
|
|
|
//
|
|
|
|
// In C++11, a non-function declarator followed by an open brace is a
|
|
|
|
// braced-init-list for an in-class member initialization, not an
|
|
|
|
// erroneous function definition.
|
2013-01-02 19:42:31 +08:00
|
|
|
if (Tok.is(tok::l_brace) && !getLangOpts().CPlusPlus11) {
|
2011-11-08 04:56:01 +08:00
|
|
|
DefinitionKind = FDK_Definition;
|
2011-05-12 14:15:49 +08:00
|
|
|
} else if (DeclaratorInfo.isFunctionDeclarator()) {
|
2011-06-12 01:19:42 +08:00
|
|
|
if (Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) {
|
2011-11-08 04:56:01 +08:00
|
|
|
DefinitionKind = FDK_Definition;
|
2011-05-12 14:15:49 +08:00
|
|
|
} else if (Tok.is(tok::equal)) {
|
|
|
|
const Token &KW = NextToken();
|
2011-11-08 04:56:01 +08:00
|
|
|
if (KW.is(tok::kw_default))
|
|
|
|
DefinitionKind = FDK_Defaulted;
|
|
|
|
else if (KW.is(tok::kw_delete))
|
|
|
|
DefinitionKind = FDK_Deleted;
|
2011-05-12 14:15:49 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-29 07:17:40 +08:00
|
|
|
// C++11 [dcl.attr.grammar] p4: If an attribute-specifier-seq appertains
|
|
|
|
// to a friend declaration, that declaration shall be a definition.
|
|
|
|
if (DeclaratorInfo.isFunctionDeclarator() &&
|
|
|
|
DefinitionKind != FDK_Definition && DS.isFriendSpecified()) {
|
|
|
|
// Diagnose attributes that appear before decl specifier:
|
|
|
|
// [[]] friend int foo();
|
|
|
|
ProhibitAttributes(FnAttrs);
|
|
|
|
}
|
|
|
|
|
2011-11-08 04:56:01 +08:00
|
|
|
if (DefinitionKind) {
|
2008-06-28 16:10:48 +08:00
|
|
|
if (!DeclaratorInfo.isFunctionDeclarator()) {
|
2012-01-21 10:59:18 +08:00
|
|
|
Diag(DeclaratorInfo.getIdentifierLoc(), diag::err_func_def_no_params);
|
2008-06-28 16:10:48 +08:00
|
|
|
ConsumeBrace();
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace);
|
2012-11-29 07:17:40 +08:00
|
|
|
|
2011-01-20 00:41:58 +08:00
|
|
|
// Consume the optional ';'
|
2013-12-31 07:29:50 +08:00
|
|
|
TryConsumeToken(tok::semi);
|
|
|
|
|
2009-03-30 00:50:03 +08:00
|
|
|
return;
|
2008-06-28 16:10:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
|
2012-01-21 10:59:18 +08:00
|
|
|
Diag(DeclaratorInfo.getIdentifierLoc(),
|
|
|
|
diag::err_function_declared_typedef);
|
2011-01-20 00:41:58 +08:00
|
|
|
|
2012-11-16 06:54:20 +08:00
|
|
|
// Recover by treating the 'typedef' as spurious.
|
|
|
|
DS.ClearStorageClassSpecs();
|
2008-06-28 16:10:48 +08:00
|
|
|
}
|
2008-06-25 06:12:16 +08:00
|
|
|
|
2011-09-09 01:42:22 +08:00
|
|
|
Decl *FunDecl =
|
2011-10-13 17:41:32 +08:00
|
|
|
ParseCXXInlineMethodDef(AS, AccessAttrs, DeclaratorInfo, TemplateInfo,
|
2011-11-08 04:56:01 +08:00
|
|
|
VS, DefinitionKind, Init);
|
2011-09-09 01:42:22 +08:00
|
|
|
|
2013-08-01 12:22:55 +08:00
|
|
|
if (FunDecl) {
|
|
|
|
for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) {
|
|
|
|
CommonLateParsedAttrs[i]->addDecl(FunDecl);
|
|
|
|
}
|
|
|
|
for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) {
|
|
|
|
LateParsedAttrs[i]->addDecl(FunDecl);
|
|
|
|
}
|
2011-09-09 01:42:22 +08:00
|
|
|
}
|
|
|
|
LateParsedAttrs.clear();
|
2011-05-12 14:15:49 +08:00
|
|
|
|
|
|
|
// Consume the ';' - it's optional unless we have a delete or default
|
2012-05-17 03:04:59 +08:00
|
|
|
if (Tok.is(tok::semi))
|
2012-07-23 13:45:25 +08:00
|
|
|
ConsumeExtraSemi(AfterMemberFunctionDefinition);
|
2011-01-20 00:41:58 +08:00
|
|
|
|
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
|
|
|
|
|
|
|
|
while (1) {
|
2012-06-10 11:12:00 +08:00
|
|
|
InClassInitStyle HasInClassInit = ICIS_NoInit;
|
2011-10-18 01:09:53 +08:00
|
|
|
if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) {
|
2011-06-12 01:19:42 +08:00
|
|
|
if (BitfieldSize.get()) {
|
|
|
|
Diag(Tok, diag::err_bitfield_member_init);
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
|
2011-06-12 01:19:42 +08:00
|
|
|
} else {
|
2011-10-10 22:49:18 +08:00
|
|
|
HasInitializer = true;
|
2012-06-10 11:12:00 +08:00
|
|
|
if (!DeclaratorInfo.isDeclarationOfFunction() &&
|
|
|
|
DeclaratorInfo.getDeclSpec().getStorageClassSpec()
|
|
|
|
!= DeclSpec::SCS_typedef)
|
|
|
|
HasInClassInit = Tok.is(tok::equal) ? ICIS_CopyInit : ICIS_ListInit;
|
2011-06-12 01:19:42 +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
|
|
|
|
2014-05-21 14:02:52 +08:00
|
|
|
NamedDecl *ThisDecl = nullptr;
|
2009-08-06 10:15:43 +08:00
|
|
|
if (DS.isFriendSpecified()) {
|
2014-01-24 07:53:27 +08:00
|
|
|
// C++11 [dcl.attr.grammar] p4: If an attribute-specifier-seq appertains
|
2012-11-29 07:17:40 +08:00
|
|
|
// to a friend declaration, that declaration shall be a definition.
|
|
|
|
//
|
2014-01-24 07:53:27 +08:00
|
|
|
// Diagnose attributes that appear in a friend member function declarator:
|
|
|
|
// friend int foo [[]] ();
|
2012-11-29 07:17:40 +08:00
|
|
|
SmallVector<SourceRange, 4> Ranges;
|
|
|
|
DeclaratorInfo.getCXX11AttributeRanges(Ranges);
|
2014-01-24 07:53:27 +08:00
|
|
|
for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(),
|
|
|
|
E = Ranges.end(); I != E; ++I)
|
|
|
|
Diag((*I).getBegin(), diag::err_attributes_not_allowed) << *I;
|
2012-11-29 07:17:40 +08:00
|
|
|
|
2010-07-03 01:43:08 +08:00
|
|
|
ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo,
|
2012-08-24 05:35:17 +08:00
|
|
|
TemplateParams);
|
2009-08-21 06:52:58 +08:00
|
|
|
} else {
|
2010-07-03 01:43:08 +08:00
|
|
|
ThisDecl = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS,
|
2009-08-06 10:15:43 +08:00
|
|
|
DeclaratorInfo,
|
2012-08-24 05:35:17 +08:00
|
|
|
TemplateParams,
|
2014-05-29 18:55:11 +08:00
|
|
|
BitfieldSize.get(),
|
2012-06-10 11:12:00 +08:00
|
|
|
VS, HasInClassInit);
|
2013-08-06 09:03:05 +08:00
|
|
|
|
|
|
|
if (VarTemplateDecl *VT =
|
2014-05-21 14:02:52 +08:00
|
|
|
ThisDecl ? dyn_cast<VarTemplateDecl>(ThisDecl) : nullptr)
|
2013-08-06 09:03:05 +08:00
|
|
|
// Re-direct this decl to refer to the templated decl so that we can
|
|
|
|
// initialize it.
|
|
|
|
ThisDecl = VT->getTemplatedDecl();
|
|
|
|
|
2013-08-01 12:22:55 +08:00
|
|
|
if (ThisDecl && AccessAttrs)
|
2013-08-29 08:47:48 +08:00
|
|
|
Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs);
|
2009-08-21 06:52:58 +08:00
|
|
|
}
|
2011-09-09 01:42:22 +08:00
|
|
|
|
2011-10-10 22:49:18 +08:00
|
|
|
// Handle the initializer.
|
2013-01-30 09:22:18 +08:00
|
|
|
if (HasInClassInit != ICIS_NoInit &&
|
|
|
|
DeclaratorInfo.getDeclSpec().getStorageClassSpec() !=
|
|
|
|
DeclSpec::SCS_static) {
|
2011-10-10 22:49:18 +08:00
|
|
|
// The initializer was deferred; parse it and cache the tokens.
|
2013-08-01 12:22:55 +08:00
|
|
|
Diag(Tok, getLangOpts().CPlusPlus11
|
|
|
|
? diag::warn_cxx98_compat_nonstatic_member_init
|
|
|
|
: diag::ext_nonstatic_member_init);
|
2011-10-15 13:09:34 +08:00
|
|
|
|
2011-06-12 01:19:42 +08:00
|
|
|
if (DeclaratorInfo.isArrayOfUnknownBound()) {
|
2012-06-10 11:12:00 +08:00
|
|
|
// C++11 [dcl.array]p3: An array bound may also be omitted when the
|
|
|
|
// declarator is followed by an initializer.
|
2011-06-12 01:19:42 +08:00
|
|
|
//
|
|
|
|
// A brace-or-equal-initializer for a member-declarator is not an
|
2012-02-14 17:00:46 +08:00
|
|
|
// initializer in the grammar, so this is ill-formed.
|
2011-06-12 01:19:42 +08:00
|
|
|
Diag(Tok, diag::err_incomplete_array_member_init);
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
|
2013-08-01 12:22:55 +08:00
|
|
|
|
|
|
|
// Avoid later warnings about a class member of incomplete type.
|
2012-02-14 17:00:46 +08:00
|
|
|
if (ThisDecl)
|
|
|
|
ThisDecl->setInvalidDecl();
|
2011-06-12 01:19:42 +08:00
|
|
|
} else
|
|
|
|
ParseCXXNonStaticMemberInitializer(ThisDecl);
|
2011-10-10 22:49:18 +08:00
|
|
|
} else if (HasInitializer) {
|
|
|
|
// Normal initializer.
|
2011-10-18 01:09:53 +08:00
|
|
|
if (!Init.isUsable())
|
2013-08-01 12:22:55 +08:00
|
|
|
Init = ParseCXXMemberInitializer(
|
|
|
|
ThisDecl, DeclaratorInfo.isDeclarationOfFunction(), EqualLoc);
|
|
|
|
|
2011-10-10 22:49:18 +08:00
|
|
|
if (Init.isInvalid())
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
|
2011-10-10 22:49:18 +08:00
|
|
|
else if (ThisDecl)
|
2012-02-22 18:50:08 +08:00
|
|
|
Actions.AddInitializerToDecl(ThisDecl, Init.get(), EqualLoc.isInvalid(),
|
2013-04-27 00:15:35 +08:00
|
|
|
DS.containsPlaceholderType());
|
2013-08-01 12:22:55 +08:00
|
|
|
} else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static)
|
2011-10-10 22:49:18 +08:00
|
|
|
// No initializer.
|
2013-04-27 00:15:35 +08:00
|
|
|
Actions.ActOnUninitializedDecl(ThisDecl, DS.containsPlaceholderType());
|
2013-08-01 12:22:55 +08:00
|
|
|
|
2011-10-10 22:49:18 +08:00
|
|
|
if (ThisDecl) {
|
2013-08-01 12:22:55 +08:00
|
|
|
if (!ThisDecl->isInvalidDecl()) {
|
|
|
|
// Set the Decl for any late parsed attributes
|
|
|
|
for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i)
|
|
|
|
CommonLateParsedAttrs[i]->addDecl(ThisDecl);
|
|
|
|
|
|
|
|
for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i)
|
|
|
|
LateParsedAttrs[i]->addDecl(ThisDecl);
|
|
|
|
}
|
2011-10-10 22:49:18 +08:00
|
|
|
Actions.FinalizeDeclaration(ThisDecl);
|
|
|
|
DeclsInGroup.push_back(ThisDecl);
|
2013-08-01 12:22:55 +08:00
|
|
|
|
|
|
|
if (DeclaratorInfo.isFunctionDeclarator() &&
|
|
|
|
DeclaratorInfo.getDeclSpec().getStorageClassSpec() !=
|
|
|
|
DeclSpec::SCS_typedef)
|
|
|
|
HandleMemberFunctionDeclDelays(DeclaratorInfo, ThisDecl);
|
2011-10-10 22:49:18 +08:00
|
|
|
}
|
2013-08-01 12:22:55 +08:00
|
|
|
LateParsedAttrs.clear();
|
2011-10-10 22:49:18 +08:00
|
|
|
|
|
|
|
DeclaratorInfo.complete(ThisDecl);
|
2011-06-12 01:19:42 +08:00
|
|
|
|
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.
|
2014-01-05 11:27:11 +08:00
|
|
|
SourceLocation CommaLoc;
|
|
|
|
if (!TryConsumeToken(tok::comma, CommaLoc))
|
2008-06-25 06:12:16 +08:00
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-01-10 06:31:44 +08:00
|
|
|
if (Tok.isAtStartOfLine() &&
|
|
|
|
!MightBeDeclarator(Declarator::MemberContext)) {
|
|
|
|
// This comma was followed by a line-break and something which can't be
|
|
|
|
// the start of a declarator. The comma was probably a typo for a
|
|
|
|
// semicolon.
|
|
|
|
Diag(CommaLoc, diag::err_expected_semi_declaration)
|
|
|
|
<< FixItHint::CreateReplacement(CommaLoc, ";");
|
|
|
|
ExpectSemi = false;
|
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-25 06:12:16 +08:00
|
|
|
// Parse the next declarator.
|
|
|
|
DeclaratorInfo.clear();
|
2011-01-28 14:07:34 +08:00
|
|
|
VS.clear();
|
2011-10-10 22:49:18 +08:00
|
|
|
BitfieldSize = true;
|
2011-10-18 01:09:53 +08:00
|
|
|
Init = true;
|
|
|
|
HasInitializer = false;
|
Improve 0-argument -Wvexing-parse diagnostic by adding notes with fix-its:
- If the declarator is at the start of a line, and the previous line contained
another declarator and ended with a comma, then that comma was probably a
typo for a semicolon:
int n = 0, m = 1, l = 2, // k = 5;
myImportantFunctionCall(); // oops!
- If removing the parentheses would correctly initialize the object, then
produce a note suggesting that fix.
- Otherwise, if there is a simple initializer we can suggest which performs
value-initialization, then provide a note suggesting a correction to that
initializer.
Sema::Declarator now tracks the location of the comma prior to the declarator in
the declaration, if there is one, to facilitate providing the note. The code to
determine an appropriate initializer from the -Wuninitialized warning has been
factored out to allow use in both that and -Wvexing-parse.
llvm-svn: 148072
2012-01-13 07:53:29 +08:00
|
|
|
DeclaratorInfo.setCommaLoc(CommaLoc);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-01-24 07:53:27 +08:00
|
|
|
// GNU attributes are allowed before the second and subsequent declarator.
|
2010-12-24 10:08:15 +08:00
|
|
|
MaybeParseGNUAttributes(DeclaratorInfo);
|
2008-06-25 06:12:16 +08:00
|
|
|
|
2014-01-24 07:53:27 +08:00
|
|
|
ParseCXXMemberDeclaratorBeforeInitializer(DeclaratorInfo, VS, BitfieldSize,
|
|
|
|
LateParsedAttrs);
|
2008-06-25 06:12:16 +08:00
|
|
|
}
|
|
|
|
|
2012-01-10 06:31:44 +08:00
|
|
|
if (ExpectSemi &&
|
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list)) {
|
2010-02-02 08:43:15 +08:00
|
|
|
// Skip to end of block or statement.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
|
2010-02-02 08:43:15 +08:00
|
|
|
// If we stopped at a ';', eat it.
|
2013-12-31 07:29:50 +08:00
|
|
|
TryConsumeToken(tok::semi);
|
2009-03-30 00:50:03 +08:00
|
|
|
return;
|
2008-06-25 06:12:16 +08:00
|
|
|
}
|
|
|
|
|
2013-07-09 20:05:01 +08:00
|
|
|
Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup);
|
2008-06-25 06:12:16 +08:00
|
|
|
}
|
|
|
|
|
2011-06-12 01:19:42 +08:00
|
|
|
/// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer or
|
|
|
|
/// pure-specifier. Also detect and reject any attempted defaulted/deleted
|
|
|
|
/// function definition. The location of the '=', if any, will be placed in
|
|
|
|
/// EqualLoc.
|
|
|
|
///
|
|
|
|
/// pure-specifier:
|
|
|
|
/// '= 0'
|
2012-02-22 18:50:08 +08:00
|
|
|
///
|
2011-06-12 01:19:42 +08:00
|
|
|
/// brace-or-equal-initializer:
|
|
|
|
/// '=' initializer-expression
|
2012-02-22 18:50:08 +08:00
|
|
|
/// braced-init-list
|
|
|
|
///
|
2011-06-12 01:19:42 +08:00
|
|
|
/// initializer-clause:
|
|
|
|
/// assignment-expression
|
2012-02-22 18:50:08 +08:00
|
|
|
/// braced-init-list
|
|
|
|
///
|
2013-11-09 12:52:51 +08:00
|
|
|
/// defaulted/deleted function-definition:
|
2011-06-12 01:19:42 +08:00
|
|
|
/// '=' 'default'
|
|
|
|
/// '=' 'delete'
|
|
|
|
///
|
|
|
|
/// Prior to C++0x, the assignment-expression in an initializer-clause must
|
|
|
|
/// be a constant-expression.
|
2012-02-21 10:22:07 +08:00
|
|
|
ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
|
2011-06-12 01:19:42 +08:00
|
|
|
SourceLocation &EqualLoc) {
|
|
|
|
assert((Tok.is(tok::equal) || Tok.is(tok::l_brace))
|
|
|
|
&& "Data member initializer not starting with '=' or '{'");
|
|
|
|
|
2012-02-21 10:22:07 +08:00
|
|
|
EnterExpressionEvaluationContext Context(Actions,
|
|
|
|
Sema::PotentiallyEvaluated,
|
|
|
|
D);
|
2014-01-05 11:27:11 +08:00
|
|
|
if (TryConsumeToken(tok::equal, EqualLoc)) {
|
2011-06-12 01:19:42 +08:00
|
|
|
if (Tok.is(tok::kw_delete)) {
|
|
|
|
// In principle, an initializer of '= delete p;' is legal, but it will
|
|
|
|
// never type-check. It's better to diagnose it as an ill-formed expression
|
|
|
|
// than as an ill-formed deleted non-function member.
|
|
|
|
// An initializer of '= delete p, foo' will never be parsed, because
|
|
|
|
// a top-level comma always ends the initializer expression.
|
|
|
|
const Token &Next = NextToken();
|
|
|
|
if (IsFunction || Next.is(tok::semi) || Next.is(tok::comma) ||
|
2013-11-23 12:06:09 +08:00
|
|
|
Next.is(tok::eof)) {
|
2011-06-12 01:19:42 +08:00
|
|
|
if (IsFunction)
|
|
|
|
Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
|
|
|
|
<< 1 /* delete */;
|
|
|
|
else
|
|
|
|
Diag(ConsumeToken(), diag::err_deleted_non_function);
|
2014-06-11 08:49:52 +08:00
|
|
|
return ExprError();
|
2011-06-12 01:19:42 +08:00
|
|
|
}
|
|
|
|
} else if (Tok.is(tok::kw_default)) {
|
|
|
|
if (IsFunction)
|
|
|
|
Diag(Tok, diag::err_default_delete_in_multiple_declaration)
|
|
|
|
<< 0 /* default */;
|
|
|
|
else
|
|
|
|
Diag(ConsumeToken(), diag::err_default_special_members);
|
2014-06-11 08:49:52 +08:00
|
|
|
return ExprError();
|
2011-06-12 01:19:42 +08:00
|
|
|
}
|
|
|
|
|
2012-02-22 18:50:08 +08:00
|
|
|
}
|
|
|
|
return ParseInitializer();
|
2011-06-12 01:19:42 +08:00
|
|
|
}
|
|
|
|
|
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]
|
|
|
|
///
|
2012-09-01 06:18:20 +08:00
|
|
|
void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
|
2013-01-08 00:57:11 +08:00
|
|
|
SourceLocation AttrFixitLoc,
|
2013-02-20 07:47:15 +08:00
|
|
|
ParsedAttributesWithRange &Attrs,
|
2012-09-01 06:18:20 +08:00
|
|
|
unsigned TagType, Decl *TagDecl) {
|
|
|
|
assert((TagType == DeclSpec::TST_struct ||
|
|
|
|
TagType == DeclSpec::TST_interface ||
|
|
|
|
TagType == DeclSpec::TST_union ||
|
|
|
|
TagType == DeclSpec::TST_class) && "Invalid TagType!");
|
|
|
|
|
2010-08-27 07:41:50 +08:00
|
|
|
PrettyDeclStackTraceEntry CrashInfo(Actions, TagDecl, RecordLoc,
|
|
|
|
"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()) {
|
2010-07-03 01:43:08 +08:00
|
|
|
for (const Scope *S = getCurScope(); S; S = S->getParent()) {
|
2010-01-17 04:52:59 +08:00
|
|
|
if (S->isClassScope()) {
|
|
|
|
// We're inside a class scope, so this is a nested class.
|
|
|
|
NonNestedClass = false;
|
2012-09-25 15:32:39 +08:00
|
|
|
|
|
|
|
// The Microsoft extension __interface does not permit nested classes.
|
|
|
|
if (getCurrentClass().IsInterface) {
|
|
|
|
Diag(RecordLoc, diag::err_invalid_member_in_interface)
|
|
|
|
<< /*ErrorType=*/6
|
|
|
|
<< (isa<NamedDecl>(TagDecl)
|
|
|
|
? cast<NamedDecl>(TagDecl)->getQualifiedNameAsString()
|
2014-04-02 13:58:29 +08:00
|
|
|
: "(anonymous)");
|
2012-09-25 15:32:39 +08:00
|
|
|
}
|
2010-01-17 04:52:59 +08:00
|
|
|
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.
|
2012-09-25 15:32:39 +08:00
|
|
|
ParsingClassDefinition ParsingDef(*this, TagDecl, NonNestedClass,
|
|
|
|
TagType == DeclSpec::TST_interface);
|
2009-05-28 07:11:45 +08:00
|
|
|
|
2009-02-07 06:42:48 +08:00
|
|
|
if (TagDecl)
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
|
2009-12-20 05:48:58 +08:00
|
|
|
|
2011-03-25 22:46:08 +08:00
|
|
|
SourceLocation FinalLoc;
|
2013-10-18 08:33:31 +08:00
|
|
|
bool IsFinalSpelledSealed = false;
|
2011-03-25 22:46:08 +08:00
|
|
|
|
|
|
|
// Parse the optional 'final' keyword.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) {
|
2013-10-18 08:33:31 +08:00
|
|
|
VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier(Tok);
|
|
|
|
assert((Specifier == VirtSpecifiers::VS_Final ||
|
|
|
|
Specifier == VirtSpecifiers::VS_Sealed) &&
|
|
|
|
"not a class definition");
|
2011-10-15 12:21:46 +08:00
|
|
|
FinalLoc = ConsumeToken();
|
2013-10-18 08:33:31 +08:00
|
|
|
IsFinalSpelledSealed = Specifier == VirtSpecifiers::VS_Sealed;
|
2011-03-25 22:46:08 +08:00
|
|
|
|
2013-10-18 08:33:31 +08:00
|
|
|
if (TagType == DeclSpec::TST_interface)
|
2012-09-25 15:32:39 +08:00
|
|
|
Diag(FinalLoc, diag::err_override_control_interface)
|
2013-10-18 08:33:31 +08:00
|
|
|
<< VirtSpecifiers::getSpecifierName(Specifier);
|
|
|
|
else if (Specifier == VirtSpecifiers::VS_Final)
|
|
|
|
Diag(FinalLoc, getLangOpts().CPlusPlus11
|
|
|
|
? diag::warn_cxx98_compat_override_control_keyword
|
|
|
|
: diag::ext_override_control_keyword)
|
|
|
|
<< VirtSpecifiers::getSpecifierName(Specifier);
|
|
|
|
else if (Specifier == VirtSpecifiers::VS_Sealed)
|
|
|
|
Diag(FinalLoc, diag::ext_ms_sealed_keyword);
|
2012-11-27 06:54:45 +08:00
|
|
|
|
2013-01-08 00:57:11 +08:00
|
|
|
// Parse any C++11 attributes after 'final' keyword.
|
|
|
|
// These attributes are not allowed to appear here,
|
|
|
|
// and the only possible place for them to appertain
|
|
|
|
// to the class would be between class-key and class-name.
|
2013-02-20 07:47:15 +08:00
|
|
|
CheckMisplacedCXX11Attribute(Attrs, AttrFixitLoc);
|
2011-03-25 22:46:08 +08:00
|
|
|
}
|
2011-01-23 00:56:46 +08:00
|
|
|
|
2009-12-20 05:48:58 +08:00
|
|
|
if (Tok.is(tok::colon)) {
|
|
|
|
ParseBaseClause(TagDecl);
|
|
|
|
if (!Tok.is(tok::l_brace)) {
|
2014-09-26 05:13:02 +08:00
|
|
|
bool SuggestFixIt = false;
|
|
|
|
SourceLocation BraceLoc = PP.getLocForEndOfToken(PrevTokLocation);
|
|
|
|
if (Tok.isAtStartOfLine()) {
|
|
|
|
switch (Tok.getKind()) {
|
|
|
|
case tok::kw_private:
|
|
|
|
case tok::kw_protected:
|
|
|
|
case tok::kw_public:
|
|
|
|
SuggestFixIt = NextToken().getKind() == tok::colon;
|
|
|
|
break;
|
|
|
|
case tok::kw_static_assert:
|
|
|
|
case tok::r_brace:
|
|
|
|
case tok::kw_using:
|
|
|
|
// base-clause can have simple-template-id; 'template' can't be there
|
|
|
|
case tok::kw_template:
|
|
|
|
SuggestFixIt = true;
|
|
|
|
break;
|
|
|
|
case tok::identifier:
|
|
|
|
SuggestFixIt = isConstructorDeclarator(true);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
SuggestFixIt = isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DiagnosticBuilder LBraceDiag =
|
|
|
|
Diag(BraceLoc, diag::err_expected_lbrace_after_base_specifiers);
|
|
|
|
if (SuggestFixIt) {
|
|
|
|
LBraceDiag << FixItHint::CreateInsertion(BraceLoc, " {");
|
|
|
|
// Try recovering from missing { after base-clause.
|
|
|
|
PP.EnterToken(Tok);
|
|
|
|
Tok.setKind(tok::l_brace);
|
|
|
|
} else {
|
|
|
|
if (TagDecl)
|
|
|
|
Actions.ActOnTagDefinitionError(getCurScope(), TagDecl);
|
|
|
|
return;
|
|
|
|
}
|
2009-12-20 05:48:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(Tok.is(tok::l_brace));
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_brace);
|
|
|
|
T.consumeOpen();
|
2009-12-20 05:48:58 +08:00
|
|
|
|
2010-05-28 16:11:17 +08:00
|
|
|
if (TagDecl)
|
2011-03-25 22:31:08 +08:00
|
|
|
Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, FinalLoc,
|
2013-10-18 08:33:31 +08:00
|
|
|
IsFinalSpelledSealed,
|
2011-10-13 00:37:45 +08:00
|
|
|
T.getOpenLocation());
|
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;
|
2011-10-13 17:41:32 +08:00
|
|
|
ParsedAttributes AccessAttrs(AttrFactory);
|
2008-06-25 06:12:16 +08:00
|
|
|
|
2010-06-22 06:31:09 +08:00
|
|
|
if (TagDecl) {
|
|
|
|
// While we still have something to read, read the member-declarations.
|
2013-11-23 12:06:09 +08:00
|
|
|
while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
|
2010-06-22 06:31:09 +08:00
|
|
|
// Each iteration of this loop reads one member-declaration.
|
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) ||
|
2011-05-25 18:19:49 +08:00
|
|
|
Tok.is(tok::kw___if_not_exists))) {
|
|
|
|
ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-06-22 06:31:09 +08:00
|
|
|
// Check for extraneous top-level semicolon.
|
|
|
|
if (Tok.is(tok::semi)) {
|
2012-07-23 13:45:25 +08:00
|
|
|
ConsumeExtraSemi(InsideStruct, TagType);
|
2010-06-22 06:31:09 +08:00
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-02-24 07:47:16 +08:00
|
|
|
if (Tok.is(tok::annot_pragma_vis)) {
|
|
|
|
HandlePragmaVisibility();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Tok.is(tok::annot_pragma_pack)) {
|
|
|
|
HandlePragmaPack();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-10-13 01:39:59 +08:00
|
|
|
if (Tok.is(tok::annot_pragma_align)) {
|
|
|
|
HandlePragmaAlign();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-03-22 14:34:35 +08:00
|
|
|
if (Tok.is(tok::annot_pragma_openmp)) {
|
|
|
|
ParseOpenMPDeclarativeDirective();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-02-11 03:50:15 +08:00
|
|
|
if (Tok.is(tok::annot_pragma_ms_pointers_to_members)) {
|
|
|
|
HandlePragmaMSPointersToMembers();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-04-09 06:30:47 +08:00
|
|
|
if (Tok.is(tok::annot_pragma_ms_pragma)) {
|
|
|
|
HandlePragmaMSPragma();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-11-09 12:52:51 +08:00
|
|
|
// If we see a namespace here, a close brace was missing somewhere.
|
|
|
|
if (Tok.is(tok::kw_namespace)) {
|
2013-11-16 07:00:02 +08:00
|
|
|
DiagnoseUnexpectedNamespace(cast<NamedDecl>(TagDecl));
|
2013-11-09 12:52:51 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-06-22 06:31:09 +08:00
|
|
|
AccessSpecifier AS = getAccessSpecifierIfPresent();
|
|
|
|
if (AS != AS_none) {
|
|
|
|
// Current token is a C++ access specifier.
|
|
|
|
CurAS = AS;
|
|
|
|
SourceLocation ASLoc = Tok.getLocation();
|
2011-10-13 14:08:43 +08:00
|
|
|
unsigned TokLength = Tok.getLength();
|
2010-06-22 06:31:09 +08:00
|
|
|
ConsumeToken();
|
2011-10-13 17:41:32 +08:00
|
|
|
AccessAttrs.clear();
|
|
|
|
MaybeParseGNUAttributes(AccessAttrs);
|
|
|
|
|
2011-10-13 14:08:43 +08:00
|
|
|
SourceLocation EndLoc;
|
2013-12-31 07:29:50 +08:00
|
|
|
if (TryConsumeToken(tok::colon, EndLoc)) {
|
|
|
|
} else if (TryConsumeToken(tok::semi, EndLoc)) {
|
|
|
|
Diag(EndLoc, diag::err_expected)
|
|
|
|
<< tok::colon << FixItHint::CreateReplacement(EndLoc, ":");
|
2011-10-13 14:08:43 +08:00
|
|
|
} else {
|
|
|
|
EndLoc = ASLoc.getLocWithOffset(TokLength);
|
2013-12-31 07:29:50 +08:00
|
|
|
Diag(EndLoc, diag::err_expected)
|
|
|
|
<< tok::colon << FixItHint::CreateInsertion(EndLoc, ":");
|
2011-10-13 14:08:43 +08:00
|
|
|
}
|
2011-10-17 17:54:52 +08:00
|
|
|
|
2012-09-25 15:32:39 +08:00
|
|
|
// The Microsoft extension __interface does not permit non-public
|
|
|
|
// access specifiers.
|
|
|
|
if (TagType == DeclSpec::TST_interface && CurAS != AS_public) {
|
|
|
|
Diag(ASLoc, diag::err_access_specifier_interface)
|
|
|
|
<< (CurAS == AS_protected);
|
|
|
|
}
|
|
|
|
|
2011-10-17 17:54:52 +08:00
|
|
|
if (Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc,
|
|
|
|
AccessAttrs.getList())) {
|
|
|
|
// found another attribute than only annotations
|
|
|
|
AccessAttrs.clear();
|
|
|
|
}
|
|
|
|
|
2010-06-22 06:31:09 +08:00
|
|
|
continue;
|
|
|
|
}
|
2008-06-25 06:12:16 +08:00
|
|
|
|
2010-06-22 06:31:09 +08:00
|
|
|
// Parse all the comma separated declarators.
|
2011-10-13 17:41:32 +08:00
|
|
|
ParseCXXClassMemberDeclaration(CurAS, AccessAttrs.getList());
|
2010-06-22 06:31:09 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2010-06-22 06:31:09 +08:00
|
|
|
} else {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace);
|
2008-06-25 06:12:16 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-25 06:12:16 +08:00
|
|
|
// If attributes exist after class contents, parse them.
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributes attrs(AttrFactory);
|
2010-12-24 10:08:15 +08:00
|
|
|
MaybeParseGNUAttributes(attrs);
|
2008-06-25 06:12:16 +08:00
|
|
|
|
2010-05-28 16:11:17 +08:00
|
|
|
if (TagDecl)
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.ActOnFinishCXXMemberSpecification(getCurScope(), RecordLoc, TagDecl,
|
2011-10-13 00:37:45 +08:00
|
|
|
T.getOpenLocation(),
|
|
|
|
T.getCloseLocation(),
|
2010-12-24 10:08:15 +08:00
|
|
|
attrs.getList());
|
2008-06-25 06:12:16 +08:00
|
|
|
|
2012-04-17 02:27:27 +08:00
|
|
|
// C++11 [class.mem]p2:
|
|
|
|
// Within the class member-specification, the class is regarded as complete
|
2012-05-03 06:22:32 +08:00
|
|
|
// within function bodies, default arguments, and
|
2012-04-17 02:27:27 +08:00
|
|
|
// brace-or-equal-initializers for non-static data members (including such
|
|
|
|
// things in nested classes).
|
2010-06-22 06:31:09 +08:00
|
|
|
if (TagDecl && 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
|
2011-09-09 01:42:22 +08:00
|
|
|
// declarations and the lexed inline method definitions, along with any
|
|
|
|
// delayed attributes.
|
2010-06-17 07:45:56 +08:00
|
|
|
SourceLocation SavedPrevTokLocation = PrevTokLocation;
|
2011-09-09 01:42:22 +08:00
|
|
|
ParseLexedAttributes(getCurrentClass());
|
2009-05-28 07:11:45 +08:00
|
|
|
ParseLexedMethodDeclarations(getCurrentClass());
|
2012-04-22 02:42:51 +08:00
|
|
|
|
|
|
|
// We've finished with all pending member declarations.
|
|
|
|
Actions.ActOnFinishCXXMemberDecls();
|
|
|
|
|
2011-06-12 01:19:42 +08:00
|
|
|
ParseLexedMemberInitializers(getCurrentClass());
|
2009-05-28 07:11:45 +08:00
|
|
|
ParseLexedMethodDefs(getCurrentClass());
|
2010-06-17 07:45:56 +08:00
|
|
|
PrevTokLocation = SavedPrevTokLocation;
|
2008-06-25 06:12:16 +08:00
|
|
|
}
|
|
|
|
|
2010-05-28 16:11:17 +08:00
|
|
|
if (TagDecl)
|
2011-10-13 00:37:45 +08:00
|
|
|
Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl,
|
|
|
|
T.getCloseLocation());
|
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
|
|
|
|
2013-11-16 07:00:02 +08:00
|
|
|
void Parser::DiagnoseUnexpectedNamespace(NamedDecl *D) {
|
2013-11-09 12:52:51 +08:00
|
|
|
assert(Tok.is(tok::kw_namespace));
|
|
|
|
|
|
|
|
// FIXME: Suggest where the close brace should have gone by looking
|
|
|
|
// at indentation changes within the definition body.
|
2013-11-16 07:00:02 +08:00
|
|
|
Diag(D->getLocation(),
|
|
|
|
diag::err_missing_end_of_definition) << D;
|
2013-11-09 12:52:51 +08:00
|
|
|
Diag(Tok.getLocation(),
|
2013-11-16 07:00:02 +08:00
|
|
|
diag::note_missing_end_of_definition_before) << D;
|
2013-11-09 12:52:51 +08:00
|
|
|
|
|
|
|
// Push '};' onto the token stream to recover.
|
|
|
|
PP.EnterToken(Tok);
|
|
|
|
|
|
|
|
Tok.startToken();
|
|
|
|
Tok.setLocation(PP.getLocForEndOfToken(PrevTokLocation));
|
|
|
|
Tok.setKind(tok::semi);
|
|
|
|
PP.EnterToken(Tok);
|
|
|
|
|
|
|
|
Tok.setKind(tok::r_brace);
|
|
|
|
}
|
|
|
|
|
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:
|
2011-01-04 08:32:56 +08:00
|
|
|
/// mem-initializer ...[opt]
|
|
|
|
/// mem-initializer ...[opt] , mem-initializer-list
|
2010-08-21 17:40:31 +08:00
|
|
|
void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
|
2008-11-05 12:29:56 +08:00
|
|
|
assert(Tok.is(tok::colon) && "Constructor initializer always starts with ':'");
|
|
|
|
|
2011-04-28 09:08:34 +08:00
|
|
|
// Poison the SEH identifiers so they are flagged as illegal in constructor initializers
|
|
|
|
PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true);
|
2008-11-05 12:29:56 +08:00
|
|
|
SourceLocation ColonLoc = ConsumeToken();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<CXXCtorInitializer*, 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 {
|
2010-08-28 08:00:50 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2013-06-24 06:58:02 +08:00
|
|
|
Actions.CodeCompleteConstructorInitializer(ConstructorDecl,
|
|
|
|
MemInitializers);
|
2011-09-04 11:32:15 +08:00
|
|
|
return cutOffParsing();
|
2010-08-28 08:00:50 +08:00
|
|
|
} else {
|
|
|
|
MemInitResult MemInit = ParseMemInitializer(ConstructorDecl);
|
|
|
|
if (!MemInit.isInvalid())
|
|
|
|
MemInitializers.push_back(MemInit.get());
|
|
|
|
else
|
|
|
|
AnyErrors = true;
|
|
|
|
}
|
|
|
|
|
2008-11-05 12:29:56 +08:00
|
|
|
if (Tok.is(tok::comma))
|
|
|
|
ConsumeToken();
|
|
|
|
else if (Tok.is(tok::l_brace))
|
|
|
|
break;
|
2010-09-07 22:35:10 +08:00
|
|
|
// If the next token looks like a base or member initializer, assume that
|
|
|
|
// we're just missing a comma.
|
2010-09-07 22:51:08 +08:00
|
|
|
else if (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) {
|
|
|
|
SourceLocation Loc = PP.getLocForEndOfToken(PrevTokLocation);
|
|
|
|
Diag(Loc, diag::err_ctor_init_missing_comma)
|
|
|
|
<< FixItHint::CreateInsertion(Loc, ", ");
|
|
|
|
} else {
|
2008-11-05 12:29:56 +08:00
|
|
|
// Skip over garbage, until we get to '{'. Don't eat the '{'.
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok.getLocation(), diag::err_expected_either) << tok::l_brace
|
|
|
|
<< tok::comma;
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
|
2008-11-05 12:29:56 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (true);
|
|
|
|
|
2013-01-17 13:26:25 +08:00
|
|
|
Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc, 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
|
|
|
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] ')'
|
2011-06-05 20:23:16 +08:00
|
|
|
/// [C++0x] mem-initializer-id braced-init-list
|
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
|
2014-10-31 14:57:07 +08:00
|
|
|
MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
|
2009-07-01 07:26:25 +08:00
|
|
|
// parse '::'[opt] nested-name-specifier[opt]
|
|
|
|
CXXScopeSpec SS;
|
2011-11-08 01:33:42 +08:00
|
|
|
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType TemplateTypeTy;
|
2009-07-02 03:21:19 +08:00
|
|
|
if (Tok.is(tok::annot_template_id)) {
|
2011-06-22 14:09:49 +08:00
|
|
|
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
|
2010-01-13 01:52:59 +08:00
|
|
|
if (TemplateId->Kind == TNK_Type_template ||
|
|
|
|
TemplateId->Kind == TNK_Dependent_template_name) {
|
2011-03-02 08:47:37 +08:00
|
|
|
AnnotateTemplateIdTokenAsType();
|
2009-07-02 03:21:19 +08:00
|
|
|
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
|
2010-08-24 13:47:05 +08:00
|
|
|
TemplateTypeTy = getTypeAnnotation(Tok);
|
2009-07-02 03:21:19 +08:00
|
|
|
}
|
|
|
|
}
|
2012-01-24 14:03:59 +08:00
|
|
|
// Uses of decltype will already have been converted to annot_decltype by
|
|
|
|
// ParseOptionalCXXScopeSpecifier at this point.
|
|
|
|
if (!TemplateTypeTy && Tok.isNot(tok::identifier)
|
|
|
|
&& Tok.isNot(tok::annot_decltype)) {
|
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
|
|
|
|
2014-05-21 14:02:52 +08:00
|
|
|
IdentifierInfo *II = nullptr;
|
2012-01-24 14:03:59 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
|
|
|
SourceLocation IdLoc = Tok.getLocation();
|
|
|
|
if (Tok.is(tok::annot_decltype)) {
|
|
|
|
// Get the decltype expression, if there is one.
|
|
|
|
ParseDecltypeSpecifier(DS);
|
|
|
|
} else {
|
|
|
|
if (Tok.is(tok::identifier))
|
|
|
|
// Get the identifier. This may be a member name or a class name,
|
|
|
|
// but we'll let the semantic analysis determine which it is.
|
|
|
|
II = Tok.getIdentifierInfo();
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
|
|
|
|
2008-11-05 12:29:56 +08:00
|
|
|
|
|
|
|
// Parse the '('.
|
2013-01-02 19:42:31 +08:00
|
|
|
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
|
2011-10-15 13:09:34 +08:00
|
|
|
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
|
|
|
|
|
2011-09-25 01:48:25 +08:00
|
|
|
ExprResult InitList = ParseBraceInitializer();
|
|
|
|
if (InitList.isInvalid())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
SourceLocation EllipsisLoc;
|
2014-01-05 11:27:11 +08:00
|
|
|
TryConsumeToken(tok::ellipsis, EllipsisLoc);
|
2011-09-25 01:48:25 +08:00
|
|
|
|
|
|
|
return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II,
|
2012-01-24 14:03:59 +08:00
|
|
|
TemplateTypeTy, DS, IdLoc,
|
2014-05-29 18:55:11 +08:00
|
|
|
InitList.get(), EllipsisLoc);
|
2011-06-05 20:23:16 +08:00
|
|
|
} else if(Tok.is(tok::l_paren)) {
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
2011-06-05 20:23:16 +08:00
|
|
|
|
|
|
|
// Parse the optional expression-list.
|
2012-08-24 06:51:59 +08:00
|
|
|
ExprVector ArgExprs;
|
2011-06-05 20:23:16 +08:00
|
|
|
CommaLocsTy CommaLocs;
|
|
|
|
if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2011-06-05 20:23:16 +08:00
|
|
|
return true;
|
|
|
|
}
|
2008-11-05 12:29:56 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2008-11-05 12:29:56 +08:00
|
|
|
|
2011-06-05 20:23:16 +08:00
|
|
|
SourceLocation EllipsisLoc;
|
2014-01-10 19:19:30 +08:00
|
|
|
TryConsumeToken(tok::ellipsis, EllipsisLoc);
|
2008-11-05 12:29:56 +08:00
|
|
|
|
2011-06-05 20:23:16 +08:00
|
|
|
return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II,
|
2012-01-24 14:03:59 +08:00
|
|
|
TemplateTypeTy, DS, IdLoc,
|
2013-05-10 07:51:52 +08:00
|
|
|
T.getOpenLocation(), ArgExprs,
|
|
|
|
T.getCloseLocation(), EllipsisLoc);
|
2011-06-05 20:23:16 +08:00
|
|
|
}
|
|
|
|
|
2013-12-24 17:48:30 +08:00
|
|
|
if (getLangOpts().CPlusPlus11)
|
|
|
|
return Diag(Tok, diag::err_expected_either) << tok::l_paren << tok::l_brace;
|
|
|
|
else
|
|
|
|
return Diag(Tok, diag::err_expected) << tok::l_paren;
|
2008-11-05 12:29:56 +08:00
|
|
|
}
|
2008-11-25 11:22:00 +08:00
|
|
|
|
2011-03-05 22:45:16 +08:00
|
|
|
/// \brief Parse a C++ exception-specification if present (C++0x [except.spec]).
|
2008-11-25 11:22:00 +08:00
|
|
|
///
|
2008-12-02 02:00:20 +08:00
|
|
|
/// exception-specification:
|
2011-03-05 22:45:16 +08:00
|
|
|
/// dynamic-exception-specification
|
|
|
|
/// noexcept-specification
|
|
|
|
///
|
|
|
|
/// noexcept-specification:
|
|
|
|
/// 'noexcept'
|
|
|
|
/// 'noexcept' '(' constant-expression ')'
|
|
|
|
ExceptionSpecificationType
|
2012-05-03 06:22:32 +08:00
|
|
|
Parser::tryParseExceptionSpecification(
|
2012-04-17 02:27:27 +08:00
|
|
|
SourceRange &SpecificationRange,
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVectorImpl<ParsedType> &DynamicExceptions,
|
|
|
|
SmallVectorImpl<SourceRange> &DynamicExceptionRanges,
|
2012-05-03 06:22:32 +08:00
|
|
|
ExprResult &NoexceptExpr) {
|
2011-03-05 22:45:16 +08:00
|
|
|
ExceptionSpecificationType Result = EST_None;
|
2012-05-03 06:22:32 +08:00
|
|
|
|
2011-03-05 22:45:16 +08:00
|
|
|
// See if there's a dynamic specification.
|
|
|
|
if (Tok.is(tok::kw_throw)) {
|
|
|
|
Result = ParseDynamicExceptionSpecification(SpecificationRange,
|
|
|
|
DynamicExceptions,
|
|
|
|
DynamicExceptionRanges);
|
|
|
|
assert(DynamicExceptions.size() == DynamicExceptionRanges.size() &&
|
|
|
|
"Produced different number of exception types and ranges.");
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there's no noexcept specification, we're done.
|
|
|
|
if (Tok.isNot(tok::kw_noexcept))
|
|
|
|
return Result;
|
|
|
|
|
2011-10-18 07:06:20 +08:00
|
|
|
Diag(Tok, diag::warn_cxx98_compat_noexcept_decl);
|
|
|
|
|
2011-03-05 22:45:16 +08:00
|
|
|
// If we already had a dynamic specification, parse the noexcept for,
|
|
|
|
// recovery, but emit a diagnostic and don't store the results.
|
|
|
|
SourceRange NoexceptRange;
|
|
|
|
ExceptionSpecificationType NoexceptType = EST_None;
|
|
|
|
|
|
|
|
SourceLocation KeywordLoc = ConsumeToken();
|
|
|
|
if (Tok.is(tok::l_paren)) {
|
|
|
|
// There is an argument.
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
2011-03-05 22:45:16 +08:00
|
|
|
NoexceptType = EST_ComputedNoexcept;
|
|
|
|
NoexceptExpr = ParseConstantExpression();
|
2011-03-12 19:50:43 +08:00
|
|
|
// The argument must be contextually convertible to bool. We use
|
|
|
|
// ActOnBooleanCondition for this purpose.
|
|
|
|
if (!NoexceptExpr.isInvalid())
|
|
|
|
NoexceptExpr = Actions.ActOnBooleanCondition(getCurScope(), KeywordLoc,
|
|
|
|
NoexceptExpr.get());
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
|
|
|
NoexceptRange = SourceRange(KeywordLoc, T.getCloseLocation());
|
2011-03-05 22:45:16 +08:00
|
|
|
} else {
|
|
|
|
// There is no argument.
|
|
|
|
NoexceptType = EST_BasicNoexcept;
|
|
|
|
NoexceptRange = SourceRange(KeywordLoc, KeywordLoc);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Result == EST_None) {
|
|
|
|
SpecificationRange = NoexceptRange;
|
|
|
|
Result = NoexceptType;
|
|
|
|
|
|
|
|
// If there's a dynamic specification after a noexcept specification,
|
|
|
|
// parse that and ignore the results.
|
|
|
|
if (Tok.is(tok::kw_throw)) {
|
|
|
|
Diag(Tok.getLocation(), diag::err_dynamic_and_noexcept_specification);
|
|
|
|
ParseDynamicExceptionSpecification(NoexceptRange, DynamicExceptions,
|
|
|
|
DynamicExceptionRanges);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Diag(Tok.getLocation(), diag::err_dynamic_and_noexcept_specification);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2013-06-13 10:02:51 +08:00
|
|
|
static void diagnoseDynamicExceptionSpecification(
|
|
|
|
Parser &P, const SourceRange &Range, bool IsNoexcept) {
|
|
|
|
if (P.getLangOpts().CPlusPlus11) {
|
|
|
|
const char *Replacement = IsNoexcept ? "noexcept" : "noexcept(false)";
|
|
|
|
P.Diag(Range.getBegin(), diag::warn_exception_spec_deprecated) << Range;
|
|
|
|
P.Diag(Range.getBegin(), diag::note_exception_spec_deprecated)
|
|
|
|
<< Replacement << FixItHint::CreateReplacement(Range, Replacement);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-05 22:45:16 +08:00
|
|
|
/// ParseDynamicExceptionSpecification - Parse a C++
|
|
|
|
/// dynamic-exception-specification (C++ [except.spec]).
|
|
|
|
///
|
|
|
|
/// dynamic-exception-specification:
|
2008-12-02 02:00:20 +08:00
|
|
|
/// '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:
|
2010-12-21 07:57:46 +08:00
|
|
|
/// type-id ... [opt]
|
|
|
|
/// type-id-list ',' type-id ... [opt]
|
2008-11-25 11:22:00 +08:00
|
|
|
///
|
2011-03-05 22:45:16 +08:00
|
|
|
ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification(
|
|
|
|
SourceRange &SpecificationRange,
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVectorImpl<ParsedType> &Exceptions,
|
|
|
|
SmallVectorImpl<SourceRange> &Ranges) {
|
2008-11-25 11:22:00 +08:00
|
|
|
assert(Tok.is(tok::kw_throw) && "expected throw");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-03-05 22:45:16 +08:00
|
|
|
SpecificationRange.setBegin(ConsumeToken());
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
if (T.consumeOpen()) {
|
2011-03-05 22:45:16 +08:00
|
|
|
Diag(Tok, diag::err_expected_lparen_after) << "throw";
|
|
|
|
SpecificationRange.setEnd(SpecificationRange.getBegin());
|
2011-03-12 19:50:43 +08:00
|
|
|
return EST_DynamicNone;
|
2008-11-25 11:22:00 +08:00
|
|
|
}
|
|
|
|
|
2008-12-02 02:00:20 +08:00
|
|
|
// Parse throw(...), a Microsoft extension that means "this function
|
|
|
|
// can throw anything".
|
|
|
|
if (Tok.is(tok::ellipsis)) {
|
|
|
|
SourceLocation EllipsisLoc = ConsumeToken();
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().MicrosoftExt)
|
2008-12-02 02:00:20 +08:00
|
|
|
Diag(EllipsisLoc, diag::ext_ellipsis_exception_spec);
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
|
|
|
SpecificationRange.setEnd(T.getCloseLocation());
|
2013-06-13 10:02:51 +08:00
|
|
|
diagnoseDynamicExceptionSpecification(*this, SpecificationRange, false);
|
2011-03-12 19:50:43 +08:00
|
|
|
return EST_MSAny;
|
2008-12-02 02:00:20 +08:00
|
|
|
}
|
|
|
|
|
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));
|
2011-03-05 22:45:16 +08:00
|
|
|
|
2010-12-21 07:57:46 +08:00
|
|
|
if (Tok.is(tok::ellipsis)) {
|
|
|
|
// C++0x [temp.variadic]p5:
|
|
|
|
// - In a dynamic-exception-specification (15.4); the pattern is a
|
|
|
|
// type-id.
|
|
|
|
SourceLocation Ellipsis = ConsumeToken();
|
2011-03-05 22:45:16 +08:00
|
|
|
Range.setEnd(Ellipsis);
|
2010-12-21 07:57:46 +08:00
|
|
|
if (!Res.isInvalid())
|
|
|
|
Res = Actions.ActOnPackExpansion(Res.get(), Ellipsis);
|
|
|
|
}
|
2011-03-05 22:45:16 +08:00
|
|
|
|
2009-05-30 02:02:33 +08:00
|
|
|
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);
|
|
|
|
}
|
2014-01-10 19:19:30 +08:00
|
|
|
|
|
|
|
if (!TryConsumeToken(tok::comma))
|
2008-11-25 11:22:00 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
|
|
|
SpecificationRange.setEnd(T.getCloseLocation());
|
2013-06-13 10:02:51 +08:00
|
|
|
diagnoseDynamicExceptionSpecification(*this, SpecificationRange,
|
|
|
|
Exceptions.empty());
|
2011-03-12 19:50:43 +08:00
|
|
|
return Exceptions.empty() ? EST_DynamicNone : EST_Dynamic;
|
2008-11-25 11:22:00 +08:00
|
|
|
}
|
2009-05-28 07:11:45 +08:00
|
|
|
|
2010-10-02 02:44:50 +08:00
|
|
|
/// ParseTrailingReturnType - Parse a trailing return type on a new-style
|
|
|
|
/// function declaration.
|
2011-08-04 23:30:47 +08:00
|
|
|
TypeResult Parser::ParseTrailingReturnType(SourceRange &Range) {
|
2010-10-02 02:44:50 +08:00
|
|
|
assert(Tok.is(tok::arrow) && "expected arrow");
|
|
|
|
|
|
|
|
ConsumeToken();
|
|
|
|
|
2012-03-12 16:56:40 +08:00
|
|
|
return ParseTypeName(&Range, Declarator::TrailingReturnContext);
|
2010-10-02 02:44:50 +08:00
|
|
|
}
|
|
|
|
|
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.
|
2011-02-14 15:13:47 +08:00
|
|
|
Sema::ParsingClassState
|
2012-09-25 15:32:39 +08:00
|
|
|
Parser::PushParsingClass(Decl *ClassDecl, bool NonNestedClass,
|
|
|
|
bool IsInterface) {
|
2010-01-17 04:52:59 +08:00
|
|
|
assert((NonNestedClass || !ClassStack.empty()) &&
|
2009-05-28 07:11:45 +08:00
|
|
|
"Nested class without outer class");
|
2012-09-25 15:32:39 +08:00
|
|
|
ClassStack.push(new ParsingClass(ClassDecl, NonNestedClass, IsInterface));
|
2011-02-14 15:13:47 +08:00
|
|
|
return Actions.PushParsingClass();
|
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) {
|
2010-10-13 00:25:54 +08:00
|
|
|
for (unsigned I = 0, N = Class->LateParsedDeclarations.size(); I != N; ++I)
|
|
|
|
delete Class->LateParsedDeclarations[I];
|
2009-05-28 07:11:45 +08:00
|
|
|
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.
|
2011-02-14 15:13:47 +08:00
|
|
|
void Parser::PopParsingClass(Sema::ParsingClassState state) {
|
2009-05-28 07:11:45 +08:00
|
|
|
assert(!ClassStack.empty() && "Mismatched push/pop for class parsing");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-02-14 15:13:47 +08:00
|
|
|
Actions.PopParsingClass(state);
|
|
|
|
|
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?");
|
|
|
|
|
2010-10-13 00:25:54 +08:00
|
|
|
if (Victim->LateParsedDeclarations.empty()) {
|
2009-05-28 07:11:45 +08:00
|
|
|
// 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.
|
2010-10-13 00:25:54 +08:00
|
|
|
DeallocateParsedClasses(Victim);
|
2009-05-28 07:11:45 +08:00
|
|
|
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.
|
2010-07-03 01:43:08 +08:00
|
|
|
assert(getCurScope()->isClassScope() && "Nested class outside of class scope?");
|
2010-10-13 00:25:54 +08:00
|
|
|
ClassStack.top()->LateParsedDeclarations.push_back(new LateParsedClass(this, Victim));
|
2010-07-03 01:43:08 +08:00
|
|
|
Victim->TemplateScope = getCurScope()->getParent()->isTemplateParamScope();
|
2009-05-28 07:11:45 +08:00
|
|
|
}
|
2009-11-21 16:43:09 +08:00
|
|
|
|
2012-04-10 11:25:07 +08:00
|
|
|
/// \brief Try to parse an 'identifier' which appears within an attribute-token.
|
|
|
|
///
|
|
|
|
/// \return the parsed identifier on success, and 0 if the next token is not an
|
|
|
|
/// attribute-token.
|
|
|
|
///
|
|
|
|
/// C++11 [dcl.attr.grammar]p3:
|
|
|
|
/// If a keyword or an alternative token that satisfies the syntactic
|
|
|
|
/// requirements of an identifier is contained in an attribute-token,
|
|
|
|
/// it is considered an identifier.
|
|
|
|
IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) {
|
|
|
|
switch (Tok.getKind()) {
|
|
|
|
default:
|
|
|
|
// Identifiers and keywords have identifier info attached.
|
|
|
|
if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
|
|
|
|
Loc = ConsumeToken();
|
|
|
|
return II;
|
|
|
|
}
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2012-04-10 11:25:07 +08:00
|
|
|
|
|
|
|
case tok::ampamp: // 'and'
|
|
|
|
case tok::pipe: // 'bitor'
|
|
|
|
case tok::pipepipe: // 'or'
|
|
|
|
case tok::caret: // 'xor'
|
|
|
|
case tok::tilde: // 'compl'
|
|
|
|
case tok::amp: // 'bitand'
|
|
|
|
case tok::ampequal: // 'and_eq'
|
|
|
|
case tok::pipeequal: // 'or_eq'
|
|
|
|
case tok::caretequal: // 'xor_eq'
|
|
|
|
case tok::exclaim: // 'not'
|
|
|
|
case tok::exclaimequal: // 'not_eq'
|
|
|
|
// Alternative tokens do not have identifier info, but their spelling
|
|
|
|
// starts with an alphabetical character.
|
2013-01-13 03:30:44 +08:00
|
|
|
SmallString<8> SpellingBuf;
|
2012-04-10 11:25:07 +08:00
|
|
|
StringRef Spelling = PP.getSpelling(Tok.getLocation(), SpellingBuf);
|
2013-02-09 06:30:41 +08:00
|
|
|
if (isLetter(Spelling[0])) {
|
2012-04-10 11:25:07 +08:00
|
|
|
Loc = ConsumeToken();
|
2012-04-23 04:43:30 +08:00
|
|
|
return &PP.getIdentifierTable().get(Spelling);
|
2012-04-10 11:25:07 +08:00
|
|
|
}
|
2014-05-21 14:02:52 +08:00
|
|
|
return nullptr;
|
2012-04-10 11:25:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-03 09:56:22 +08:00
|
|
|
static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
|
|
|
|
IdentifierInfo *ScopeName) {
|
|
|
|
switch (AttributeList::getKind(AttrName, ScopeName,
|
|
|
|
AttributeList::AS_CXX11)) {
|
|
|
|
case AttributeList::AT_CarriesDependency:
|
2014-04-15 00:03:22 +08:00
|
|
|
case AttributeList::AT_Deprecated:
|
2012-10-03 09:56:22 +08:00
|
|
|
case AttributeList::AT_FallThrough:
|
2013-01-17 09:30:42 +08:00
|
|
|
case AttributeList::AT_CXX11NoReturn: {
|
2012-10-03 09:56:22 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-01 01:32:39 +08:00
|
|
|
/// ParseCXX11AttributeArgs -- Parse a C++11 attribute-argument-clause.
|
|
|
|
///
|
|
|
|
/// [C++11] attribute-argument-clause:
|
|
|
|
/// '(' balanced-token-seq ')'
|
|
|
|
///
|
|
|
|
/// [C++11] balanced-token-seq:
|
|
|
|
/// balanced-token
|
|
|
|
/// balanced-token-seq balanced-token
|
|
|
|
///
|
|
|
|
/// [C++11] balanced-token:
|
|
|
|
/// '(' balanced-token-seq ')'
|
|
|
|
/// '[' balanced-token-seq ']'
|
|
|
|
/// '{' balanced-token-seq '}'
|
|
|
|
/// any token but '(', ')', '[', ']', '{', or '}'
|
|
|
|
bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
|
|
|
|
SourceLocation AttrNameLoc,
|
|
|
|
ParsedAttributes &Attrs,
|
|
|
|
SourceLocation *EndLoc,
|
|
|
|
IdentifierInfo *ScopeName,
|
|
|
|
SourceLocation ScopeLoc) {
|
|
|
|
assert(Tok.is(tok::l_paren) && "Not a C++11 attribute argument list");
|
2014-04-15 00:03:22 +08:00
|
|
|
SourceLocation LParenLoc = Tok.getLocation();
|
2014-04-01 01:32:39 +08:00
|
|
|
|
|
|
|
// If the attribute isn't known, we will not attempt to parse any
|
|
|
|
// arguments.
|
|
|
|
if (!hasAttribute(AttrSyntax::CXX, ScopeName, AttrName,
|
|
|
|
getTargetInfo().getTriple(), getLangOpts())) {
|
|
|
|
// Eat the left paren, then skip to the ending right paren.
|
|
|
|
ConsumeParen();
|
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ScopeName && ScopeName->getName() == "gnu")
|
|
|
|
// GNU-scoped attributes have some special cases to handle GNU-specific
|
|
|
|
// behaviors.
|
|
|
|
ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
|
2014-05-21 14:02:52 +08:00
|
|
|
ScopeLoc, AttributeList::AS_CXX11, nullptr);
|
2014-04-15 00:03:22 +08:00
|
|
|
else {
|
|
|
|
unsigned NumArgs =
|
|
|
|
ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc,
|
|
|
|
ScopeName, ScopeLoc, AttributeList::AS_CXX11);
|
|
|
|
|
|
|
|
const AttributeList *Attr = Attrs.getList();
|
|
|
|
if (Attr && IsBuiltInOrStandardCXX11Attribute(AttrName, ScopeName)) {
|
|
|
|
// If the attribute is a standard or built-in attribute and we are
|
|
|
|
// parsing an argument list, we need to determine whether this attribute
|
|
|
|
// was allowed to have an argument list (such as [[deprecated]]), and how
|
|
|
|
// many arguments were parsed (so we can diagnose on [[deprecated()]]).
|
2014-05-28 19:19:43 +08:00
|
|
|
if (Attr->getMaxArgs() && !NumArgs) {
|
|
|
|
// The attribute was allowed to have arguments, but none were provided
|
|
|
|
// even though the attribute parsed successfully. This is an error.
|
|
|
|
// FIXME: This is a good place for a fixit which removes the parens.
|
|
|
|
Diag(LParenLoc, diag::err_attribute_requires_arguments) << AttrName;
|
|
|
|
return false;
|
|
|
|
} else if (!Attr->getMaxArgs()) {
|
|
|
|
// The attribute parsed successfully, but was not allowed to have any
|
|
|
|
// arguments. It doesn't matter whether any were provided -- the
|
2014-04-15 00:03:22 +08:00
|
|
|
// presence of the argument list (even if empty) is diagnosed.
|
|
|
|
Diag(LParenLoc, diag::err_cxx11_attribute_forbids_arguments)
|
|
|
|
<< AttrName;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-04-01 01:32:39 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseCXX11AttributeSpecifier - Parse a C++11 attribute-specifier.
|
2009-11-21 16:43:09 +08:00
|
|
|
///
|
2012-04-10 09:32:12 +08:00
|
|
|
/// [C++11] attribute-specifier:
|
2009-11-21 16:43:09 +08:00
|
|
|
/// '[' '[' attribute-list ']' ']'
|
2011-09-30 02:04:28 +08:00
|
|
|
/// alignment-specifier
|
2009-11-21 16:43:09 +08:00
|
|
|
///
|
2012-04-10 09:32:12 +08:00
|
|
|
/// [C++11] attribute-list:
|
2009-11-21 16:43:09 +08:00
|
|
|
/// attribute[opt]
|
|
|
|
/// attribute-list ',' attribute[opt]
|
2012-04-10 11:25:07 +08:00
|
|
|
/// attribute '...'
|
|
|
|
/// attribute-list ',' attribute '...'
|
2009-11-21 16:43:09 +08:00
|
|
|
///
|
2012-04-10 09:32:12 +08:00
|
|
|
/// [C++11] attribute:
|
2009-11-21 16:43:09 +08:00
|
|
|
/// attribute-token attribute-argument-clause[opt]
|
|
|
|
///
|
2012-04-10 09:32:12 +08:00
|
|
|
/// [C++11] attribute-token:
|
2009-11-21 16:43:09 +08:00
|
|
|
/// identifier
|
|
|
|
/// attribute-scoped-token
|
|
|
|
///
|
2012-04-10 09:32:12 +08:00
|
|
|
/// [C++11] attribute-scoped-token:
|
2009-11-21 16:43:09 +08:00
|
|
|
/// attribute-namespace '::' identifier
|
|
|
|
///
|
2012-04-10 09:32:12 +08:00
|
|
|
/// [C++11] attribute-namespace:
|
2009-11-21 16:43:09 +08:00
|
|
|
/// identifier
|
2012-04-10 11:25:07 +08:00
|
|
|
void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
|
2011-09-30 02:04:05 +08:00
|
|
|
SourceLocation *endLoc) {
|
2011-09-30 02:04:28 +08:00
|
|
|
if (Tok.is(tok::kw_alignas)) {
|
2011-10-15 04:48:27 +08:00
|
|
|
Diag(Tok.getLocation(), diag::warn_cxx98_compat_alignas);
|
2011-09-30 02:04:28 +08:00
|
|
|
ParseAlignmentSpecifier(attrs, endLoc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-11-21 16:43:09 +08:00
|
|
|
assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square)
|
2012-04-10 09:32:12 +08:00
|
|
|
&& "Not a C++11 attribute list");
|
2009-11-21 16:43:09 +08:00
|
|
|
|
2011-10-15 04:48:27 +08:00
|
|
|
Diag(Tok.getLocation(), diag::warn_cxx98_compat_attribute);
|
|
|
|
|
2009-11-21 16:43:09 +08:00
|
|
|
ConsumeBracket();
|
|
|
|
ConsumeBracket();
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2013-01-17 09:30:42 +08:00
|
|
|
llvm::SmallDenseMap<IdentifierInfo*, SourceLocation, 4> SeenAttrs;
|
|
|
|
|
2012-04-10 11:25:07 +08:00
|
|
|
while (Tok.isNot(tok::r_square)) {
|
2009-11-21 16:43:09 +08:00
|
|
|
// attribute not present
|
2014-01-10 19:19:30 +08:00
|
|
|
if (TryConsumeToken(tok::comma))
|
2009-11-21 16:43:09 +08:00
|
|
|
continue;
|
|
|
|
|
2012-04-10 11:25:07 +08:00
|
|
|
SourceLocation ScopeLoc, AttrLoc;
|
2014-05-21 14:02:52 +08:00
|
|
|
IdentifierInfo *ScopeName = nullptr, *AttrName = nullptr;
|
2012-04-10 11:25:07 +08:00
|
|
|
|
|
|
|
AttrName = TryParseCXX11AttributeIdentifier(AttrLoc);
|
|
|
|
if (!AttrName)
|
|
|
|
// Break out to the "expected ']'" diagnostic.
|
|
|
|
break;
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2009-11-21 16:43:09 +08:00
|
|
|
// scoped attribute
|
2014-01-10 19:19:30 +08:00
|
|
|
if (TryConsumeToken(tok::coloncolon)) {
|
2012-04-10 11:25:07 +08:00
|
|
|
ScopeName = AttrName;
|
|
|
|
ScopeLoc = AttrLoc;
|
|
|
|
|
|
|
|
AttrName = TryParseCXX11AttributeIdentifier(AttrLoc);
|
|
|
|
if (!AttrName) {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square, tok::comma, StopAtSemi | StopBeforeMatch);
|
2009-11-21 16:43:09 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-01 01:32:39 +08:00
|
|
|
bool StandardAttr = IsBuiltInOrStandardCXX11Attribute(AttrName, ScopeName);
|
2009-11-21 16:43:09 +08:00
|
|
|
bool AttrParsed = false;
|
2012-10-03 09:56:22 +08:00
|
|
|
|
2013-01-17 09:30:42 +08:00
|
|
|
if (StandardAttr &&
|
|
|
|
!SeenAttrs.insert(std::make_pair(AttrName, AttrLoc)).second)
|
|
|
|
Diag(AttrLoc, diag::err_cxx11_attribute_repeated)
|
2014-04-01 01:32:39 +08:00
|
|
|
<< AttrName << SourceRange(SeenAttrs[AttrName]);
|
2013-01-17 09:30:42 +08:00
|
|
|
|
2012-10-03 09:56:22 +08:00
|
|
|
// Parse attribute arguments
|
2014-04-15 00:03:22 +08:00
|
|
|
if (Tok.is(tok::l_paren))
|
2014-04-01 01:32:39 +08:00
|
|
|
AttrParsed = ParseCXX11AttributeArgs(AttrName, AttrLoc, attrs, endLoc,
|
|
|
|
ScopeName, ScopeLoc);
|
2009-11-21 16:43:09 +08:00
|
|
|
|
2012-10-03 09:56:22 +08:00
|
|
|
if (!AttrParsed)
|
2012-05-04 02:27:39 +08:00
|
|
|
attrs.addNew(AttrName,
|
|
|
|
SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc,
|
|
|
|
AttrLoc),
|
2014-05-21 14:02:52 +08:00
|
|
|
ScopeName, ScopeLoc, nullptr, 0, AttributeList::AS_CXX11);
|
2012-04-10 09:32:12 +08:00
|
|
|
|
2014-01-10 19:19:30 +08:00
|
|
|
if (TryConsumeToken(tok::ellipsis))
|
2012-10-03 09:56:22 +08:00
|
|
|
Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis)
|
|
|
|
<< AttrName->getName();
|
2009-11-21 16:43:09 +08:00
|
|
|
}
|
|
|
|
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::r_square))
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square);
|
2011-09-30 02:04:05 +08:00
|
|
|
if (endLoc)
|
|
|
|
*endLoc = Tok.getLocation();
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::r_square))
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square);
|
2011-09-30 02:04:05 +08:00
|
|
|
}
|
|
|
|
|
2012-06-23 13:07:58 +08:00
|
|
|
/// ParseCXX11Attributes - Parse a C++11 attribute-specifier-seq.
|
2011-09-30 02:04:05 +08:00
|
|
|
///
|
|
|
|
/// attribute-specifier-seq:
|
|
|
|
/// attribute-specifier-seq[opt] attribute-specifier
|
2012-04-10 11:25:07 +08:00
|
|
|
void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs,
|
2011-09-30 02:04:05 +08:00
|
|
|
SourceLocation *endLoc) {
|
2013-02-22 17:15:49 +08:00
|
|
|
assert(getLangOpts().CPlusPlus11);
|
|
|
|
|
2011-09-30 02:04:05 +08:00
|
|
|
SourceLocation StartLoc = Tok.getLocation(), Loc;
|
|
|
|
if (!endLoc)
|
|
|
|
endLoc = &Loc;
|
|
|
|
|
2011-10-08 04:35:25 +08:00
|
|
|
do {
|
2012-04-10 11:25:07 +08:00
|
|
|
ParseCXX11AttributeSpecifier(attrs, endLoc);
|
2012-04-10 09:32:12 +08:00
|
|
|
} while (isCXX11AttributeSpecifier());
|
2009-11-21 16:43:09 +08:00
|
|
|
|
2011-09-30 02:04:05 +08:00
|
|
|
attrs.Range = SourceRange(StartLoc, *endLoc);
|
2009-11-21 16:43:09 +08:00
|
|
|
}
|
|
|
|
|
2013-10-15 09:34:54 +08:00
|
|
|
void Parser::DiagnoseAndSkipCXX11Attributes() {
|
|
|
|
// Start and end location of an attribute or an attribute list.
|
|
|
|
SourceLocation StartLoc = Tok.getLocation();
|
2014-06-19 19:42:00 +08:00
|
|
|
SourceLocation EndLoc = SkipCXX11Attributes();
|
|
|
|
|
|
|
|
if (EndLoc.isValid()) {
|
|
|
|
SourceRange Range(StartLoc, EndLoc);
|
|
|
|
Diag(StartLoc, diag::err_attributes_not_allowed)
|
|
|
|
<< Range;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation Parser::SkipCXX11Attributes() {
|
2013-10-15 09:34:54 +08:00
|
|
|
SourceLocation EndLoc;
|
|
|
|
|
2014-06-19 19:42:00 +08:00
|
|
|
if (!isCXX11AttributeSpecifier())
|
|
|
|
return EndLoc;
|
|
|
|
|
2013-10-15 09:34:54 +08:00
|
|
|
do {
|
|
|
|
if (Tok.is(tok::l_square)) {
|
|
|
|
BalancedDelimiterTracker T(*this, tok::l_square);
|
|
|
|
T.consumeOpen();
|
|
|
|
T.skipToEnd();
|
|
|
|
EndLoc = T.getCloseLocation();
|
|
|
|
} else {
|
|
|
|
assert(Tok.is(tok::kw_alignas) && "not an attribute specifier");
|
|
|
|
ConsumeToken();
|
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
if (!T.consumeOpen())
|
|
|
|
T.skipToEnd();
|
|
|
|
EndLoc = T.getCloseLocation();
|
|
|
|
}
|
|
|
|
} while (isCXX11AttributeSpecifier());
|
|
|
|
|
2014-06-19 19:42:00 +08:00
|
|
|
return EndLoc;
|
2013-10-15 09:34:54 +08:00
|
|
|
}
|
|
|
|
|
2010-10-11 20:59:39 +08:00
|
|
|
/// ParseMicrosoftAttributes - Parse a Microsoft attribute [Attr]
|
|
|
|
///
|
|
|
|
/// [MS] ms-attribute:
|
|
|
|
/// '[' token-seq ']'
|
|
|
|
///
|
|
|
|
/// [MS] ms-attribute-seq:
|
|
|
|
/// ms-attribute[opt]
|
|
|
|
/// ms-attribute ms-attribute-seq
|
2010-12-24 10:08:15 +08:00
|
|
|
void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs,
|
|
|
|
SourceLocation *endLoc) {
|
2010-10-11 20:59:39 +08:00
|
|
|
assert(Tok.is(tok::l_square) && "Not a Microsoft attribute list");
|
|
|
|
|
|
|
|
while (Tok.is(tok::l_square)) {
|
2012-04-10 09:32:12 +08:00
|
|
|
// FIXME: If this is actually a C++11 attribute, parse it as one.
|
2010-10-11 20:59:39 +08:00
|
|
|
ConsumeBracket();
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch);
|
2010-12-24 10:08:15 +08:00
|
|
|
if (endLoc) *endLoc = Tok.getLocation();
|
2014-01-01 11:08:43 +08:00
|
|
|
ExpectAndConsume(tok::r_square);
|
2010-10-11 20:59:39 +08:00
|
|
|
}
|
|
|
|
}
|
2011-05-25 18:19:49 +08:00
|
|
|
|
|
|
|
void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType,
|
|
|
|
AccessSpecifier& CurAS) {
|
2011-10-25 06:31:10 +08:00
|
|
|
IfExistsCondition Result;
|
2011-05-25 18:19:49 +08:00
|
|
|
if (ParseMicrosoftIfExistsCondition(Result))
|
|
|
|
return;
|
|
|
|
|
2011-10-25 06:31:10 +08:00
|
|
|
BalancedDelimiterTracker Braces(*this, tok::l_brace);
|
|
|
|
if (Braces.consumeOpen()) {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::l_brace;
|
2011-05-25 18:19:49 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-10-25 06:31:10 +08:00
|
|
|
switch (Result.Behavior) {
|
|
|
|
case IEB_Parse:
|
|
|
|
// Parse the declarations below.
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IEB_Dependent:
|
|
|
|
Diag(Result.KeywordLoc, diag::warn_microsoft_dependent_exists)
|
|
|
|
<< Result.IsIfExists;
|
|
|
|
// Fall through to skip.
|
|
|
|
|
|
|
|
case IEB_Skip:
|
|
|
|
Braces.skipToEnd();
|
2011-05-25 18:19:49 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-23 12:06:09 +08:00
|
|
|
while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
|
2011-05-25 18:19:49 +08:00
|
|
|
// __if_exists, __if_not_exists can nest.
|
|
|
|
if ((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists))) {
|
|
|
|
ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for extraneous top-level semicolon.
|
|
|
|
if (Tok.is(tok::semi)) {
|
2012-07-23 13:45:25 +08:00
|
|
|
ConsumeExtraSemi(InsideStruct, TagType);
|
2011-05-25 18:19:49 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
AccessSpecifier AS = getAccessSpecifierIfPresent();
|
|
|
|
if (AS != AS_none) {
|
|
|
|
// Current token is a C++ access specifier.
|
|
|
|
CurAS = AS;
|
|
|
|
SourceLocation ASLoc = Tok.getLocation();
|
|
|
|
ConsumeToken();
|
|
|
|
if (Tok.is(tok::colon))
|
|
|
|
Actions.ActOnAccessSpecifier(AS, ASLoc, Tok.getLocation());
|
|
|
|
else
|
2013-12-31 07:29:50 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::colon;
|
2011-05-25 18:19:49 +08:00
|
|
|
ConsumeToken();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse all the comma separated declarators.
|
2014-05-21 14:02:52 +08:00
|
|
|
ParseCXXClassMemberDeclaration(CurAS, nullptr);
|
2011-05-25 18:19:49 +08:00
|
|
|
}
|
2011-10-25 06:31:10 +08:00
|
|
|
|
|
|
|
Braces.consumeClose();
|
2011-05-25 18:19:49 +08:00
|
|
|
}
|