aboutsummaryrefslogtreecommitdiff
path: root/lib/Parse
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Parse')
-rw-r--r--lib/Parse/AttributeList.cpp145
-rw-r--r--lib/Parse/DeclSpec.cpp25
-rw-r--r--lib/Parse/MinimalAction.cpp5
-rw-r--r--lib/Parse/ParseDecl.cpp359
-rw-r--r--lib/Parse/ParseDeclCXX.cpp60
-rw-r--r--lib/Parse/ParseExpr.cpp168
-rw-r--r--lib/Parse/ParseExprCXX.cpp623
-rw-r--r--lib/Parse/ParseObjc.cpp146
-rw-r--r--lib/Parse/ParseStmt.cpp3
-rw-r--r--lib/Parse/ParseTemplate.cpp32
-rw-r--r--lib/Parse/Parser.cpp84
11 files changed, 1023 insertions, 627 deletions
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp
index 224a31cd5a5e..344ce9e90e55 100644
--- a/lib/Parse/AttributeList.cpp
+++ b/lib/Parse/AttributeList.cpp
@@ -13,6 +13,7 @@
#include "clang/Parse/AttributeList.h"
#include "clang/Basic/IdentifierTable.h"
+#include "llvm/ADT/StringSwitch.h"
using namespace clang;
AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc,
@@ -52,94 +53,58 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
AttrName = AttrName.substr(2, AttrName.size() - 4);
// FIXME: Hand generating this is neither smart nor efficient.
- const char *Str = AttrName.data();
- switch (AttrName.size()) {
- case 4:
- if (!memcmp(Str, "weak", 4)) return AT_weak;
- if (!memcmp(Str, "pure", 4)) return AT_pure;
- if (!memcmp(Str, "mode", 4)) return AT_mode;
- if (!memcmp(Str, "used", 4)) return AT_used;
- break;
- case 5:
- if (!memcmp(Str, "alias", 5)) return AT_alias;
- if (!memcmp(Str, "const", 5)) return AT_const;
- break;
- case 6:
- if (!memcmp(Str, "packed", 6)) return AT_packed;
- if (!memcmp(Str, "malloc", 6)) return AT_malloc;
- if (!memcmp(Str, "format", 6)) return AT_format;
- if (!memcmp(Str, "unused", 6)) return AT_unused;
- if (!memcmp(Str, "blocks", 6)) return AT_blocks;
- break;
- case 7:
- if (!memcmp(Str, "aligned", 7)) return AT_aligned;
- if (!memcmp(Str, "cleanup", 7)) return AT_cleanup;
- if (!memcmp(Str, "nodebug", 7)) return AT_nodebug;
- if (!memcmp(Str, "nonnull", 7)) return AT_nonnull;
- if (!memcmp(Str, "nothrow", 7)) return AT_nothrow;
- if (!memcmp(Str, "objc_gc", 7)) return AT_objc_gc;
- if (!memcmp(Str, "regparm", 7)) return AT_regparm;
- if (!memcmp(Str, "section", 7)) return AT_section;
- if (!memcmp(Str, "stdcall", 7)) return AT_stdcall;
- break;
- case 8:
- if (!memcmp(Str, "annotate", 8)) return AT_annotate;
- if (!memcmp(Str, "noreturn", 8)) return AT_noreturn;
- if (!memcmp(Str, "noinline", 8)) return AT_noinline;
- if (!memcmp(Str, "fastcall", 8)) return AT_fastcall;
- if (!memcmp(Str, "iboutlet", 8)) return AT_IBOutlet;
- if (!memcmp(Str, "sentinel", 8)) return AT_sentinel;
- if (!memcmp(Str, "NSObject", 8)) return AT_nsobject;
- break;
- case 9:
- if (!memcmp(Str, "dllimport", 9)) return AT_dllimport;
- if (!memcmp(Str, "dllexport", 9)) return AT_dllexport;
- if (!memcmp(Str, "may_alias", 9)) return IgnoredAttribute; // FIXME: TBAA
- break;
- case 10:
- if (!memcmp(Str, "deprecated", 10)) return AT_deprecated;
- if (!memcmp(Str, "visibility", 10)) return AT_visibility;
- if (!memcmp(Str, "destructor", 10)) return AT_destructor;
- if (!memcmp(Str, "format_arg", 10)) return AT_format_arg;
- if (!memcmp(Str, "gnu_inline", 10)) return AT_gnu_inline;
- break;
- case 11:
- if (!memcmp(Str, "weak_import", 11)) return AT_weak_import;
- if (!memcmp(Str, "vector_size", 11)) return AT_vector_size;
- if (!memcmp(Str, "constructor", 11)) return AT_constructor;
- if (!memcmp(Str, "unavailable", 11)) return AT_unavailable;
- break;
- case 12:
- if (!memcmp(Str, "overloadable", 12)) return AT_overloadable;
- break;
- case 13:
- if (!memcmp(Str, "address_space", 13)) return AT_address_space;
- if (!memcmp(Str, "always_inline", 13)) return AT_always_inline;
- if (!memcmp(Str, "vec_type_hint", 13)) return IgnoredAttribute;
- break;
- case 14:
- if (!memcmp(Str, "objc_exception", 14)) return AT_objc_exception;
- break;
- case 15:
- if (!memcmp(Str, "ext_vector_type", 15)) return AT_ext_vector_type;
- break;
- case 17:
- if (!memcmp(Str, "transparent_union", 17)) return AT_transparent_union;
- if (!memcmp(Str, "analyzer_noreturn", 17)) return AT_analyzer_noreturn;
- break;
- case 18:
- if (!memcmp(Str, "warn_unused_result", 18)) return AT_warn_unused_result;
- break;
- case 19:
- if (!memcmp(Str, "ns_returns_retained", 19)) return AT_ns_returns_retained;
- if (!memcmp(Str, "cf_returns_retained", 19)) return AT_cf_returns_retained;
- break;
- case 20:
- if (!memcmp(Str, "reqd_work_group_size", 20)) return AT_reqd_wg_size;
- case 22:
- if (!memcmp(Str, "no_instrument_function", 22))
- return AT_no_instrument_function;
- break;
- }
- return UnknownAttribute;
+ return llvm::StringSwitch<AttributeList::Kind>(AttrName)
+ .Case("weak", AT_weak)
+ .Case("pure", AT_pure)
+ .Case("mode", AT_mode)
+ .Case("used", AT_used)
+ .Case("alias", AT_alias)
+ .Case("const", AT_const)
+ .Case("packed", AT_packed)
+ .Case("malloc", AT_malloc)
+ .Case("format", AT_format)
+ .Case("unused", AT_unused)
+ .Case("blocks", AT_blocks)
+ .Case("aligned", AT_aligned)
+ .Case("cleanup", AT_cleanup)
+ .Case("nodebug", AT_nodebug)
+ .Case("nonnull", AT_nonnull)
+ .Case("nothrow", AT_nothrow)
+ .Case("objc_gc", AT_objc_gc)
+ .Case("regparm", AT_regparm)
+ .Case("section", AT_section)
+ .Case("stdcall", AT_stdcall)
+ .Case("annotate", AT_annotate)
+ .Case("noreturn", AT_noreturn)
+ .Case("noinline", AT_noinline)
+ .Case("fastcall", AT_fastcall)
+ .Case("iboutlet", AT_IBOutlet)
+ .Case("sentinel", AT_sentinel)
+ .Case("NSObject", AT_nsobject)
+ .Case("dllimport", AT_dllimport)
+ .Case("dllexport", AT_dllexport)
+ .Case("may_alias", IgnoredAttribute) // FIXME: TBAA
+ .Case("deprecated", AT_deprecated)
+ .Case("visibility", AT_visibility)
+ .Case("destructor", AT_destructor)
+ .Case("format_arg", AT_format_arg)
+ .Case("gnu_inline", AT_gnu_inline)
+ .Case("weak_import", AT_weak_import)
+ .Case("vector_size", AT_vector_size)
+ .Case("constructor", AT_constructor)
+ .Case("unavailable", AT_unavailable)
+ .Case("overloadable", AT_overloadable)
+ .Case("address_space", AT_address_space)
+ .Case("always_inline", AT_always_inline)
+ .Case("vec_type_hint", IgnoredAttribute)
+ .Case("objc_exception", AT_objc_exception)
+ .Case("ext_vector_type", AT_ext_vector_type)
+ .Case("transparent_union", AT_transparent_union)
+ .Case("analyzer_noreturn", AT_analyzer_noreturn)
+ .Case("warn_unused_result", AT_warn_unused_result)
+ .Case("ns_returns_retained", AT_ns_returns_retained)
+ .Case("cf_returns_retained", AT_cf_returns_retained)
+ .Case("reqd_work_group_size", AT_reqd_wg_size)
+ .Case("no_instrument_function", AT_no_instrument_function)
+ .Default(UnknownAttribute);
}
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
index b8422aad5a84..3436900027e4 100644
--- a/lib/Parse/DeclSpec.cpp
+++ b/lib/Parse/DeclSpec.cpp
@@ -446,3 +446,28 @@ bool DeclSpec::isMissingDeclaratorOk() {
|| tst == TST_enum
) && getTypeRep() != 0 && StorageClassSpec != DeclSpec::SCS_typedef;
}
+
+void UnqualifiedId::clear() {
+ if (Kind == IK_TemplateId)
+ TemplateId->Destroy();
+
+ Kind = IK_Identifier;
+ Identifier = 0;
+ StartLocation = SourceLocation();
+ EndLocation = SourceLocation();
+}
+
+void UnqualifiedId::setOperatorFunctionId(SourceLocation OperatorLoc,
+ OverloadedOperatorKind Op,
+ SourceLocation SymbolLocations[3]) {
+ Kind = IK_OperatorFunctionId;
+ StartLocation = OperatorLoc;
+ EndLocation = OperatorLoc;
+ OperatorFunctionId.Operator = Op;
+ for (unsigned I = 0; I != 3; ++I) {
+ OperatorFunctionId.SymbolLocations[I] = SymbolLocations[I].getRawEncoding();
+
+ if (SymbolLocations[I].isValid())
+ EndLocation = SymbolLocations[I];
+ }
+}
diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp
index 71b22cad6f62..1e7d397fdf37 100644
--- a/lib/Parse/MinimalAction.cpp
+++ b/lib/Parse/MinimalAction.cpp
@@ -161,9 +161,8 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *,
TemplateNameKind
MinimalAction::isTemplateName(Scope *S,
- const IdentifierInfo &II,
- SourceLocation IdLoc,
- const CXXScopeSpec *SS,
+ const CXXScopeSpec &SS,
+ UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringScope,
TemplateTy &TemplateDecl) {
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index b56c33170cbf..e905553fd818 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -336,10 +336,9 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context,
/// If RequireSemi is false, this does not check for a ';' at the end of the
/// declaration.
Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context,
- SourceLocation &DeclEnd,
- bool RequireSemi) {
+ SourceLocation &DeclEnd) {
// Parse the common declaration-specifiers piece.
- DeclSpec DS;
+ ParsingDeclSpec DS(*this);
ParseDeclarationSpecifiers(DS);
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
@@ -347,32 +346,109 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context,
if (Tok.is(tok::semi)) {
ConsumeToken();
DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ DS.complete(TheDecl);
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
- Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context);
- ParseDeclarator(DeclaratorInfo);
+ DeclGroupPtrTy DG = ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false,
+ &DeclEnd);
+ return DG;
+}
- DeclGroupPtrTy DG =
- ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo);
+/// ParseDeclGroup - Having concluded that this is either a function
+/// definition or a group of object declarations, actually parse the
+/// result.
+Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
+ unsigned Context,
+ bool AllowFunctionDefinitions,
+ SourceLocation *DeclEnd) {
+ // Parse the first declarator.
+ ParsingDeclarator D(*this, DS, static_cast<Declarator::TheContext>(Context));
+ ParseDeclarator(D);
+
+ // Bail out if the first declarator didn't seem well-formed.
+ if (!D.hasName() && !D.mayOmitIdentifier()) {
+ // Skip until ; or }.
+ SkipUntil(tok::r_brace, true, true);
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+ return DeclGroupPtrTy();
+ }
+
+ if (AllowFunctionDefinitions && D.isFunctionDeclarator()) {
+ if (isDeclarationAfterDeclarator()) {
+ // Fall though. We have to check this first, though, because
+ // __attribute__ might be the start of a function definition in
+ // (extended) K&R C.
+ } else if (isStartOfFunctionDefinition()) {
+ if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
+ Diag(Tok, diag::err_function_declared_typedef);
+
+ // Recover by treating the 'typedef' as spurious.
+ DS.ClearStorageClassSpecs();
+ }
- DeclEnd = Tok.getLocation();
+ DeclPtrTy TheDecl = ParseFunctionDefinition(D);
+ return Actions.ConvertDeclToDeclGroup(TheDecl);
+ } else {
+ Diag(Tok, diag::err_expected_fn_body);
+ SkipUntil(tok::semi);
+ return DeclGroupPtrTy();
+ }
+ }
- // If the client wants to check what comes after the declaration, just return
- // immediately without checking anything!
- if (!RequireSemi) return DG;
+ llvm::SmallVector<DeclPtrTy, 8> DeclsInGroup;
+ DeclPtrTy FirstDecl = ParseDeclarationAfterDeclarator(D);
+ D.complete(FirstDecl);
+ if (FirstDecl.get())
+ DeclsInGroup.push_back(FirstDecl);
- if (Tok.is(tok::semi)) {
+ // If we don't have a comma, it is either the end of the list (a ';') or an
+ // error, bail out.
+ while (Tok.is(tok::comma)) {
+ // Consume the comma.
ConsumeToken();
- return DG;
+
+ // Parse the next declarator.
+ D.clear();
+
+ // Accept attributes in an init-declarator. In the first declarator in a
+ // declaration, these would be part of the declspec. In subsequent
+ // declarators, they become part of the declarator itself, so that they
+ // don't apply to declarators after *this* one. Examples:
+ // short __attribute__((common)) var; -> declspec
+ // short var __attribute__((common)); -> declarator
+ // short x, __attribute__((common)) var; -> declarator
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ D.AddAttributes(AttrList, Loc);
+ }
+
+ ParseDeclarator(D);
+
+ DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(D);
+ D.complete(ThisDecl);
+ if (ThisDecl.get())
+ DeclsInGroup.push_back(ThisDecl);
}
- Diag(Tok, diag::err_expected_semi_declaration);
- // Skip to end of block or statement
- SkipUntil(tok::r_brace, true, true);
- if (Tok.is(tok::semi))
- ConsumeToken();
- return DG;
+ if (DeclEnd)
+ *DeclEnd = Tok.getLocation();
+
+ if (Context != Declarator::ForContext &&
+ ExpectAndConsume(tok::semi,
+ Context == Declarator::FileContext
+ ? diag::err_invalid_token_after_toplevel_declarator
+ : diag::err_expected_semi_declaration)) {
+ SkipUntil(tok::r_brace, true, true);
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+ }
+
+ return Actions.FinalizeDeclaratorGroup(CurScope, DS,
+ DeclsInGroup.data(),
+ DeclsInGroup.size());
}
/// \brief Parse 'declaration' after parsing 'declaration-specifiers
@@ -498,63 +574,6 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D,
return ThisDecl;
}
-/// ParseInitDeclaratorListAfterFirstDeclarator - Parse 'declaration' after
-/// parsing 'declaration-specifiers declarator'. This method is split out this
-/// way to handle the ambiguity between top-level function-definitions and
-/// declarations.
-///
-/// init-declarator-list: [C99 6.7]
-/// init-declarator
-/// init-declarator-list ',' init-declarator
-///
-/// According to the standard grammar, =default and =delete are function
-/// definitions, but that definitely doesn't fit with the parser here.
-///
-Parser::DeclGroupPtrTy Parser::
-ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) {
- // Declarators may be grouped together ("int X, *Y, Z();"). Remember the decls
- // that we parse together here.
- llvm::SmallVector<DeclPtrTy, 8> DeclsInGroup;
-
- // At this point, we know that it is not a function definition. Parse the
- // rest of the init-declarator-list.
- while (1) {
- DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(D);
- if (ThisDecl.get())
- DeclsInGroup.push_back(ThisDecl);
-
- // If we don't have a comma, it is either the end of the list (a ';') or an
- // error, bail out.
- if (Tok.isNot(tok::comma))
- break;
-
- // Consume the comma.
- ConsumeToken();
-
- // Parse the next declarator.
- D.clear();
-
- // Accept attributes in an init-declarator. In the first declarator in a
- // declaration, these would be part of the declspec. In subsequent
- // declarators, they become part of the declarator itself, so that they
- // don't apply to declarators after *this* one. Examples:
- // short __attribute__((common)) var; -> declspec
- // short var __attribute__((common)); -> declarator
- // short x, __attribute__((common)) var; -> declarator
- if (Tok.is(tok::kw___attribute)) {
- SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
- D.AddAttributes(AttrList, Loc);
- }
-
- ParseDeclarator(D);
- }
-
- return Actions.FinalizeDeclaratorGroup(CurScope, D.getDeclSpec(),
- DeclsInGroup.data(),
- DeclsInGroup.size());
-}
-
/// ParseSpecifierQualifierList
/// specifier-qualifier-list:
/// type-specifier specifier-qualifier-list[opt]
@@ -1468,8 +1487,7 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
/// [GNU] declarator[opt] ':' constant-expression attributes[opt]
///
void Parser::
-ParseStructDeclaration(DeclSpec &DS,
- llvm::SmallVectorImpl<FieldDeclarator> &Fields) {
+ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) {
if (Tok.is(tok::kw___extension__)) {
// __extension__ silences extension warnings in the subexpression.
ExtensionRAIIObject O(Diags); // Use RAII to do this.
@@ -1489,9 +1507,17 @@ ParseStructDeclaration(DeclSpec &DS,
}
// Read struct-declarators until we find the semicolon.
- Fields.push_back(FieldDeclarator(DS));
+ bool FirstDeclarator = true;
while (1) {
- FieldDeclarator &DeclaratorInfo = Fields.back();
+ ParsingDeclRAIIObject PD(*this);
+ FieldDeclarator DeclaratorInfo(DS);
+
+ // Attributes are only allowed here on successive declarators.
+ if (!FirstDeclarator && Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ DeclaratorInfo.D.AddAttributes(AttrList, Loc);
+ }
/// struct-declarator: declarator
/// struct-declarator: declarator[opt] ':' constant-expression
@@ -1514,6 +1540,10 @@ ParseStructDeclaration(DeclSpec &DS,
DeclaratorInfo.D.AddAttributes(AttrList, Loc);
}
+ // We're done with this declarator; invoke the callback.
+ DeclPtrTy D = Fields.invoke(DeclaratorInfo);
+ PD.complete(D);
+
// If we don't have a comma, it is either the end of the list (a ';')
// or an error, bail out.
if (Tok.isNot(tok::comma))
@@ -1522,15 +1552,7 @@ ParseStructDeclaration(DeclSpec &DS,
// Consume the comma.
ConsumeToken();
- // Parse the next declarator.
- Fields.push_back(FieldDeclarator(DS));
-
- // Attributes are only allowed on the second declarator.
- if (Tok.is(tok::kw___attribute)) {
- SourceLocation Loc;
- AttributeList *AttrList = ParseAttributes(&Loc);
- Fields.back().D.AddAttributes(AttrList, Loc);
- }
+ FirstDeclarator = false;
}
}
@@ -1562,7 +1584,6 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
<< DeclSpec::getSpecifierName((DeclSpec::TST)TagType);
llvm::SmallVector<DeclPtrTy, 32> FieldDecls;
- llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators;
// While we still have something to read, read the declarations in the struct.
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
@@ -1578,28 +1599,28 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
// Parse all the comma separated declarators.
DeclSpec DS;
- FieldDeclarators.clear();
+
if (!Tok.is(tok::at)) {
- ParseStructDeclaration(DS, FieldDeclarators);
-
- // Convert them all to fields.
- for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) {
- FieldDeclarator &FD = FieldDeclarators[i];
- DeclPtrTy Field;
- // Install the declarator into the current TagDecl.
- if (FD.D.getExtension()) {
- // Silences extension warnings
- ExtensionRAIIObject O(Diags);
- Field = Actions.ActOnField(CurScope, TagDecl,
- DS.getSourceRange().getBegin(),
- FD.D, FD.BitfieldSize);
- } else {
- Field = Actions.ActOnField(CurScope, TagDecl,
- DS.getSourceRange().getBegin(),
- FD.D, FD.BitfieldSize);
+ struct CFieldCallback : FieldCallback {
+ Parser &P;
+ DeclPtrTy TagDecl;
+ llvm::SmallVectorImpl<DeclPtrTy> &FieldDecls;
+
+ CFieldCallback(Parser &P, DeclPtrTy TagDecl,
+ llvm::SmallVectorImpl<DeclPtrTy> &FieldDecls) :
+ P(P), TagDecl(TagDecl), FieldDecls(FieldDecls) {}
+
+ virtual DeclPtrTy invoke(FieldDeclarator &FD) {
+ // Install the declarator into the current TagDecl.
+ DeclPtrTy Field = P.Actions.ActOnField(P.CurScope, TagDecl,
+ FD.D.getDeclSpec().getSourceRange().getBegin(),
+ FD.D, FD.BitfieldSize);
+ FieldDecls.push_back(Field);
+ return Field;
}
- FieldDecls.push_back(Field);
- }
+ } Callback(*this, TagDecl, FieldDecls);
+
+ ParseStructDeclaration(DS, Callback);
} else { // Handle @defs
ConsumeToken();
if (!Tok.isObjCAtKeyword(tok::objc_defs)) {
@@ -2107,7 +2128,6 @@ void Parser::ParseDeclarator(Declarator &D) {
/// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt]
void Parser::ParseDeclaratorInternal(Declarator &D,
DirectDeclParseFunction DirectDeclParser) {
-
if (Diags.hasAllExtensionsSilenced())
D.setExtension();
// C++ member pointers start with a '::' or a nested-name.
@@ -2270,97 +2290,47 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
void Parser::ParseDirectDeclarator(Declarator &D) {
DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec());
- if (getLang().CPlusPlus) {
- if (D.mayHaveIdentifier()) {
- // ParseDeclaratorInternal might already have parsed the scope.
- bool afterCXXScope = D.getCXXScopeSpec().isSet() ||
- ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0,
- true);
- if (afterCXXScope) {
- // Change the declaration context for name lookup, until this function
- // is exited (and the declarator has been parsed).
- DeclScopeObj.EnterDeclaratorScope();
- }
-
- if (Tok.is(tok::identifier)) {
- assert(Tok.getIdentifierInfo() && "Not an identifier?");
-
- // If this identifier is the name of the current class, it's a
- // constructor name.
- if (!D.getDeclSpec().hasTypeSpecifier() &&
- Actions.isCurrentClassName(*Tok.getIdentifierInfo(),CurScope)) {
- CXXScopeSpec *SS = afterCXXScope? &D.getCXXScopeSpec() : 0;
- D.setConstructor(Actions.getTypeName(*Tok.getIdentifierInfo(),
- Tok.getLocation(), CurScope, SS),
- Tok.getLocation());
- // This is a normal identifier.
- } else
- D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
- ConsumeToken();
- goto PastIdentifier;
- } else if (Tok.is(tok::annot_template_id)) {
- TemplateIdAnnotation *TemplateId
- = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
-
- D.setTemplateId(TemplateId);
- ConsumeToken();
- goto PastIdentifier;
- } else if (Tok.is(tok::kw_operator)) {
- SourceLocation OperatorLoc = Tok.getLocation();
- SourceLocation EndLoc;
-
- // First try the name of an overloaded operator
- if (OverloadedOperatorKind Op = TryParseOperatorFunctionId(&EndLoc)) {
- D.setOverloadedOperator(Op, OperatorLoc, EndLoc);
- } else {
- // This must be a conversion function (C++ [class.conv.fct]).
- if (TypeTy *ConvType = ParseConversionFunctionId(&EndLoc))
- D.setConversionFunction(ConvType, OperatorLoc, EndLoc);
- else {
- D.SetIdentifier(0, Tok.getLocation());
- }
- }
- goto PastIdentifier;
- } else if (Tok.is(tok::tilde)) {
- // This should be a C++ destructor.
- SourceLocation TildeLoc = ConsumeToken();
- if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) {
- // FIXME: Inaccurate.
- SourceLocation NameLoc = Tok.getLocation();
- SourceLocation EndLoc;
- CXXScopeSpec *SS = afterCXXScope? &D.getCXXScopeSpec() : 0;
- TypeResult Type = ParseClassName(EndLoc, SS, true);
- if (Type.isInvalid())
- D.SetIdentifier(0, TildeLoc);
- else
- D.setDestructor(Type.get(), TildeLoc, NameLoc);
- } else {
- Diag(Tok, diag::err_destructor_class_name);
- D.SetIdentifier(0, TildeLoc);
- }
- goto PastIdentifier;
- }
-
- // If we reached this point, token is not identifier and not '~'.
-
- if (afterCXXScope) {
- Diag(Tok, diag::err_expected_unqualified_id);
+ if (getLang().CPlusPlus && D.mayHaveIdentifier()) {
+ // ParseDeclaratorInternal might already have parsed the scope.
+ bool afterCXXScope = D.getCXXScopeSpec().isSet() ||
+ ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0,
+ true);
+ if (afterCXXScope) {
+ // Change the declaration context for name lookup, until this function
+ // is exited (and the declarator has been parsed).
+ DeclScopeObj.EnterDeclaratorScope();
+ }
+
+ if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) ||
+ Tok.is(tok::annot_template_id) || Tok.is(tok::tilde)) {
+ // We found something that indicates the start of an unqualified-id.
+ // Parse that unqualified-id.
+ if (ParseUnqualifiedId(D.getCXXScopeSpec(),
+ /*EnteringContext=*/true,
+ /*AllowDestructorName=*/true,
+ /*AllowConstructorName=*/!D.getDeclSpec().hasTypeSpecifier(),
+ /*ObjectType=*/0,
+ D.getName())) {
D.SetIdentifier(0, Tok.getLocation());
D.setInvalidType(true);
- goto PastIdentifier;
+ } else {
+ // Parsed the unqualified-id; update range information and move along.
+ if (D.getSourceRange().getBegin().isInvalid())
+ D.SetRangeBegin(D.getName().getSourceRange().getBegin());
+ D.SetRangeEnd(D.getName().getSourceRange().getEnd());
}
+ goto PastIdentifier;
}
- }
-
- // If we reached this point, we are either in C/ObjC or the token didn't
- // satisfy any of the C++-specific checks.
- if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) {
+ } else if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) {
assert(!getLang().CPlusPlus &&
"There's a C++-specific check for tok::identifier above");
assert(Tok.getIdentifierInfo() && "Not an identifier?");
D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
ConsumeToken();
- } else if (Tok.is(tok::l_paren)) {
+ goto PastIdentifier;
+ }
+
+ if (Tok.is(tok::l_paren)) {
// direct-declarator: '(' declarator ')'
// direct-declarator: '(' attributes declarator ')'
// Example: 'char (*X)' or 'int (*XX)(void)'
@@ -2374,7 +2344,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
Diag(Tok, diag::err_expected_member_name_or_semi)
<< D.getDeclSpec().getSourceRange();
else if (getLang().CPlusPlus)
- Diag(Tok, diag::err_expected_unqualified_id);
+ Diag(Tok, diag::err_expected_unqualified_id) << getLang().CPlusPlus;
else
Diag(Tok, diag::err_expected_ident_lparen);
D.SetIdentifier(0, Tok.getLocation());
@@ -2623,6 +2593,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
SourceLocation DSStart = Tok.getLocation();
// Parse the declaration-specifiers.
+ // Just use the ParsingDeclaration "scope" of the declarator.
DeclSpec DS;
// If the caller parsed attributes for the first argument, add them now.
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index d381e3e97472..91f86864f81f 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -323,6 +323,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
SkipUntil(tok::semi);
return DeclPtrTy();
}
+ // FIXME: what about conversion functions?
} else if (Tok.is(tok::identifier)) {
// Parse identifier.
TargetName = Tok.getIdentifierInfo();
@@ -589,6 +590,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
Diag(Tok, diag::err_expected_ident);
+ TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
+
// Parse the (optional) class name or simple-template-id.
IdentifierInfo *Name = 0;
SourceLocation NameLoc;
@@ -596,6 +599,56 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (Tok.is(tok::identifier)) {
Name = Tok.getIdentifierInfo();
NameLoc = ConsumeToken();
+
+ if (Tok.is(tok::less)) {
+ // The name was supposed to refer to a template, but didn't.
+ // Eat the template argument list and try to continue parsing this as
+ // a class (or template thereof).
+ TemplateArgList TemplateArgs;
+ TemplateArgIsTypeList TemplateArgIsType;
+ TemplateArgLocationList TemplateArgLocations;
+ SourceLocation LAngleLoc, RAngleLoc;
+ if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, &SS,
+ true, LAngleLoc,
+ TemplateArgs, TemplateArgIsType,
+ TemplateArgLocations, RAngleLoc)) {
+ // 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();
+ }
+
+ Diag(NameLoc, diag::err_explicit_spec_non_template)
+ << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
+ << (TagType == DeclSpec::TST_class? 0
+ : TagType == DeclSpec::TST_struct? 1
+ : 2)
+ << Name
+ << SourceRange(LAngleLoc, RAngleLoc);
+
+ // Strip off the last template parameter list if it was empty, since
+ // we've removed its template argument list.
+ if (TemplateParams && TemplateInfo.LastParameterListWasEmpty) {
+ if (TemplateParams && TemplateParams->size() > 1) {
+ TemplateParams->pop_back();
+ } else {
+ TemplateParams = 0;
+ const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind
+ = ParsedTemplateInfo::NonTemplate;
+ }
+ } else if (TemplateInfo.Kind
+ == ParsedTemplateInfo::ExplicitInstantiation) {
+ // Pretend this is just a forward declaration.
+ TemplateParams = 0;
+ const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind
+ = ParsedTemplateInfo::NonTemplate;
+ const_cast<ParsedTemplateInfo&>(TemplateInfo).TemplateLoc
+ = SourceLocation();
+ const_cast<ParsedTemplateInfo&>(TemplateInfo).ExternLoc
+ = SourceLocation();
+ }
+
+
+ }
} else if (Tok.is(tok::annot_template_id)) {
TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
NameLoc = ConsumeToken();
@@ -660,7 +713,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Create the tag portion of the class or class template.
Action::DeclResult TagOrTempResult = true; // invalid
Action::TypeResult TypeResult = true; // invalid
- TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
// FIXME: When TUK == TUK_Reference and we have a template-id, we need
// to turn that template-id into a type.
@@ -1047,7 +1099,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
SourceLocation DSStart = Tok.getLocation();
// decl-specifier-seq:
// Parse the common declaration-specifiers piece.
- DeclSpec DS;
+ ParsingDeclSpec DS(*this);
ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class);
Action::MultiTemplateParamsArg TemplateParams(Actions,
@@ -1060,7 +1112,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return;
}
- Declarator DeclaratorInfo(DS, Declarator::MemberContext);
+ ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext);
if (Tok.isNot(tok::colon)) {
// Parse the first declarator.
@@ -1179,6 +1231,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
HandleMemberFunctionDefaultArgs(DeclaratorInfo, ThisDecl);
}
+ DeclaratorInfo.complete(ThisDecl);
+
// If we don't have a comma, it is either the end of the list (a ';')
// or an error, bail out.
if (Tok.isNot(tok::comma))
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 8be89a891680..95a0e989471e 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -340,7 +340,18 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
// Eat the colon.
ColonLoc = ConsumeToken();
}
-
+
+ if ((OpToken.is(tok::periodstar) || OpToken.is(tok::arrowstar))
+ && Tok.is(tok::identifier)) {
+ CXXScopeSpec SS;
+ if (Actions.getTypeName(*Tok.getIdentifierInfo(),
+ Tok.getLocation(), CurScope, &SS)) {
+ const char *Opc = OpToken.is(tok::periodstar) ? "'.*'" : "'->*'";
+ Diag(OpToken, diag::err_pointer_to_member_type) << Opc;
+ return ExprError();
+ }
+
+ }
// Parse another leaf here for the RHS of the operator.
// ParseCastExpression works here because all RHS expressions in C have it
// as a prefix, at least. However, in C++, an assignment-expression could
@@ -612,36 +623,39 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
}
- // Support 'Class.property' notation.
- // We don't use isTokObjCMessageIdentifierReceiver(), since it allows
- // 'super' (which is inappropriate here).
- if (getLang().ObjC1 &&
- Actions.getTypeName(*Tok.getIdentifierInfo(),
- Tok.getLocation(), CurScope) &&
- NextToken().is(tok::period)) {
- IdentifierInfo &ReceiverName = *Tok.getIdentifierInfo();
- SourceLocation IdentLoc = ConsumeToken();
+ // Consume the identifier so that we can see if it is followed by a '(' or
+ // '.'.
+ IdentifierInfo &II = *Tok.getIdentifierInfo();
+ SourceLocation ILoc = ConsumeToken();
+
+ // Support 'Class.property' notation. We don't use
+ // isTokObjCMessageIdentifierReceiver(), since it allows 'super' (which is
+ // inappropriate here).
+ if (getLang().ObjC1 && Tok.is(tok::period) &&
+ Actions.getTypeName(II, ILoc, CurScope)) {
SourceLocation DotLoc = ConsumeToken();
-
+
if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident);
+ Diag(Tok, diag::err_expected_property_name);
return ExprError();
}
IdentifierInfo &PropertyName = *Tok.getIdentifierInfo();
SourceLocation PropertyLoc = ConsumeToken();
-
- Res = Actions.ActOnClassPropertyRefExpr(ReceiverName, PropertyName,
- IdentLoc, PropertyLoc);
+
+ Res = Actions.ActOnClassPropertyRefExpr(II, PropertyName,
+ ILoc, PropertyLoc);
// These can be followed by postfix-expr pieces.
return ParsePostfixExpressionSuffix(move(Res));
}
- // Consume the identifier so that we can see if it is followed by a '('.
+
// Function designators are allowed to be undeclared (C99 6.5.1p2), so we
// need to know whether or not this identifier is a function designator or
// not.
- IdentifierInfo &II = *Tok.getIdentifierInfo();
- SourceLocation L = ConsumeToken();
- Res = Actions.ActOnIdentifierExpr(CurScope, L, II, Tok.is(tok::l_paren));
+ UnqualifiedId Name;
+ CXXScopeSpec ScopeSpec;
+ Name.setIdentifier(&II, ILoc);
+ Res = Actions.ActOnIdExpression(CurScope, ScopeSpec, Name,
+ Tok.is(tok::l_paren), false);
// These can be followed by postfix-expr pieces.
return ParsePostfixExpressionSuffix(move(Res));
}
@@ -954,110 +968,20 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
ConsumeToken();
}
- if (Tok.is(tok::identifier)) {
- if (!LHS.isInvalid())
- LHS = Actions.ActOnMemberReferenceExpr(CurScope, move(LHS), OpLoc,
- OpKind, Tok.getLocation(),
- *Tok.getIdentifierInfo(),
- ObjCImpDecl, &SS);
- ConsumeToken();
- } else if (getLang().CPlusPlus && Tok.is(tok::tilde)) {
- // We have a C++ pseudo-destructor or a destructor call, e.g., t.~T()
-
- // Consume the tilde.
- ConsumeToken();
-
- if (!Tok.is(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident);
- return ExprError();
- }
-
- if (NextToken().is(tok::less)) {
- // class-name:
- // ~ simple-template-id
- TemplateTy Template
- = Actions.ActOnDependentTemplateName(SourceLocation(),
- *Tok.getIdentifierInfo(),
- Tok.getLocation(),
- SS,
- ObjectType);
- if (AnnotateTemplateIdToken(Template, TNK_Type_template, &SS,
- SourceLocation(), true))
- return ExprError();
-
- assert(Tok.is(tok::annot_typename) &&
- "AnnotateTemplateIdToken didn't work?");
- if (!LHS.isInvalid())
- LHS = Actions.ActOnDestructorReferenceExpr(CurScope, move(LHS),
- OpLoc, OpKind,
- Tok.getAnnotationRange(),
- Tok.getAnnotationValue(),
- SS,
- NextToken().is(tok::l_paren));
- } else {
- // class-name:
- // ~ identifier
- if (!LHS.isInvalid())
- LHS = Actions.ActOnDestructorReferenceExpr(CurScope, move(LHS),
- OpLoc, OpKind,
- Tok.getLocation(),
- Tok.getIdentifierInfo(),
- SS,
- NextToken().is(tok::l_paren));
- }
-
- // Consume the identifier or template-id token.
- ConsumeToken();
- } else if (getLang().CPlusPlus && Tok.is(tok::kw_operator)) {
- // We have a reference to a member operator, e.g., t.operator int or
- // t.operator+.
- SourceLocation OperatorLoc = Tok.getLocation();
-
- if (OverloadedOperatorKind Op = TryParseOperatorFunctionId()) {
- if (!LHS.isInvalid())
- LHS = Actions.ActOnOverloadedOperatorReferenceExpr(CurScope,
- move(LHS), OpLoc,
- OpKind,
- OperatorLoc,
- Op, &SS);
- // TryParseOperatorFunctionId already consumed our token, so
- // don't bother
- } else if (TypeTy *ConvType = ParseConversionFunctionId()) {
- if (!LHS.isInvalid())
- LHS = Actions.ActOnConversionOperatorReferenceExpr(CurScope,
- move(LHS), OpLoc,
- OpKind,
- OperatorLoc,
- ConvType, &SS);
- } else {
- // Don't emit a diagnostic; ParseConversionFunctionId does it for us
- return ExprError();
- }
- } else if (getLang().CPlusPlus && Tok.is(tok::annot_template_id)) {
- // We have a reference to a member template along with explicitly-
- // specified template arguments, e.g., t.f<int>.
- TemplateIdAnnotation *TemplateId
- = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
- if (!LHS.isInvalid()) {
- ASTTemplateArgsPtr TemplateArgsPtr(Actions,
- TemplateId->getTemplateArgs(),
- TemplateId->getTemplateArgIsType(),
- TemplateId->NumArgs);
-
- LHS = Actions.ActOnMemberTemplateIdReferenceExpr(CurScope, move(LHS),
- OpLoc, OpKind, SS,
- TemplateTy::make(TemplateId->Template),
- TemplateId->TemplateNameLoc,
- TemplateId->LAngleLoc,
- TemplateArgsPtr,
- TemplateId->getTemplateArgLocations(),
- TemplateId->RAngleLoc);
- }
- ConsumeToken();
- } else {
- Diag(Tok, diag::err_expected_ident);
+ UnqualifiedId Name;
+ if (ParseUnqualifiedId(SS,
+ /*EnteringContext=*/false,
+ /*AllowDestructorName=*/true,
+ /*AllowConstructorName=*/false,
+ ObjectType,
+ Name))
return ExprError();
- }
+
+ if (!LHS.isInvalid())
+ LHS = Actions.ActOnMemberAccessExpr(CurScope, move(LHS), OpLoc, OpKind,
+ SS, Name, ObjCImpDecl,
+ Tok.is(tok::l_paren));
+
break;
}
case tok::plusplus: // postfix-expression: postfix-expression '++'
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index fa651569f8e1..a7ca0c54dbe6 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -14,6 +14,8 @@
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/DeclSpec.h"
+#include "llvm/Support/ErrorHandling.h"
+
using namespace clang;
/// \brief Parse global scope or nested-name-specifier if present.
@@ -107,31 +109,58 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
break;
SourceLocation TemplateKWLoc = ConsumeToken();
-
- if (Tok.isNot(tok::identifier)) {
+
+ UnqualifiedId TemplateName;
+ if (Tok.is(tok::identifier)) {
+ TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
+
+ // If the next token is not '<', we may have a stray 'template' keyword.
+ // Complain and suggest removing the template keyword, but otherwise
+ // allow parsing to continue.
+ if (NextToken().isNot(tok::less)) {
+ Diag(NextToken().getLocation(),
+ diag::err_less_after_template_name_in_nested_name_spec)
+ << Tok.getIdentifierInfo()->getName()
+ << CodeModificationHint::CreateRemoval(SourceRange(TemplateKWLoc));
+ break;
+ }
+
+ // Consume the identifier.
+ ConsumeToken();
+ } else if (Tok.is(tok::kw_operator)) {
+ if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType,
+ TemplateName))
+ break;
+
+ if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId) {
+ Diag(TemplateName.getSourceRange().getBegin(),
+ diag::err_id_after_template_in_nested_name_spec)
+ << TemplateName.getSourceRange();
+ break;
+ } else if (Tok.isNot(tok::less)) {
+ std::string OperatorName = "operator ";
+ OperatorName += getOperatorSpelling(
+ TemplateName.OperatorFunctionId.Operator);
+ Diag(Tok.getLocation(),
+ diag::err_less_after_template_name_in_nested_name_spec)
+ << OperatorName
+ << TemplateName.getSourceRange();
+ break;
+ }
+ } else {
Diag(Tok.getLocation(),
diag::err_id_after_template_in_nested_name_spec)
<< SourceRange(TemplateKWLoc);
break;
}
- if (NextToken().isNot(tok::less)) {
- Diag(NextToken().getLocation(),
- diag::err_less_after_template_name_in_nested_name_spec)
- << Tok.getIdentifierInfo()->getName()
- << SourceRange(TemplateKWLoc, Tok.getLocation());
- break;
- }
-
TemplateTy Template
- = Actions.ActOnDependentTemplateName(TemplateKWLoc,
- *Tok.getIdentifierInfo(),
- Tok.getLocation(), SS,
+ = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, TemplateName,
ObjectType);
if (!Template)
break;
if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name,
- &SS, TemplateKWLoc, false))
+ &SS, TemplateName, TemplateKWLoc, false))
break;
continue;
@@ -218,9 +247,10 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// type-name '<'
if (Next.is(tok::less)) {
TemplateTy Template;
- if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, II,
- Tok.getLocation(),
- &SS,
+ UnqualifiedId TemplateName;
+ TemplateName.setIdentifier(&II, Tok.getLocation());
+ if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS,
+ TemplateName,
ObjectType,
EnteringContext,
Template)) {
@@ -230,8 +260,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// because some clients (e.g., the parsing of class template
// specializations) still want to see the original template-id
// token.
- if (AnnotateTemplateIdToken(Template, TNK, &SS, SourceLocation(),
- false))
+ ConsumeToken();
+ if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName,
+ SourceLocation(), false))
break;
continue;
}
@@ -251,25 +282,12 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
/// unqualified-id
/// qualified-id
///
-/// unqualified-id:
-/// identifier
-/// operator-function-id
-/// conversion-function-id [TODO]
-/// '~' class-name [TODO]
-/// template-id
-///
/// qualified-id:
/// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
/// '::' identifier
/// '::' operator-function-id
/// '::' template-id
///
-/// nested-name-specifier:
-/// type-name '::'
-/// namespace-name '::'
-/// nested-name-specifier identifier '::'
-/// nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
-///
/// NOTE: The standard specifies that, for qualified-id, the parser does not
/// expect:
///
@@ -307,69 +325,19 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
//
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
-
- // unqualified-id:
- // identifier
- // operator-function-id
- // conversion-function-id
- // '~' class-name [TODO]
- // template-id
- //
- switch (Tok.getKind()) {
- default:
- return ExprError(Diag(Tok, diag::err_expected_unqualified_id));
-
- case tok::identifier: {
- // Consume the identifier so that we can see if it is followed by a '('.
- IdentifierInfo &II = *Tok.getIdentifierInfo();
- SourceLocation L = ConsumeToken();
- return Actions.ActOnIdentifierExpr(CurScope, L, II, Tok.is(tok::l_paren),
- &SS, isAddressOfOperand);
- }
-
- case tok::kw_operator: {
- SourceLocation OperatorLoc = Tok.getLocation();
- if (OverloadedOperatorKind Op = TryParseOperatorFunctionId())
- return Actions.ActOnCXXOperatorFunctionIdExpr(
- CurScope, OperatorLoc, Op, Tok.is(tok::l_paren), SS,
- isAddressOfOperand);
- if (TypeTy *Type = ParseConversionFunctionId())
- return Actions.ActOnCXXConversionFunctionExpr(CurScope, OperatorLoc, Type,
- Tok.is(tok::l_paren), SS,
- isAddressOfOperand);
-
- // We already complained about a bad conversion-function-id,
- // above.
+
+ UnqualifiedId Name;
+ if (ParseUnqualifiedId(SS,
+ /*EnteringContext=*/false,
+ /*AllowDestructorName=*/false,
+ /*AllowConstructorName=*/false,
+ /*ObjectType=*/0,
+ Name))
return ExprError();
- }
-
- case tok::annot_template_id: {
- TemplateIdAnnotation *TemplateId
- = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
- assert((TemplateId->Kind == TNK_Function_template ||
- TemplateId->Kind == TNK_Dependent_template_name) &&
- "A template type name is not an ID expression");
-
- ASTTemplateArgsPtr TemplateArgsPtr(Actions,
- TemplateId->getTemplateArgs(),
- TemplateId->getTemplateArgIsType(),
- TemplateId->NumArgs);
-
- OwningExprResult Result
- = Actions.ActOnTemplateIdExpr(SS,
- TemplateTy::make(TemplateId->Template),
- TemplateId->TemplateNameLoc,
- TemplateId->LAngleLoc,
- TemplateArgsPtr,
- TemplateId->getTemplateArgLocations(),
- TemplateId->RAngleLoc);
- ConsumeToken(); // Consume the template-id token
- return move(Result);
- }
-
- } // switch.
-
- assert(0 && "The switch was supposed to take care everything.");
+
+ return Actions.ActOnIdExpression(CurScope, SS, Name, Tok.is(tok::l_paren),
+ isAddressOfOperand);
+
}
/// ParseCXXCasts - This handles the various ways to cast expressions to another
@@ -761,6 +729,473 @@ bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
return false;
}
+/// \brief Finish parsing a C++ unqualified-id that is a template-id of
+/// some form.
+///
+/// This routine is invoked when a '<' is encountered after an identifier or
+/// operator-function-id is parsed by \c ParseUnqualifiedId() to determine
+/// whether the unqualified-id is actually a template-id. This routine will
+/// then parse the template arguments and form the appropriate template-id to
+/// return to the caller.
+///
+/// \param SS the nested-name-specifier that precedes this template-id, if
+/// we're actually parsing a qualified-id.
+///
+/// \param Name for constructor and destructor names, this is the actual
+/// identifier that may be a template-name.
+///
+/// \param NameLoc the location of the class-name in a constructor or
+/// destructor.
+///
+/// \param EnteringContext whether we're entering the scope of the
+/// nested-name-specifier.
+///
+/// \param ObjectType if this unqualified-id occurs within a member access
+/// expression, the type of the base object whose member is being accessed.
+///
+/// \param Id as input, describes the template-name or operator-function-id
+/// that precedes the '<'. If template arguments were parsed successfully,
+/// will be updated with the template-id.
+///
+/// \returns true if a parse error occurred, false otherwise.
+bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ bool EnteringContext,
+ TypeTy *ObjectType,
+ UnqualifiedId &Id) {
+ assert(Tok.is(tok::less) && "Expected '<' to finish parsing a template-id");
+
+ TemplateTy Template;
+ TemplateNameKind TNK = TNK_Non_template;
+ switch (Id.getKind()) {
+ case UnqualifiedId::IK_Identifier:
+ case UnqualifiedId::IK_OperatorFunctionId:
+ TNK = Actions.isTemplateName(CurScope, SS, Id, ObjectType, EnteringContext,
+ Template);
+ break;
+
+ case UnqualifiedId::IK_ConstructorName: {
+ UnqualifiedId TemplateName;
+ TemplateName.setIdentifier(Name, NameLoc);
+ TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType,
+ EnteringContext, Template);
+ break;
+ }
+
+ case UnqualifiedId::IK_DestructorName: {
+ UnqualifiedId TemplateName;
+ TemplateName.setIdentifier(Name, NameLoc);
+ if (ObjectType) {
+ Template = Actions.ActOnDependentTemplateName(SourceLocation(), SS,
+ TemplateName, ObjectType);
+ TNK = TNK_Dependent_template_name;
+ if (!Template.get())
+ return true;
+ } else {
+ TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType,
+ EnteringContext, Template);
+
+ if (TNK == TNK_Non_template && Id.DestructorName == 0) {
+ // The identifier following the destructor did not refer to a template
+ // or to a type. Complain.
+ if (ObjectType)
+ Diag(NameLoc, diag::err_ident_in_pseudo_dtor_not_a_type)
+ << Name;
+ else
+ Diag(NameLoc, diag::err_destructor_class_name);
+ return true;
+ }
+ }
+ break;
+ }
+
+ default:
+ return false;
+ }
+
+ if (TNK == TNK_Non_template)
+ return false;
+
+ // Parse the enclosed template argument list.
+ SourceLocation LAngleLoc, RAngleLoc;
+ TemplateArgList TemplateArgs;
+ TemplateArgIsTypeList TemplateArgIsType;
+ TemplateArgLocationList TemplateArgLocations;
+ if (ParseTemplateIdAfterTemplateName(Template, Id.StartLocation,
+ &SS, true, LAngleLoc,
+ TemplateArgs,
+ TemplateArgIsType,
+ TemplateArgLocations,
+ RAngleLoc))
+ return true;
+
+ if (Id.getKind() == UnqualifiedId::IK_Identifier ||
+ Id.getKind() == UnqualifiedId::IK_OperatorFunctionId) {
+ // Form a parsed representation of the template-id to be stored in the
+ // UnqualifiedId.
+ TemplateIdAnnotation *TemplateId
+ = TemplateIdAnnotation::Allocate(TemplateArgs.size());
+
+ if (Id.getKind() == UnqualifiedId::IK_Identifier) {
+ TemplateId->Name = Id.Identifier;
+ TemplateId->Operator = OO_None;
+ TemplateId->TemplateNameLoc = Id.StartLocation;
+ } else {
+ TemplateId->Name = 0;
+ TemplateId->Operator = Id.OperatorFunctionId.Operator;
+ TemplateId->TemplateNameLoc = Id.StartLocation;
+ }
+
+ TemplateId->Template = Template.getAs<void*>();
+ TemplateId->Kind = TNK;
+ TemplateId->LAngleLoc = LAngleLoc;
+ TemplateId->RAngleLoc = RAngleLoc;
+ void **Args = TemplateId->getTemplateArgs();
+ bool *ArgIsType = TemplateId->getTemplateArgIsType();
+ SourceLocation *ArgLocs = TemplateId->getTemplateArgLocations();
+ for (unsigned Arg = 0, ArgEnd = TemplateArgs.size();
+ Arg != ArgEnd; ++Arg) {
+ Args[Arg] = TemplateArgs[Arg];
+ ArgIsType[Arg] = TemplateArgIsType[Arg];
+ ArgLocs[Arg] = TemplateArgLocations[Arg];
+ }
+
+ Id.setTemplateId(TemplateId);
+ return false;
+ }
+
+ // Bundle the template arguments together.
+ ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(),
+ TemplateArgIsType.data(),
+ TemplateArgs.size());
+
+ // Constructor and destructor names.
+ Action::TypeResult Type
+ = Actions.ActOnTemplateIdType(Template, NameLoc,
+ LAngleLoc, TemplateArgsPtr,
+ &TemplateArgLocations[0],
+ RAngleLoc);
+ if (Type.isInvalid())
+ return true;
+
+ if (Id.getKind() == UnqualifiedId::IK_ConstructorName)
+ Id.setConstructorName(Type.get(), NameLoc, RAngleLoc);
+ else
+ Id.setDestructorName(Id.StartLocation, Type.get(), RAngleLoc);
+
+ return false;
+}
+
+/// \brief Parse an operator-function-id or conversion-function-id as part
+/// of a C++ unqualified-id.
+///
+/// This routine is responsible only for parsing the operator-function-id or
+/// conversion-function-id; it does not handle template arguments in any way.
+///
+/// \code
+/// operator-function-id: [C++ 13.5]
+/// 'operator' operator
+///
+/// operator: one of
+/// new delete new[] delete[]
+/// + - * / % ^ & | ~
+/// ! = < > += -= *= /= %=
+/// ^= &= |= << >> >>= <<= == !=
+/// <= >= && || ++ -- , ->* ->
+/// () []
+///
+/// conversion-function-id: [C++ 12.3.2]
+/// operator conversion-type-id
+///
+/// conversion-type-id:
+/// type-specifier-seq conversion-declarator[opt]
+///
+/// conversion-declarator:
+/// ptr-operator conversion-declarator[opt]
+/// \endcode
+///
+/// \param The nested-name-specifier that preceded this unqualified-id. If
+/// non-empty, then we are parsing the unqualified-id of a qualified-id.
+///
+/// \param EnteringContext whether we are entering the scope of the
+/// nested-name-specifier.
+///
+/// \param ObjectType if this unqualified-id occurs within a member access
+/// expression, the type of the base object whose member is being accessed.
+///
+/// \param Result on a successful parse, contains the parsed unqualified-id.
+///
+/// \returns true if parsing fails, false otherwise.
+bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
+ TypeTy *ObjectType,
+ UnqualifiedId &Result) {
+ assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
+
+ // Consume the 'operator' keyword.
+ SourceLocation KeywordLoc = ConsumeToken();
+
+ // Determine what kind of operator name we have.
+ unsigned SymbolIdx = 0;
+ SourceLocation SymbolLocations[3];
+ OverloadedOperatorKind Op = OO_None;
+ switch (Tok.getKind()) {
+ case tok::kw_new:
+ case tok::kw_delete: {
+ bool isNew = Tok.getKind() == tok::kw_new;
+ // Consume the 'new' or 'delete'.
+ SymbolLocations[SymbolIdx++] = ConsumeToken();
+ if (Tok.is(tok::l_square)) {
+ // Consume the '['.
+ SourceLocation LBracketLoc = ConsumeBracket();
+ // Consume the ']'.
+ SourceLocation RBracketLoc = MatchRHSPunctuation(tok::r_square,
+ LBracketLoc);
+ if (RBracketLoc.isInvalid())
+ return true;
+
+ SymbolLocations[SymbolIdx++] = LBracketLoc;
+ SymbolLocations[SymbolIdx++] = RBracketLoc;
+ Op = isNew? OO_Array_New : OO_Array_Delete;
+ } else {
+ Op = isNew? OO_New : OO_Delete;
+ }
+ break;
+ }
+
+#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
+ case tok::Token: \
+ SymbolLocations[SymbolIdx++] = ConsumeToken(); \
+ Op = OO_##Name; \
+ break;
+#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly)
+#include "clang/Basic/OperatorKinds.def"
+
+ case tok::l_paren: {
+ // Consume the '('.
+ SourceLocation LParenLoc = ConsumeParen();
+ // Consume the ')'.
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren,
+ LParenLoc);
+ if (RParenLoc.isInvalid())
+ return true;
+
+ SymbolLocations[SymbolIdx++] = LParenLoc;
+ SymbolLocations[SymbolIdx++] = RParenLoc;
+ Op = OO_Call;
+ break;
+ }
+
+ case tok::l_square: {
+ // Consume the '['.
+ SourceLocation LBracketLoc = ConsumeBracket();
+ // Consume the ']'.
+ SourceLocation RBracketLoc = MatchRHSPunctuation(tok::r_square,
+ LBracketLoc);
+ if (RBracketLoc.isInvalid())
+ return true;
+
+ SymbolLocations[SymbolIdx++] = LBracketLoc;
+ SymbolLocations[SymbolIdx++] = RBracketLoc;
+ Op = OO_Subscript;
+ break;
+ }
+
+ case tok::code_completion: {
+ // Code completion for the operator name.
+ Actions.CodeCompleteOperatorName(CurScope);
+
+ // Consume the operator token.
+ ConsumeToken();
+
+ // Don't try to parse any further.
+ return true;
+ }
+
+ default:
+ break;
+ }
+
+ if (Op != OO_None) {
+ // We have parsed an operator-function-id.
+ Result.setOperatorFunctionId(KeywordLoc, Op, SymbolLocations);
+ return false;
+ }
+
+ // Parse a conversion-function-id.
+ //
+ // conversion-function-id: [C++ 12.3.2]
+ // operator conversion-type-id
+ //
+ // conversion-type-id:
+ // type-specifier-seq conversion-declarator[opt]
+ //
+ // conversion-declarator:
+ // ptr-operator conversion-declarator[opt]
+
+ // Parse the type-specifier-seq.
+ DeclSpec DS;
+ if (ParseCXXTypeSpecifierSeq(DS))
+ return true;
+
+ // Parse the conversion-declarator, which is merely a sequence of
+ // ptr-operators.
+ Declarator D(DS, Declarator::TypeNameContext);
+ ParseDeclaratorInternal(D, /*DirectDeclParser=*/0);
+
+ // Finish up the type.
+ Action::TypeResult Ty = Actions.ActOnTypeName(CurScope, D);
+ if (Ty.isInvalid())
+ return true;
+
+ // Note that this is a conversion-function-id.
+ Result.setConversionFunctionId(KeywordLoc, Ty.get(),
+ D.getSourceRange().getEnd());
+ return false;
+}
+
+/// \brief Parse a C++ unqualified-id (or a C identifier), which describes the
+/// name of an entity.
+///
+/// \code
+/// unqualified-id: [C++ expr.prim.general]
+/// identifier
+/// operator-function-id
+/// conversion-function-id
+/// [C++0x] literal-operator-id [TODO]
+/// ~ class-name
+/// template-id
+///
+/// \endcode
+///
+/// \param The nested-name-specifier that preceded this unqualified-id. If
+/// non-empty, then we are parsing the unqualified-id of a qualified-id.
+///
+/// \param EnteringContext whether we are entering the scope of the
+/// nested-name-specifier.
+///
+/// \param AllowDestructorName whether we allow parsing of a destructor name.
+///
+/// \param AllowConstructorName whether we allow parsing a constructor name.
+///
+/// \param ObjectType if this unqualified-id occurs within a member access
+/// expression, the type of the base object whose member is being accessed.
+///
+/// \param Result on a successful parse, contains the parsed unqualified-id.
+///
+/// \returns true if parsing fails, false otherwise.
+bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
+ bool AllowDestructorName,
+ bool AllowConstructorName,
+ TypeTy *ObjectType,
+ UnqualifiedId &Result) {
+ // unqualified-id:
+ // identifier
+ // template-id (when it hasn't already been annotated)
+ if (Tok.is(tok::identifier)) {
+ // Consume the identifier.
+ IdentifierInfo *Id = Tok.getIdentifierInfo();
+ SourceLocation IdLoc = ConsumeToken();
+
+ if (AllowConstructorName &&
+ Actions.isCurrentClassName(*Id, CurScope, &SS)) {
+ // We have parsed a constructor name.
+ Result.setConstructorName(Actions.getTypeName(*Id, IdLoc, CurScope,
+ &SS, false),
+ IdLoc, IdLoc);
+ } else {
+ // We have parsed an identifier.
+ Result.setIdentifier(Id, IdLoc);
+ }
+
+ // If the next token is a '<', we may have a template.
+ if (Tok.is(tok::less))
+ return ParseUnqualifiedIdTemplateId(SS, Id, IdLoc, EnteringContext,
+ ObjectType, Result);
+
+ return false;
+ }
+
+ // unqualified-id:
+ // template-id (already parsed and annotated)
+ if (Tok.is(tok::annot_template_id)) {
+ // FIXME: Could this be a constructor name???
+
+ // We have already parsed a template-id; consume the annotation token as
+ // our unqualified-id.
+ Result.setTemplateId(
+ static_cast<TemplateIdAnnotation*>(Tok.getAnnotationValue()));
+ ConsumeToken();
+ return false;
+ }
+
+ // unqualified-id:
+ // operator-function-id
+ // conversion-function-id
+ if (Tok.is(tok::kw_operator)) {
+ if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, Result))
+ return true;
+
+ // If we have an operator-function-id and the next token is a '<', we may
+ // have a
+ //
+ // template-id:
+ // operator-function-id < template-argument-list[opt] >
+ if (Result.getKind() == UnqualifiedId::IK_OperatorFunctionId &&
+ Tok.is(tok::less))
+ return ParseUnqualifiedIdTemplateId(SS, 0, SourceLocation(),
+ EnteringContext, ObjectType,
+ Result);
+
+ return false;
+ }
+
+ if ((AllowDestructorName || SS.isSet()) && Tok.is(tok::tilde)) {
+ // C++ [expr.unary.op]p10:
+ // There is an ambiguity in the unary-expression ~X(), where X is a
+ // class-name. The ambiguity is resolved in favor of treating ~ as a
+ // unary complement rather than treating ~X as referring to a destructor.
+
+ // Parse the '~'.
+ SourceLocation TildeLoc = ConsumeToken();
+
+ // Parse the class-name.
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_destructor_class_name);
+ return true;
+ }
+
+ // Parse the class-name (or template-name in a simple-template-id).
+ IdentifierInfo *ClassName = Tok.getIdentifierInfo();
+ SourceLocation ClassNameLoc = ConsumeToken();
+
+ if (Tok.is(tok::less)) {
+ Result.setDestructorName(TildeLoc, 0, ClassNameLoc);
+ return ParseUnqualifiedIdTemplateId(SS, ClassName, ClassNameLoc,
+ EnteringContext, ObjectType, Result);
+ }
+
+ // Note that this is a destructor name.
+ Action::TypeTy *Ty = Actions.getTypeName(*ClassName, ClassNameLoc,
+ CurScope, &SS);
+ if (!Ty) {
+ if (ObjectType)
+ Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type)
+ << ClassName;
+ else
+ Diag(ClassNameLoc, diag::err_destructor_class_name);
+ return true;
+ }
+
+ Result.setDestructorName(TildeLoc, Ty, ClassNameLoc);
+ return false;
+ }
+
+ Diag(Tok, diag::err_expected_unqualified_id)
+ << getLang().CPlusPlus;
+ return true;
+}
+
/// TryParseOperatorFunctionId - Attempts to parse a C++ overloaded
/// operator name (C++ [over.oper]). If successful, returns the
/// predefined identifier that corresponds to that overloaded
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 2e0cd6d0d932..b043dd99f304 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -305,51 +305,68 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
if (Tok.is(tok::l_paren))
ParseObjCPropertyAttribute(OCDS);
+ struct ObjCPropertyCallback : FieldCallback {
+ Parser &P;
+ DeclPtrTy IDecl;
+ llvm::SmallVectorImpl<DeclPtrTy> &Props;
+ ObjCDeclSpec &OCDS;
+ SourceLocation AtLoc;
+ tok::ObjCKeywordKind MethodImplKind;
+
+ ObjCPropertyCallback(Parser &P, DeclPtrTy IDecl,
+ llvm::SmallVectorImpl<DeclPtrTy> &Props,
+ ObjCDeclSpec &OCDS, SourceLocation AtLoc,
+ tok::ObjCKeywordKind MethodImplKind) :
+ P(P), IDecl(IDecl), Props(Props), OCDS(OCDS), AtLoc(AtLoc),
+ MethodImplKind(MethodImplKind) {
+ }
+
+ DeclPtrTy invoke(FieldDeclarator &FD) {
+ if (FD.D.getIdentifier() == 0) {
+ P.Diag(AtLoc, diag::err_objc_property_requires_field_name)
+ << FD.D.getSourceRange();
+ return DeclPtrTy();
+ }
+ if (FD.BitfieldSize) {
+ P.Diag(AtLoc, diag::err_objc_property_bitfield)
+ << FD.D.getSourceRange();
+ return DeclPtrTy();
+ }
+
+ // Install the property declarator into interfaceDecl.
+ IdentifierInfo *SelName =
+ OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
+
+ Selector GetterSel =
+ P.PP.getSelectorTable().getNullarySelector(SelName);
+ IdentifierInfo *SetterName = OCDS.getSetterName();
+ Selector SetterSel;
+ if (SetterName)
+ SetterSel = P.PP.getSelectorTable().getSelector(1, &SetterName);
+ else
+ SetterSel = SelectorTable::constructSetterName(P.PP.getIdentifierTable(),
+ P.PP.getSelectorTable(),
+ FD.D.getIdentifier());
+ bool isOverridingProperty = false;
+ DeclPtrTy Property =
+ P.Actions.ActOnProperty(P.CurScope, AtLoc, FD, OCDS,
+ GetterSel, SetterSel, IDecl,
+ &isOverridingProperty,
+ MethodImplKind);
+ if (!isOverridingProperty)
+ Props.push_back(Property);
+
+ return Property;
+ }
+ } Callback(*this, interfaceDecl, allProperties,
+ OCDS, AtLoc, MethodImplKind);
+
// Parse all the comma separated declarators.
DeclSpec DS;
- llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators;
- ParseStructDeclaration(DS, FieldDeclarators);
+ ParseStructDeclaration(DS, Callback);
ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list, "",
tok::at);
-
- // Convert them all to property declarations.
- for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) {
- FieldDeclarator &FD = FieldDeclarators[i];
- if (FD.D.getIdentifier() == 0) {
- Diag(AtLoc, diag::err_objc_property_requires_field_name)
- << FD.D.getSourceRange();
- continue;
- }
- if (FD.BitfieldSize) {
- Diag(AtLoc, diag::err_objc_property_bitfield)
- << FD.D.getSourceRange();
- continue;
- }
-
- // Install the property declarator into interfaceDecl.
- IdentifierInfo *SelName =
- OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
-
- Selector GetterSel =
- PP.getSelectorTable().getNullarySelector(SelName);
- IdentifierInfo *SetterName = OCDS.getSetterName();
- Selector SetterSel;
- if (SetterName)
- SetterSel = PP.getSelectorTable().getSelector(1, &SetterName);
- else
- SetterSel = SelectorTable::constructSetterName(PP.getIdentifierTable(),
- PP.getSelectorTable(),
- FD.D.getIdentifier());
- bool isOverridingProperty = false;
- DeclPtrTy Property = Actions.ActOnProperty(CurScope, AtLoc, FD, OCDS,
- GetterSel, SetterSel,
- interfaceDecl,
- &isOverridingProperty,
- MethodImplKind);
- if (!isOverridingProperty)
- allProperties.push_back(Property);
- }
break;
}
}
@@ -681,6 +698,8 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
tok::TokenKind mType,
DeclPtrTy IDecl,
tok::ObjCKeywordKind MethodImplKind) {
+ ParsingDeclRAIIObject PD(*this);
+
// Parse the return type if present.
TypeTy *ReturnType = 0;
ObjCDeclSpec DSRet;
@@ -707,10 +726,13 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
MethodAttrs = ParseAttributes();
Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
- return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
+ DeclPtrTy Result
+ = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
mType, IDecl, DSRet, ReturnType, Sel,
0, CargNames, MethodAttrs,
MethodImplKind);
+ PD.complete(Result);
+ return Result;
}
llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
@@ -783,10 +805,13 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
return DeclPtrTy();
Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(),
&KeyIdents[0]);
- return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
+ DeclPtrTy Result
+ = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
mType, IDecl, DSRet, ReturnType, Sel,
&ArgInfos[0], CargNames, MethodAttrs,
MethodImplKind, isVariadic);
+ PD.complete(Result);
+ return Result;
}
/// objc-protocol-refs:
@@ -858,7 +883,6 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
SourceLocation atLoc) {
assert(Tok.is(tok::l_brace) && "expected {");
llvm::SmallVector<DeclPtrTy, 32> AllIvarDecls;
- llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators;
ParseScope ClassScope(this, Scope::DeclScope|Scope::ClassScope);
@@ -893,21 +917,31 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
}
}
+ struct ObjCIvarCallback : FieldCallback {
+ Parser &P;
+ DeclPtrTy IDecl;
+ tok::ObjCKeywordKind visibility;
+ llvm::SmallVectorImpl<DeclPtrTy> &AllIvarDecls;
+
+ ObjCIvarCallback(Parser &P, DeclPtrTy IDecl, tok::ObjCKeywordKind V,
+ llvm::SmallVectorImpl<DeclPtrTy> &AllIvarDecls) :
+ P(P), IDecl(IDecl), visibility(V), AllIvarDecls(AllIvarDecls) {
+ }
+
+ DeclPtrTy invoke(FieldDeclarator &FD) {
+ // Install the declarator into the interface decl.
+ DeclPtrTy Field
+ = P.Actions.ActOnIvar(P.CurScope,
+ FD.D.getDeclSpec().getSourceRange().getBegin(),
+ IDecl, FD.D, FD.BitfieldSize, visibility);
+ AllIvarDecls.push_back(Field);
+ return Field;
+ }
+ } Callback(*this, interfaceDecl, visibility, AllIvarDecls);
+
// Parse all the comma separated declarators.
DeclSpec DS;
- FieldDeclarators.clear();
- ParseStructDeclaration(DS, FieldDeclarators);
-
- // Convert them all to fields.
- for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) {
- FieldDeclarator &FD = FieldDeclarators[i];
- // Install the declarator into interfaceDecl.
- DeclPtrTy Field = Actions.ActOnIvar(CurScope,
- DS.getSourceRange().getBegin(),
- interfaceDecl,
- FD.D, FD.BitfieldSize, visibility);
- AllIvarDecls.push_back(Field);
- }
+ ParseStructDeclaration(DS, Callback);
if (Tok.is(tok::semi)) {
ConsumeToken();
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 272be2f66017..7637382ac032 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -938,8 +938,7 @@ Parser::OwningStmtResult Parser::ParseForStatement() {
Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
- DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd,
- false);
+ DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd);
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
if (Tok.is(tok::semi)) { // for (int x = 4;
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 8e63fb89db31..045acd86ad0f 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -101,6 +101,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
// (and retrieves the outer template parameter list from its
// context).
bool isSpecialization = true;
+ bool LastParamListWasEmpty = false;
TemplateParameterLists ParamLists;
TemplateParameterDepthCounter Depth(TemplateParameterDepth);
do {
@@ -140,13 +141,16 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
if (!TemplateParams.empty()) {
isSpecialization = false;
++Depth;
+ } else {
+ LastParamListWasEmpty = true;
}
} while (Tok.is(tok::kw_export) || Tok.is(tok::kw_template));
// Parse the actual template declaration.
return ParseSingleDeclarationAfterTemplate(Context,
ParsedTemplateInfo(&ParamLists,
- isSpecialization),
+ isSpecialization,
+ LastParamListWasEmpty),
DeclEnd, AS);
}
@@ -186,16 +190,18 @@ Parser::ParseSingleDeclarationAfterTemplate(
}
// Parse the declaration specifiers.
- DeclSpec DS;
+ ParsingDeclSpec DS(*this);
ParseDeclarationSpecifiers(DS, TemplateInfo, AS);
if (Tok.is(tok::semi)) {
DeclEnd = ConsumeToken();
- return Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ DeclPtrTy Decl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ DS.complete(Decl);
+ return Decl;
}
// Parse the declarator.
- Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context);
+ ParsingDeclarator DeclaratorInfo(*this, DS, (Declarator::TheContext)Context);
ParseDeclarator(DeclaratorInfo);
// Error parsing the declarator?
if (!DeclaratorInfo.hasName()) {
@@ -221,6 +227,7 @@ Parser::ParseSingleDeclarationAfterTemplate(
// Eat the semi colon after the declaration.
ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration);
+ DS.complete(ThisDecl);
return ThisDecl;
}
@@ -668,22 +675,23 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
///
bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
const CXXScopeSpec *SS,
+ UnqualifiedId &TemplateName,
SourceLocation TemplateKWLoc,
bool AllowTypeAnnotation) {
assert(getLang().CPlusPlus && "Can only annotate template-ids in C++");
- assert(Template && Tok.is(tok::identifier) && NextToken().is(tok::less) &&
+ assert(Template && Tok.is(tok::less) &&
"Parser isn't at the beginning of a template-id");
// Consume the template-name.
- IdentifierInfo *Name = Tok.getIdentifierInfo();
- SourceLocation TemplateNameLoc = ConsumeToken();
+ SourceLocation TemplateNameLoc = TemplateName.getSourceRange().getBegin();
// Parse the enclosed template argument list.
SourceLocation LAngleLoc, RAngleLoc;
TemplateArgList TemplateArgs;
TemplateArgIsTypeList TemplateArgIsType;
TemplateArgLocationList TemplateArgLocations;
- bool Invalid = ParseTemplateIdAfterTemplateName(Template, TemplateNameLoc,
+ bool Invalid = ParseTemplateIdAfterTemplateName(Template,
+ TemplateNameLoc,
SS, false, LAngleLoc,
TemplateArgs,
TemplateArgIsType,
@@ -732,7 +740,13 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
TemplateIdAnnotation *TemplateId
= TemplateIdAnnotation::Allocate(TemplateArgs.size());
TemplateId->TemplateNameLoc = TemplateNameLoc;
- TemplateId->Name = Name;
+ if (TemplateName.getKind() == UnqualifiedId::IK_Identifier) {
+ TemplateId->Name = TemplateName.Identifier;
+ TemplateId->Operator = OO_None;
+ } else {
+ TemplateId->Name = 0;
+ TemplateId->Operator = TemplateName.OperatorFunctionId.Operator;
+ }
TemplateId->Template = Template.getAs<void*>();
TemplateId->Kind = TNK;
TemplateId->LAngleLoc = LAngleLoc;
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index bc737e9f0c80..335a6cf36254 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -526,7 +526,7 @@ bool Parser::isStartOfFunctionDefinition() {
Parser::DeclGroupPtrTy
Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) {
// Parse the common declaration-specifiers piece.
- DeclSpec DS;
+ ParsingDeclSpec DS(*this);
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS);
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
@@ -534,6 +534,7 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) {
if (Tok.is(tok::semi)) {
ConsumeToken();
DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ DS.complete(TheDecl);
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
@@ -548,6 +549,9 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) {
SkipUntil(tok::semi); // FIXME: better skip?
return DeclGroupPtrTy();
}
+
+ DS.abort();
+
const char *PrevSpec = 0;
unsigned DiagID;
if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec, DiagID))
@@ -567,58 +571,12 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) {
if (Tok.is(tok::string_literal) && getLang().CPlusPlus &&
DS.getStorageClassSpec() == DeclSpec::SCS_extern &&
DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) {
+ DS.abort();
DeclPtrTy TheDecl = ParseLinkage(Declarator::FileContext);
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
- // Parse the first declarator.
- Declarator DeclaratorInfo(DS, Declarator::FileContext);
- ParseDeclarator(DeclaratorInfo);
- // Error parsing the declarator?
- if (!DeclaratorInfo.hasName()) {
- // If so, skip until the semi-colon or a }.
- SkipUntil(tok::r_brace, true, true);
- if (Tok.is(tok::semi))
- ConsumeToken();
- return DeclGroupPtrTy();
- }
-
- // If we have a declaration or declarator list, handle it.
- if (isDeclarationAfterDeclarator()) {
- // Parse the init-declarator-list for a normal declaration.
- DeclGroupPtrTy DG =
- ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo);
- // Eat the semi colon after the declaration.
- ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration);
- return DG;
- }
-
- if (DeclaratorInfo.isFunctionDeclarator() &&
- isStartOfFunctionDefinition()) {
- if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
- Diag(Tok, diag::err_function_declared_typedef);
-
- if (Tok.is(tok::l_brace)) {
- // This recovery skips the entire function body. It would be nice
- // to simply call ParseFunctionDefinition() below, however Sema
- // assumes the declarator represents a function, not a typedef.
- ConsumeBrace();
- SkipUntil(tok::r_brace, true);
- } else {
- SkipUntil(tok::semi);
- }
- return DeclGroupPtrTy();
- }
- DeclPtrTy TheDecl = ParseFunctionDefinition(DeclaratorInfo);
- return Actions.ConvertDeclToDeclGroup(TheDecl);
- }
-
- if (DeclaratorInfo.isFunctionDeclarator())
- Diag(Tok, diag::err_expected_fn_body);
- else
- Diag(Tok, diag::err_invalid_token_after_toplevel_declarator);
- SkipUntil(tok::semi);
- return DeclGroupPtrTy();
+ return ParseDeclGroup(DS, Declarator::FileContext, true);
}
/// ParseFunctionDefinition - We parsed and verified that the specified
@@ -635,7 +593,7 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) {
/// [C++] function-definition: [C++ 8.4]
/// decl-specifier-seq[opt] declarator function-try-block
///
-Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D,
+Parser::DeclPtrTy Parser::ParseFunctionDefinition(ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo) {
const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0);
assert(FnTypeInfo.Kind == DeclaratorChunk::Function &&
@@ -687,6 +645,13 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D,
D)
: Actions.ActOnStartOfFunctionDef(CurScope, D);
+ // Break out of the ParsingDeclarator context before we parse the body.
+ D.complete(Res);
+
+ // Break out of the ParsingDeclSpec context, too. This const_cast is
+ // safe because we're always the sole owner.
+ D.getMutableDeclSpec().abort();
+
if (Tok.is(tok::kw_try))
return ParseFunctionTryBlock(Res);
@@ -981,17 +946,21 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
// If this is a template-id, annotate with a template-id or type token.
if (NextToken().is(tok::less)) {
TemplateTy Template;
+ UnqualifiedId TemplateName;
+ TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
if (TemplateNameKind TNK
- = Actions.isTemplateName(CurScope, *Tok.getIdentifierInfo(),
- Tok.getLocation(), &SS,
+ = Actions.isTemplateName(CurScope, SS, TemplateName,
/*ObjectType=*/0, EnteringContext,
- Template))
- if (AnnotateTemplateIdToken(Template, TNK, &SS)) {
+ Template)) {
+ // Consume the identifier.
+ ConsumeToken();
+ if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName)) {
// If an unrecoverable error occurred, we need to return true here,
// because the token stream is in a damaged state. We may not return
// a valid identifier.
return Tok.isNot(tok::identifier);
}
+ }
}
// The current token, which is either an identifier or a
@@ -1065,3 +1034,10 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
PP.AnnotateCachedTokens(Tok);
return true;
}
+
+// Anchor the Parser::FieldCallback vtable to this translation unit.
+// We use a spurious method instead of the destructor because
+// destroying FieldCallbacks can actually be slightly
+// performance-sensitive.
+void Parser::FieldCallback::_anchor() {
+}