summaryrefslogtreecommitdiffstats
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/CMakeLists.txt21
-rw-r--r--lib/Parse/DeclSpec.cpp395
-rw-r--r--lib/Parse/ExtensionRAIIObject.h40
-rw-r--r--lib/Parse/Makefile22
-rw-r--r--lib/Parse/MinimalAction.cpp225
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp271
-rw-r--r--lib/Parse/ParseDecl.cpp2707
-rw-r--r--lib/Parse/ParseDeclCXX.cpp1292
-rw-r--r--lib/Parse/ParseExpr.cpp1514
-rw-r--r--lib/Parse/ParseExprCXX.cpp1166
-rw-r--r--lib/Parse/ParseInit.cpp308
-rw-r--r--lib/Parse/ParseObjc.cpp1708
-rw-r--r--lib/Parse/ParsePragma.cpp182
-rw-r--r--lib/Parse/ParsePragma.h44
-rw-r--r--lib/Parse/ParseStmt.cpp1435
-rw-r--r--lib/Parse/ParseTemplate.cpp812
-rw-r--r--lib/Parse/ParseTentative.cpp920
-rw-r--r--lib/Parse/Parser.cpp996
19 files changed, 14203 insertions, 0 deletions
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp
new file mode 100644
index 0000000..0170a06
--- /dev/null
+++ b/lib/Parse/AttributeList.cpp
@@ -0,0 +1,145 @@
+//===--- AttributeList.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the AttributeList class implementation
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/AttributeList.h"
+#include "clang/Basic/IdentifierTable.h"
+using namespace clang;
+
+AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc,
+ IdentifierInfo *pName, SourceLocation pLoc,
+ ActionBase::ExprTy **ExprList, unsigned numArgs,
+ AttributeList *n)
+ : AttrName(aName), AttrLoc(aLoc), ParmName(pName), ParmLoc(pLoc),
+ NumArgs(numArgs), Next(n) {
+
+ if (numArgs == 0)
+ Args = 0;
+ else {
+ Args = new ActionBase::ExprTy*[numArgs];
+ memcpy(Args, ExprList, numArgs*sizeof(Args[0]));
+ }
+}
+
+AttributeList::~AttributeList() {
+ if (Args) {
+ // FIXME: before we delete the vector, we need to make sure the Expr's
+ // have been deleted. Since ActionBase::ExprTy is "void", we are dependent
+ // on the actions module for actually freeing the memory. The specific
+ // hooks are ActOnDeclarator, ActOnTypeName, ActOnParamDeclaratorType,
+ // ParseField, ParseTag. Once these routines have freed the expression,
+ // they should zero out the Args slot (to indicate the memory has been
+ // freed). If any element of the vector is non-null, we should assert.
+ delete [] Args;
+ }
+ delete Next;
+}
+
+AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
+ const char *Str = Name->getName();
+ unsigned Len = Name->getLength();
+
+ // Normalize the attribute name, __foo__ becomes foo.
+ if (Len > 4 && Str[0] == '_' && Str[1] == '_' &&
+ Str[Len - 2] == '_' && Str[Len - 1] == '_') {
+ Str += 2;
+ Len -= 4;
+ }
+
+ // FIXME: Hand generating this is neither smart nor efficient.
+ switch (Len) {
+ 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 IgnoredAttribute; // FIXME: noalias.
+ 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;
+ 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 22:
+ if (!memcmp(Str, "no_instrument_function", 22))
+ return AT_no_instrument_function;
+ break;
+ }
+ return UnknownAttribute;
+}
diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt
new file mode 100644
index 0000000..8fb7cd2
--- /dev/null
+++ b/lib/Parse/CMakeLists.txt
@@ -0,0 +1,21 @@
+set(LLVM_NO_RTTI 1)
+
+add_clang_library(clangParse
+ AttributeList.cpp
+ DeclSpec.cpp
+ MinimalAction.cpp
+ ParseCXXInlineMethods.cpp
+ ParseDecl.cpp
+ ParseDeclCXX.cpp
+ ParseExpr.cpp
+ ParseExprCXX.cpp
+ ParseInit.cpp
+ ParseObjc.cpp
+ ParsePragma.cpp
+ Parser.cpp
+ ParseStmt.cpp
+ ParseTentative.cpp
+ ParseTemplate.cpp
+ )
+
+add_dependencies(clangParse ClangDiagnosticParse)
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
new file mode 100644
index 0000000..d8c6986
--- /dev/null
+++ b/lib/Parse/DeclSpec.cpp
@@ -0,0 +1,395 @@
+//===--- SemaDeclSpec.cpp - Declaration Specifier Semantic Analysis -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for declaration specifiers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/STLExtras.h"
+#include <cstring>
+using namespace clang;
+
+
+static DiagnosticBuilder Diag(Diagnostic &D, SourceLocation Loc,
+ SourceManager &SrcMgr, unsigned DiagID) {
+ return D.Report(FullSourceLoc(Loc, SrcMgr), DiagID);
+}
+
+/// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
+/// "TheDeclarator" is the declarator that this will be added to.
+DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
+ SourceLocation EllipsisLoc,
+ ParamInfo *ArgInfo,
+ unsigned NumArgs,
+ unsigned TypeQuals,
+ bool hasExceptionSpec,
+ SourceLocation ThrowLoc,
+ bool hasAnyExceptionSpec,
+ ActionBase::TypeTy **Exceptions,
+ SourceRange *ExceptionRanges,
+ unsigned NumExceptions,
+ SourceLocation Loc,
+ Declarator &TheDeclarator) {
+ DeclaratorChunk I;
+ I.Kind = Function;
+ I.Loc = Loc;
+ I.Fun.hasPrototype = hasProto;
+ I.Fun.isVariadic = isVariadic;
+ I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding();
+ I.Fun.DeleteArgInfo = false;
+ I.Fun.TypeQuals = TypeQuals;
+ I.Fun.NumArgs = NumArgs;
+ I.Fun.ArgInfo = 0;
+ I.Fun.hasExceptionSpec = hasExceptionSpec;
+ I.Fun.ThrowLoc = ThrowLoc.getRawEncoding();
+ I.Fun.hasAnyExceptionSpec = hasAnyExceptionSpec;
+ I.Fun.NumExceptions = NumExceptions;
+ I.Fun.Exceptions = 0;
+
+ // new[] an argument array if needed.
+ if (NumArgs) {
+ // If the 'InlineParams' in Declarator is unused and big enough, put our
+ // parameter list there (in an effort to avoid new/delete traffic). If it
+ // is already used (consider a function returning a function pointer) or too
+ // small (function taking too many arguments), go to the heap.
+ if (!TheDeclarator.InlineParamsUsed &&
+ NumArgs <= llvm::array_lengthof(TheDeclarator.InlineParams)) {
+ I.Fun.ArgInfo = TheDeclarator.InlineParams;
+ I.Fun.DeleteArgInfo = false;
+ TheDeclarator.InlineParamsUsed = true;
+ } else {
+ I.Fun.ArgInfo = new DeclaratorChunk::ParamInfo[NumArgs];
+ I.Fun.DeleteArgInfo = true;
+ }
+ memcpy(I.Fun.ArgInfo, ArgInfo, sizeof(ArgInfo[0])*NumArgs);
+ }
+ // new[] an exception array if needed
+ if (NumExceptions) {
+ I.Fun.Exceptions = new DeclaratorChunk::TypeAndRange[NumExceptions];
+ for (unsigned i = 0; i != NumExceptions; ++i) {
+ I.Fun.Exceptions[i].Ty = Exceptions[i];
+ I.Fun.Exceptions[i].Range = ExceptionRanges[i];
+ }
+ }
+ return I;
+}
+
+/// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this
+/// declaration specifier includes.
+///
+unsigned DeclSpec::getParsedSpecifiers() const {
+ unsigned Res = 0;
+ if (StorageClassSpec != SCS_unspecified ||
+ SCS_thread_specified)
+ Res |= PQ_StorageClassSpecifier;
+
+ if (TypeQualifiers != TQ_unspecified)
+ Res |= PQ_TypeQualifier;
+
+ if (hasTypeSpecifier())
+ Res |= PQ_TypeSpecifier;
+
+ if (FS_inline_specified || FS_virtual_specified || FS_explicit_specified)
+ Res |= PQ_FunctionSpecifier;
+ return Res;
+}
+
+const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) {
+ switch (S) {
+ default: assert(0 && "Unknown typespec!");
+ case DeclSpec::SCS_unspecified: return "unspecified";
+ case DeclSpec::SCS_typedef: return "typedef";
+ case DeclSpec::SCS_extern: return "extern";
+ case DeclSpec::SCS_static: return "static";
+ case DeclSpec::SCS_auto: return "auto";
+ case DeclSpec::SCS_register: return "register";
+ case DeclSpec::SCS_private_extern: return "__private_extern__";
+ case DeclSpec::SCS_mutable: return "mutable";
+ }
+}
+
+bool DeclSpec::BadSpecifier(SCS S, const char *&PrevSpec) {
+ PrevSpec = getSpecifierName(S);
+ return true;
+}
+
+bool DeclSpec::BadSpecifier(TSW W, const char *&PrevSpec) {
+ switch (W) {
+ case TSW_unspecified: PrevSpec = "unspecified"; break;
+ case TSW_short: PrevSpec = "short"; break;
+ case TSW_long: PrevSpec = "long"; break;
+ case TSW_longlong: PrevSpec = "long long"; break;
+ }
+ return true;
+}
+
+bool DeclSpec::BadSpecifier(TSC C, const char *&PrevSpec) {
+ switch (C) {
+ case TSC_unspecified: PrevSpec = "unspecified"; break;
+ case TSC_imaginary: PrevSpec = "imaginary"; break;
+ case TSC_complex: PrevSpec = "complex"; break;
+ }
+ return true;
+}
+
+
+bool DeclSpec::BadSpecifier(TSS S, const char *&PrevSpec) {
+ switch (S) {
+ case TSS_unspecified: PrevSpec = "unspecified"; break;
+ case TSS_signed: PrevSpec = "signed"; break;
+ case TSS_unsigned: PrevSpec = "unsigned"; break;
+ }
+ return true;
+}
+
+const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
+ switch (T) {
+ default: assert(0 && "Unknown typespec!");
+ case DeclSpec::TST_unspecified: return "unspecified";
+ case DeclSpec::TST_void: return "void";
+ case DeclSpec::TST_char: return "char";
+ case DeclSpec::TST_wchar: return "wchar_t";
+ case DeclSpec::TST_int: return "int";
+ case DeclSpec::TST_float: return "float";
+ case DeclSpec::TST_double: return "double";
+ case DeclSpec::TST_bool: return "_Bool";
+ case DeclSpec::TST_decimal32: return "_Decimal32";
+ case DeclSpec::TST_decimal64: return "_Decimal64";
+ case DeclSpec::TST_decimal128: return "_Decimal128";
+ case DeclSpec::TST_enum: return "enum";
+ case DeclSpec::TST_class: return "class";
+ case DeclSpec::TST_union: return "union";
+ case DeclSpec::TST_struct: return "struct";
+ case DeclSpec::TST_typename: return "type-name";
+ case DeclSpec::TST_typeofType:
+ case DeclSpec::TST_typeofExpr: return "typeof";
+ }
+}
+
+bool DeclSpec::BadSpecifier(TST T, const char *&PrevSpec) {
+ PrevSpec = getSpecifierName(T);
+ return true;
+}
+
+bool DeclSpec::BadSpecifier(TQ T, const char *&PrevSpec) {
+ switch (T) {
+ case DeclSpec::TQ_unspecified: PrevSpec = "unspecified"; break;
+ case DeclSpec::TQ_const: PrevSpec = "const"; break;
+ case DeclSpec::TQ_restrict: PrevSpec = "restrict"; break;
+ case DeclSpec::TQ_volatile: PrevSpec = "volatile"; break;
+ }
+ return true;
+}
+
+bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc,
+ const char *&PrevSpec) {
+ if (StorageClassSpec != SCS_unspecified)
+ return BadSpecifier((SCS)StorageClassSpec, PrevSpec);
+ StorageClassSpec = S;
+ StorageClassSpecLoc = Loc;
+ assert((unsigned)S == StorageClassSpec && "SCS constants overflow bitfield");
+ return false;
+}
+
+bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc,
+ const char *&PrevSpec) {
+ if (SCS_thread_specified) {
+ PrevSpec = "__thread";
+ return true;
+ }
+ SCS_thread_specified = true;
+ SCS_threadLoc = Loc;
+ return false;
+}
+
+
+/// These methods set the specified attribute of the DeclSpec, but return true
+/// and ignore the request if invalid (e.g. "extern" then "auto" is
+/// specified).
+bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc,
+ const char *&PrevSpec) {
+ if (TypeSpecWidth != TSW_unspecified &&
+ // Allow turning long -> long long.
+ (W != TSW_longlong || TypeSpecWidth != TSW_long))
+ return BadSpecifier((TSW)TypeSpecWidth, PrevSpec);
+ TypeSpecWidth = W;
+ TSWLoc = Loc;
+ return false;
+}
+
+bool DeclSpec::SetTypeSpecComplex(TSC C, SourceLocation Loc,
+ const char *&PrevSpec) {
+ if (TypeSpecComplex != TSC_unspecified)
+ return BadSpecifier((TSC)TypeSpecComplex, PrevSpec);
+ TypeSpecComplex = C;
+ TSCLoc = Loc;
+ return false;
+}
+
+bool DeclSpec::SetTypeSpecSign(TSS S, SourceLocation Loc,
+ const char *&PrevSpec) {
+ if (TypeSpecSign != TSS_unspecified)
+ return BadSpecifier((TSS)TypeSpecSign, PrevSpec);
+ TypeSpecSign = S;
+ TSSLoc = Loc;
+ return false;
+}
+
+bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
+ const char *&PrevSpec, void *Rep,
+ bool Owned) {
+ if (TypeSpecType != TST_unspecified)
+ return BadSpecifier((TST)TypeSpecType, PrevSpec);
+ TypeSpecType = T;
+ TypeRep = Rep;
+ TSTLoc = Loc;
+ TypeSpecOwned = Owned;
+ return false;
+}
+
+bool DeclSpec::SetTypeSpecError() {
+ TypeSpecType = TST_error;
+ TypeRep = 0;
+ TSTLoc = SourceLocation();
+ return false;
+}
+
+bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
+ const LangOptions &Lang) {
+ // Duplicates turn into warnings pre-C99.
+ if ((TypeQualifiers & T) && !Lang.C99)
+ return BadSpecifier(T, PrevSpec);
+ TypeQualifiers |= T;
+
+ switch (T) {
+ default: assert(0 && "Unknown type qualifier!");
+ case TQ_const: TQ_constLoc = Loc; break;
+ case TQ_restrict: TQ_restrictLoc = Loc; break;
+ case TQ_volatile: TQ_volatileLoc = Loc; break;
+ }
+ return false;
+}
+
+bool DeclSpec::SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec){
+ // 'inline inline' is ok.
+ FS_inline_specified = true;
+ FS_inlineLoc = Loc;
+ return false;
+}
+
+bool DeclSpec::SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec){
+ // 'virtual virtual' is ok.
+ FS_virtual_specified = true;
+ FS_virtualLoc = Loc;
+ return false;
+}
+
+bool DeclSpec::SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec){
+ // 'explicit explicit' is ok.
+ FS_explicit_specified = true;
+ FS_explicitLoc = Loc;
+ return false;
+}
+
+bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec) {
+ if (Friend_specified) {
+ PrevSpec = "friend";
+ return true;
+ }
+
+ Friend_specified = true;
+ FriendLoc = Loc;
+ return false;
+}
+
+/// Finish - This does final analysis of the declspec, rejecting things like
+/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or
+/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method,
+/// DeclSpec is guaranteed self-consistent, even if an error occurred.
+void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) {
+ // Check the type specifier components first.
+ SourceManager &SrcMgr = PP.getSourceManager();
+
+ // signed/unsigned are only valid with int/char/wchar_t.
+ if (TypeSpecSign != TSS_unspecified) {
+ if (TypeSpecType == TST_unspecified)
+ TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int.
+ else if (TypeSpecType != TST_int &&
+ TypeSpecType != TST_char && TypeSpecType != TST_wchar) {
+ Diag(D, TSSLoc, SrcMgr, diag::err_invalid_sign_spec)
+ << getSpecifierName((TST)TypeSpecType);
+ // signed double -> double.
+ TypeSpecSign = TSS_unspecified;
+ }
+ }
+
+ // Validate the width of the type.
+ switch (TypeSpecWidth) {
+ case TSW_unspecified: break;
+ case TSW_short: // short int
+ case TSW_longlong: // long long int
+ if (TypeSpecType == TST_unspecified)
+ TypeSpecType = TST_int; // short -> short int, long long -> long long int.
+ else if (TypeSpecType != TST_int) {
+ Diag(D, TSWLoc, SrcMgr,
+ TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec
+ : diag::err_invalid_longlong_spec)
+ << getSpecifierName((TST)TypeSpecType);
+ TypeSpecType = TST_int;
+ }
+ break;
+ case TSW_long: // long double, long int
+ if (TypeSpecType == TST_unspecified)
+ TypeSpecType = TST_int; // long -> long int.
+ else if (TypeSpecType != TST_int && TypeSpecType != TST_double) {
+ Diag(D, TSWLoc, SrcMgr, diag::err_invalid_long_spec)
+ << getSpecifierName((TST)TypeSpecType);
+ TypeSpecType = TST_int;
+ }
+ break;
+ }
+
+ // TODO: if the implementation does not implement _Complex or _Imaginary,
+ // disallow their use. Need information about the backend.
+ if (TypeSpecComplex != TSC_unspecified) {
+ if (TypeSpecType == TST_unspecified) {
+ Diag(D, TSCLoc, SrcMgr, diag::ext_plain_complex)
+ << CodeModificationHint::CreateInsertion(
+ PP.getLocForEndOfToken(getTypeSpecComplexLoc()),
+ " double");
+ TypeSpecType = TST_double; // _Complex -> _Complex double.
+ } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) {
+ // Note that this intentionally doesn't include _Complex _Bool.
+ Diag(D, TSTLoc, SrcMgr, diag::ext_integer_complex);
+ } else if (TypeSpecType != TST_float && TypeSpecType != TST_double) {
+ Diag(D, TSCLoc, SrcMgr, diag::err_invalid_complex_spec)
+ << getSpecifierName((TST)TypeSpecType);
+ TypeSpecComplex = TSC_unspecified;
+ }
+ }
+
+ // Okay, now we can infer the real type.
+
+ // TODO: return "auto function" and other bad things based on the real type.
+
+ // 'data definition has no type or storage class'?
+}
+
+bool DeclSpec::isMissingDeclaratorOk() {
+ TST tst = getTypeSpecType();
+ return (tst == TST_union
+ || tst == TST_struct
+ || tst == TST_class
+ || tst == TST_enum
+ ) && getTypeRep() != 0 && StorageClassSpec != DeclSpec::SCS_typedef;
+}
diff --git a/lib/Parse/ExtensionRAIIObject.h b/lib/Parse/ExtensionRAIIObject.h
new file mode 100644
index 0000000..2b2bd3b
--- /dev/null
+++ b/lib/Parse/ExtensionRAIIObject.h
@@ -0,0 +1,40 @@
+//===--- ExtensionRAIIObject.h - Use RAII for __extension__ -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines and implements the ExtensionRAIIObject class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PARSE_EXTENSION_RAII_OBJECT_H
+#define LLVM_CLANG_PARSE_EXTENSION_RAII_OBJECT_H
+
+#include "clang/Parse/ParseDiagnostic.h"
+
+namespace clang {
+
+ /// ExtensionRAIIObject - This saves the state of extension warnings when
+ /// constructed and disables them. When destructed, it restores them back to
+ /// the way they used to be. This is used to handle __extension__ in the
+ /// parser.
+ class ExtensionRAIIObject {
+ void operator=(const ExtensionRAIIObject &); // DO NOT IMPLEMENT
+ ExtensionRAIIObject(const ExtensionRAIIObject&); // DO NOT IMPLEMENT
+ Diagnostic &Diags;
+ public:
+ ExtensionRAIIObject(Diagnostic &diags) : Diags(diags) {
+ Diags.IncrementAllExtensionsSilenced();
+ }
+
+ ~ExtensionRAIIObject() {
+ Diags.DecrementAllExtensionsSilenced();
+ }
+ };
+}
+
+#endif
diff --git a/lib/Parse/Makefile b/lib/Parse/Makefile
new file mode 100644
index 0000000..5d69029
--- /dev/null
+++ b/lib/Parse/Makefile
@@ -0,0 +1,22 @@
+##===- clang/lib/Parse/Makefile ----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# This implements the Parser library for the C-Language front-end.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../../..
+LIBRARYNAME := clangParse
+BUILD_ARCHIVE = 1
+CXXFLAGS = -fno-rtti
+
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+
+include $(LEVEL)/Makefile.common
+
diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp
new file mode 100644
index 0000000..b018e36
--- /dev/null
+++ b/lib/Parse/MinimalAction.cpp
@@ -0,0 +1,225 @@
+//===--- MinimalAction.cpp - Implement the MinimalAction class ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the MinimalAction interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/RecyclingAllocator.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+/// Out-of-line virtual destructor to provide home for ActionBase class.
+ActionBase::~ActionBase() {}
+
+/// Out-of-line virtual destructor to provide home for Action class.
+Action::~Action() {}
+
+// Defined out-of-line here because of dependecy on AttributeList
+Action::DeclPtrTy Action::ActOnUsingDirective(Scope *CurScope,
+ SourceLocation UsingLoc,
+ SourceLocation NamespcLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ IdentifierInfo *NamespcName,
+ AttributeList *AttrList) {
+
+ // FIXME: Parser seems to assume that Action::ActOn* takes ownership over
+ // passed AttributeList, however other actions don't free it, is it
+ // temporary state or bug?
+ delete AttrList;
+ return DeclPtrTy();
+}
+
+
+void PrettyStackTraceActionsDecl::print(llvm::raw_ostream &OS) const {
+ if (Loc.isValid()) {
+ Loc.print(OS, SM);
+ OS << ": ";
+ }
+ OS << Message;
+
+ std::string Name = Actions.getDeclName(TheDecl);
+ if (!Name.empty())
+ OS << " '" << Name << '\'';
+
+ OS << '\n';
+}
+
+/// TypeNameInfo - A link exists here for each scope that an identifier is
+/// defined.
+namespace {
+ struct TypeNameInfo {
+ TypeNameInfo *Prev;
+ bool isTypeName;
+
+ TypeNameInfo(bool istypename, TypeNameInfo *prev) {
+ isTypeName = istypename;
+ Prev = prev;
+ }
+ };
+
+ struct TypeNameInfoTable {
+ llvm::RecyclingAllocator<llvm::BumpPtrAllocator, TypeNameInfo> Allocator;
+
+ void AddEntry(bool isTypename, IdentifierInfo *II) {
+ TypeNameInfo *TI = Allocator.Allocate<TypeNameInfo>();
+ new (TI) TypeNameInfo(isTypename, II->getFETokenInfo<TypeNameInfo>());
+ II->setFETokenInfo(TI);
+ }
+
+ void DeleteEntry(TypeNameInfo *Entry) {
+ Entry->~TypeNameInfo();
+ Allocator.Deallocate(Entry);
+ }
+ };
+}
+
+static TypeNameInfoTable *getTable(void *TP) {
+ return static_cast<TypeNameInfoTable*>(TP);
+}
+
+MinimalAction::MinimalAction(Preprocessor &pp)
+ : Idents(pp.getIdentifierTable()), PP(pp) {
+ TypeNameInfoTablePtr = new TypeNameInfoTable();
+}
+
+MinimalAction::~MinimalAction() {
+ delete getTable(TypeNameInfoTablePtr);
+}
+
+void MinimalAction::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
+ TUScope = S;
+
+ TypeNameInfoTable &TNIT = *getTable(TypeNameInfoTablePtr);
+
+ if (PP.getTargetInfo().getPointerWidth(0) >= 64) {
+ // Install [u]int128_t for 64-bit targets.
+ TNIT.AddEntry(true, &Idents.get("__int128_t"));
+ TNIT.AddEntry(true, &Idents.get("__uint128_t"));
+ }
+
+ if (PP.getLangOptions().ObjC1) {
+ // Recognize the ObjC built-in type identifiers as types.
+ TNIT.AddEntry(true, &Idents.get("id"));
+ TNIT.AddEntry(true, &Idents.get("SEL"));
+ TNIT.AddEntry(true, &Idents.get("Class"));
+ TNIT.AddEntry(true, &Idents.get("Protocol"));
+ }
+}
+
+/// isTypeName - This looks at the IdentifierInfo::FETokenInfo field to
+/// determine whether the name is a type name (objc class name or typedef) or
+/// not in this scope.
+///
+/// FIXME: Use the passed CXXScopeSpec for accurate C++ type checking.
+Action::TypeTy *
+MinimalAction::getTypeName(IdentifierInfo &II, SourceLocation Loc,
+ Scope *S, const CXXScopeSpec *SS) {
+ if (TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>())
+ if (TI->isTypeName)
+ return TI;
+ return 0;
+}
+
+/// isCurrentClassName - Always returns false, because MinimalAction
+/// does not support C++ classes with constructors.
+bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *,
+ const CXXScopeSpec *) {
+ return false;
+}
+
+TemplateNameKind
+MinimalAction::isTemplateName(const IdentifierInfo &II, Scope *S,
+ TemplateTy &TemplateDecl,
+ const CXXScopeSpec *SS) {
+ return TNK_Non_template;
+}
+
+/// ActOnDeclarator - If this is a typedef declarator, we modify the
+/// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is
+/// popped.
+Action::DeclPtrTy
+MinimalAction::ActOnDeclarator(Scope *S, Declarator &D) {
+ IdentifierInfo *II = D.getIdentifier();
+
+ // If there is no identifier associated with this declarator, bail out.
+ if (II == 0) return DeclPtrTy();
+
+ TypeNameInfo *weCurrentlyHaveTypeInfo = II->getFETokenInfo<TypeNameInfo>();
+ bool isTypeName =
+ D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef;
+
+ // this check avoids creating TypeNameInfo objects for the common case.
+ // It does need to handle the uncommon case of shadowing a typedef name with a
+ // non-typedef name. e.g. { typedef int a; a xx; { int a; } }
+ if (weCurrentlyHaveTypeInfo || isTypeName) {
+ // Allocate and add the 'TypeNameInfo' "decl".
+ getTable(TypeNameInfoTablePtr)->AddEntry(isTypeName, II);
+
+ // Remember that this needs to be removed when the scope is popped.
+ S->AddDecl(DeclPtrTy::make(II));
+ }
+ return DeclPtrTy();
+}
+
+Action::DeclPtrTy
+MinimalAction::ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassLoc,
+ IdentifierInfo *SuperName,
+ SourceLocation SuperLoc,
+ const DeclPtrTy *ProtoRefs,
+ unsigned NumProtocols,
+ SourceLocation EndProtoLoc,
+ AttributeList *AttrList) {
+ // Allocate and add the 'TypeNameInfo' "decl".
+ getTable(TypeNameInfoTablePtr)->AddEntry(true, ClassName);
+ return DeclPtrTy();
+}
+
+/// ActOnForwardClassDeclaration -
+/// Scope will always be top level file scope.
+Action::DeclPtrTy
+MinimalAction::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
+ IdentifierInfo **IdentList, unsigned NumElts) {
+ for (unsigned i = 0; i != NumElts; ++i) {
+ // Allocate and add the 'TypeNameInfo' "decl".
+ getTable(TypeNameInfoTablePtr)->AddEntry(true, IdentList[i]);
+
+ // Remember that this needs to be removed when the scope is popped.
+ TUScope->AddDecl(DeclPtrTy::make(IdentList[i]));
+ }
+ return DeclPtrTy();
+}
+
+/// ActOnPopScope - When a scope is popped, if any typedefs are now
+/// out-of-scope, they are removed from the IdentifierInfo::FETokenInfo field.
+void MinimalAction::ActOnPopScope(SourceLocation Loc, Scope *S) {
+ TypeNameInfoTable &Table = *getTable(TypeNameInfoTablePtr);
+
+ for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end();
+ I != E; ++I) {
+ IdentifierInfo &II = *(*I).getAs<IdentifierInfo>();
+ TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>();
+ assert(TI && "This decl didn't get pushed??");
+
+ if (TI) {
+ TypeNameInfo *Next = TI->Prev;
+ Table.DeleteEntry(TI);
+
+ II.setFETokenInfo(Next);
+ }
+ }
+}
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
new file mode 100644
index 0000000..af6fab7
--- /dev/null
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -0,0 +1,271 @@
+//===--- ParseCXXInlineMethods.cpp - C++ class inline methods parsing------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements parsing for C++ class inline methods.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+using namespace clang;
+
+/// ParseCXXInlineMethodDef - We parsed and verified that the specified
+/// Declarator is a well formed C++ inline method definition. Now lex its body
+/// and store its tokens for parsing after the C++ class is complete.
+Parser::DeclPtrTy
+Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) {
+ assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
+ "This isn't a function declarator!");
+ assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) &&
+ "Current token not a '{', ':' or 'try'!");
+
+ DeclPtrTy FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, 0, 0);
+
+ // Consume the tokens and store them for later parsing.
+
+ getCurrentClass().MethodDefs.push_back(LexedMethod(FnD));
+ CachedTokens &Toks = getCurrentClass().MethodDefs.back().Toks;
+
+ tok::TokenKind kind = Tok.getKind();
+ // We may have a constructor initializer or function-try-block here.
+ if (kind == tok::colon || kind == tok::kw_try) {
+ // Consume everything up to (and including) the left brace.
+ if (!ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks, tok::semi)) {
+ // We didn't find the left-brace we expected after the
+ // constructor initializer.
+ if (Tok.is(tok::semi)) {
+ // We found a semicolon; complain, consume the semicolon, and
+ // don't try to parse this method later.
+ Diag(Tok.getLocation(), diag::err_expected_lbrace);
+ ConsumeAnyToken();
+ getCurrentClass().MethodDefs.pop_back();
+ return FnD;
+ }
+ }
+
+ } else {
+ // Begin by storing the '{' token.
+ Toks.push_back(Tok);
+ ConsumeBrace();
+ }
+ // Consume everything up to (and including) the matching right brace.
+ ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);
+
+ // If we're in a function-try-block, we need to store all the catch blocks.
+ if (kind == tok::kw_try) {
+ while (Tok.is(tok::kw_catch)) {
+ ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks);
+ ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);
+ }
+ }
+
+ return FnD;
+}
+
+/// ParseLexedMethodDeclarations - We finished parsing the member
+/// specification of a top (non-nested) C++ class. Now go over the
+/// stack of method declarations with some parts for which parsing was
+/// delayed (such as default arguments) and parse them.
+void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) {
+ bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
+ ParseScope TemplateScope(this, Scope::TemplateParamScope, HasTemplateScope);
+ if (HasTemplateScope)
+ Actions.ActOnReenterTemplateScope(CurScope, Class.TagOrTemplate);
+
+ bool HasClassScope = !Class.TopLevelClass;
+ ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope,
+ HasClassScope);
+
+ for (; !Class.MethodDecls.empty(); Class.MethodDecls.pop_front()) {
+ LateParsedMethodDeclaration &LM = Class.MethodDecls.front();
+
+ // FIXME: For member function templates, we'll need to introduce a
+ // scope for the template parameters.
+
+ // Start the delayed C++ method declaration
+ Actions.ActOnStartDelayedCXXMethodDeclaration(CurScope, LM.Method);
+
+ // Introduce the parameters into scope and parse their default
+ // arguments.
+ ParseScope PrototypeScope(this,
+ Scope::FunctionPrototypeScope|Scope::DeclScope);
+ for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) {
+ // Introduce the parameter into scope.
+ Actions.ActOnDelayedCXXMethodParameter(CurScope, LM.DefaultArgs[I].Param);
+
+ if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) {
+ // Parse the default argument from its saved token stream.
+ Toks->push_back(Tok); // So that the current token doesn't get lost
+ PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false);
+
+ // Consume the previously-pushed token.
+ ConsumeAnyToken();
+
+ // Consume the '='.
+ assert(Tok.is(tok::equal) && "Default argument not starting with '='");
+ SourceLocation EqualLoc = ConsumeToken();
+
+ OwningExprResult DefArgResult(ParseAssignmentExpression());
+ if (DefArgResult.isInvalid())
+ Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param);
+ else
+ Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc,
+ move(DefArgResult));
+ delete Toks;
+ LM.DefaultArgs[I].Toks = 0;
+ }
+ }
+ PrototypeScope.Exit();
+
+ // Finish the delayed C++ method declaration.
+ Actions.ActOnFinishDelayedCXXMethodDeclaration(CurScope, LM.Method);
+ }
+
+ for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I)
+ ParseLexedMethodDeclarations(*Class.NestedClasses[I]);
+}
+
+/// ParseLexedMethodDefs - We finished parsing the member specification of a top
+/// (non-nested) C++ class. Now go over the stack of lexed methods that were
+/// collected during its parsing and parse them all.
+void Parser::ParseLexedMethodDefs(ParsingClass &Class) {
+ bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
+ ParseScope TemplateScope(this, Scope::TemplateParamScope, HasTemplateScope);
+ if (HasTemplateScope)
+ Actions.ActOnReenterTemplateScope(CurScope, Class.TagOrTemplate);
+
+ bool HasClassScope = !Class.TopLevelClass;
+ ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope,
+ HasClassScope);
+
+ for (; !Class.MethodDefs.empty(); Class.MethodDefs.pop_front()) {
+ LexedMethod &LM = Class.MethodDefs.front();
+
+ assert(!LM.Toks.empty() && "Empty body!");
+ // Append the current token at the end of the new token stream so that it
+ // doesn't get lost.
+ LM.Toks.push_back(Tok);
+ PP.EnterTokenStream(&LM.Toks.front(), LM.Toks.size(), true, false);
+
+ // Consume the previously pushed token.
+ ConsumeAnyToken();
+ assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try))
+ && "Inline method not starting with '{', ':' or 'try'");
+
+ // Parse the method body. Function body parsing code is similar enough
+ // to be re-used for method bodies as well.
+ ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope);
+ Actions.ActOnStartOfFunctionDef(CurScope, LM.D);
+
+ if (Tok.is(tok::kw_try)) {
+ ParseFunctionTryBlock(LM.D);
+ continue;
+ }
+ if (Tok.is(tok::colon))
+ ParseConstructorInitializer(LM.D);
+ // FIXME: What if ParseConstructorInitializer doesn't leave us with a '{'??
+ ParseFunctionStatementBody(LM.D);
+ }
+
+ for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I)
+ ParseLexedMethodDefs(*Class.NestedClasses[I]);
+}
+
+/// ConsumeAndStoreUntil - Consume and store the token at the passed token
+/// container until the token 'T' is reached (which gets
+/// consumed/stored too, if ConsumeFinalToken).
+/// If EarlyAbortIf is specified, then we will stop early if we find that
+/// token at the top level.
+/// Returns true if token 'T1' or 'T2' was found.
+/// NOTE: This is a specialized version of Parser::SkipUntil.
+bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
+ CachedTokens &Toks,
+ tok::TokenKind EarlyAbortIf,
+ bool ConsumeFinalToken) {
+ // We always want this function to consume at least one token if the first
+ // token isn't T and if not at EOF.
+ bool isFirstTokenConsumed = true;
+ while (1) {
+ // If we found one of the tokens, stop and return true.
+ if (Tok.is(T1) || Tok.is(T2)) {
+ if (ConsumeFinalToken) {
+ Toks.push_back(Tok);
+ ConsumeAnyToken();
+ }
+ return true;
+ }
+
+ // If we found the early-abort token, return.
+ if (Tok.is(EarlyAbortIf))
+ return false;
+
+ switch (Tok.getKind()) {
+ case tok::eof:
+ // Ran out of tokens.
+ return false;
+
+ case tok::l_paren:
+ // Recursively consume properly-nested parens.
+ Toks.push_back(Tok);
+ ConsumeParen();
+ ConsumeAndStoreUntil(tok::r_paren, tok::unknown, Toks);
+ break;
+ case tok::l_square:
+ // Recursively consume properly-nested square brackets.
+ Toks.push_back(Tok);
+ ConsumeBracket();
+ ConsumeAndStoreUntil(tok::r_square, tok::unknown, Toks);
+ break;
+ case tok::l_brace:
+ // Recursively consume properly-nested braces.
+ Toks.push_back(Tok);
+ ConsumeBrace();
+ ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);
+ break;
+
+ // Okay, we found a ']' or '}' or ')', which we think should be balanced.
+ // Since the user wasn't looking for this token (if they were, it would
+ // already be handled), this isn't balanced. If there is a LHS token at a
+ // higher level, we will assume that this matches the unbalanced token
+ // and return it. Otherwise, this is a spurious RHS token, which we skip.
+ case tok::r_paren:
+ if (ParenCount && !isFirstTokenConsumed)
+ return false; // Matches something.
+ Toks.push_back(Tok);
+ ConsumeParen();
+ break;
+ case tok::r_square:
+ if (BracketCount && !isFirstTokenConsumed)
+ return false; // Matches something.
+ Toks.push_back(Tok);
+ ConsumeBracket();
+ break;
+ case tok::r_brace:
+ if (BraceCount && !isFirstTokenConsumed)
+ return false; // Matches something.
+ Toks.push_back(Tok);
+ ConsumeBrace();
+ break;
+
+ case tok::string_literal:
+ case tok::wide_string_literal:
+ Toks.push_back(Tok);
+ ConsumeStringToken();
+ break;
+ default:
+ // consume this token.
+ Toks.push_back(Tok);
+ ConsumeToken();
+ break;
+ }
+ isFirstTokenConsumed = false;
+ }
+}
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
new file mode 100644
index 0000000..39eaf36
--- /dev/null
+++ b/lib/Parse/ParseDecl.cpp
@@ -0,0 +1,2707 @@
+//===--- ParseDecl.cpp - Declaration Parsing ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Declaration portions of the Parser interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/Scope.h"
+#include "ExtensionRAIIObject.h"
+#include "llvm/ADT/SmallSet.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// C99 6.7: Declarations.
+//===----------------------------------------------------------------------===//
+
+/// ParseTypeName
+/// type-name: [C99 6.7.6]
+/// specifier-qualifier-list abstract-declarator[opt]
+///
+/// Called type-id in C++.
+Action::TypeResult Parser::ParseTypeName(SourceRange *Range) {
+ // Parse the common declaration-specifiers piece.
+ DeclSpec DS;
+ ParseSpecifierQualifierList(DS);
+
+ // Parse the abstract-declarator, if present.
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ ParseDeclarator(DeclaratorInfo);
+ if (Range)
+ *Range = DeclaratorInfo.getSourceRange();
+
+ if (DeclaratorInfo.isInvalidType())
+ return true;
+
+ return Actions.ActOnTypeName(CurScope, DeclaratorInfo);
+}
+
+/// ParseAttributes - Parse a non-empty attributes list.
+///
+/// [GNU] attributes:
+/// attribute
+/// attributes attribute
+///
+/// [GNU] attribute:
+/// '__attribute__' '(' '(' attribute-list ')' ')'
+///
+/// [GNU] attribute-list:
+/// attrib
+/// attribute_list ',' attrib
+///
+/// [GNU] attrib:
+/// empty
+/// attrib-name
+/// attrib-name '(' identifier ')'
+/// attrib-name '(' identifier ',' nonempty-expr-list ')'
+/// attrib-name '(' argument-expression-list [C99 6.5.2] ')'
+///
+/// [GNU] attrib-name:
+/// identifier
+/// typespec
+/// typequal
+/// storageclass
+///
+/// FIXME: The GCC grammar/code for this construct implies we need two
+/// token lookahead. Comment from gcc: "If they start with an identifier
+/// which is followed by a comma or close parenthesis, then the arguments
+/// start with that identifier; otherwise they are an expression list."
+///
+/// At the moment, I am not doing 2 token lookahead. I am also unaware of
+/// any attributes that don't work (based on my limited testing). Most
+/// attributes are very simple in practice. Until we find a bug, I don't see
+/// a pressing need to implement the 2 token lookahead.
+
+AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
+ assert(Tok.is(tok::kw___attribute) && "Not an attribute list!");
+
+ AttributeList *CurrAttr = 0;
+
+ while (Tok.is(tok::kw___attribute)) {
+ ConsumeToken();
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
+ "attribute")) {
+ SkipUntil(tok::r_paren, true); // skip until ) or ;
+ return CurrAttr;
+ }
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "(")) {
+ SkipUntil(tok::r_paren, true); // skip until ) or ;
+ return CurrAttr;
+ }
+ // Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") ))
+ while (Tok.is(tok::identifier) || isDeclarationSpecifier() ||
+ Tok.is(tok::comma)) {
+
+ if (Tok.is(tok::comma)) {
+ // allows for empty/non-empty attributes. ((__vector_size__(16),,,,))
+ ConsumeToken();
+ continue;
+ }
+ // we have an identifier or declaration specifier (const, int, etc.)
+ IdentifierInfo *AttrName = Tok.getIdentifierInfo();
+ SourceLocation AttrNameLoc = ConsumeToken();
+
+ // check if we have a "paramterized" attribute
+ if (Tok.is(tok::l_paren)) {
+ ConsumeParen(); // ignore the left paren loc for now
+
+ if (Tok.is(tok::identifier)) {
+ IdentifierInfo *ParmName = Tok.getIdentifierInfo();
+ SourceLocation ParmLoc = ConsumeToken();
+
+ if (Tok.is(tok::r_paren)) {
+ // __attribute__(( mode(byte) ))
+ ConsumeParen(); // ignore the right paren loc for now
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ ParmName, ParmLoc, 0, 0, CurrAttr);
+ } else if (Tok.is(tok::comma)) {
+ ConsumeToken();
+ // __attribute__(( format(printf, 1, 2) ))
+ ExprVector ArgExprs(Actions);
+ bool ArgExprsOk = true;
+
+ // now parse the non-empty comma separated list of expressions
+ while (1) {
+ OwningExprResult ArgExpr(ParseAssignmentExpression());
+ if (ArgExpr.isInvalid()) {
+ ArgExprsOk = false;
+ SkipUntil(tok::r_paren);
+ break;
+ } else {
+ ArgExprs.push_back(ArgExpr.release());
+ }
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken(); // Eat the comma, move to the next argument
+ }
+ if (ArgExprsOk && Tok.is(tok::r_paren)) {
+ ConsumeParen(); // ignore the right paren loc for now
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, ParmName,
+ ParmLoc, ArgExprs.take(), ArgExprs.size(), CurrAttr);
+ }
+ }
+ } else { // not an identifier
+ // parse a possibly empty comma separated list of expressions
+ if (Tok.is(tok::r_paren)) {
+ // __attribute__(( nonnull() ))
+ ConsumeParen(); // ignore the right paren loc for now
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ 0, SourceLocation(), 0, 0, CurrAttr);
+ } else {
+ // __attribute__(( aligned(16) ))
+ ExprVector ArgExprs(Actions);
+ bool ArgExprsOk = true;
+
+ // now parse the list of expressions
+ while (1) {
+ OwningExprResult ArgExpr(ParseAssignmentExpression());
+ if (ArgExpr.isInvalid()) {
+ ArgExprsOk = false;
+ SkipUntil(tok::r_paren);
+ break;
+ } else {
+ ArgExprs.push_back(ArgExpr.release());
+ }
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken(); // Eat the comma, move to the next argument
+ }
+ // Match the ')'.
+ if (ArgExprsOk && Tok.is(tok::r_paren)) {
+ ConsumeParen(); // ignore the right paren loc for now
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
+ SourceLocation(), ArgExprs.take(), ArgExprs.size(),
+ CurrAttr);
+ }
+ }
+ }
+ } else {
+ CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+ 0, SourceLocation(), 0, 0, CurrAttr);
+ }
+ }
+ if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
+ SkipUntil(tok::r_paren, false);
+ SourceLocation Loc = Tok.getLocation();;
+ if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) {
+ SkipUntil(tok::r_paren, false);
+ }
+ if (EndLoc)
+ *EndLoc = Loc;
+ }
+ return CurrAttr;
+}
+
+/// FuzzyParseMicrosoftDeclSpec. When -fms-extensions is enabled, this
+/// routine is called to skip/ignore tokens that comprise the MS declspec.
+void Parser::FuzzyParseMicrosoftDeclSpec() {
+ assert(Tok.is(tok::kw___declspec) && "Not a declspec!");
+ ConsumeToken();
+ if (Tok.is(tok::l_paren)) {
+ unsigned short savedParenCount = ParenCount;
+ do {
+ ConsumeAnyToken();
+ } while (ParenCount > savedParenCount && Tok.isNot(tok::eof));
+ }
+ return;
+}
+
+/// ParseDeclaration - Parse a full 'declaration', which consists of
+/// declaration-specifiers, some number of declarators, and a semicolon.
+/// 'Context' should be a Declarator::TheContext value. This returns the
+/// location of the semicolon in DeclEnd.
+///
+/// declaration: [C99 6.7]
+/// block-declaration ->
+/// simple-declaration
+/// others [FIXME]
+/// [C++] template-declaration
+/// [C++] namespace-definition
+/// [C++] using-directive
+/// [C++] using-declaration [TODO]
+/// [C++0x] static_assert-declaration
+/// others... [FIXME]
+///
+Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context,
+ SourceLocation &DeclEnd) {
+ DeclPtrTy SingleDecl;
+ switch (Tok.getKind()) {
+ case tok::kw_template:
+ case tok::kw_export:
+ SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd);
+ break;
+ case tok::kw_namespace:
+ SingleDecl = ParseNamespace(Context, DeclEnd);
+ break;
+ case tok::kw_using:
+ SingleDecl = ParseUsingDirectiveOrDeclaration(Context, DeclEnd);
+ break;
+ case tok::kw_static_assert:
+ SingleDecl = ParseStaticAssertDeclaration(DeclEnd);
+ break;
+ default:
+ return ParseSimpleDeclaration(Context, DeclEnd);
+ }
+
+ // This routine returns a DeclGroup, if the thing we parsed only contains a
+ // single decl, convert it now.
+ return Actions.ConvertDeclToDeclGroup(SingleDecl);
+}
+
+/// simple-declaration: [C99 6.7: declaration] [C++ 7p1: dcl.dcl]
+/// declaration-specifiers init-declarator-list[opt] ';'
+///[C90/C++]init-declarator-list ';' [TODO]
+/// [OMP] threadprivate-directive [TODO]
+///
+/// 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) {
+ // Parse the common declaration-specifiers piece.
+ DeclSpec DS;
+ ParseDeclarationSpecifiers(DS);
+
+ // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
+ // declaration-specifiers init-declarator-list[opt] ';'
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ return Actions.ConvertDeclToDeclGroup(TheDecl);
+ }
+
+ Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context);
+ ParseDeclarator(DeclaratorInfo);
+
+ DeclGroupPtrTy DG =
+ ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo);
+
+ DeclEnd = Tok.getLocation();
+
+ // If the client wants to check what comes after the declaration, just return
+ // immediately without checking anything!
+ if (!RequireSemi) return DG;
+
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ return DG;
+ }
+
+ Diag(Tok, diag::err_expected_semi_declation);
+ // Skip to end of block or statement
+ SkipUntil(tok::r_brace, true, true);
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+ return DG;
+}
+
+/// \brief Parse 'declaration' after parsing 'declaration-specifiers
+/// declarator'. This method parses the remainder of the declaration
+/// (including any attributes or initializer, among other things) and
+/// finalizes the declaration.
+///
+/// init-declarator: [C99 6.7]
+/// declarator
+/// declarator '=' initializer
+/// [GNU] declarator simple-asm-expr[opt] attributes[opt]
+/// [GNU] declarator simple-asm-expr[opt] attributes[opt] '=' initializer
+/// [C++] declarator initializer[opt]
+///
+/// [C++] initializer:
+/// [C++] '=' initializer-clause
+/// [C++] '(' expression-list ')'
+/// [C++0x] '=' 'default' [TODO]
+/// [C++0x] '=' 'delete'
+///
+/// According to the standard grammar, =default and =delete are function
+/// definitions, but that definitely doesn't fit with the parser here.
+///
+Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D) {
+ // If a simple-asm-expr is present, parse it.
+ if (Tok.is(tok::kw_asm)) {
+ SourceLocation Loc;
+ OwningExprResult AsmLabel(ParseSimpleAsm(&Loc));
+ if (AsmLabel.isInvalid()) {
+ SkipUntil(tok::semi, true, true);
+ return DeclPtrTy();
+ }
+
+ D.setAsmLabel(AsmLabel.release());
+ D.SetRangeEnd(Loc);
+ }
+
+ // If attributes are present, parse them.
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ D.AddAttributes(AttrList, Loc);
+ }
+
+ // Inform the current actions module that we just parsed this declarator.
+ DeclPtrTy ThisDecl = Actions.ActOnDeclarator(CurScope, D);
+
+ // Parse declarator '=' initializer.
+ if (Tok.is(tok::equal)) {
+ ConsumeToken();
+ if (getLang().CPlusPlus0x && Tok.is(tok::kw_delete)) {
+ SourceLocation DelLoc = ConsumeToken();
+ Actions.SetDeclDeleted(ThisDecl, DelLoc);
+ } else {
+ OwningExprResult Init(ParseInitializer());
+ if (Init.isInvalid()) {
+ SkipUntil(tok::semi, true, true);
+ return DeclPtrTy();
+ }
+ Actions.AddInitializerToDecl(ThisDecl, Actions.FullExpr(Init));
+ }
+ } else if (Tok.is(tok::l_paren)) {
+ // Parse C++ direct initializer: '(' expression-list ')'
+ SourceLocation LParenLoc = ConsumeParen();
+ ExprVector Exprs(Actions);
+ CommaLocsTy CommaLocs;
+
+ if (ParseExpressionList(Exprs, CommaLocs)) {
+ SkipUntil(tok::r_paren);
+ } else {
+ // Match the ')'.
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() &&
+ "Unexpected number of commas!");
+ Actions.AddCXXDirectInitializerToDecl(ThisDecl, LParenLoc,
+ move_arg(Exprs),
+ CommaLocs.data(), RParenLoc);
+ }
+ } else {
+ Actions.ActOnUninitializedDecl(ThisDecl);
+ }
+
+ 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]
+/// type-qualifier specifier-qualifier-list[opt]
+/// [GNU] attributes specifier-qualifier-list[opt]
+///
+void Parser::ParseSpecifierQualifierList(DeclSpec &DS) {
+ /// specifier-qualifier-list is a subset of declaration-specifiers. Just
+ /// parse declaration-specifiers and complain about extra stuff.
+ ParseDeclarationSpecifiers(DS);
+
+ // Validate declspec for type-name.
+ unsigned Specs = DS.getParsedSpecifiers();
+ if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() &&
+ !DS.getAttributes())
+ Diag(Tok, diag::err_typename_requires_specqual);
+
+ // Issue diagnostic and remove storage class if present.
+ if (Specs & DeclSpec::PQ_StorageClassSpecifier) {
+ if (DS.getStorageClassSpecLoc().isValid())
+ Diag(DS.getStorageClassSpecLoc(),diag::err_typename_invalid_storageclass);
+ else
+ Diag(DS.getThreadSpecLoc(), diag::err_typename_invalid_storageclass);
+ DS.ClearStorageClassSpecs();
+ }
+
+ // Issue diagnostic and remove function specfier if present.
+ if (Specs & DeclSpec::PQ_FunctionSpecifier) {
+ if (DS.isInlineSpecified())
+ Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_functionspec);
+ if (DS.isVirtualSpecified())
+ Diag(DS.getVirtualSpecLoc(), diag::err_typename_invalid_functionspec);
+ if (DS.isExplicitSpecified())
+ Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec);
+ DS.ClearFunctionSpecs();
+ }
+}
+
+/// isValidAfterIdentifierInDeclaratorAfterDeclSpec - Return true if the
+/// specified token is valid after the identifier in a declarator which
+/// immediately follows the declspec. For example, these things are valid:
+///
+/// int x [ 4]; // direct-declarator
+/// int x ( int y); // direct-declarator
+/// int(int x ) // direct-declarator
+/// int x ; // simple-declaration
+/// int x = 17; // init-declarator-list
+/// int x , y; // init-declarator-list
+/// int x __asm__ ("foo"); // init-declarator-list
+/// int x : 4; // struct-declarator
+/// int x { 5}; // C++'0x unified initializers
+///
+/// This is not, because 'x' does not immediately follow the declspec (though
+/// ')' happens to be valid anyway).
+/// int (x)
+///
+static bool isValidAfterIdentifierInDeclarator(const Token &T) {
+ return T.is(tok::l_square) || T.is(tok::l_paren) || T.is(tok::r_paren) ||
+ T.is(tok::semi) || T.is(tok::comma) || T.is(tok::equal) ||
+ T.is(tok::kw_asm) || T.is(tok::l_brace) || T.is(tok::colon);
+}
+
+
+/// ParseImplicitInt - This method is called when we have an non-typename
+/// identifier in a declspec (which normally terminates the decl spec) when
+/// the declspec has no type specifier. In this case, the declspec is either
+/// malformed or is "implicit int" (in K&R and C89).
+///
+/// This method handles diagnosing this prettily and returns false if the
+/// declspec is done being processed. If it recovers and thinks there may be
+/// other pieces of declspec after it, it returns true.
+///
+bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
+ const ParsedTemplateInfo &TemplateInfo,
+ AccessSpecifier AS) {
+ assert(Tok.is(tok::identifier) && "should have identifier");
+
+ SourceLocation Loc = Tok.getLocation();
+ // If we see an identifier that is not a type name, we normally would
+ // parse it as the identifer being declared. However, when a typename
+ // is typo'd or the definition is not included, this will incorrectly
+ // parse the typename as the identifier name and fall over misparsing
+ // later parts of the diagnostic.
+ //
+ // As such, we try to do some look-ahead in cases where this would
+ // otherwise be an "implicit-int" case to see if this is invalid. For
+ // example: "static foo_t x = 4;" In this case, if we parsed foo_t as
+ // an identifier with implicit int, we'd get a parse error because the
+ // next token is obviously invalid for a type. Parse these as a case
+ // with an invalid type specifier.
+ assert(!DS.hasTypeSpecifier() && "Type specifier checked above");
+
+ // Since we know that this either implicit int (which is rare) or an
+ // error, we'd do lookahead to try to do better recovery.
+ if (isValidAfterIdentifierInDeclarator(NextToken())) {
+ // If this token is valid for implicit int, e.g. "static x = 4", then
+ // we just avoid eating the identifier, so it will be parsed as the
+ // identifier in the declarator.
+ return false;
+ }
+
+ // Otherwise, if we don't consume this token, we are going to emit an
+ // error anyway. Try to recover from various common problems. Check
+ // to see if this was a reference to a tag name without a tag specified.
+ // This is a common problem in C (saying 'foo' instead of 'struct foo').
+ //
+ // C++ doesn't need this, and isTagName doesn't take SS.
+ if (SS == 0) {
+ const char *TagName = 0;
+ tok::TokenKind TagKind = tok::unknown;
+
+ switch (Actions.isTagName(*Tok.getIdentifierInfo(), CurScope)) {
+ default: break;
+ case DeclSpec::TST_enum: TagName="enum" ;TagKind=tok::kw_enum ;break;
+ case DeclSpec::TST_union: TagName="union" ;TagKind=tok::kw_union ;break;
+ case DeclSpec::TST_struct:TagName="struct";TagKind=tok::kw_struct;break;
+ case DeclSpec::TST_class: TagName="class" ;TagKind=tok::kw_class ;break;
+ }
+
+ if (TagName) {
+ Diag(Loc, diag::err_use_of_tag_name_without_tag)
+ << Tok.getIdentifierInfo() << TagName
+ << CodeModificationHint::CreateInsertion(Tok.getLocation(),TagName);
+
+ // Parse this as a tag as if the missing tag were present.
+ if (TagKind == tok::kw_enum)
+ ParseEnumSpecifier(Loc, DS, AS);
+ else
+ ParseClassSpecifier(TagKind, Loc, DS, TemplateInfo, AS);
+ return true;
+ }
+ }
+
+ // Since this is almost certainly an invalid type name, emit a
+ // diagnostic that says it, eat the token, and mark the declspec as
+ // invalid.
+ SourceRange R;
+ if (SS) R = SS->getRange();
+
+ Diag(Loc, diag::err_unknown_typename) << Tok.getIdentifierInfo() << R;
+ const char *PrevSpec;
+ DS.SetTypeSpecType(DeclSpec::TST_error, Loc, PrevSpec);
+ DS.SetRangeEnd(Tok.getLocation());
+ ConsumeToken();
+
+ // TODO: Could inject an invalid typedef decl in an enclosing scope to
+ // avoid rippling error messages on subsequent uses of the same type,
+ // could be useful if #include was forgotten.
+ return false;
+}
+
+/// ParseDeclarationSpecifiers
+/// declaration-specifiers: [C99 6.7]
+/// storage-class-specifier declaration-specifiers[opt]
+/// type-specifier declaration-specifiers[opt]
+/// [C99] function-specifier declaration-specifiers[opt]
+/// [GNU] attributes declaration-specifiers[opt]
+///
+/// storage-class-specifier: [C99 6.7.1]
+/// 'typedef'
+/// 'extern'
+/// 'static'
+/// 'auto'
+/// 'register'
+/// [C++] 'mutable'
+/// [GNU] '__thread'
+/// function-specifier: [C99 6.7.4]
+/// [C99] 'inline'
+/// [C++] 'virtual'
+/// [C++] 'explicit'
+/// 'friend': [C++ dcl.friend]
+
+///
+void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
+ const ParsedTemplateInfo &TemplateInfo,
+ AccessSpecifier AS) {
+ DS.SetRangeStart(Tok.getLocation());
+ while (1) {
+ int isInvalid = false;
+ const char *PrevSpec = 0;
+ SourceLocation Loc = Tok.getLocation();
+
+ switch (Tok.getKind()) {
+ default:
+ DoneWithDeclSpec:
+ // If this is not a declaration specifier token, we're done reading decl
+ // specifiers. First verify that DeclSpec's are consistent.
+ DS.Finish(Diags, PP);
+ return;
+
+ case tok::coloncolon: // ::foo::bar
+ // Annotate C++ scope specifiers. If we get one, loop.
+ if (TryAnnotateCXXScopeToken())
+ continue;
+ goto DoneWithDeclSpec;
+
+ case tok::annot_cxxscope: {
+ if (DS.hasTypeSpecifier())
+ goto DoneWithDeclSpec;
+
+ // We are looking for a qualified typename.
+ Token Next = NextToken();
+ if (Next.is(tok::annot_template_id) &&
+ static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue())
+ ->Kind == TNK_Type_template) {
+ // We have a qualified template-id, e.g., N::A<int>
+ CXXScopeSpec SS;
+ ParseOptionalCXXScopeSpecifier(SS);
+ assert(Tok.is(tok::annot_template_id) &&
+ "ParseOptionalCXXScopeSpecifier not working");
+ AnnotateTemplateIdTokenAsType(&SS);
+ continue;
+ }
+
+ if (Next.isNot(tok::identifier))
+ goto DoneWithDeclSpec;
+
+ CXXScopeSpec SS;
+ SS.setScopeRep(Tok.getAnnotationValue());
+ SS.setRange(Tok.getAnnotationRange());
+
+ // If the next token is the name of the class type that the C++ scope
+ // denotes, followed by a '(', then this is a constructor declaration.
+ // We're done with the decl-specifiers.
+ if (Actions.isCurrentClassName(*Next.getIdentifierInfo(),
+ CurScope, &SS) &&
+ GetLookAheadToken(2).is(tok::l_paren))
+ goto DoneWithDeclSpec;
+
+ TypeTy *TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(),
+ Next.getLocation(), CurScope, &SS);
+
+ // If the referenced identifier is not a type, then this declspec is
+ // erroneous: We already checked about that it has no type specifier, and
+ // C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the
+ // typename.
+ if (TypeRep == 0) {
+ ConsumeToken(); // Eat the scope spec so the identifier is current.
+ if (ParseImplicitInt(DS, &SS, TemplateInfo, AS)) continue;
+ goto DoneWithDeclSpec;
+ }
+
+ ConsumeToken(); // The C++ scope.
+
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
+ TypeRep);
+ if (isInvalid)
+ break;
+
+ DS.SetRangeEnd(Tok.getLocation());
+ ConsumeToken(); // The typename.
+
+ continue;
+ }
+
+ case tok::annot_typename: {
+ if (Tok.getAnnotationValue())
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
+ Tok.getAnnotationValue());
+ else
+ DS.SetTypeSpecError();
+ DS.SetRangeEnd(Tok.getAnnotationEndLoc());
+ ConsumeToken(); // The typename
+
+ // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
+ // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
+ // Objective-C interface. If we don't have Objective-C or a '<', this is
+ // just a normal reference to a typedef name.
+ if (!Tok.is(tok::less) || !getLang().ObjC1)
+ continue;
+
+ SourceLocation EndProtoLoc;
+ llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl;
+ ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
+ DS.setProtocolQualifiers(&ProtocolDecl[0], ProtocolDecl.size());
+
+ DS.SetRangeEnd(EndProtoLoc);
+ continue;
+ }
+
+ // typedef-name
+ case tok::identifier: {
+ // In C++, check to see if this is a scope specifier like foo::bar::, if
+ // so handle it as such. This is important for ctor parsing.
+ if (getLang().CPlusPlus && TryAnnotateCXXScopeToken())
+ continue;
+
+ // This identifier can only be a typedef name if we haven't already seen
+ // a type-specifier. Without this check we misparse:
+ // typedef int X; struct Y { short X; }; as 'short int'.
+ if (DS.hasTypeSpecifier())
+ goto DoneWithDeclSpec;
+
+ // It has to be available as a typedef too!
+ TypeTy *TypeRep = Actions.getTypeName(*Tok.getIdentifierInfo(),
+ Tok.getLocation(), CurScope);
+
+ // If this is not a typedef name, don't parse it as part of the declspec,
+ // it must be an implicit int or an error.
+ if (TypeRep == 0) {
+ if (ParseImplicitInt(DS, 0, TemplateInfo, AS)) continue;
+ goto DoneWithDeclSpec;
+ }
+
+ // C++: If the identifier is actually the name of the class type
+ // being defined and the next token is a '(', then this is a
+ // constructor declaration. We're done with the decl-specifiers
+ // and will treat this token as an identifier.
+ if (getLang().CPlusPlus && CurScope->isClassScope() &&
+ Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope) &&
+ NextToken().getKind() == tok::l_paren)
+ goto DoneWithDeclSpec;
+
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
+ TypeRep);
+ if (isInvalid)
+ break;
+
+ DS.SetRangeEnd(Tok.getLocation());
+ ConsumeToken(); // The identifier
+
+ // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
+ // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
+ // Objective-C interface. If we don't have Objective-C or a '<', this is
+ // just a normal reference to a typedef name.
+ if (!Tok.is(tok::less) || !getLang().ObjC1)
+ continue;
+
+ SourceLocation EndProtoLoc;
+ llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl;
+ ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
+ DS.setProtocolQualifiers(&ProtocolDecl[0], ProtocolDecl.size());
+
+ DS.SetRangeEnd(EndProtoLoc);
+
+ // Need to support trailing type qualifiers (e.g. "id<p> const").
+ // If a type specifier follows, it will be diagnosed elsewhere.
+ continue;
+ }
+
+ // type-name
+ case tok::annot_template_id: {
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ if (TemplateId->Kind != TNK_Type_template) {
+ // This template-id does not refer to a type name, so we're
+ // done with the type-specifiers.
+ goto DoneWithDeclSpec;
+ }
+
+ // Turn the template-id annotation token into a type annotation
+ // token, then try again to parse it as a type-specifier.
+ AnnotateTemplateIdTokenAsType();
+ continue;
+ }
+
+ // GNU attributes support.
+ case tok::kw___attribute:
+ DS.AddAttributes(ParseAttributes());
+ continue;
+
+ // Microsoft declspec support.
+ case tok::kw___declspec:
+ if (!PP.getLangOptions().Microsoft)
+ goto DoneWithDeclSpec;
+ FuzzyParseMicrosoftDeclSpec();
+ continue;
+
+ // Microsoft single token adornments.
+ case tok::kw___forceinline:
+ case tok::kw___w64:
+ case tok::kw___cdecl:
+ case tok::kw___stdcall:
+ case tok::kw___fastcall:
+ if (!PP.getLangOptions().Microsoft)
+ goto DoneWithDeclSpec;
+ // Just ignore it.
+ break;
+
+ // storage-class-specifier
+ case tok::kw_typedef:
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Loc, PrevSpec);
+ break;
+ case tok::kw_extern:
+ if (DS.isThreadSpecified())
+ Diag(Tok, diag::ext_thread_before) << "extern";
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_extern, Loc, PrevSpec);
+ break;
+ case tok::kw___private_extern__:
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_private_extern, Loc,
+ PrevSpec);
+ break;
+ case tok::kw_static:
+ if (DS.isThreadSpecified())
+ Diag(Tok, diag::ext_thread_before) << "static";
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_static, Loc, PrevSpec);
+ break;
+ case tok::kw_auto:
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec);
+ break;
+ case tok::kw_register:
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, Loc, PrevSpec);
+ break;
+ case tok::kw_mutable:
+ isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_mutable, Loc, PrevSpec);
+ break;
+ case tok::kw___thread:
+ isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec)*2;
+ break;
+
+ // function-specifier
+ case tok::kw_inline:
+ isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec);
+ break;
+ case tok::kw_virtual:
+ isInvalid = DS.SetFunctionSpecVirtual(Loc, PrevSpec);
+ break;
+ case tok::kw_explicit:
+ isInvalid = DS.SetFunctionSpecExplicit(Loc, PrevSpec);
+ break;
+
+ // friend
+ case tok::kw_friend:
+ isInvalid = DS.SetFriendSpec(Loc, PrevSpec);
+ break;
+
+ // type-specifier
+ case tok::kw_short:
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec);
+ break;
+ case tok::kw_long:
+ if (DS.getTypeSpecWidth() != DeclSpec::TSW_long)
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec);
+ else
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec);
+ break;
+ case tok::kw_signed:
+ isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec);
+ break;
+ case tok::kw_unsigned:
+ isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec);
+ break;
+ case tok::kw__Complex:
+ isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec);
+ break;
+ case tok::kw__Imaginary:
+ isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec);
+ break;
+ case tok::kw_void:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec);
+ break;
+ case tok::kw_char:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec);
+ break;
+ case tok::kw_int:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec);
+ break;
+ case tok::kw_float:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec);
+ break;
+ case tok::kw_double:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec);
+ break;
+ case tok::kw_wchar_t:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec);
+ break;
+ case tok::kw_bool:
+ case tok::kw__Bool:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec);
+ break;
+ case tok::kw__Decimal32:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec);
+ break;
+ case tok::kw__Decimal64:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec);
+ break;
+ case tok::kw__Decimal128:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec);
+ break;
+
+ // class-specifier:
+ case tok::kw_class:
+ case tok::kw_struct:
+ case tok::kw_union: {
+ tok::TokenKind Kind = Tok.getKind();
+ ConsumeToken();
+ ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS);
+ continue;
+ }
+
+ // enum-specifier:
+ case tok::kw_enum:
+ ConsumeToken();
+ ParseEnumSpecifier(Loc, DS, AS);
+ continue;
+
+ // cv-qualifier:
+ case tok::kw_const:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec,getLang())*2;
+ break;
+ case tok::kw_volatile:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec,
+ getLang())*2;
+ break;
+ case tok::kw_restrict:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec,
+ getLang())*2;
+ break;
+
+ // C++ typename-specifier:
+ case tok::kw_typename:
+ if (TryAnnotateTypeOrScopeToken())
+ continue;
+ break;
+
+ // GNU typeof support.
+ case tok::kw_typeof:
+ ParseTypeofSpecifier(DS);
+ continue;
+
+ case tok::less:
+ // GCC ObjC supports types like "<SomeProtocol>" as a synonym for
+ // "id<SomeProtocol>". This is hopelessly old fashioned and dangerous,
+ // but we support it.
+ if (DS.hasTypeSpecifier() || !getLang().ObjC1)
+ goto DoneWithDeclSpec;
+
+ {
+ SourceLocation EndProtoLoc;
+ llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl;
+ ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
+ DS.setProtocolQualifiers(&ProtocolDecl[0], ProtocolDecl.size());
+ DS.SetRangeEnd(EndProtoLoc);
+
+ Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id)
+ << CodeModificationHint::CreateInsertion(Loc, "id")
+ << SourceRange(Loc, EndProtoLoc);
+ // Need to support trailing type qualifiers (e.g. "id<p> const").
+ // If a type specifier follows, it will be diagnosed elsewhere.
+ continue;
+ }
+ }
+ // If the specifier combination wasn't legal, issue a diagnostic.
+ if (isInvalid) {
+ assert(PrevSpec && "Method did not return previous specifier!");
+ // Pick between error or extwarn.
+ unsigned DiagID = isInvalid == 1 ? diag::err_invalid_decl_spec_combination
+ : diag::ext_duplicate_declspec;
+ Diag(Tok, DiagID) << PrevSpec;
+ }
+ DS.SetRangeEnd(Tok.getLocation());
+ ConsumeToken();
+ }
+}
+
+/// ParseOptionalTypeSpecifier - Try to parse a single type-specifier. We
+/// primarily follow the C++ grammar with additions for C99 and GNU,
+/// which together subsume the C grammar. Note that the C++
+/// type-specifier also includes the C type-qualifier (for const,
+/// volatile, and C99 restrict). Returns true if a type-specifier was
+/// found (and parsed), false otherwise.
+///
+/// type-specifier: [C++ 7.1.5]
+/// simple-type-specifier
+/// class-specifier
+/// enum-specifier
+/// elaborated-type-specifier [TODO]
+/// cv-qualifier
+///
+/// cv-qualifier: [C++ 7.1.5.1]
+/// 'const'
+/// 'volatile'
+/// [C99] 'restrict'
+///
+/// simple-type-specifier: [ C++ 7.1.5.2]
+/// '::'[opt] nested-name-specifier[opt] type-name [TODO]
+/// '::'[opt] nested-name-specifier 'template' template-id [TODO]
+/// 'char'
+/// 'wchar_t'
+/// 'bool'
+/// 'short'
+/// 'int'
+/// 'long'
+/// 'signed'
+/// 'unsigned'
+/// 'float'
+/// 'double'
+/// 'void'
+/// [C99] '_Bool'
+/// [C99] '_Complex'
+/// [C99] '_Imaginary' // Removed in TC2?
+/// [GNU] '_Decimal32'
+/// [GNU] '_Decimal64'
+/// [GNU] '_Decimal128'
+/// [GNU] typeof-specifier
+/// [OBJC] class-name objc-protocol-refs[opt] [TODO]
+/// [OBJC] typedef-name objc-protocol-refs[opt] [TODO]
+bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid,
+ const char *&PrevSpec,
+ const ParsedTemplateInfo &TemplateInfo) {
+ SourceLocation Loc = Tok.getLocation();
+
+ switch (Tok.getKind()) {
+ case tok::identifier: // foo::bar
+ case tok::kw_typename: // typename foo::bar
+ // Annotate typenames and C++ scope specifiers. If we get one, just
+ // recurse to handle whatever we get.
+ if (TryAnnotateTypeOrScopeToken())
+ return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, TemplateInfo);
+ // Otherwise, not a type specifier.
+ return false;
+ case tok::coloncolon: // ::foo::bar
+ if (NextToken().is(tok::kw_new) || // ::new
+ NextToken().is(tok::kw_delete)) // ::delete
+ return false;
+
+ // Annotate typenames and C++ scope specifiers. If we get one, just
+ // recurse to handle whatever we get.
+ if (TryAnnotateTypeOrScopeToken())
+ return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, TemplateInfo);
+ // Otherwise, not a type specifier.
+ return false;
+
+ // simple-type-specifier:
+ case tok::annot_typename: {
+ if (Tok.getAnnotationValue())
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
+ Tok.getAnnotationValue());
+ else
+ DS.SetTypeSpecError();
+ DS.SetRangeEnd(Tok.getAnnotationEndLoc());
+ ConsumeToken(); // The typename
+
+ // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
+ // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
+ // Objective-C interface. If we don't have Objective-C or a '<', this is
+ // just a normal reference to a typedef name.
+ if (!Tok.is(tok::less) || !getLang().ObjC1)
+ return true;
+
+ SourceLocation EndProtoLoc;
+ llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl;
+ ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc);
+ DS.setProtocolQualifiers(&ProtocolDecl[0], ProtocolDecl.size());
+
+ DS.SetRangeEnd(EndProtoLoc);
+ return true;
+ }
+
+ case tok::kw_short:
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec);
+ break;
+ case tok::kw_long:
+ if (DS.getTypeSpecWidth() != DeclSpec::TSW_long)
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec);
+ else
+ isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec);
+ break;
+ case tok::kw_signed:
+ isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec);
+ break;
+ case tok::kw_unsigned:
+ isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec);
+ break;
+ case tok::kw__Complex:
+ isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec);
+ break;
+ case tok::kw__Imaginary:
+ isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec);
+ break;
+ case tok::kw_void:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec);
+ break;
+ case tok::kw_char:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec);
+ break;
+ case tok::kw_int:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec);
+ break;
+ case tok::kw_float:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec);
+ break;
+ case tok::kw_double:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec);
+ break;
+ case tok::kw_wchar_t:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec);
+ break;
+ case tok::kw_bool:
+ case tok::kw__Bool:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec);
+ break;
+ case tok::kw__Decimal32:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec);
+ break;
+ case tok::kw__Decimal64:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec);
+ break;
+ case tok::kw__Decimal128:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec);
+ break;
+
+ // class-specifier:
+ case tok::kw_class:
+ case tok::kw_struct:
+ case tok::kw_union: {
+ tok::TokenKind Kind = Tok.getKind();
+ ConsumeToken();
+ ParseClassSpecifier(Kind, Loc, DS, TemplateInfo);
+ return true;
+ }
+
+ // enum-specifier:
+ case tok::kw_enum:
+ ConsumeToken();
+ ParseEnumSpecifier(Loc, DS);
+ return true;
+
+ // cv-qualifier:
+ case tok::kw_const:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec,
+ getLang())*2;
+ break;
+ case tok::kw_volatile:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec,
+ getLang())*2;
+ break;
+ case tok::kw_restrict:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec,
+ getLang())*2;
+ break;
+
+ // GNU typeof support.
+ case tok::kw_typeof:
+ ParseTypeofSpecifier(DS);
+ return true;
+
+ case tok::kw___cdecl:
+ case tok::kw___stdcall:
+ case tok::kw___fastcall:
+ if (!PP.getLangOptions().Microsoft) return false;
+ ConsumeToken();
+ return true;
+
+ default:
+ // Not a type-specifier; do nothing.
+ return false;
+ }
+
+ // If the specifier combination wasn't legal, issue a diagnostic.
+ if (isInvalid) {
+ assert(PrevSpec && "Method did not return previous specifier!");
+ // Pick between error or extwarn.
+ unsigned DiagID = isInvalid == 1 ? diag::err_invalid_decl_spec_combination
+ : diag::ext_duplicate_declspec;
+ Diag(Tok, DiagID) << PrevSpec;
+ }
+ DS.SetRangeEnd(Tok.getLocation());
+ ConsumeToken(); // whatever we parsed above.
+ return true;
+}
+
+/// ParseStructDeclaration - Parse a struct declaration without the terminating
+/// semicolon.
+///
+/// struct-declaration:
+/// specifier-qualifier-list struct-declarator-list
+/// [GNU] __extension__ struct-declaration
+/// [GNU] specifier-qualifier-list
+/// struct-declarator-list:
+/// struct-declarator
+/// struct-declarator-list ',' struct-declarator
+/// [GNU] struct-declarator-list ',' attributes[opt] struct-declarator
+/// struct-declarator:
+/// declarator
+/// [GNU] declarator attributes[opt]
+/// declarator[opt] ':' constant-expression
+/// [GNU] declarator[opt] ':' constant-expression attributes[opt]
+///
+void Parser::
+ParseStructDeclaration(DeclSpec &DS,
+ llvm::SmallVectorImpl<FieldDeclarator> &Fields) {
+ if (Tok.is(tok::kw___extension__)) {
+ // __extension__ silences extension warnings in the subexpression.
+ ExtensionRAIIObject O(Diags); // Use RAII to do this.
+ ConsumeToken();
+ return ParseStructDeclaration(DS, Fields);
+ }
+
+ // Parse the common specifier-qualifiers-list piece.
+ SourceLocation DSStart = Tok.getLocation();
+ ParseSpecifierQualifierList(DS);
+
+ // If there are no declarators, this is a free-standing declaration
+ // specifier. Let the actions module cope with it.
+ if (Tok.is(tok::semi)) {
+ Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ return;
+ }
+
+ // Read struct-declarators until we find the semicolon.
+ Fields.push_back(FieldDeclarator(DS));
+ while (1) {
+ FieldDeclarator &DeclaratorInfo = Fields.back();
+
+ /// struct-declarator: declarator
+ /// struct-declarator: declarator[opt] ':' constant-expression
+ if (Tok.isNot(tok::colon))
+ ParseDeclarator(DeclaratorInfo.D);
+
+ if (Tok.is(tok::colon)) {
+ ConsumeToken();
+ OwningExprResult Res(ParseConstantExpression());
+ if (Res.isInvalid())
+ SkipUntil(tok::semi, true, true);
+ else
+ DeclaratorInfo.BitfieldSize = Res.release();
+ }
+
+ // If attributes exist after the declarator, parse them.
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ DeclaratorInfo.D.AddAttributes(AttrList, Loc);
+ }
+
+ // 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))
+ return;
+
+ // 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);
+ }
+ }
+}
+
+/// ParseStructUnionBody
+/// struct-contents:
+/// struct-declaration-list
+/// [EXT] empty
+/// [GNU] "struct-declaration-list" without terminatoring ';'
+/// struct-declaration-list:
+/// struct-declaration
+/// struct-declaration-list struct-declaration
+/// [OBC] '@' 'defs' '(' class-name ')'
+///
+void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
+ unsigned TagType, DeclPtrTy TagDecl) {
+ PrettyStackTraceActionsDecl CrashInfo(TagDecl, RecordLoc, Actions,
+ PP.getSourceManager(),
+ "parsing struct/union body");
+
+ SourceLocation LBraceLoc = ConsumeBrace();
+
+ ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope);
+ Actions.ActOnTagStartDefinition(CurScope, TagDecl);
+
+ // Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in
+ // C++.
+ if (Tok.is(tok::r_brace) && !getLang().CPlusPlus)
+ Diag(Tok, diag::ext_empty_struct_union_enum)
+ << 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)) {
+ // Each iteration of this loop reads one struct-declaration.
+
+ // Check for extraneous top-level semicolon.
+ if (Tok.is(tok::semi)) {
+ Diag(Tok, diag::ext_extra_struct_semi)
+ << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation()));
+ ConsumeToken();
+ continue;
+ }
+
+ // 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];
+ // Install the declarator into the current TagDecl.
+ DeclPtrTy Field = Actions.ActOnField(CurScope, TagDecl,
+ DS.getSourceRange().getBegin(),
+ FD.D, FD.BitfieldSize);
+ FieldDecls.push_back(Field);
+ }
+ } else { // Handle @defs
+ ConsumeToken();
+ if (!Tok.isObjCAtKeyword(tok::objc_defs)) {
+ Diag(Tok, diag::err_unexpected_at);
+ SkipUntil(tok::semi, true, true);
+ continue;
+ }
+ ConsumeToken();
+ ExpectAndConsume(tok::l_paren, diag::err_expected_lparen);
+ if (!Tok.is(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::semi, true, true);
+ continue;
+ }
+ llvm::SmallVector<DeclPtrTy, 16> Fields;
+ Actions.ActOnDefs(CurScope, TagDecl, Tok.getLocation(),
+ Tok.getIdentifierInfo(), Fields);
+ FieldDecls.insert(FieldDecls.end(), Fields.begin(), Fields.end());
+ ConsumeToken();
+ ExpectAndConsume(tok::r_paren, diag::err_expected_rparen);
+ }
+
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ } else if (Tok.is(tok::r_brace)) {
+ Diag(Tok, diag::ext_expected_semi_decl_list);
+ break;
+ } else {
+ Diag(Tok, diag::err_expected_semi_decl_list);
+ // Skip to end of block or statement
+ SkipUntil(tok::r_brace, true, true);
+ }
+ }
+
+ SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
+
+ AttributeList *AttrList = 0;
+ // If attributes exist after struct contents, parse them.
+ if (Tok.is(tok::kw___attribute))
+ AttrList = ParseAttributes();
+
+ Actions.ActOnFields(CurScope,
+ RecordLoc, TagDecl, FieldDecls.data(), FieldDecls.size(),
+ LBraceLoc, RBraceLoc,
+ AttrList);
+ StructScope.Exit();
+ Actions.ActOnTagFinishDefinition(CurScope, TagDecl);
+}
+
+
+/// ParseEnumSpecifier
+/// enum-specifier: [C99 6.7.2.2]
+/// 'enum' identifier[opt] '{' enumerator-list '}'
+///[C99/C++]'enum' identifier[opt] '{' enumerator-list ',' '}'
+/// [GNU] 'enum' attributes[opt] identifier[opt] '{' enumerator-list ',' [opt]
+/// '}' attributes[opt]
+/// 'enum' identifier
+/// [GNU] 'enum' attributes[opt] identifier
+///
+/// [C++] elaborated-type-specifier:
+/// [C++] 'enum' '::'[opt] nested-name-specifier[opt] identifier
+///
+void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
+ AccessSpecifier AS) {
+ // Parse the tag portion of this.
+
+ AttributeList *Attr = 0;
+ // If attributes exist after tag, parse them.
+ if (Tok.is(tok::kw___attribute))
+ Attr = ParseAttributes();
+
+ CXXScopeSpec SS;
+ if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS)) {
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ if (Tok.isNot(tok::l_brace)) {
+ // Has no name and is not a definition.
+ // Skip the rest of this declarator, up until the comma or semicolon.
+ SkipUntil(tok::comma, true);
+ return;
+ }
+ }
+ }
+
+ // Must have either 'enum name' or 'enum {...}'.
+ if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace)) {
+ Diag(Tok, diag::err_expected_ident_lbrace);
+
+ // Skip the rest of this declarator, up until the comma or semicolon.
+ SkipUntil(tok::comma, true);
+ return;
+ }
+
+ // If an identifier is present, consume and remember it.
+ IdentifierInfo *Name = 0;
+ SourceLocation NameLoc;
+ if (Tok.is(tok::identifier)) {
+ Name = Tok.getIdentifierInfo();
+ NameLoc = ConsumeToken();
+ }
+
+ // There are three options here. If we have 'enum foo;', then this is a
+ // forward declaration. If we have 'enum foo {...' then this is a
+ // definition. Otherwise we have something like 'enum foo xyz', a reference.
+ //
+ // This is needed to handle stuff like this right (C99 6.7.2.3p11):
+ // enum foo {..}; void bar() { enum foo; } <- new foo in bar.
+ // enum foo {..}; void bar() { enum foo x; } <- use of old foo.
+ //
+ Action::TagKind TK;
+ if (Tok.is(tok::l_brace))
+ TK = Action::TK_Definition;
+ else if (Tok.is(tok::semi))
+ TK = Action::TK_Declaration;
+ else
+ TK = Action::TK_Reference;
+ bool Owned = false;
+ DeclPtrTy TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TK,
+ StartLoc, SS, Name, NameLoc, Attr, AS,
+ Owned);
+
+ if (Tok.is(tok::l_brace))
+ ParseEnumBody(StartLoc, TagDecl);
+
+ // TODO: semantic analysis on the declspec for enums.
+ const char *PrevSpec = 0;
+ if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, PrevSpec,
+ TagDecl.getAs<void>(), Owned))
+ Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
+}
+
+/// ParseEnumBody - Parse a {} enclosed enumerator-list.
+/// enumerator-list:
+/// enumerator
+/// enumerator-list ',' enumerator
+/// enumerator:
+/// enumeration-constant
+/// enumeration-constant '=' constant-expression
+/// enumeration-constant:
+/// identifier
+///
+void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) {
+ // Enter the scope of the enum body and start the definition.
+ ParseScope EnumScope(this, Scope::DeclScope);
+ Actions.ActOnTagStartDefinition(CurScope, EnumDecl);
+
+ SourceLocation LBraceLoc = ConsumeBrace();
+
+ // C does not allow an empty enumerator-list, C++ does [dcl.enum].
+ if (Tok.is(tok::r_brace) && !getLang().CPlusPlus)
+ Diag(Tok, diag::ext_empty_struct_union_enum) << "enum";
+
+ llvm::SmallVector<DeclPtrTy, 32> EnumConstantDecls;
+
+ DeclPtrTy LastEnumConstDecl;
+
+ // Parse the enumerator-list.
+ while (Tok.is(tok::identifier)) {
+ IdentifierInfo *Ident = Tok.getIdentifierInfo();
+ SourceLocation IdentLoc = ConsumeToken();
+
+ SourceLocation EqualLoc;
+ OwningExprResult AssignedVal(Actions);
+ if (Tok.is(tok::equal)) {
+ EqualLoc = ConsumeToken();
+ AssignedVal = ParseConstantExpression();
+ if (AssignedVal.isInvalid())
+ SkipUntil(tok::comma, tok::r_brace, true, true);
+ }
+
+ // Install the enumerator constant into EnumDecl.
+ DeclPtrTy EnumConstDecl = Actions.ActOnEnumConstant(CurScope, EnumDecl,
+ LastEnumConstDecl,
+ IdentLoc, Ident,
+ EqualLoc,
+ AssignedVal.release());
+ EnumConstantDecls.push_back(EnumConstDecl);
+ LastEnumConstDecl = EnumConstDecl;
+
+ if (Tok.isNot(tok::comma))
+ break;
+ SourceLocation CommaLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::identifier) &&
+ !(getLang().C99 || getLang().CPlusPlus0x))
+ Diag(CommaLoc, diag::ext_enumerator_list_comma)
+ << getLang().CPlusPlus
+ << CodeModificationHint::CreateRemoval((SourceRange(CommaLoc)));
+ }
+
+ // Eat the }.
+ SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
+
+ Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl,
+ EnumConstantDecls.data(), EnumConstantDecls.size());
+
+ Action::AttrTy *AttrList = 0;
+ // If attributes exist after the identifier list, parse them.
+ if (Tok.is(tok::kw___attribute))
+ AttrList = ParseAttributes(); // FIXME: where do they do?
+
+ EnumScope.Exit();
+ Actions.ActOnTagFinishDefinition(CurScope, EnumDecl);
+}
+
+/// isTypeSpecifierQualifier - Return true if the current token could be the
+/// start of a type-qualifier-list.
+bool Parser::isTypeQualifier() const {
+ switch (Tok.getKind()) {
+ default: return false;
+ // type-qualifier
+ case tok::kw_const:
+ case tok::kw_volatile:
+ case tok::kw_restrict:
+ return true;
+ }
+}
+
+/// isTypeSpecifierQualifier - Return true if the current token could be the
+/// start of a specifier-qualifier-list.
+bool Parser::isTypeSpecifierQualifier() {
+ switch (Tok.getKind()) {
+ default: return false;
+
+ case tok::identifier: // foo::bar
+ case tok::kw_typename: // typename T::type
+ // Annotate typenames and C++ scope specifiers. If we get one, just
+ // recurse to handle whatever we get.
+ if (TryAnnotateTypeOrScopeToken())
+ return isTypeSpecifierQualifier();
+ // Otherwise, not a type specifier.
+ return false;
+
+ case tok::coloncolon: // ::foo::bar
+ if (NextToken().is(tok::kw_new) || // ::new
+ NextToken().is(tok::kw_delete)) // ::delete
+ return false;
+
+ // Annotate typenames and C++ scope specifiers. If we get one, just
+ // recurse to handle whatever we get.
+ if (TryAnnotateTypeOrScopeToken())
+ return isTypeSpecifierQualifier();
+ // Otherwise, not a type specifier.
+ return false;
+
+ // GNU attributes support.
+ case tok::kw___attribute:
+ // GNU typeof support.
+ case tok::kw_typeof:
+
+ // type-specifiers
+ case tok::kw_short:
+ case tok::kw_long:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw__Complex:
+ case tok::kw__Imaginary:
+ case tok::kw_void:
+ case tok::kw_char:
+ case tok::kw_wchar_t:
+ case tok::kw_int:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_bool:
+ case tok::kw__Bool:
+ case tok::kw__Decimal32:
+ case tok::kw__Decimal64:
+ case tok::kw__Decimal128:
+
+ // struct-or-union-specifier (C99) or class-specifier (C++)
+ case tok::kw_class:
+ case tok::kw_struct:
+ case tok::kw_union:
+ // enum-specifier
+ case tok::kw_enum:
+
+ // type-qualifier
+ case tok::kw_const:
+ case tok::kw_volatile:
+ case tok::kw_restrict:
+
+ // typedef-name
+ case tok::annot_typename:
+ return true;
+
+ // GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'.
+ case tok::less:
+ return getLang().ObjC1;
+
+ case tok::kw___cdecl:
+ case tok::kw___stdcall:
+ case tok::kw___fastcall:
+ return PP.getLangOptions().Microsoft;
+ }
+}
+
+/// isDeclarationSpecifier() - Return true if the current token is part of a
+/// declaration specifier.
+bool Parser::isDeclarationSpecifier() {
+ switch (Tok.getKind()) {
+ default: return false;
+
+ case tok::identifier: // foo::bar
+ // Unfortunate hack to support "Class.factoryMethod" notation.
+ if (getLang().ObjC1 && NextToken().is(tok::period))
+ return false;
+ // Fall through
+
+ case tok::kw_typename: // typename T::type
+ // Annotate typenames and C++ scope specifiers. If we get one, just
+ // recurse to handle whatever we get.
+ if (TryAnnotateTypeOrScopeToken())
+ return isDeclarationSpecifier();
+ // Otherwise, not a declaration specifier.
+ return false;
+ case tok::coloncolon: // ::foo::bar
+ if (NextToken().is(tok::kw_new) || // ::new
+ NextToken().is(tok::kw_delete)) // ::delete
+ return false;
+
+ // Annotate typenames and C++ scope specifiers. If we get one, just
+ // recurse to handle whatever we get.
+ if (TryAnnotateTypeOrScopeToken())
+ return isDeclarationSpecifier();
+ // Otherwise, not a declaration specifier.
+ return false;
+
+ // storage-class-specifier
+ case tok::kw_typedef:
+ case tok::kw_extern:
+ case tok::kw___private_extern__:
+ case tok::kw_static:
+ case tok::kw_auto:
+ case tok::kw_register:
+ case tok::kw___thread:
+
+ // type-specifiers
+ case tok::kw_short:
+ case tok::kw_long:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw__Complex:
+ case tok::kw__Imaginary:
+ case tok::kw_void:
+ case tok::kw_char:
+ case tok::kw_wchar_t:
+ case tok::kw_int:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_bool:
+ case tok::kw__Bool:
+ case tok::kw__Decimal32:
+ case tok::kw__Decimal64:
+ case tok::kw__Decimal128:
+
+ // struct-or-union-specifier (C99) or class-specifier (C++)
+ case tok::kw_class:
+ case tok::kw_struct:
+ case tok::kw_union:
+ // enum-specifier
+ case tok::kw_enum:
+
+ // type-qualifier
+ case tok::kw_const:
+ case tok::kw_volatile:
+ case tok::kw_restrict:
+
+ // function-specifier
+ case tok::kw_inline:
+ case tok::kw_virtual:
+ case tok::kw_explicit:
+
+ // typedef-name
+ case tok::annot_typename:
+
+ // GNU typeof support.
+ case tok::kw_typeof:
+
+ // GNU attributes.
+ case tok::kw___attribute:
+ return true;
+
+ // GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'.
+ case tok::less:
+ return getLang().ObjC1;
+
+ case tok::kw___declspec:
+ case tok::kw___cdecl:
+ case tok::kw___stdcall:
+ case tok::kw___fastcall:
+ return PP.getLangOptions().Microsoft;
+ }
+}
+
+
+/// ParseTypeQualifierListOpt
+/// type-qualifier-list: [C99 6.7.5]
+/// type-qualifier
+/// [GNU] attributes [ only if AttributesAllowed=true ]
+/// type-qualifier-list type-qualifier
+/// [GNU] type-qualifier-list attributes [ only if AttributesAllowed=true ]
+///
+void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed) {
+ while (1) {
+ int isInvalid = false;
+ const char *PrevSpec = 0;
+ SourceLocation Loc = Tok.getLocation();
+
+ switch (Tok.getKind()) {
+ case tok::kw_const:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec,
+ getLang())*2;
+ break;
+ case tok::kw_volatile:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec,
+ getLang())*2;
+ break;
+ case tok::kw_restrict:
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec,
+ getLang())*2;
+ break;
+ case tok::kw___ptr64:
+ case tok::kw___cdecl:
+ case tok::kw___stdcall:
+ case tok::kw___fastcall:
+ if (!PP.getLangOptions().Microsoft)
+ goto DoneWithTypeQuals;
+ // Just ignore it.
+ break;
+ case tok::kw___attribute:
+ if (AttributesAllowed) {
+ DS.AddAttributes(ParseAttributes());
+ continue; // do *not* consume the next token!
+ }
+ // otherwise, FALL THROUGH!
+ default:
+ DoneWithTypeQuals:
+ // If this is not a type-qualifier token, we're done reading type
+ // qualifiers. First verify that DeclSpec's are consistent.
+ DS.Finish(Diags, PP);
+ return;
+ }
+
+ // If the specifier combination wasn't legal, issue a diagnostic.
+ if (isInvalid) {
+ assert(PrevSpec && "Method did not return previous specifier!");
+ // Pick between error or extwarn.
+ unsigned DiagID = isInvalid == 1 ? diag::err_invalid_decl_spec_combination
+ : diag::ext_duplicate_declspec;
+ Diag(Tok, DiagID) << PrevSpec;
+ }
+ ConsumeToken();
+ }
+}
+
+
+/// ParseDeclarator - Parse and verify a newly-initialized declarator.
+///
+void Parser::ParseDeclarator(Declarator &D) {
+ /// This implements the 'declarator' production in the C grammar, then checks
+ /// for well-formedness and issues diagnostics.
+ ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator);
+}
+
+/// ParseDeclaratorInternal - Parse a C or C++ declarator. The direct-declarator
+/// is parsed by the function passed to it. Pass null, and the direct-declarator
+/// isn't parsed at all, making this function effectively parse the C++
+/// ptr-operator production.
+///
+/// declarator: [C99 6.7.5] [C++ 8p4, dcl.decl]
+/// [C] pointer[opt] direct-declarator
+/// [C++] direct-declarator
+/// [C++] ptr-operator declarator
+///
+/// pointer: [C99 6.7.5]
+/// '*' type-qualifier-list[opt]
+/// '*' type-qualifier-list[opt] pointer
+///
+/// ptr-operator:
+/// '*' cv-qualifier-seq[opt]
+/// '&'
+/// [C++0x] '&&'
+/// [GNU] '&' restrict[opt] attributes[opt]
+/// [GNU?] '&&' restrict[opt] attributes[opt]
+/// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt]
+void Parser::ParseDeclaratorInternal(Declarator &D,
+ DirectDeclParseFunction DirectDeclParser) {
+
+ // C++ member pointers start with a '::' or a nested-name.
+ // Member pointers get special handling, since there's no place for the
+ // scope spec in the generic path below.
+ if (getLang().CPlusPlus &&
+ (Tok.is(tok::coloncolon) || Tok.is(tok::identifier) ||
+ Tok.is(tok::annot_cxxscope))) {
+ CXXScopeSpec SS;
+ if (ParseOptionalCXXScopeSpecifier(SS)) {
+ if(Tok.isNot(tok::star)) {
+ // The scope spec really belongs to the direct-declarator.
+ D.getCXXScopeSpec() = SS;
+ if (DirectDeclParser)
+ (this->*DirectDeclParser)(D);
+ return;
+ }
+
+ SourceLocation Loc = ConsumeToken();
+ D.SetRangeEnd(Loc);
+ DeclSpec DS;
+ ParseTypeQualifierListOpt(DS);
+ D.ExtendWithDeclSpec(DS);
+
+ // Recurse to parse whatever is left.
+ ParseDeclaratorInternal(D, DirectDeclParser);
+
+ // Sema will have to catch (syntactically invalid) pointers into global
+ // scope. It has to catch pointers into namespace scope anyway.
+ D.AddTypeInfo(DeclaratorChunk::getMemberPointer(SS,DS.getTypeQualifiers(),
+ Loc, DS.TakeAttributes()),
+ /* Don't replace range end. */SourceLocation());
+ return;
+ }
+ }
+
+ tok::TokenKind Kind = Tok.getKind();
+ // Not a pointer, C++ reference, or block.
+ if (Kind != tok::star && Kind != tok::caret &&
+ (Kind != tok::amp || !getLang().CPlusPlus) &&
+ // We parse rvalue refs in C++03, because otherwise the errors are scary.
+ (Kind != tok::ampamp || !getLang().CPlusPlus)) {
+ if (DirectDeclParser)
+ (this->*DirectDeclParser)(D);
+ return;
+ }
+
+ // Otherwise, '*' -> pointer, '^' -> block, '&' -> lvalue reference,
+ // '&&' -> rvalue reference
+ SourceLocation Loc = ConsumeToken(); // Eat the *, ^, & or &&.
+ D.SetRangeEnd(Loc);
+
+ if (Kind == tok::star || Kind == tok::caret) {
+ // Is a pointer.
+ DeclSpec DS;
+
+ ParseTypeQualifierListOpt(DS);
+ D.ExtendWithDeclSpec(DS);
+
+ // Recursively parse the declarator.
+ ParseDeclaratorInternal(D, DirectDeclParser);
+ if (Kind == tok::star)
+ // Remember that we parsed a pointer type, and remember the type-quals.
+ D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc,
+ DS.TakeAttributes()),
+ SourceLocation());
+ else
+ // Remember that we parsed a Block type, and remember the type-quals.
+ D.AddTypeInfo(DeclaratorChunk::getBlockPointer(DS.getTypeQualifiers(),
+ Loc, DS.TakeAttributes()),
+ SourceLocation());
+ } else {
+ // Is a reference
+ DeclSpec DS;
+
+ // Complain about rvalue references in C++03, but then go on and build
+ // the declarator.
+ if (Kind == tok::ampamp && !getLang().CPlusPlus0x)
+ Diag(Loc, diag::err_rvalue_reference);
+
+ // C++ 8.3.2p1: cv-qualified references are ill-formed except when the
+ // cv-qualifiers are introduced through the use of a typedef or of a
+ // template type argument, in which case the cv-qualifiers are ignored.
+ //
+ // [GNU] Retricted references are allowed.
+ // [GNU] Attributes on references are allowed.
+ ParseTypeQualifierListOpt(DS);
+ D.ExtendWithDeclSpec(DS);
+
+ if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) {
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
+ Diag(DS.getConstSpecLoc(),
+ diag::err_invalid_reference_qualifier_application) << "const";
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
+ Diag(DS.getVolatileSpecLoc(),
+ diag::err_invalid_reference_qualifier_application) << "volatile";
+ }
+
+ // Recursively parse the declarator.
+ ParseDeclaratorInternal(D, DirectDeclParser);
+
+ if (D.getNumTypeObjects() > 0) {
+ // C++ [dcl.ref]p4: There shall be no references to references.
+ DeclaratorChunk& InnerChunk = D.getTypeObject(D.getNumTypeObjects() - 1);
+ if (InnerChunk.Kind == DeclaratorChunk::Reference) {
+ if (const IdentifierInfo *II = D.getIdentifier())
+ Diag(InnerChunk.Loc, diag::err_illegal_decl_reference_to_reference)
+ << II;
+ else
+ Diag(InnerChunk.Loc, diag::err_illegal_decl_reference_to_reference)
+ << "type name";
+
+ // Once we've complained about the reference-to-reference, we
+ // can go ahead and build the (technically ill-formed)
+ // declarator: reference collapsing will take care of it.
+ }
+ }
+
+ // Remember that we parsed a reference type. It doesn't have type-quals.
+ D.AddTypeInfo(DeclaratorChunk::getReference(DS.getTypeQualifiers(), Loc,
+ DS.TakeAttributes(),
+ Kind == tok::amp),
+ SourceLocation());
+ }
+}
+
+/// ParseDirectDeclarator
+/// direct-declarator: [C99 6.7.5]
+/// [C99] identifier
+/// '(' declarator ')'
+/// [GNU] '(' attributes declarator ')'
+/// [C90] direct-declarator '[' constant-expression[opt] ']'
+/// [C99] direct-declarator '[' type-qual-list[opt] assignment-expr[opt] ']'
+/// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']'
+/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']'
+/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']'
+/// direct-declarator '(' parameter-type-list ')'
+/// direct-declarator '(' identifier-list[opt] ')'
+/// [GNU] direct-declarator '(' parameter-forward-declarations
+/// parameter-type-list[opt] ')'
+/// [C++] direct-declarator '(' parameter-declaration-clause ')'
+/// cv-qualifier-seq[opt] exception-specification[opt]
+/// [C++] declarator-id
+///
+/// declarator-id: [C++ 8]
+/// id-expression
+/// '::'[opt] nested-name-specifier[opt] type-name
+///
+/// id-expression: [C++ 5.1]
+/// unqualified-id
+/// qualified-id [TODO]
+///
+/// unqualified-id: [C++ 5.1]
+/// identifier
+/// operator-function-id
+/// conversion-function-id [TODO]
+/// '~' class-name
+/// template-id
+///
+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());
+ 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)) {
+ D.setConstructor(Actions.getTypeName(*Tok.getIdentifierInfo(),
+ Tok.getLocation(), CurScope),
+ 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());
+
+ // FIXME: Could this template-id name a constructor?
+
+ // FIXME: This is an egregious hack, where we silently ignore
+ // the specialization (which should be a function template
+ // specialization name) and use the name instead. This hack
+ // will go away when we have support for function
+ // specializations.
+ D.SetIdentifier(TemplateId->Name, Tok.getLocation());
+ TemplateId->Destroy();
+ 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)) {
+ // FIXME: Inaccurate.
+ SourceLocation NameLoc = Tok.getLocation();
+ SourceLocation EndLoc;
+ TypeResult Type = ParseClassName(EndLoc);
+ if (Type.isInvalid())
+ D.SetIdentifier(0, TildeLoc);
+ else
+ D.setDestructor(Type.get(), TildeLoc, NameLoc);
+ } else {
+ Diag(Tok, diag::err_expected_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);
+ D.SetIdentifier(0, Tok.getLocation());
+ D.setInvalidType(true);
+ 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()) {
+ 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)) {
+ // direct-declarator: '(' declarator ')'
+ // direct-declarator: '(' attributes declarator ')'
+ // Example: 'char (*X)' or 'int (*XX)(void)'
+ ParseParenDeclarator(D);
+ } else if (D.mayOmitIdentifier()) {
+ // This could be something simple like "int" (in which case the declarator
+ // portion is empty), if an abstract-declarator is allowed.
+ D.SetIdentifier(0, Tok.getLocation());
+ } else {
+ if (D.getContext() == Declarator::MemberContext)
+ Diag(Tok, diag::err_expected_member_name_or_semi)
+ << D.getDeclSpec().getSourceRange();
+ else if (getLang().CPlusPlus)
+ Diag(Tok, diag::err_expected_unqualified_id);
+ else
+ Diag(Tok, diag::err_expected_ident_lparen);
+ D.SetIdentifier(0, Tok.getLocation());
+ D.setInvalidType(true);
+ }
+
+ PastIdentifier:
+ assert(D.isPastIdentifier() &&
+ "Haven't past the location of the identifier yet?");
+
+ while (1) {
+ if (Tok.is(tok::l_paren)) {
+ // The paren may be part of a C++ direct initializer, eg. "int x(1);".
+ // In such a case, check if we actually have a function declarator; if it
+ // is not, the declarator has been fully parsed.
+ if (getLang().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) {
+ // When not in file scope, warn for ambiguous function declarators, just
+ // in case the author intended it as a variable definition.
+ bool warnIfAmbiguous = D.getContext() != Declarator::FileContext;
+ if (!isCXXFunctionDeclarator(warnIfAmbiguous))
+ break;
+ }
+ ParseFunctionDeclarator(ConsumeParen(), D);
+ } else if (Tok.is(tok::l_square)) {
+ ParseBracketDeclarator(D);
+ } else {
+ break;
+ }
+ }
+}
+
+/// ParseParenDeclarator - We parsed the declarator D up to a paren. This is
+/// only called before the identifier, so these are most likely just grouping
+/// parens for precedence. If we find that these are actually function
+/// parameter parens in an abstract-declarator, we call ParseFunctionDeclarator.
+///
+/// direct-declarator:
+/// '(' declarator ')'
+/// [GNU] '(' attributes declarator ')'
+/// direct-declarator '(' parameter-type-list ')'
+/// direct-declarator '(' identifier-list[opt] ')'
+/// [GNU] direct-declarator '(' parameter-forward-declarations
+/// parameter-type-list[opt] ')'
+///
+void Parser::ParseParenDeclarator(Declarator &D) {
+ SourceLocation StartLoc = ConsumeParen();
+ assert(!D.isPastIdentifier() && "Should be called before passing identifier");
+
+ // Eat any attributes before we look at whether this is a grouping or function
+ // declarator paren. If this is a grouping paren, the attribute applies to
+ // the type being built up, for example:
+ // int (__attribute__(()) *x)(long y)
+ // If this ends up not being a grouping paren, the attribute applies to the
+ // first argument, for example:
+ // int (__attribute__(()) int x)
+ // In either case, we need to eat any attributes to be able to determine what
+ // sort of paren this is.
+ //
+ AttributeList *AttrList = 0;
+ bool RequiresArg = false;
+ if (Tok.is(tok::kw___attribute)) {
+ AttrList = ParseAttributes();
+
+ // We require that the argument list (if this is a non-grouping paren) be
+ // present even if the attribute list was empty.
+ RequiresArg = true;
+ }
+ // Eat any Microsoft extensions.
+ while ((Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___stdcall) ||
+ (Tok.is(tok::kw___fastcall))) && PP.getLangOptions().Microsoft)
+ ConsumeToken();
+
+ // If we haven't past the identifier yet (or where the identifier would be
+ // stored, if this is an abstract declarator), then this is probably just
+ // grouping parens. However, if this could be an abstract-declarator, then
+ // this could also be the start of function arguments (consider 'void()').
+ bool isGrouping;
+
+ if (!D.mayOmitIdentifier()) {
+ // If this can't be an abstract-declarator, this *must* be a grouping
+ // paren, because we haven't seen the identifier yet.
+ isGrouping = true;
+ } else if (Tok.is(tok::r_paren) || // 'int()' is a function.
+ (getLang().CPlusPlus && Tok.is(tok::ellipsis)) || // C++ int(...)
+ isDeclarationSpecifier()) { // 'int(int)' is a function.
+ // This handles C99 6.7.5.3p11: in "typedef int X; void foo(X)", X is
+ // considered to be a type, not a K&R identifier-list.
+ isGrouping = false;
+ } else {
+ // Otherwise, this is a grouping paren, e.g. 'int (*X)' or 'int(X)'.
+ isGrouping = true;
+ }
+
+ // If this is a grouping paren, handle:
+ // direct-declarator: '(' declarator ')'
+ // direct-declarator: '(' attributes declarator ')'
+ if (isGrouping) {
+ bool hadGroupingParens = D.hasGroupingParens();
+ D.setGroupingParens(true);
+ if (AttrList)
+ D.AddAttributes(AttrList, SourceLocation());
+
+ ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator);
+ // Match the ')'.
+ SourceLocation Loc = MatchRHSPunctuation(tok::r_paren, StartLoc);
+
+ D.setGroupingParens(hadGroupingParens);
+ D.SetRangeEnd(Loc);
+ return;
+ }
+
+ // Okay, if this wasn't a grouping paren, it must be the start of a function
+ // argument list. Recognize that this declarator will never have an
+ // identifier (and remember where it would have been), then call into
+ // ParseFunctionDeclarator to handle of argument list.
+ D.SetIdentifier(0, Tok.getLocation());
+
+ ParseFunctionDeclarator(StartLoc, D, AttrList, RequiresArg);
+}
+
+/// ParseFunctionDeclarator - We are after the identifier and have parsed the
+/// declarator D up to a paren, which indicates that we are parsing function
+/// arguments.
+///
+/// If AttrList is non-null, then the caller parsed those arguments immediately
+/// after the open paren - they should be considered to be the first argument of
+/// a parameter. If RequiresArg is true, then the first argument of the
+/// function is required to be present and required to not be an identifier
+/// list.
+///
+/// This method also handles this portion of the grammar:
+/// parameter-type-list: [C99 6.7.5]
+/// parameter-list
+/// parameter-list ',' '...'
+///
+/// parameter-list: [C99 6.7.5]
+/// parameter-declaration
+/// parameter-list ',' parameter-declaration
+///
+/// parameter-declaration: [C99 6.7.5]
+/// declaration-specifiers declarator
+/// [C++] declaration-specifiers declarator '=' assignment-expression
+/// [GNU] declaration-specifiers declarator attributes
+/// declaration-specifiers abstract-declarator[opt]
+/// [C++] declaration-specifiers abstract-declarator[opt]
+/// '=' assignment-expression
+/// [GNU] declaration-specifiers abstract-declarator[opt] attributes
+///
+/// For C++, after the parameter-list, it also parses "cv-qualifier-seq[opt]"
+/// and "exception-specification[opt]".
+///
+void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
+ AttributeList *AttrList,
+ bool RequiresArg) {
+ // lparen is already consumed!
+ assert(D.isPastIdentifier() && "Should not call before identifier!");
+
+ // This parameter list may be empty.
+ if (Tok.is(tok::r_paren)) {
+ if (RequiresArg) {
+ Diag(Tok, diag::err_argument_required_after_attribute);
+ delete AttrList;
+ }
+
+ SourceLocation Loc = ConsumeParen(); // Eat the closing ')'.
+
+ // cv-qualifier-seq[opt].
+ DeclSpec DS;
+ bool hasExceptionSpec = false;
+ SourceLocation ThrowLoc;
+ bool hasAnyExceptionSpec = false;
+ llvm::SmallVector<TypeTy*, 2> Exceptions;
+ llvm::SmallVector<SourceRange, 2> ExceptionRanges;
+ if (getLang().CPlusPlus) {
+ ParseTypeQualifierListOpt(DS, false /*no attributes*/);
+ if (!DS.getSourceRange().getEnd().isInvalid())
+ Loc = DS.getSourceRange().getEnd();
+
+ // Parse exception-specification[opt].
+ if (Tok.is(tok::kw_throw)) {
+ hasExceptionSpec = true;
+ ThrowLoc = Tok.getLocation();
+ ParseExceptionSpecification(Loc, Exceptions, ExceptionRanges,
+ hasAnyExceptionSpec);
+ assert(Exceptions.size() == ExceptionRanges.size() &&
+ "Produced different number of exception types and ranges.");
+ }
+ }
+
+ // Remember that we parsed a function type, and remember the attributes.
+ // int() -> no prototype, no '...'.
+ D.AddTypeInfo(DeclaratorChunk::getFunction(/*prototype*/getLang().CPlusPlus,
+ /*variadic*/ false,
+ SourceLocation(),
+ /*arglist*/ 0, 0,
+ DS.getTypeQualifiers(),
+ hasExceptionSpec, ThrowLoc,
+ hasAnyExceptionSpec,
+ Exceptions.data(),
+ ExceptionRanges.data(),
+ Exceptions.size(),
+ LParenLoc, D),
+ Loc);
+ return;
+ }
+
+ // Alternatively, this parameter list may be an identifier list form for a
+ // K&R-style function: void foo(a,b,c)
+ if (!getLang().CPlusPlus && Tok.is(tok::identifier)) {
+ if (!TryAnnotateTypeOrScopeToken()) {
+ // K&R identifier lists can't have typedefs as identifiers, per
+ // C99 6.7.5.3p11.
+ if (RequiresArg) {
+ Diag(Tok, diag::err_argument_required_after_attribute);
+ delete AttrList;
+ }
+ // Identifier list. Note that '(' identifier-list ')' is only allowed for
+ // normal declarators, not for abstract-declarators.
+ return ParseFunctionDeclaratorIdentifierList(LParenLoc, D);
+ }
+ }
+
+ // Finally, a normal, non-empty parameter type list.
+
+ // Build up an array of information about the parsed arguments.
+ llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
+
+ // Enter function-declaration scope, limiting any declarators to the
+ // function prototype scope, including parameter declarators.
+ ParseScope PrototypeScope(this,
+ Scope::FunctionPrototypeScope|Scope::DeclScope);
+
+ bool IsVariadic = false;
+ SourceLocation EllipsisLoc;
+ while (1) {
+ if (Tok.is(tok::ellipsis)) {
+ IsVariadic = true;
+ EllipsisLoc = ConsumeToken(); // Consume the ellipsis.
+ break;
+ }
+
+ SourceLocation DSStart = Tok.getLocation();
+
+ // Parse the declaration-specifiers.
+ DeclSpec DS;
+
+ // If the caller parsed attributes for the first argument, add them now.
+ if (AttrList) {
+ DS.AddAttributes(AttrList);
+ AttrList = 0; // Only apply the attributes to the first parameter.
+ }
+ ParseDeclarationSpecifiers(DS);
+
+ // Parse the declarator. This is "PrototypeContext", because we must
+ // accept either 'declarator' or 'abstract-declarator' here.
+ Declarator ParmDecl(DS, Declarator::PrototypeContext);
+ ParseDeclarator(ParmDecl);
+
+ // Parse GNU attributes, if present.
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ ParmDecl.AddAttributes(AttrList, Loc);
+ }
+
+ // Remember this parsed parameter in ParamInfo.
+ IdentifierInfo *ParmII = ParmDecl.getIdentifier();
+
+ // DefArgToks is used when the parsing of default arguments needs
+ // to be delayed.
+ CachedTokens *DefArgToks = 0;
+
+ // If no parameter was specified, verify that *something* was specified,
+ // otherwise we have a missing type and identifier.
+ if (DS.isEmpty() && ParmDecl.getIdentifier() == 0 &&
+ ParmDecl.getNumTypeObjects() == 0) {
+ // Completely missing, emit error.
+ Diag(DSStart, diag::err_missing_param);
+ } else {
+ // Otherwise, we have something. Add it and let semantic analysis try
+ // to grok it and add the result to the ParamInfo we are building.
+
+ // Inform the actions module about the parameter declarator, so it gets
+ // added to the current scope.
+ DeclPtrTy Param = Actions.ActOnParamDeclarator(CurScope, ParmDecl);
+
+ // Parse the default argument, if any. We parse the default
+ // arguments in all dialects; the semantic analysis in
+ // ActOnParamDefaultArgument will reject the default argument in
+ // C.
+ if (Tok.is(tok::equal)) {
+ SourceLocation EqualLoc = Tok.getLocation();
+
+ // Parse the default argument
+ if (D.getContext() == Declarator::MemberContext) {
+ // If we're inside a class definition, cache the tokens
+ // corresponding to the default argument. We'll actually parse
+ // them when we see the end of the class definition.
+ // FIXME: Templates will require something similar.
+ // FIXME: Can we use a smart pointer for Toks?
+ DefArgToks = new CachedTokens;
+
+ if (!ConsumeAndStoreUntil(tok::comma, tok::r_paren, *DefArgToks,
+ tok::semi, false)) {
+ delete DefArgToks;
+ DefArgToks = 0;
+ Actions.ActOnParamDefaultArgumentError(Param);
+ } else
+ Actions.ActOnParamUnparsedDefaultArgument(Param, EqualLoc);
+ } else {
+ // Consume the '='.
+ ConsumeToken();
+
+ OwningExprResult DefArgResult(ParseAssignmentExpression());
+ if (DefArgResult.isInvalid()) {
+ Actions.ActOnParamDefaultArgumentError(Param);
+ SkipUntil(tok::comma, tok::r_paren, true, true);
+ } else {
+ // Inform the actions module about the default argument
+ Actions.ActOnParamDefaultArgument(Param, EqualLoc,
+ move(DefArgResult));
+ }
+ }
+ }
+
+ ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
+ ParmDecl.getIdentifierLoc(), Param,
+ DefArgToks));
+ }
+
+ // If the next token is a comma, consume it and keep reading arguments.
+ if (Tok.isNot(tok::comma)) break;
+
+ // Consume the comma.
+ ConsumeToken();
+ }
+
+ // Leave prototype scope.
+ PrototypeScope.Exit();
+
+ // If we have the closing ')', eat it.
+ SourceLocation Loc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ DeclSpec DS;
+ bool hasExceptionSpec = false;
+ SourceLocation ThrowLoc;
+ bool hasAnyExceptionSpec = false;
+ llvm::SmallVector<TypeTy*, 2> Exceptions;
+ llvm::SmallVector<SourceRange, 2> ExceptionRanges;
+ if (getLang().CPlusPlus) {
+ // Parse cv-qualifier-seq[opt].
+ ParseTypeQualifierListOpt(DS, false /*no attributes*/);
+ if (!DS.getSourceRange().getEnd().isInvalid())
+ Loc = DS.getSourceRange().getEnd();
+
+ // Parse exception-specification[opt].
+ if (Tok.is(tok::kw_throw)) {
+ hasExceptionSpec = true;
+ ThrowLoc = Tok.getLocation();
+ ParseExceptionSpecification(Loc, Exceptions, ExceptionRanges,
+ hasAnyExceptionSpec);
+ assert(Exceptions.size() == ExceptionRanges.size() &&
+ "Produced different number of exception types and ranges.");
+ }
+ }
+
+ // Remember that we parsed a function type, and remember the attributes.
+ D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/true, IsVariadic,
+ EllipsisLoc,
+ ParamInfo.data(), ParamInfo.size(),
+ DS.getTypeQualifiers(),
+ hasExceptionSpec, ThrowLoc,
+ hasAnyExceptionSpec,
+ Exceptions.data(),
+ ExceptionRanges.data(),
+ Exceptions.size(), LParenLoc, D),
+ Loc);
+}
+
+/// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator
+/// we found a K&R-style identifier list instead of a type argument list. The
+/// current token is known to be the first identifier in the list.
+///
+/// identifier-list: [C99 6.7.5]
+/// identifier
+/// identifier-list ',' identifier
+///
+void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
+ Declarator &D) {
+ // Build up an array of information about the parsed arguments.
+ llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
+ llvm::SmallSet<const IdentifierInfo*, 16> ParamsSoFar;
+
+ // If there was no identifier specified for the declarator, either we are in
+ // an abstract-declarator, or we are in a parameter declarator which was found
+ // to be abstract. In abstract-declarators, identifier lists are not valid:
+ // diagnose this.
+ if (!D.getIdentifier())
+ Diag(Tok, diag::ext_ident_list_in_param);
+
+ // Tok is known to be the first identifier in the list. Remember this
+ // identifier in ParamInfo.
+ ParamsSoFar.insert(Tok.getIdentifierInfo());
+ ParamInfo.push_back(DeclaratorChunk::ParamInfo(Tok.getIdentifierInfo(),
+ Tok.getLocation(),
+ DeclPtrTy()));
+
+ ConsumeToken(); // eat the first identifier.
+
+ while (Tok.is(tok::comma)) {
+ // Eat the comma.
+ ConsumeToken();
+
+ // If this isn't an identifier, report the error and skip until ')'.
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::r_paren);
+ return;
+ }
+
+ IdentifierInfo *ParmII = Tok.getIdentifierInfo();
+
+ // Reject 'typedef int y; int test(x, y)', but continue parsing.
+ if (Actions.getTypeName(*ParmII, Tok.getLocation(), CurScope))
+ Diag(Tok, diag::err_unexpected_typedef_ident) << ParmII;
+
+ // Verify that the argument identifier has not already been mentioned.
+ if (!ParamsSoFar.insert(ParmII)) {
+ Diag(Tok, diag::err_param_redefinition) << ParmII;
+ } else {
+ // Remember this identifier in ParamInfo.
+ ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
+ Tok.getLocation(),
+ DeclPtrTy()));
+ }
+
+ // Eat the identifier.
+ ConsumeToken();
+ }
+
+ // If we have the closing ')', eat it and we're done.
+ SourceLocation RLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ // Remember that we parsed a function type, and remember the attributes. This
+ // function type is always a K&R style function type, which is not varargs and
+ // has no prototype.
+ D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/false, /*varargs*/false,
+ SourceLocation(),
+ &ParamInfo[0], ParamInfo.size(),
+ /*TypeQuals*/0,
+ /*exception*/false,
+ SourceLocation(), false, 0, 0, 0,
+ LParenLoc, D),
+ RLoc);
+}
+
+/// [C90] direct-declarator '[' constant-expression[opt] ']'
+/// [C99] direct-declarator '[' type-qual-list[opt] assignment-expr[opt] ']'
+/// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']'
+/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']'
+/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']'
+void Parser::ParseBracketDeclarator(Declarator &D) {
+ SourceLocation StartLoc = ConsumeBracket();
+
+ // C array syntax has many features, but by-far the most common is [] and [4].
+ // This code does a fast path to handle some of the most obvious cases.
+ if (Tok.getKind() == tok::r_square) {
+ SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
+ // Remember that we parsed the empty array type.
+ OwningExprResult NumElements(Actions);
+ D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0, StartLoc),
+ EndLoc);
+ return;
+ } else if (Tok.getKind() == tok::numeric_constant &&
+ GetLookAheadToken(1).is(tok::r_square)) {
+ // [4] is very common. Parse the numeric constant expression.
+ OwningExprResult ExprRes(Actions.ActOnNumericConstant(Tok));
+ ConsumeToken();
+
+ SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
+
+ // If there was an error parsing the assignment-expression, recover.
+ if (ExprRes.isInvalid())
+ ExprRes.release(); // Deallocate expr, just use [].
+
+ // Remember that we parsed a array type, and remember its features.
+ D.AddTypeInfo(DeclaratorChunk::getArray(0, false, 0,
+ ExprRes.release(), StartLoc),
+ EndLoc);
+ return;
+ }
+
+ // If valid, this location is the position where we read the 'static' keyword.
+ SourceLocation StaticLoc;
+ if (Tok.is(tok::kw_static))
+ StaticLoc = ConsumeToken();
+
+ // If there is a type-qualifier-list, read it now.
+ // Type qualifiers in an array subscript are a C99 feature.
+ DeclSpec DS;
+ ParseTypeQualifierListOpt(DS, false /*no attributes*/);
+
+ // If we haven't already read 'static', check to see if there is one after the
+ // type-qualifier-list.
+ if (!StaticLoc.isValid() && Tok.is(tok::kw_static))
+ StaticLoc = ConsumeToken();
+
+ // Handle "direct-declarator [ type-qual-list[opt] * ]".
+ bool isStar = false;
+ OwningExprResult NumElements(Actions);
+
+ // Handle the case where we have '[*]' as the array size. However, a leading
+ // star could be the start of an expression, for example 'X[*p + 4]'. Verify
+ // the the token after the star is a ']'. Since stars in arrays are
+ // infrequent, use of lookahead is not costly here.
+ if (Tok.is(tok::star) && GetLookAheadToken(1).is(tok::r_square)) {
+ ConsumeToken(); // Eat the '*'.
+
+ if (StaticLoc.isValid()) {
+ Diag(StaticLoc, diag::err_unspecified_vla_size_with_static);
+ StaticLoc = SourceLocation(); // Drop the static.
+ }
+ isStar = true;
+ } else if (Tok.isNot(tok::r_square)) {
+ // Note, in C89, this production uses the constant-expr production instead
+ // of assignment-expr. The only difference is that assignment-expr allows
+ // things like '=' and '*='. Sema rejects these in C89 mode because they
+ // are not i-c-e's, so we don't need to distinguish between the two here.
+
+ // Parse the assignment-expression now.
+ NumElements = ParseAssignmentExpression();
+ }
+
+ // If there was an error parsing the assignment-expression, recover.
+ if (NumElements.isInvalid()) {
+ D.setInvalidType(true);
+ // If the expression was invalid, skip it.
+ SkipUntil(tok::r_square);
+ return;
+ }
+
+ SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
+
+ // Remember that we parsed a array type, and remember its features.
+ D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(),
+ StaticLoc.isValid(), isStar,
+ NumElements.release(), StartLoc),
+ EndLoc);
+}
+
+/// [GNU] typeof-specifier:
+/// typeof ( expressions )
+/// typeof ( type-name )
+/// [GNU/C++] typeof unary-expression
+///
+void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
+ assert(Tok.is(tok::kw_typeof) && "Not a typeof specifier");
+ Token OpTok = Tok;
+ SourceLocation StartLoc = ConsumeToken();
+
+ bool isCastExpr;
+ TypeTy *CastTy;
+ SourceRange CastRange;
+ OwningExprResult Operand = ParseExprAfterTypeofSizeofAlignof(OpTok,
+ isCastExpr,
+ CastTy,
+ CastRange);
+
+ if (CastRange.getEnd().isInvalid())
+ // FIXME: Not accurate, the range gets one token more than it should.
+ DS.SetRangeEnd(Tok.getLocation());
+ else
+ DS.SetRangeEnd(CastRange.getEnd());
+
+ if (isCastExpr) {
+ if (!CastTy) {
+ DS.SetTypeSpecError();
+ return;
+ }
+
+ const char *PrevSpec = 0;
+ // Check for duplicate type specifiers (e.g. "int typeof(int)").
+ if (DS.SetTypeSpecType(DeclSpec::TST_typeofType, StartLoc, PrevSpec,
+ CastTy))
+ Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
+ return;
+ }
+
+ // If we get here, the operand to the typeof was an expresion.
+ if (Operand.isInvalid()) {
+ DS.SetTypeSpecError();
+ return;
+ }
+
+ const char *PrevSpec = 0;
+ // Check for duplicate type specifiers (e.g. "int typeof(int)").
+ if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec,
+ Operand.release()))
+ Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
+}
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
new file mode 100644
index 0000000..809dc10
--- /dev/null
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -0,0 +1,1292 @@
+//===--- ParseDeclCXX.cpp - C++ Declaration Parsing -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the C++ Declaration portions of the Parser interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+#include "ExtensionRAIIObject.h"
+using namespace clang;
+
+/// ParseNamespace - We know that the current token is a namespace keyword. This
+/// may either be a top level namespace or a block-level namespace alias.
+///
+/// namespace-definition: [C++ 7.3: basic.namespace]
+/// named-namespace-definition
+/// unnamed-namespace-definition
+///
+/// unnamed-namespace-definition:
+/// 'namespace' attributes[opt] '{' namespace-body '}'
+///
+/// named-namespace-definition:
+/// original-namespace-definition
+/// extension-namespace-definition
+///
+/// original-namespace-definition:
+/// 'namespace' identifier attributes[opt] '{' namespace-body '}'
+///
+/// extension-namespace-definition:
+/// 'namespace' original-namespace-name '{' namespace-body '}'
+///
+/// namespace-alias-definition: [C++ 7.3.2: namespace.alias]
+/// 'namespace' identifier '=' qualified-namespace-specifier ';'
+///
+Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context,
+ SourceLocation &DeclEnd) {
+ assert(Tok.is(tok::kw_namespace) && "Not a namespace!");
+ SourceLocation NamespaceLoc = ConsumeToken(); // eat the 'namespace'.
+
+ SourceLocation IdentLoc;
+ IdentifierInfo *Ident = 0;
+
+ if (Tok.is(tok::identifier)) {
+ Ident = Tok.getIdentifierInfo();
+ IdentLoc = ConsumeToken(); // eat the identifier.
+ }
+
+ // Read label attributes, if present.
+ Action::AttrTy *AttrList = 0;
+ if (Tok.is(tok::kw___attribute))
+ // FIXME: save these somewhere.
+ AttrList = ParseAttributes();
+
+ if (Tok.is(tok::equal))
+ // FIXME: Verify no attributes were present.
+ return ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident, DeclEnd);
+
+ if (Tok.isNot(tok::l_brace)) {
+ Diag(Tok, Ident ? diag::err_expected_lbrace :
+ diag::err_expected_ident_lbrace);
+ return DeclPtrTy();
+ }
+
+ SourceLocation LBrace = ConsumeBrace();
+
+ // Enter a scope for the namespace.
+ ParseScope NamespaceScope(this, Scope::DeclScope);
+
+ DeclPtrTy NamespcDecl =
+ Actions.ActOnStartNamespaceDef(CurScope, IdentLoc, Ident, LBrace);
+
+ PrettyStackTraceActionsDecl CrashInfo(NamespcDecl, NamespaceLoc, Actions,
+ PP.getSourceManager(),
+ "parsing namespace");
+
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof))
+ ParseExternalDeclaration();
+
+ // Leave the namespace scope.
+ NamespaceScope.Exit();
+
+ SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBrace);
+ Actions.ActOnFinishNamespaceDef(NamespcDecl, RBraceLoc);
+
+ DeclEnd = RBraceLoc;
+ return NamespcDecl;
+}
+
+/// ParseNamespaceAlias - Parse the part after the '=' in a namespace
+/// alias definition.
+///
+Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
+ SourceLocation AliasLoc,
+ IdentifierInfo *Alias,
+ SourceLocation &DeclEnd) {
+ assert(Tok.is(tok::equal) && "Not equal token");
+
+ ConsumeToken(); // eat the '='.
+
+ CXXScopeSpec SS;
+ // Parse (optional) nested-name-specifier.
+ ParseOptionalCXXScopeSpecifier(SS);
+
+ if (SS.isInvalid() || Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_namespace_name);
+ // Skip to end of the definition and eat the ';'.
+ SkipUntil(tok::semi);
+ return DeclPtrTy();
+ }
+
+ // Parse identifier.
+ IdentifierInfo *Ident = Tok.getIdentifierInfo();
+ SourceLocation IdentLoc = ConsumeToken();
+
+ // Eat the ';'.
+ DeclEnd = Tok.getLocation();
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
+ "namespace name", tok::semi);
+
+ return Actions.ActOnNamespaceAliasDef(CurScope, NamespaceLoc, AliasLoc, Alias,
+ SS, IdentLoc, Ident);
+}
+
+/// 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
+///
+Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) {
+ assert(Tok.is(tok::string_literal) && "Not a string literal!");
+ llvm::SmallVector<char, 8> LangBuffer;
+ // LangBuffer is guaranteed to be big enough.
+ LangBuffer.resize(Tok.getLength());
+ const char *LangBufPtr = &LangBuffer[0];
+ unsigned StrSize = PP.getSpelling(Tok, LangBufPtr);
+
+ SourceLocation Loc = ConsumeStringToken();
+
+ ParseScope LinkageScope(this, Scope::DeclScope);
+ DeclPtrTy LinkageSpec
+ = Actions.ActOnStartLinkageSpecification(CurScope,
+ /*FIXME: */SourceLocation(),
+ Loc, LangBufPtr, StrSize,
+ Tok.is(tok::l_brace)? Tok.getLocation()
+ : SourceLocation());
+
+ if (Tok.isNot(tok::l_brace)) {
+ ParseDeclarationOrFunctionDefinition();
+ return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec,
+ SourceLocation());
+ }
+
+ SourceLocation LBrace = ConsumeBrace();
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ ParseExternalDeclaration();
+ }
+
+ SourceLocation RBrace = MatchRHSPunctuation(tok::r_brace, LBrace);
+ return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec, RBrace);
+}
+
+/// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or
+/// using-directive. Assumes that current token is 'using'.
+Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
+ SourceLocation &DeclEnd) {
+ assert(Tok.is(tok::kw_using) && "Not using token");
+
+ // Eat 'using'.
+ SourceLocation UsingLoc = ConsumeToken();
+
+ if (Tok.is(tok::kw_namespace))
+ // Next token after 'using' is 'namespace' so it must be using-directive
+ return ParseUsingDirective(Context, UsingLoc, DeclEnd);
+
+ // Otherwise, it must be using-declaration.
+ return ParseUsingDeclaration(Context, UsingLoc, DeclEnd);
+}
+
+/// 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] ;
+///
+Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context,
+ SourceLocation UsingLoc,
+ SourceLocation &DeclEnd) {
+ assert(Tok.is(tok::kw_namespace) && "Not 'namespace' token");
+
+ // Eat 'namespace'.
+ SourceLocation NamespcLoc = ConsumeToken();
+
+ CXXScopeSpec SS;
+ // Parse (optional) nested-name-specifier.
+ ParseOptionalCXXScopeSpecifier(SS);
+
+ AttributeList *AttrList = 0;
+ IdentifierInfo *NamespcName = 0;
+ SourceLocation IdentLoc = SourceLocation();
+
+ // Parse namespace-name.
+ if (SS.isInvalid() || Tok.isNot(tok::identifier)) {
+ 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?
+ return DeclPtrTy();
+ }
+
+ // Parse identifier.
+ NamespcName = Tok.getIdentifierInfo();
+ IdentLoc = ConsumeToken();
+
+ // Parse (optional) attributes (most likely GNU strong-using extension).
+ if (Tok.is(tok::kw___attribute))
+ AttrList = ParseAttributes();
+
+ // Eat ';'.
+ DeclEnd = Tok.getLocation();
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
+ AttrList ? "attributes list" : "namespace name", tok::semi);
+
+ return Actions.ActOnUsingDirective(CurScope, UsingLoc, NamespcLoc, SS,
+ IdentLoc, NamespcName, AttrList);
+}
+
+/// ParseUsingDeclaration - Parse C++ using-declaration. Assumes that
+/// 'using' was already seen.
+///
+/// using-declaration: [C++ 7.3.p3: namespace.udecl]
+/// 'using' 'typename'[opt] ::[opt] nested-name-specifier
+/// unqualified-id [TODO]
+/// 'using' :: unqualified-id [TODO]
+///
+Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,
+ SourceLocation UsingLoc,
+ SourceLocation &DeclEnd) {
+ assert(false && "Not implemented");
+ // FIXME: Implement parsing.
+ return DeclPtrTy();
+}
+
+/// ParseStaticAssertDeclaration - Parse C++0x static_assert-declaratoion.
+///
+/// static_assert-declaration:
+/// static_assert ( constant-expression , string-literal ) ;
+///
+Parser::DeclPtrTy Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
+ assert(Tok.is(tok::kw_static_assert) && "Not a static_assert declaration");
+ SourceLocation StaticAssertLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen);
+ return DeclPtrTy();
+ }
+
+ SourceLocation LParenLoc = ConsumeParen();
+
+ OwningExprResult AssertExpr(ParseConstantExpression());
+ if (AssertExpr.isInvalid()) {
+ SkipUntil(tok::semi);
+ return DeclPtrTy();
+ }
+
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::semi))
+ return DeclPtrTy();
+
+ if (Tok.isNot(tok::string_literal)) {
+ Diag(Tok, diag::err_expected_string_literal);
+ SkipUntil(tok::semi);
+ return DeclPtrTy();
+ }
+
+ OwningExprResult AssertMessage(ParseStringLiteralExpression());
+ if (AssertMessage.isInvalid())
+ return DeclPtrTy();
+
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ DeclEnd = Tok.getLocation();
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after_static_assert);
+
+ return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc, move(AssertExpr),
+ move(AssertMessage));
+}
+
+/// ParseClassName - Parse a C++ class-name, which names a class. Note
+/// that we only check that the result names a type; semantic analysis
+/// will need to verify that the type names a class. The result is
+/// either a type or NULL, depending on whether a type name was
+/// found.
+///
+/// class-name: [C++ 9.1]
+/// identifier
+/// simple-template-id
+///
+Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
+ const CXXScopeSpec *SS) {
+ // Check whether we have a template-id that names a type.
+ if (Tok.is(tok::annot_template_id)) {
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ if (TemplateId->Kind == TNK_Type_template) {
+ AnnotateTemplateIdTokenAsType(SS);
+
+ assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
+ TypeTy *Type = Tok.getAnnotationValue();
+ EndLocation = Tok.getAnnotationEndLoc();
+ ConsumeToken();
+
+ if (Type)
+ return Type;
+ return true;
+ }
+
+ // Fall through to produce an error below.
+ }
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_class_name);
+ return true;
+ }
+
+ // We have an identifier; check whether it is actually a type.
+ TypeTy *Type = Actions.getTypeName(*Tok.getIdentifierInfo(),
+ Tok.getLocation(), CurScope, SS);
+ if (!Type) {
+ Diag(Tok, diag::err_expected_class_name);
+ return true;
+ }
+
+ // Consume the identifier.
+ EndLocation = ConsumeToken();
+ return Type;
+}
+
+/// ParseClassSpecifier - Parse a C++ class-specifier [C++ class] or
+/// elaborated-type-specifier [C++ dcl.type.elab]; we can't tell which
+/// until we reach the start of a definition or see a token that
+/// cannot start a definition.
+///
+/// class-specifier: [C++ class]
+/// class-head '{' member-specification[opt] '}'
+/// class-head '{' member-specification[opt] '}' attributes[opt]
+/// class-head:
+/// class-key identifier[opt] base-clause[opt]
+/// class-key nested-name-specifier identifier base-clause[opt]
+/// class-key nested-name-specifier[opt] simple-template-id
+/// base-clause[opt]
+/// [GNU] class-key attributes[opt] identifier[opt] base-clause[opt]
+/// [GNU] class-key attributes[opt] nested-name-specifier
+/// identifier base-clause[opt]
+/// [GNU] class-key attributes[opt] nested-name-specifier[opt]
+/// simple-template-id base-clause[opt]
+/// class-key:
+/// 'class'
+/// 'struct'
+/// 'union'
+///
+/// elaborated-type-specifier: [C++ dcl.type.elab]
+/// class-key ::[opt] nested-name-specifier[opt] identifier
+/// class-key ::[opt] nested-name-specifier[opt] 'template'[opt]
+/// simple-template-id
+///
+/// Note that the C++ class-specifier and elaborated-type-specifier,
+/// together, subsume the C99 struct-or-union-specifier:
+///
+/// struct-or-union-specifier: [C99 6.7.2.1]
+/// struct-or-union identifier[opt] '{' struct-contents '}'
+/// struct-or-union identifier
+/// [GNU] struct-or-union attributes[opt] identifier[opt] '{' struct-contents
+/// '}' attributes[opt]
+/// [GNU] struct-or-union attributes[opt] identifier
+/// struct-or-union:
+/// 'struct'
+/// 'union'
+void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
+ SourceLocation StartLoc, DeclSpec &DS,
+ const ParsedTemplateInfo &TemplateInfo,
+ AccessSpecifier AS) {
+ DeclSpec::TST TagType;
+ if (TagTokKind == tok::kw_struct)
+ TagType = DeclSpec::TST_struct;
+ else if (TagTokKind == tok::kw_class)
+ TagType = DeclSpec::TST_class;
+ else {
+ assert(TagTokKind == tok::kw_union && "Not a class specifier");
+ TagType = DeclSpec::TST_union;
+ }
+
+ AttributeList *Attr = 0;
+ // If attributes exist after tag, parse them.
+ if (Tok.is(tok::kw___attribute))
+ Attr = ParseAttributes();
+
+ // If declspecs exist after tag, parse them.
+ if (Tok.is(tok::kw___declspec) && PP.getLangOptions().Microsoft)
+ FuzzyParseMicrosoftDeclSpec();
+
+ // Parse the (optional) nested-name-specifier.
+ CXXScopeSpec SS;
+ if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS))
+ if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
+ Diag(Tok, diag::err_expected_ident);
+
+ // Parse the (optional) class name or simple-template-id.
+ IdentifierInfo *Name = 0;
+ SourceLocation NameLoc;
+ TemplateIdAnnotation *TemplateId = 0;
+ if (Tok.is(tok::identifier)) {
+ Name = Tok.getIdentifierInfo();
+ NameLoc = ConsumeToken();
+ } else if (Tok.is(tok::annot_template_id)) {
+ TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ NameLoc = ConsumeToken();
+
+ if (TemplateId->Kind != TNK_Type_template) {
+ // The template-name in the simple-template-id refers to
+ // something other than a class template. Give an appropriate
+ // error message and skip to the ';'.
+ SourceRange Range(NameLoc);
+ if (SS.isNotEmpty())
+ Range.setBegin(SS.getBeginLoc());
+
+ Diag(TemplateId->LAngleLoc, diag::err_template_spec_syntax_non_template)
+ << Name << static_cast<int>(TemplateId->Kind) << Range;
+
+ DS.SetTypeSpecError();
+ SkipUntil(tok::semi, false, true);
+ TemplateId->Destroy();
+ return;
+ }
+ }
+
+ // There are three options here. If we have 'struct foo;', then
+ // this is a forward declaration. If we have 'struct foo {...' or
+ // 'struct foo :...' then this is a definition. Otherwise we have
+ // something like 'struct foo xyz', a reference.
+ Action::TagKind TK;
+ if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon)))
+ TK = Action::TK_Definition;
+ else if (Tok.is(tok::semi) && !DS.isFriendSpecified())
+ TK = Action::TK_Declaration;
+ else
+ TK = Action::TK_Reference;
+
+ if (!Name && !TemplateId && TK != Action::TK_Definition) {
+ // We have a declaration or reference to an anonymous class.
+ Diag(StartLoc, diag::err_anon_type_definition)
+ << DeclSpec::getSpecifierName(TagType);
+
+ // Skip the rest of this declarator, up until the comma or semicolon.
+ SkipUntil(tok::comma, true);
+
+ if (TemplateId)
+ TemplateId->Destroy();
+ return;
+ }
+
+ // Create the tag portion of the class or class template.
+ Action::DeclResult TagOrTempResult;
+ TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
+
+ // FIXME: When TK == TK_Reference and we have a template-id, we need
+ // to turn that template-id into a type.
+
+ bool Owned = false;
+ if (TemplateId && TK != Action::TK_Reference) {
+ // Explicit specialization, class template partial specialization,
+ // or explicit instantiation.
+ ASTTemplateArgsPtr TemplateArgsPtr(Actions,
+ TemplateId->getTemplateArgs(),
+ TemplateId->getTemplateArgIsType(),
+ TemplateId->NumArgs);
+ if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
+ TK == Action::TK_Declaration) {
+ // This is an explicit instantiation of a class template.
+ TagOrTempResult
+ = Actions.ActOnExplicitInstantiation(CurScope,
+ TemplateInfo.TemplateLoc,
+ TagType,
+ StartLoc,
+ SS,
+ TemplateTy::make(TemplateId->Template),
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc,
+ TemplateArgsPtr,
+ TemplateId->getTemplateArgLocations(),
+ TemplateId->RAngleLoc,
+ Attr);
+ } 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>
+ //
+ // but it actually has a definition. Most likely, this was
+ // meant to be an explicit specialization, but the user forgot
+ // the '<>' after 'template'.
+ assert(TK == Action::TK_Definition && "Expected a definition here");
+
+ SourceLocation LAngleLoc
+ = PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
+ Diag(TemplateId->TemplateNameLoc,
+ diag::err_explicit_instantiation_with_definition)
+ << SourceRange(TemplateInfo.TemplateLoc)
+ << CodeModificationHint::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(0, SourceLocation(),
+ TemplateInfo.TemplateLoc,
+ LAngleLoc,
+ 0, 0,
+ LAngleLoc));
+ TemplateParams = &FakedParamLists;
+ }
+
+ // Build the class template specialization.
+ TagOrTempResult
+ = Actions.ActOnClassTemplateSpecialization(CurScope, TagType, TK,
+ StartLoc, SS,
+ TemplateTy::make(TemplateId->Template),
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc,
+ TemplateArgsPtr,
+ TemplateId->getTemplateArgLocations(),
+ TemplateId->RAngleLoc,
+ Attr,
+ Action::MultiTemplateParamsArg(Actions,
+ TemplateParams? &(*TemplateParams)[0] : 0,
+ TemplateParams? TemplateParams->size() : 0));
+ }
+ TemplateId->Destroy();
+ } else if (TemplateParams && TK != Action::TK_Reference) {
+ // Class template declaration or definition.
+ TagOrTempResult = Actions.ActOnClassTemplate(CurScope, TagType, TK,
+ StartLoc, SS, Name, NameLoc,
+ Attr,
+ Action::MultiTemplateParamsArg(Actions,
+ &(*TemplateParams)[0],
+ TemplateParams->size()),
+ AS);
+ } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
+ TK == Action::TK_Declaration) {
+ // Explicit instantiation of a member of a class template
+ // specialization, e.g.,
+ //
+ // template struct Outer<int>::Inner;
+ //
+ TagOrTempResult
+ = Actions.ActOnExplicitInstantiation(CurScope,
+ TemplateInfo.TemplateLoc,
+ TagType, StartLoc, SS, Name,
+ NameLoc, Attr);
+ } else {
+ if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
+ TK == Action::TK_Definition) {
+ // FIXME: Diagnose this particular error.
+ }
+
+ // Declaration or definition of a class type
+ TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, SS,
+ Name, NameLoc, Attr, AS, Owned);
+ }
+
+ // Parse the optional base clause (C++ only).
+ if (getLang().CPlusPlus && Tok.is(tok::colon))
+ ParseBaseClause(TagOrTempResult.get());
+
+ // If there is a body, parse it and inform the actions module.
+ if (Tok.is(tok::l_brace))
+ if (getLang().CPlusPlus)
+ ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get());
+ else
+ ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get());
+ else if (TK == Action::TK_Definition) {
+ // FIXME: Complain that we have a base-specifier list but no
+ // definition.
+ Diag(Tok, diag::err_expected_lbrace);
+ }
+
+ const char *PrevSpec = 0;
+ if (TagOrTempResult.isInvalid()) {
+ DS.SetTypeSpecError();
+ return;
+ }
+
+ if (DS.SetTypeSpecType(TagType, StartLoc, PrevSpec,
+ TagOrTempResult.get().getAs<void>(), Owned))
+ Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
+
+ if (DS.isFriendSpecified())
+ Actions.ActOnFriendDecl(CurScope, DS.getFriendSpecLoc(),
+ TagOrTempResult.get());
+}
+
+/// ParseBaseClause - Parse the base-clause of a C++ class [C++ class.derived].
+///
+/// base-clause : [C++ class.derived]
+/// ':' base-specifier-list
+/// base-specifier-list:
+/// base-specifier '...'[opt]
+/// base-specifier-list ',' base-specifier '...'[opt]
+void Parser::ParseBaseClause(DeclPtrTy ClassDecl) {
+ assert(Tok.is(tok::colon) && "Not a base clause");
+ ConsumeToken();
+
+ // Build up an array of parsed base specifiers.
+ llvm::SmallVector<BaseTy *, 8> BaseInfo;
+
+ while (true) {
+ // Parse a base-specifier.
+ BaseResult Result = ParseBaseSpecifier(ClassDecl);
+ if (Result.isInvalid()) {
+ // Skip the rest of this base specifier, up until the comma or
+ // opening brace.
+ SkipUntil(tok::comma, tok::l_brace, true, true);
+ } else {
+ // Add this to our array of base specifiers.
+ BaseInfo.push_back(Result.get());
+ }
+
+ // If the next token is a comma, consume it and keep reading
+ // base-specifiers.
+ if (Tok.isNot(tok::comma)) break;
+
+ // Consume the comma.
+ ConsumeToken();
+ }
+
+ // Attach the base specifiers
+ Actions.ActOnBaseSpecifiers(ClassDecl, BaseInfo.data(), BaseInfo.size());
+}
+
+/// ParseBaseSpecifier - Parse a C++ base-specifier. A base-specifier is
+/// one entry in the base class list of a class specifier, for example:
+/// class foo : public bar, virtual private baz {
+/// 'public bar' and 'virtual private baz' are each base-specifiers.
+///
+/// base-specifier: [C++ class.derived]
+/// ::[opt] nested-name-specifier[opt] class-name
+/// 'virtual' access-specifier[opt] ::[opt] nested-name-specifier[opt]
+/// class-name
+/// access-specifier 'virtual'[opt] ::[opt] nested-name-specifier[opt]
+/// class-name
+Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) {
+ bool IsVirtual = false;
+ SourceLocation StartLoc = Tok.getLocation();
+
+ // Parse the 'virtual' keyword.
+ if (Tok.is(tok::kw_virtual)) {
+ ConsumeToken();
+ IsVirtual = true;
+ }
+
+ // Parse an (optional) access specifier.
+ AccessSpecifier Access = getAccessSpecifierIfPresent();
+ if (Access)
+ ConsumeToken();
+
+ // Parse the 'virtual' keyword (again!), in case it came after the
+ // access specifier.
+ if (Tok.is(tok::kw_virtual)) {
+ SourceLocation VirtualLoc = ConsumeToken();
+ if (IsVirtual) {
+ // Complain about duplicate 'virtual'
+ Diag(VirtualLoc, diag::err_dup_virtual)
+ << CodeModificationHint::CreateRemoval(SourceRange(VirtualLoc));
+ }
+
+ IsVirtual = true;
+ }
+
+ // Parse optional '::' and optional nested-name-specifier.
+ CXXScopeSpec SS;
+ ParseOptionalCXXScopeSpecifier(SS);
+
+ // The location of the base class itself.
+ SourceLocation BaseLoc = Tok.getLocation();
+
+ // Parse the class-name.
+ SourceLocation EndLocation;
+ TypeResult BaseType = ParseClassName(EndLocation, &SS);
+ if (BaseType.isInvalid())
+ return true;
+
+ // Find the complete source range for the base-specifier.
+ SourceRange Range(StartLoc, EndLocation);
+
+ // Notify semantic analysis that we have parsed a complete
+ // base-specifier.
+ return Actions.ActOnBaseSpecifier(ClassDecl, Range, IsVirtual, Access,
+ BaseType.get(), BaseLoc);
+}
+
+/// getAccessSpecifierIfPresent - Determine whether the next token is
+/// a C++ access-specifier.
+///
+/// access-specifier: [C++ class.derived]
+/// 'private'
+/// 'protected'
+/// 'public'
+AccessSpecifier Parser::getAccessSpecifierIfPresent() const
+{
+ 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;
+ }
+}
+
+/// 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]
+/// [C++0x] static_assert-declaration
+/// template-declaration
+/// [GNU] '__extension__' member-declaration
+///
+/// member-declarator-list:
+/// member-declarator
+/// member-declarator-list ',' member-declarator
+///
+/// member-declarator:
+/// declarator pure-specifier[opt]
+/// declarator constant-initializer[opt]
+/// identifier[opt] ':' constant-expression
+///
+/// pure-specifier:
+/// '= 0'
+///
+/// constant-initializer:
+/// '=' constant-expression
+///
+void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) {
+ // static_assert-declaration
+ if (Tok.is(tok::kw_static_assert)) {
+ SourceLocation DeclEnd;
+ ParseStaticAssertDeclaration(DeclEnd);
+ return;
+ }
+
+ if (Tok.is(tok::kw_template)) {
+ SourceLocation DeclEnd;
+ ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd,
+ AS);
+ return;
+ }
+
+ // Handle: member-declaration ::= '__extension__' member-declaration
+ if (Tok.is(tok::kw___extension__)) {
+ // __extension__ silences extension warnings in the subexpression.
+ ExtensionRAIIObject O(Diags); // Use RAII to do this.
+ ConsumeToken();
+ return ParseCXXClassMemberDeclaration(AS);
+ }
+
+ SourceLocation DSStart = Tok.getLocation();
+ // decl-specifier-seq:
+ // Parse the common declaration-specifiers piece.
+ DeclSpec DS;
+ ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS);
+
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ // C++ 9.2p7: The member-declarator-list can be omitted only after a
+ // class-specifier or an enum-specifier or in a friend declaration.
+ // FIXME: Friend declarations.
+ switch (DS.getTypeSpecType()) {
+ case DeclSpec::TST_struct:
+ case DeclSpec::TST_union:
+ case DeclSpec::TST_class:
+ case DeclSpec::TST_enum:
+ Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ return;
+ default:
+ Diag(DSStart, diag::err_no_declarators);
+ return;
+ }
+ }
+
+ Declarator DeclaratorInfo(DS, Declarator::MemberContext);
+
+ if (Tok.isNot(tok::colon)) {
+ // Parse the first declarator.
+ ParseDeclarator(DeclaratorInfo);
+ // Error parsing the declarator?
+ if (!DeclaratorInfo.hasName()) {
+ // If so, skip until the semi-colon or a }.
+ SkipUntil(tok::r_brace, true);
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+ return;
+ }
+
+ // function-definition:
+ if (Tok.is(tok::l_brace)
+ || (DeclaratorInfo.isFunctionDeclarator() &&
+ (Tok.is(tok::colon) || Tok.is(tok::kw_try)))) {
+ if (!DeclaratorInfo.isFunctionDeclarator()) {
+ Diag(Tok, diag::err_func_def_no_params);
+ ConsumeBrace();
+ SkipUntil(tok::r_brace, true);
+ return;
+ }
+
+ if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
+ Diag(Tok, diag::err_function_declared_typedef);
+ // This recovery skips the entire function body. It would be nice
+ // to simply call ParseCXXInlineMethodDef() below, however Sema
+ // assumes the declarator represents a function, not a typedef.
+ ConsumeBrace();
+ SkipUntil(tok::r_brace, true);
+ return;
+ }
+
+ ParseCXXInlineMethodDef(AS, DeclaratorInfo);
+ return;
+ }
+ }
+
+ // member-declarator-list:
+ // member-declarator
+ // member-declarator-list ',' member-declarator
+
+ llvm::SmallVector<DeclPtrTy, 8> DeclsInGroup;
+ OwningExprResult BitfieldSize(Actions);
+ OwningExprResult Init(Actions);
+ bool Deleted = false;
+
+ while (1) {
+
+ // member-declarator:
+ // declarator pure-specifier[opt]
+ // declarator constant-initializer[opt]
+ // identifier[opt] ':' constant-expression
+
+ if (Tok.is(tok::colon)) {
+ ConsumeToken();
+ BitfieldSize = ParseConstantExpression();
+ if (BitfieldSize.isInvalid())
+ SkipUntil(tok::comma, true, true);
+ }
+
+ // pure-specifier:
+ // '= 0'
+ //
+ // constant-initializer:
+ // '=' constant-expression
+ //
+ // defaulted/deleted function-definition:
+ // '=' 'default' [TODO]
+ // '=' 'delete'
+
+ if (Tok.is(tok::equal)) {
+ ConsumeToken();
+ if (getLang().CPlusPlus0x && Tok.is(tok::kw_delete)) {
+ ConsumeToken();
+ Deleted = true;
+ } else {
+ Init = ParseInitializer();
+ if (Init.isInvalid())
+ SkipUntil(tok::comma, true, true);
+ }
+ }
+
+ // If attributes exist after the declarator, parse them.
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ DeclaratorInfo.AddAttributes(AttrList, Loc);
+ }
+
+ // NOTE: If Sema is the Action module and declarator is an instance field,
+ // this call will *not* return the created decl; It will return null.
+ // See Sema::ActOnCXXMemberDeclarator for details.
+ DeclPtrTy ThisDecl = Actions.ActOnCXXMemberDeclarator(CurScope, AS,
+ DeclaratorInfo,
+ BitfieldSize.release(),
+ Init.release(),
+ Deleted);
+ if (ThisDecl)
+ DeclsInGroup.push_back(ThisDecl);
+
+ if (DeclaratorInfo.isFunctionDeclarator() &&
+ DeclaratorInfo.getDeclSpec().getStorageClassSpec()
+ != DeclSpec::SCS_typedef) {
+ // We just declared a member function. If this member function
+ // has any default arguments, we'll need to parse them later.
+ LateParsedMethodDeclaration *LateMethod = 0;
+ DeclaratorChunk::FunctionTypeInfo &FTI
+ = DeclaratorInfo.getTypeObject(0).Fun;
+ for (unsigned ParamIdx = 0; ParamIdx < FTI.NumArgs; ++ParamIdx) {
+ if (LateMethod || FTI.ArgInfo[ParamIdx].DefaultArgTokens) {
+ if (!LateMethod) {
+ // Push this method onto the stack of late-parsed method
+ // declarations.
+ getCurrentClass().MethodDecls.push_back(
+ LateParsedMethodDeclaration(ThisDecl));
+ LateMethod = &getCurrentClass().MethodDecls.back();
+
+ // Add all of the parameters prior to this one (they don't
+ // have default arguments).
+ LateMethod->DefaultArgs.reserve(FTI.NumArgs);
+ for (unsigned I = 0; I < ParamIdx; ++I)
+ LateMethod->DefaultArgs.push_back(
+ LateParsedDefaultArgument(FTI.ArgInfo[ParamIdx].Param));
+ }
+
+ // Add this parameter to the list of parameters (it or may
+ // not have a default argument).
+ LateMethod->DefaultArgs.push_back(
+ LateParsedDefaultArgument(FTI.ArgInfo[ParamIdx].Param,
+ FTI.ArgInfo[ParamIdx].DefaultArgTokens));
+ }
+ }
+ }
+
+ // If we don't have a comma, it is either the end of the list (a ';')
+ // or an error, bail out.
+ if (Tok.isNot(tok::comma))
+ break;
+
+ // Consume the comma.
+ ConsumeToken();
+
+ // Parse the next declarator.
+ DeclaratorInfo.clear();
+ BitfieldSize = 0;
+ Init = 0;
+ Deleted = false;
+
+ // Attributes are only allowed on the second declarator.
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ DeclaratorInfo.AddAttributes(AttrList, Loc);
+ }
+
+ if (Tok.isNot(tok::colon))
+ ParseDeclarator(DeclaratorInfo);
+ }
+
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ Actions.FinalizeDeclaratorGroup(CurScope, DS, DeclsInGroup.data(),
+ DeclsInGroup.size());
+ return;
+ }
+
+ Diag(Tok, diag::err_expected_semi_decl_list);
+ // Skip to end of block or statement
+ SkipUntil(tok::r_brace, true, true);
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+ return;
+}
+
+/// ParseCXXMemberSpecification - Parse the class definition.
+///
+/// member-specification:
+/// member-declaration member-specification[opt]
+/// access-specifier ':' member-specification[opt]
+///
+void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
+ unsigned TagType, DeclPtrTy TagDecl) {
+ assert((TagType == DeclSpec::TST_struct ||
+ TagType == DeclSpec::TST_union ||
+ TagType == DeclSpec::TST_class) && "Invalid TagType!");
+
+ PrettyStackTraceActionsDecl CrashInfo(TagDecl, RecordLoc, Actions,
+ PP.getSourceManager(),
+ "parsing struct/union/class body");
+
+ SourceLocation LBraceLoc = ConsumeBrace();
+
+ // Determine whether this is a top-level (non-nested) class.
+ bool TopLevelClass = ClassStack.empty() ||
+ CurScope->isInCXXInlineMethodScope();
+
+ // Enter a scope for the class.
+ ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope);
+
+ // Note that we are parsing a new (potentially-nested) class definition.
+ ParsingClassDefinition ParsingDef(*this, TagDecl, TopLevelClass);
+
+ if (TagDecl)
+ Actions.ActOnTagStartDefinition(CurScope, TagDecl);
+ else {
+ SkipUntil(tok::r_brace, false, false);
+ return;
+ }
+
+ // C++ 11p3: Members of a class defined with the keyword class are private
+ // by default. Members of a class defined with the keywords struct or union
+ // are public by default.
+ AccessSpecifier CurAS;
+ if (TagType == DeclSpec::TST_class)
+ CurAS = AS_private;
+ else
+ CurAS = AS_public;
+
+ // While we still have something to read, read the member-declarations.
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ // Each iteration of this loop reads one member-declaration.
+
+ // Check for extraneous top-level semicolon.
+ if (Tok.is(tok::semi)) {
+ Diag(Tok, diag::ext_extra_struct_semi);
+ ConsumeToken();
+ continue;
+ }
+
+ AccessSpecifier AS = getAccessSpecifierIfPresent();
+ if (AS != AS_none) {
+ // Current token is a C++ access specifier.
+ CurAS = AS;
+ ConsumeToken();
+ ExpectAndConsume(tok::colon, diag::err_expected_colon);
+ continue;
+ }
+
+ // Parse all the comma separated declarators.
+ ParseCXXClassMemberDeclaration(CurAS);
+ }
+
+ SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
+
+ AttributeList *AttrList = 0;
+ // If attributes exist after class contents, parse them.
+ if (Tok.is(tok::kw___attribute))
+ AttrList = ParseAttributes(); // FIXME: where should I put them?
+
+ Actions.ActOnFinishCXXMemberSpecification(CurScope, RecordLoc, TagDecl,
+ LBraceLoc, RBraceLoc);
+
+ // C++ 9.2p2: Within the class member-specification, the class is regarded as
+ // complete within function bodies, default arguments,
+ // exception-specifications, and constructor ctor-initializers (including
+ // such things in nested classes).
+ //
+ // FIXME: Only function bodies and constructor ctor-initializers are
+ // parsed correctly, fix the rest.
+ if (TopLevelClass) {
+ // We are not inside a nested class. This class and its nested classes
+ // are complete and we can parse the delayed portions of method
+ // declarations and the lexed inline method definitions.
+ ParseLexedMethodDeclarations(getCurrentClass());
+ ParseLexedMethodDefs(getCurrentClass());
+ }
+
+ // Leave the class scope.
+ ParsingDef.Pop();
+ ClassScope.Exit();
+
+ Actions.ActOnTagFinishDefinition(CurScope, TagDecl);
+}
+
+/// ParseConstructorInitializer - Parse a C++ constructor initializer,
+/// which explicitly initializes the members or base classes of a
+/// class (C++ [class.base.init]). For example, the three initializers
+/// after the ':' in the Derived constructor below:
+///
+/// @code
+/// class Base { };
+/// class Derived : Base {
+/// int x;
+/// float f;
+/// public:
+/// Derived(float f) : Base(), x(17), f(f) { }
+/// };
+/// @endcode
+///
+/// [C++] ctor-initializer:
+/// ':' mem-initializer-list
+///
+/// [C++] mem-initializer-list:
+/// mem-initializer
+/// mem-initializer , mem-initializer-list
+void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) {
+ assert(Tok.is(tok::colon) && "Constructor initializer always starts with ':'");
+
+ SourceLocation ColonLoc = ConsumeToken();
+
+ llvm::SmallVector<MemInitTy*, 4> MemInitializers;
+
+ do {
+ MemInitResult MemInit = ParseMemInitializer(ConstructorDecl);
+ if (!MemInit.isInvalid())
+ MemInitializers.push_back(MemInit.get());
+
+ if (Tok.is(tok::comma))
+ ConsumeToken();
+ else if (Tok.is(tok::l_brace))
+ break;
+ else {
+ // Skip over garbage, until we get to '{'. Don't eat the '{'.
+ Diag(Tok.getLocation(), diag::err_expected_lbrace_or_comma);
+ SkipUntil(tok::l_brace, true, true);
+ break;
+ }
+ } while (true);
+
+ Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc,
+ MemInitializers.data(), MemInitializers.size());
+}
+
+/// ParseMemInitializer - Parse a C++ member initializer, which is
+/// part of a constructor initializer that explicitly initializes one
+/// member or base class (C++ [class.base.init]). See
+/// ParseConstructorInitializer for an example.
+///
+/// [C++] mem-initializer:
+/// mem-initializer-id '(' expression-list[opt] ')'
+///
+/// [C++] mem-initializer-id:
+/// '::'[opt] nested-name-specifier[opt] class-name
+/// identifier
+Parser::MemInitResult Parser::ParseMemInitializer(DeclPtrTy ConstructorDecl) {
+ // FIXME: parse '::'[opt] nested-name-specifier[opt]
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_member_or_base_name);
+ return true;
+ }
+
+ // Get the identifier. This may be a member name or a class name,
+ // but we'll let the semantic analysis determine which it is.
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ SourceLocation IdLoc = ConsumeToken();
+
+ // Parse the '('.
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen);
+ return true;
+ }
+ SourceLocation LParenLoc = ConsumeParen();
+
+ // Parse the optional expression-list.
+ ExprVector ArgExprs(Actions);
+ CommaLocsTy CommaLocs;
+ if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) {
+ SkipUntil(tok::r_paren);
+ return true;
+ }
+
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ return Actions.ActOnMemInitializer(ConstructorDecl, CurScope, II, IdLoc,
+ LParenLoc, ArgExprs.take(),
+ ArgExprs.size(), CommaLocs.data(),
+ RParenLoc);
+}
+
+/// ParseExceptionSpecification - Parse a C++ exception-specification
+/// (C++ [except.spec]).
+///
+/// exception-specification:
+/// 'throw' '(' type-id-list [opt] ')'
+/// [MS] 'throw' '(' '...' ')'
+///
+/// type-id-list:
+/// type-id
+/// type-id-list ',' type-id
+///
+bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc,
+ llvm::SmallVector<TypeTy*, 2>
+ &Exceptions,
+ llvm::SmallVector<SourceRange, 2>
+ &Ranges,
+ bool &hasAnyExceptionSpec) {
+ assert(Tok.is(tok::kw_throw) && "expected throw");
+
+ SourceLocation ThrowLoc = ConsumeToken();
+
+ if (!Tok.is(tok::l_paren)) {
+ return Diag(Tok, diag::err_expected_lparen_after) << "throw";
+ }
+ SourceLocation LParenLoc = ConsumeParen();
+
+ // Parse throw(...), a Microsoft extension that means "this function
+ // can throw anything".
+ if (Tok.is(tok::ellipsis)) {
+ hasAnyExceptionSpec = true;
+ SourceLocation EllipsisLoc = ConsumeToken();
+ if (!getLang().Microsoft)
+ Diag(EllipsisLoc, diag::ext_ellipsis_exception_spec);
+ EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ return false;
+ }
+
+ // Parse the sequence of type-ids.
+ SourceRange Range;
+ while (Tok.isNot(tok::r_paren)) {
+ TypeResult Res(ParseTypeName(&Range));
+ if (!Res.isInvalid()) {
+ Exceptions.push_back(Res.get());
+ Ranges.push_back(Range);
+ }
+ if (Tok.is(tok::comma))
+ ConsumeToken();
+ else
+ break;
+ }
+
+ EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ return false;
+}
+
+/// \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.
+void Parser::PushParsingClass(DeclPtrTy ClassDecl, bool TopLevelClass) {
+ assert((TopLevelClass || !ClassStack.empty()) &&
+ "Nested class without outer class");
+ ClassStack.push(new ParsingClass(ClassDecl, TopLevelClass));
+}
+
+/// \brief Deallocate the given parsed class and all of its nested
+/// classes.
+void Parser::DeallocateParsedClasses(Parser::ParsingClass *Class) {
+ for (unsigned I = 0, N = Class->NestedClasses.size(); I != N; ++I)
+ DeallocateParsedClasses(Class->NestedClasses[I]);
+ delete Class;
+}
+
+/// \brief Pop the top class of the stack of classes that are
+/// currently being parsed.
+///
+/// This routine should be called when we have finished parsing the
+/// definition of a class, but have not yet popped the Scope
+/// associated with the class's definition.
+///
+/// \returns true if the class we've popped is a top-level class,
+/// false otherwise.
+void Parser::PopParsingClass() {
+ assert(!ClassStack.empty() && "Mismatched push/pop for class parsing");
+
+ 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;
+ }
+ assert(!ClassStack.empty() && "Missing top-level class?");
+
+ if (Victim->MethodDecls.empty() && Victim->MethodDefs.empty() &&
+ Victim->NestedClasses.empty()) {
+ // The victim is a nested class, but we will not need to perform
+ // any processing after the definition of this class since it has
+ // no members whose handling was delayed. Therefore, we can just
+ // remove this nested class.
+ delete Victim;
+ return;
+ }
+
+ // This nested class has some members that will need to be processed
+ // after the top-level class is completely defined. Therefore, add
+ // it to the list of nested classes within its parent.
+ assert(CurScope->isClassScope() && "Nested class outside of class scope?");
+ ClassStack.top()->NestedClasses.push_back(Victim);
+ Victim->TemplateScope = CurScope->getParent()->isTemplateParamScope();
+}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
new file mode 100644
index 0000000..cd62c64
--- /dev/null
+++ b/lib/Parse/ParseExpr.cpp
@@ -0,0 +1,1514 @@
+//===--- ParseExpr.cpp - Expression Parsing -------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Expression parsing implementation. Expressions in
+// C99 basically consist of a bunch of binary operators with unary operators and
+// other random stuff at the leaves.
+//
+// In the C99 grammar, these unary operators bind tightest and are represented
+// as the 'cast-expression' production. Everything else is either a binary
+// operator (e.g. '/') or a ternary operator ("?:"). The unary leaves are
+// handled by ParseCastExpression, the higher level pieces are handled by
+// ParseBinaryExpression.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+#include "clang/Basic/PrettyStackTrace.h"
+#include "ExtensionRAIIObject.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/SmallString.h"
+using namespace clang;
+
+/// PrecedenceLevels - These are precedences for the binary/ternary operators in
+/// the C99 grammar. These have been named to relate with the C99 grammar
+/// productions. Low precedences numbers bind more weakly than high numbers.
+namespace prec {
+ enum Level {
+ Unknown = 0, // Not binary operator.
+ Comma = 1, // ,
+ Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
+ Conditional = 3, // ?
+ LogicalOr = 4, // ||
+ LogicalAnd = 5, // &&
+ InclusiveOr = 6, // |
+ ExclusiveOr = 7, // ^
+ And = 8, // &
+ Equality = 9, // ==, !=
+ Relational = 10, // >=, <=, >, <
+ Shift = 11, // <<, >>
+ Additive = 12, // -, +
+ Multiplicative = 13, // *, /, %
+ PointerToMember = 14 // .*, ->*
+ };
+}
+
+
+/// getBinOpPrecedence - Return the precedence of the specified binary operator
+/// token. This returns:
+///
+static prec::Level getBinOpPrecedence(tok::TokenKind Kind,
+ bool GreaterThanIsOperator,
+ bool CPlusPlus0x) {
+ switch (Kind) {
+ case tok::greater:
+ // C++ [temp.names]p3:
+ // [...] When parsing a template-argument-list, the first
+ // non-nested > is taken as the ending delimiter rather than a
+ // greater-than operator. [...]
+ if (GreaterThanIsOperator)
+ return prec::Relational;
+ return prec::Unknown;
+
+ case tok::greatergreater:
+ // C++0x [temp.names]p3:
+ //
+ // [...] Similarly, the first non-nested >> is treated as two
+ // consecutive but distinct > tokens, the first of which is
+ // taken as the end of the template-argument-list and completes
+ // the template-id. [...]
+ if (GreaterThanIsOperator || !CPlusPlus0x)
+ return prec::Shift;
+ return prec::Unknown;
+
+ default: return prec::Unknown;
+ case tok::comma: return prec::Comma;
+ case tok::equal:
+ case tok::starequal:
+ case tok::slashequal:
+ case tok::percentequal:
+ case tok::plusequal:
+ case tok::minusequal:
+ case tok::lesslessequal:
+ case tok::greatergreaterequal:
+ case tok::ampequal:
+ case tok::caretequal:
+ case tok::pipeequal: return prec::Assignment;
+ case tok::question: return prec::Conditional;
+ case tok::pipepipe: return prec::LogicalOr;
+ case tok::ampamp: return prec::LogicalAnd;
+ case tok::pipe: return prec::InclusiveOr;
+ case tok::caret: return prec::ExclusiveOr;
+ case tok::amp: return prec::And;
+ case tok::exclaimequal:
+ case tok::equalequal: return prec::Equality;
+ case tok::lessequal:
+ case tok::less:
+ case tok::greaterequal: return prec::Relational;
+ case tok::lessless: return prec::Shift;
+ case tok::plus:
+ case tok::minus: return prec::Additive;
+ case tok::percent:
+ case tok::slash:
+ case tok::star: return prec::Multiplicative;
+ case tok::periodstar:
+ case tok::arrowstar: return prec::PointerToMember;
+ }
+}
+
+
+/// ParseExpression - Simple precedence-based parser for binary/ternary
+/// operators.
+///
+/// Note: we diverge from the C99 grammar when parsing the assignment-expression
+/// production. C99 specifies that the LHS of an assignment operator should be
+/// parsed as a unary-expression, but consistency dictates that it be a
+/// conditional-expession. In practice, the important thing here is that the
+/// LHS of an assignment has to be an l-value, which productions between
+/// unary-expression and conditional-expression don't produce. Because we want
+/// consistency, we parse the LHS as a conditional-expression, then check for
+/// l-value-ness in semantic analysis stages.
+///
+/// pm-expression: [C++ 5.5]
+/// cast-expression
+/// pm-expression '.*' cast-expression
+/// pm-expression '->*' cast-expression
+///
+/// multiplicative-expression: [C99 6.5.5]
+/// Note: in C++, apply pm-expression instead of cast-expression
+/// cast-expression
+/// multiplicative-expression '*' cast-expression
+/// multiplicative-expression '/' cast-expression
+/// multiplicative-expression '%' cast-expression
+///
+/// additive-expression: [C99 6.5.6]
+/// multiplicative-expression
+/// additive-expression '+' multiplicative-expression
+/// additive-expression '-' multiplicative-expression
+///
+/// shift-expression: [C99 6.5.7]
+/// additive-expression
+/// shift-expression '<<' additive-expression
+/// shift-expression '>>' additive-expression
+///
+/// relational-expression: [C99 6.5.8]
+/// shift-expression
+/// relational-expression '<' shift-expression
+/// relational-expression '>' shift-expression
+/// relational-expression '<=' shift-expression
+/// relational-expression '>=' shift-expression
+///
+/// equality-expression: [C99 6.5.9]
+/// relational-expression
+/// equality-expression '==' relational-expression
+/// equality-expression '!=' relational-expression
+///
+/// AND-expression: [C99 6.5.10]
+/// equality-expression
+/// AND-expression '&' equality-expression
+///
+/// exclusive-OR-expression: [C99 6.5.11]
+/// AND-expression
+/// exclusive-OR-expression '^' AND-expression
+///
+/// inclusive-OR-expression: [C99 6.5.12]
+/// exclusive-OR-expression
+/// inclusive-OR-expression '|' exclusive-OR-expression
+///
+/// logical-AND-expression: [C99 6.5.13]
+/// inclusive-OR-expression
+/// logical-AND-expression '&&' inclusive-OR-expression
+///
+/// logical-OR-expression: [C99 6.5.14]
+/// logical-AND-expression
+/// logical-OR-expression '||' logical-AND-expression
+///
+/// conditional-expression: [C99 6.5.15]
+/// logical-OR-expression
+/// logical-OR-expression '?' expression ':' conditional-expression
+/// [GNU] logical-OR-expression '?' ':' conditional-expression
+/// [C++] the third operand is an assignment-expression
+///
+/// assignment-expression: [C99 6.5.16]
+/// conditional-expression
+/// unary-expression assignment-operator assignment-expression
+/// [C++] throw-expression [C++ 15]
+///
+/// assignment-operator: one of
+/// = *= /= %= += -= <<= >>= &= ^= |=
+///
+/// expression: [C99 6.5.17]
+/// assignment-expression
+/// expression ',' assignment-expression
+///
+Parser::OwningExprResult Parser::ParseExpression() {
+ OwningExprResult LHS(ParseAssignmentExpression());
+ if (LHS.isInvalid()) return move(LHS);
+
+ return ParseRHSOfBinaryExpression(move(LHS), prec::Comma);
+}
+
+/// This routine is called when the '@' is seen and consumed.
+/// Current token is an Identifier and is not a 'try'. This
+/// routine is necessary to disambiguate @try-statement from,
+/// for example, @encode-expression.
+///
+Parser::OwningExprResult
+Parser::ParseExpressionWithLeadingAt(SourceLocation AtLoc) {
+ OwningExprResult LHS(ParseObjCAtExpression(AtLoc));
+ if (LHS.isInvalid()) return move(LHS);
+
+ return ParseRHSOfBinaryExpression(move(LHS), prec::Comma);
+}
+
+/// This routine is called when a leading '__extension__' is seen and
+/// consumed. This is necessary because the token gets consumed in the
+/// process of disambiguating between an expression and a declaration.
+Parser::OwningExprResult
+Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) {
+ OwningExprResult LHS(Actions, true);
+ {
+ // Silence extension warnings in the sub-expression
+ ExtensionRAIIObject O(Diags);
+
+ LHS = ParseCastExpression(false);
+ if (LHS.isInvalid()) return move(LHS);
+ }
+
+ LHS = Actions.ActOnUnaryOp(CurScope, ExtLoc, tok::kw___extension__,
+ move(LHS));
+ if (LHS.isInvalid()) return move(LHS);
+
+ return ParseRHSOfBinaryExpression(move(LHS), prec::Comma);
+}
+
+/// ParseAssignmentExpression - Parse an expr that doesn't include commas.
+///
+Parser::OwningExprResult Parser::ParseAssignmentExpression() {
+ if (Tok.is(tok::kw_throw))
+ return ParseThrowExpression();
+
+ OwningExprResult LHS(ParseCastExpression(false));
+ if (LHS.isInvalid()) return move(LHS);
+
+ return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment);
+}
+
+/// ParseAssignmentExprWithObjCMessageExprStart - Parse an assignment expression
+/// where part of an objc message send has already been parsed. In this case
+/// LBracLoc indicates the location of the '[' of the message send, and either
+/// ReceiverName or ReceiverExpr is non-null indicating the receiver of the
+/// message.
+///
+/// Since this handles full assignment-expression's, it handles postfix
+/// expressions and other binary operators for these expressions as well.
+Parser::OwningExprResult
+Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc,
+ SourceLocation NameLoc,
+ IdentifierInfo *ReceiverName,
+ ExprArg ReceiverExpr) {
+ OwningExprResult R(ParseObjCMessageExpressionBody(LBracLoc, NameLoc,
+ ReceiverName,
+ move(ReceiverExpr)));
+ if (R.isInvalid()) return move(R);
+ R = ParsePostfixExpressionSuffix(move(R));
+ if (R.isInvalid()) return move(R);
+ return ParseRHSOfBinaryExpression(move(R), prec::Assignment);
+}
+
+
+Parser::OwningExprResult Parser::ParseConstantExpression() {
+ OwningExprResult LHS(ParseCastExpression(false));
+ if (LHS.isInvalid()) return move(LHS);
+
+ return ParseRHSOfBinaryExpression(move(LHS), prec::Conditional);
+}
+
+/// ParseRHSOfBinaryExpression - Parse a binary expression that starts with
+/// LHS and has a precedence of at least MinPrec.
+Parser::OwningExprResult
+Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
+ unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind(),
+ GreaterThanIsOperator,
+ getLang().CPlusPlus0x);
+ SourceLocation ColonLoc;
+
+ while (1) {
+ // If this token has a lower precedence than we are allowed to parse (e.g.
+ // because we are called recursively, or because the token is not a binop),
+ // then we are done!
+ if (NextTokPrec < MinPrec)
+ return move(LHS);
+
+ // Consume the operator, saving the operator token for error reporting.
+ Token OpToken = Tok;
+ ConsumeToken();
+
+ // Special case handling for the ternary operator.
+ OwningExprResult TernaryMiddle(Actions, true);
+ if (NextTokPrec == prec::Conditional) {
+ if (Tok.isNot(tok::colon)) {
+ // Handle this production specially:
+ // logical-OR-expression '?' expression ':' conditional-expression
+ // In particular, the RHS of the '?' is 'expression', not
+ // 'logical-OR-expression' as we might expect.
+ TernaryMiddle = ParseExpression();
+ if (TernaryMiddle.isInvalid())
+ return move(TernaryMiddle);
+ } else {
+ // Special case handling of "X ? Y : Z" where Y is empty:
+ // logical-OR-expression '?' ':' conditional-expression [GNU]
+ TernaryMiddle = 0;
+ Diag(Tok, diag::ext_gnu_conditional_expr);
+ }
+
+ if (Tok.isNot(tok::colon)) {
+ Diag(Tok, diag::err_expected_colon);
+ Diag(OpToken, diag::note_matching) << "?";
+ return ExprError();
+ }
+
+ // Eat the colon.
+ ColonLoc = ConsumeToken();
+ }
+
+ // 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
+ // be a throw-expression, which is not a valid cast-expression.
+ // Therefore we need some special-casing here.
+ // Also note that the third operand of the conditional operator is
+ // an assignment-expression in C++.
+ OwningExprResult RHS(Actions);
+ if (getLang().CPlusPlus && NextTokPrec <= prec::Conditional)
+ RHS = ParseAssignmentExpression();
+ else
+ RHS = ParseCastExpression(false);
+ if (RHS.isInvalid())
+ return move(RHS);
+
+ // Remember the precedence of this operator and get the precedence of the
+ // operator immediately to the right of the RHS.
+ unsigned ThisPrec = NextTokPrec;
+ NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
+ getLang().CPlusPlus0x);
+
+ // Assignment and conditional expressions are right-associative.
+ bool isRightAssoc = ThisPrec == prec::Conditional ||
+ ThisPrec == prec::Assignment;
+
+ // Get the precedence of the operator to the right of the RHS. If it binds
+ // more tightly with RHS than we do, evaluate it completely first.
+ if (ThisPrec < NextTokPrec ||
+ (ThisPrec == NextTokPrec && isRightAssoc)) {
+ // If this is left-associative, only parse things on the RHS that bind
+ // more tightly than the current operator. If it is left-associative, it
+ // is okay, to bind exactly as tightly. For example, compile A=B=C=D as
+ // A=(B=(C=D)), where each paren is a level of recursion here.
+ // The function takes ownership of the RHS.
+ RHS = ParseRHSOfBinaryExpression(move(RHS), ThisPrec + !isRightAssoc);
+ if (RHS.isInvalid())
+ return move(RHS);
+
+ NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
+ getLang().CPlusPlus0x);
+ }
+ assert(NextTokPrec <= ThisPrec && "Recursion didn't work!");
+
+ if (!LHS.isInvalid()) {
+ // Combine the LHS and RHS into the LHS (e.g. build AST).
+ if (TernaryMiddle.isInvalid()) {
+ // If we're using '>>' as an operator within a template
+ // argument list (in C++98), suggest the addition of
+ // parentheses so that the code remains well-formed in C++0x.
+ if (!GreaterThanIsOperator && OpToken.is(tok::greatergreater))
+ SuggestParentheses(OpToken.getLocation(),
+ diag::warn_cxx0x_right_shift_in_template_arg,
+ SourceRange(Actions.getExprRange(LHS.get()).getBegin(),
+ Actions.getExprRange(RHS.get()).getEnd()));
+
+ LHS = Actions.ActOnBinOp(CurScope, OpToken.getLocation(),
+ OpToken.getKind(), move(LHS), move(RHS));
+ } else
+ LHS = Actions.ActOnConditionalOp(OpToken.getLocation(), ColonLoc,
+ move(LHS), move(TernaryMiddle),
+ move(RHS));
+ }
+ }
+}
+
+/// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is
+/// true, parse a unary-expression. isAddressOfOperand exists because an
+/// id-expression that is the operand of address-of gets special treatment
+/// due to member pointers.
+///
+Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
+ bool isAddressOfOperand) {
+ bool NotCastExpr;
+ OwningExprResult Res = ParseCastExpression(isUnaryExpression,
+ isAddressOfOperand,
+ NotCastExpr);
+ if (NotCastExpr)
+ Diag(Tok, diag::err_expected_expression);
+ return move(Res);
+}
+
+/// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is
+/// true, parse a unary-expression. isAddressOfOperand exists because an
+/// id-expression that is the operand of address-of gets special treatment
+/// due to member pointers. NotCastExpr is set to true if the token is not the
+/// start of a cast-expression, and no diagnostic is emitted in this case.
+///
+/// cast-expression: [C99 6.5.4]
+/// unary-expression
+/// '(' type-name ')' cast-expression
+///
+/// unary-expression: [C99 6.5.3]
+/// postfix-expression
+/// '++' unary-expression
+/// '--' unary-expression
+/// unary-operator cast-expression
+/// 'sizeof' unary-expression
+/// 'sizeof' '(' type-name ')'
+/// [GNU] '__alignof' unary-expression
+/// [GNU] '__alignof' '(' type-name ')'
+/// [C++0x] 'alignof' '(' type-id ')'
+/// [GNU] '&&' identifier
+/// [C++] new-expression
+/// [C++] delete-expression
+///
+/// unary-operator: one of
+/// '&' '*' '+' '-' '~' '!'
+/// [GNU] '__extension__' '__real' '__imag'
+///
+/// primary-expression: [C99 6.5.1]
+/// [C99] identifier
+/// [C++] id-expression
+/// constant
+/// string-literal
+/// [C++] boolean-literal [C++ 2.13.5]
+/// [C++0x] 'nullptr' [C++0x 2.14.7]
+/// '(' expression ')'
+/// '__func__' [C99 6.4.2.2]
+/// [GNU] '__FUNCTION__'
+/// [GNU] '__PRETTY_FUNCTION__'
+/// [GNU] '(' compound-statement ')'
+/// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')'
+/// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')'
+/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ','
+/// assign-expr ')'
+/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
+/// [GNU] '__null'
+/// [OBJC] '[' objc-message-expr ']'
+/// [OBJC] '@selector' '(' objc-selector-arg ')'
+/// [OBJC] '@protocol' '(' identifier ')'
+/// [OBJC] '@encode' '(' type-name ')'
+/// [OBJC] objc-string-literal
+/// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
+/// [C++] typename-specifier '(' expression-list[opt] ')' [TODO]
+/// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
+/// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
+/// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
+/// [C++] 'static_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
+/// [C++] 'typeid' '(' expression ')' [C++ 5.2p1]
+/// [C++] 'typeid' '(' type-id ')' [C++ 5.2p1]
+/// [C++] 'this' [C++ 9.3.2]
+/// [G++] unary-type-trait '(' type-id ')'
+/// [G++] binary-type-trait '(' type-id ',' type-id ')' [TODO]
+/// [clang] '^' block-literal
+///
+/// constant: [C99 6.4.4]
+/// integer-constant
+/// floating-constant
+/// enumeration-constant -> identifier
+/// character-constant
+///
+/// id-expression: [C++ 5.1]
+/// unqualified-id
+/// qualified-id [TODO]
+///
+/// unqualified-id: [C++ 5.1]
+/// identifier
+/// operator-function-id
+/// conversion-function-id [TODO]
+/// '~' class-name [TODO]
+/// template-id [TODO]
+///
+/// new-expression: [C++ 5.3.4]
+/// '::'[opt] 'new' new-placement[opt] new-type-id
+/// new-initializer[opt]
+/// '::'[opt] 'new' new-placement[opt] '(' type-id ')'
+/// new-initializer[opt]
+///
+/// delete-expression: [C++ 5.3.5]
+/// '::'[opt] 'delete' cast-expression
+/// '::'[opt] 'delete' '[' ']' cast-expression
+///
+/// [GNU] unary-type-trait:
+/// '__has_nothrow_assign' [TODO]
+/// '__has_nothrow_copy' [TODO]
+/// '__has_nothrow_constructor' [TODO]
+/// '__has_trivial_assign' [TODO]
+/// '__has_trivial_copy' [TODO]
+/// '__has_trivial_constructor'
+/// '__has_trivial_destructor'
+/// '__has_virtual_destructor' [TODO]
+/// '__is_abstract' [TODO]
+/// '__is_class'
+/// '__is_empty' [TODO]
+/// '__is_enum'
+/// '__is_pod'
+/// '__is_polymorphic'
+/// '__is_union'
+///
+/// [GNU] binary-type-trait:
+/// '__is_base_of' [TODO]
+///
+Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
+ bool isAddressOfOperand,
+ bool &NotCastExpr) {
+ OwningExprResult Res(Actions);
+ tok::TokenKind SavedKind = Tok.getKind();
+ NotCastExpr = false;
+
+ // This handles all of cast-expression, unary-expression, postfix-expression,
+ // and primary-expression. We handle them together like this for efficiency
+ // and to simplify handling of an expression starting with a '(' token: which
+ // may be one of a parenthesized expression, cast-expression, compound literal
+ // expression, or statement expression.
+ //
+ // If the parsed tokens consist of a primary-expression, the cases below
+ // call ParsePostfixExpressionSuffix to handle the postfix expression
+ // suffixes. Cases that cannot be followed by postfix exprs should
+ // return without invoking ParsePostfixExpressionSuffix.
+ switch (SavedKind) {
+ case tok::l_paren: {
+ // If this expression is limited to being a unary-expression, the parent can
+ // not start a cast expression.
+ ParenParseOption ParenExprType =
+ isUnaryExpression ? CompoundLiteral : CastExpr;
+ TypeTy *CastTy;
+ SourceLocation LParenLoc = Tok.getLocation();
+ SourceLocation RParenLoc;
+ Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/,
+ CastTy, RParenLoc);
+ if (Res.isInvalid()) return move(Res);
+
+ switch (ParenExprType) {
+ case SimpleExpr: break; // Nothing else to do.
+ case CompoundStmt: break; // Nothing else to do.
+ case CompoundLiteral:
+ // We parsed '(' type-name ')' '{' ... '}'. If any suffixes of
+ // postfix-expression exist, parse them now.
+ break;
+ case CastExpr:
+ // We have parsed the cast-expression and no postfix-expr pieces are
+ // following.
+ return move(Res);
+ }
+
+ // These can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(move(Res));
+ }
+
+ // primary-expression
+ case tok::numeric_constant:
+ // constant: integer-constant
+ // constant: floating-constant
+
+ Res = Actions.ActOnNumericConstant(Tok);
+ ConsumeToken();
+
+ // These can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(move(Res));
+
+ case tok::kw_true:
+ case tok::kw_false:
+ return ParseCXXBoolLiteral();
+
+ case tok::kw_nullptr:
+ return Actions.ActOnCXXNullPtrLiteral(ConsumeToken());
+
+ case tok::identifier: { // primary-expression: identifier
+ // unqualified-id: identifier
+ // constant: enumeration-constant
+ // Turn a potentially qualified name into a annot_typename or
+ // annot_cxxscope if it would be valid. This handles things like x::y, etc.
+ if (getLang().CPlusPlus) {
+ // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse.
+ if (TryAnnotateTypeOrScopeToken())
+ 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();
+ SourceLocation DotLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ return ExprError();
+ }
+ IdentifierInfo &PropertyName = *Tok.getIdentifierInfo();
+ SourceLocation PropertyLoc = ConsumeToken();
+
+ Res = Actions.ActOnClassPropertyRefExpr(ReceiverName, PropertyName,
+ IdentLoc, 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));
+ // These can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(move(Res));
+ }
+ case tok::char_constant: // constant: character-constant
+ Res = Actions.ActOnCharacterConstant(Tok);
+ ConsumeToken();
+ // These can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(move(Res));
+ case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2]
+ case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU]
+ case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU]
+ Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind);
+ ConsumeToken();
+ // These can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(move(Res));
+ case tok::string_literal: // primary-expression: string-literal
+ case tok::wide_string_literal:
+ Res = ParseStringLiteralExpression();
+ if (Res.isInvalid()) return move(Res);
+ // This can be followed by postfix-expr pieces (e.g. "foo"[1]).
+ return ParsePostfixExpressionSuffix(move(Res));
+ case tok::kw___builtin_va_arg:
+ case tok::kw___builtin_offsetof:
+ case tok::kw___builtin_choose_expr:
+ case tok::kw___builtin_types_compatible_p:
+ return ParseBuiltinPrimaryExpression();
+ case tok::kw___null:
+ return Actions.ActOnGNUNullExpr(ConsumeToken());
+ break;
+ case tok::plusplus: // unary-expression: '++' unary-expression
+ case tok::minusminus: { // unary-expression: '--' unary-expression
+ SourceLocation SavedLoc = ConsumeToken();
+ Res = ParseCastExpression(true);
+ if (!Res.isInvalid())
+ Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, move(Res));
+ return move(Res);
+ }
+ case tok::amp: { // unary-expression: '&' cast-expression
+ // Special treatment because of member pointers
+ SourceLocation SavedLoc = ConsumeToken();
+ Res = ParseCastExpression(false, true);
+ if (!Res.isInvalid())
+ Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, move(Res));
+ return move(Res);
+ }
+
+ case tok::star: // unary-expression: '*' cast-expression
+ case tok::plus: // unary-expression: '+' cast-expression
+ case tok::minus: // unary-expression: '-' cast-expression
+ case tok::tilde: // unary-expression: '~' cast-expression
+ case tok::exclaim: // unary-expression: '!' cast-expression
+ case tok::kw___real: // unary-expression: '__real' cast-expression [GNU]
+ case tok::kw___imag: { // unary-expression: '__imag' cast-expression [GNU]
+ SourceLocation SavedLoc = ConsumeToken();
+ Res = ParseCastExpression(false);
+ if (!Res.isInvalid())
+ Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, move(Res));
+ return move(Res);
+ }
+
+ case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU]
+ // __extension__ silences extension warnings in the subexpression.
+ ExtensionRAIIObject O(Diags); // Use RAII to do this.
+ SourceLocation SavedLoc = ConsumeToken();
+ Res = ParseCastExpression(false);
+ if (!Res.isInvalid())
+ Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, move(Res));
+ return move(Res);
+ }
+ case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression
+ // unary-expression: 'sizeof' '(' type-name ')'
+ case tok::kw_alignof:
+ case tok::kw___alignof: // unary-expression: '__alignof' unary-expression
+ // unary-expression: '__alignof' '(' type-name ')'
+ // unary-expression: 'alignof' '(' type-id ')'
+ return ParseSizeofAlignofExpression();
+ case tok::ampamp: { // unary-expression: '&&' identifier
+ SourceLocation AmpAmpLoc = ConsumeToken();
+ if (Tok.isNot(tok::identifier))
+ return ExprError(Diag(Tok, diag::err_expected_ident));
+
+ Diag(AmpAmpLoc, diag::ext_gnu_address_of_label);
+ Res = Actions.ActOnAddrLabel(AmpAmpLoc, Tok.getLocation(),
+ Tok.getIdentifierInfo());
+ ConsumeToken();
+ return move(Res);
+ }
+ case tok::kw_const_cast:
+ case tok::kw_dynamic_cast:
+ case tok::kw_reinterpret_cast:
+ case tok::kw_static_cast:
+ Res = ParseCXXCasts();
+ // These can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(move(Res));
+ case tok::kw_typeid:
+ Res = ParseCXXTypeid();
+ // This can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(move(Res));
+ case tok::kw_this:
+ Res = ParseCXXThis();
+ // This can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(move(Res));
+
+ case tok::kw_char:
+ case tok::kw_wchar_t:
+ case tok::kw_bool:
+ case tok::kw_short:
+ case tok::kw_int:
+ case tok::kw_long:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_void:
+ case tok::kw_typename:
+ case tok::kw_typeof:
+ case tok::annot_typename: {
+ if (!getLang().CPlusPlus) {
+ Diag(Tok, diag::err_expected_expression);
+ return ExprError();
+ }
+
+ // postfix-expression: simple-type-specifier '(' expression-list[opt] ')'
+ //
+ DeclSpec DS;
+ ParseCXXSimpleTypeSpecifier(DS);
+ if (Tok.isNot(tok::l_paren))
+ return ExprError(Diag(Tok, diag::err_expected_lparen_after_type)
+ << DS.getSourceRange());
+
+ Res = ParseCXXTypeConstructExpression(DS);
+ // This can be followed by postfix-expr pieces.
+ return ParsePostfixExpressionSuffix(move(Res));
+ }
+
+ case tok::annot_cxxscope: // [C++] id-expression: qualified-id
+ case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id
+ // template-id
+ Res = ParseCXXIdExpression(isAddressOfOperand);
+ return ParsePostfixExpressionSuffix(move(Res));
+
+ case tok::coloncolon: {
+ // ::foo::bar -> global qualified name etc. If TryAnnotateTypeOrScopeToken
+ // annotates the token, tail recurse.
+ if (TryAnnotateTypeOrScopeToken())
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
+
+ // ::new -> [C++] new-expression
+ // ::delete -> [C++] delete-expression
+ SourceLocation CCLoc = ConsumeToken();
+ if (Tok.is(tok::kw_new))
+ return ParseCXXNewExpression(true, CCLoc);
+ if (Tok.is(tok::kw_delete))
+ return ParseCXXDeleteExpression(true, CCLoc);
+
+ // This is not a type name or scope specifier, it is an invalid expression.
+ Diag(CCLoc, diag::err_expected_expression);
+ return ExprError();
+ }
+
+ case tok::kw_new: // [C++] new-expression
+ return ParseCXXNewExpression(false, Tok.getLocation());
+
+ case tok::kw_delete: // [C++] delete-expression
+ return ParseCXXDeleteExpression(false, Tok.getLocation());
+
+ case tok::kw___is_pod: // [GNU] unary-type-trait
+ case tok::kw___is_class:
+ case tok::kw___is_enum:
+ case tok::kw___is_union:
+ case tok::kw___is_polymorphic:
+ case tok::kw___is_abstract:
+ case tok::kw___has_trivial_constructor:
+ case tok::kw___has_trivial_destructor:
+ return ParseUnaryTypeTrait();
+
+ case tok::at: {
+ SourceLocation AtLoc = ConsumeToken();
+ return ParseObjCAtExpression(AtLoc);
+ }
+ case tok::caret:
+ return ParsePostfixExpressionSuffix(ParseBlockLiteralExpression());
+ case tok::l_square:
+ // These can be followed by postfix-expr pieces.
+ if (getLang().ObjC1)
+ return ParsePostfixExpressionSuffix(ParseObjCMessageExpression());
+ // FALL THROUGH.
+ default:
+ NotCastExpr = true;
+ return ExprError();
+ }
+
+ // unreachable.
+ abort();
+}
+
+/// ParsePostfixExpressionSuffix - Once the leading part of a postfix-expression
+/// is parsed, this method parses any suffixes that apply.
+///
+/// postfix-expression: [C99 6.5.2]
+/// primary-expression
+/// postfix-expression '[' expression ']'
+/// postfix-expression '(' argument-expression-list[opt] ')'
+/// postfix-expression '.' identifier
+/// postfix-expression '->' identifier
+/// postfix-expression '++'
+/// postfix-expression '--'
+/// '(' type-name ')' '{' initializer-list '}'
+/// '(' type-name ')' '{' initializer-list ',' '}'
+///
+/// argument-expression-list: [C99 6.5.2]
+/// argument-expression
+/// argument-expression-list ',' assignment-expression
+///
+Parser::OwningExprResult
+Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
+ // Now that the primary-expression piece of the postfix-expression has been
+ // parsed, see if there are any postfix-expression pieces here.
+ SourceLocation Loc;
+ while (1) {
+ switch (Tok.getKind()) {
+ default: // Not a postfix-expression suffix.
+ return move(LHS);
+ case tok::l_square: { // postfix-expression: p-e '[' expression ']'
+ Loc = ConsumeBracket();
+ OwningExprResult Idx(ParseExpression());
+
+ SourceLocation RLoc = Tok.getLocation();
+
+ if (!LHS.isInvalid() && !Idx.isInvalid() && Tok.is(tok::r_square)) {
+ LHS = Actions.ActOnArraySubscriptExpr(CurScope, move(LHS), Loc,
+ move(Idx), RLoc);
+ } else
+ LHS = ExprError();
+
+ // Match the ']'.
+ MatchRHSPunctuation(tok::r_square, Loc);
+ break;
+ }
+
+ case tok::l_paren: { // p-e: p-e '(' argument-expression-list[opt] ')'
+ ExprVector ArgExprs(Actions);
+ CommaLocsTy CommaLocs;
+
+ Loc = ConsumeParen();
+
+ if (Tok.isNot(tok::r_paren)) {
+ if (ParseExpressionList(ArgExprs, CommaLocs)) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+ }
+
+ // Match the ')'.
+ if (Tok.isNot(tok::r_paren)) {
+ MatchRHSPunctuation(tok::r_paren, Loc);
+ return ExprError();
+ }
+
+ if (!LHS.isInvalid()) {
+ assert((ArgExprs.size() == 0 || ArgExprs.size()-1 == CommaLocs.size())&&
+ "Unexpected number of commas!");
+ LHS = Actions.ActOnCallExpr(CurScope, move(LHS), Loc,
+ move_arg(ArgExprs), CommaLocs.data(),
+ Tok.getLocation());
+ }
+
+ ConsumeParen();
+ break;
+ }
+ case tok::arrow: // postfix-expression: p-e '->' identifier
+ case tok::period: { // postfix-expression: p-e '.' identifier
+ tok::TokenKind OpKind = Tok.getKind();
+ SourceLocation OpLoc = ConsumeToken(); // Eat the "." or "->" token.
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ return ExprError();
+ }
+
+ if (!LHS.isInvalid()) {
+ LHS = Actions.ActOnMemberReferenceExpr(CurScope, move(LHS), OpLoc,
+ OpKind, Tok.getLocation(),
+ *Tok.getIdentifierInfo(),
+ ObjCImpDecl);
+ }
+ ConsumeToken();
+ break;
+ }
+ case tok::plusplus: // postfix-expression: postfix-expression '++'
+ case tok::minusminus: // postfix-expression: postfix-expression '--'
+ if (!LHS.isInvalid()) {
+ LHS = Actions.ActOnPostfixUnaryOp(CurScope, Tok.getLocation(),
+ Tok.getKind(), move(LHS));
+ }
+ ConsumeToken();
+ break;
+ }
+ }
+}
+
+/// ParseExprAfterTypeofSizeofAlignof - We parsed a typeof/sizeof/alignof and
+/// we are at the start of an expression or a parenthesized type-id.
+/// OpTok is the operand token (typeof/sizeof/alignof). Returns the expression
+/// (isCastExpr == false) or the type (isCastExpr == true).
+///
+/// unary-expression: [C99 6.5.3]
+/// 'sizeof' unary-expression
+/// 'sizeof' '(' type-name ')'
+/// [GNU] '__alignof' unary-expression
+/// [GNU] '__alignof' '(' type-name ')'
+/// [C++0x] 'alignof' '(' type-id ')'
+///
+/// [GNU] typeof-specifier:
+/// typeof ( expressions )
+/// typeof ( type-name )
+/// [GNU/C++] typeof unary-expression
+///
+Parser::OwningExprResult
+Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
+ bool &isCastExpr,
+ TypeTy *&CastTy,
+ SourceRange &CastRange) {
+
+ assert((OpTok.is(tok::kw_typeof) || OpTok.is(tok::kw_sizeof) ||
+ OpTok.is(tok::kw___alignof) || OpTok.is(tok::kw_alignof)) &&
+ "Not a typeof/sizeof/alignof expression!");
+
+ OwningExprResult Operand(Actions);
+
+ // If the operand doesn't start with an '(', it must be an expression.
+ if (Tok.isNot(tok::l_paren)) {
+ isCastExpr = false;
+ if (OpTok.is(tok::kw_typeof) && !getLang().CPlusPlus) {
+ Diag(Tok,diag::err_expected_lparen_after_id) << OpTok.getIdentifierInfo();
+ return ExprError();
+ }
+ Operand = ParseCastExpression(true/*isUnaryExpression*/);
+
+ } else {
+ // If it starts with a '(', we know that it is either a parenthesized
+ // type-name, or it is a unary-expression that starts with a compound
+ // literal, or starts with a primary-expression that is a parenthesized
+ // expression.
+ ParenParseOption ExprType = CastExpr;
+ SourceLocation LParenLoc = Tok.getLocation(), RParenLoc;
+ Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/,
+ CastTy, RParenLoc);
+ CastRange = SourceRange(LParenLoc, RParenLoc);
+
+ // If ParseParenExpression parsed a '(typename)' sequence only, then this is
+ // a type.
+ if (ExprType == CastExpr) {
+ isCastExpr = true;
+ return ExprEmpty();
+ }
+
+ // If this is a parenthesized expression, it is the start of a
+ // unary-expression, but doesn't include any postfix pieces. Parse these
+ // now if present.
+ Operand = ParsePostfixExpressionSuffix(move(Operand));
+ }
+
+ // If we get here, the operand to the typeof/sizeof/alignof was an expresion.
+ isCastExpr = false;
+ return move(Operand);
+}
+
+
+/// ParseSizeofAlignofExpression - Parse a sizeof or alignof expression.
+/// unary-expression: [C99 6.5.3]
+/// 'sizeof' unary-expression
+/// 'sizeof' '(' type-name ')'
+/// [GNU] '__alignof' unary-expression
+/// [GNU] '__alignof' '(' type-name ')'
+/// [C++0x] 'alignof' '(' type-id ')'
+Parser::OwningExprResult Parser::ParseSizeofAlignofExpression() {
+ assert((Tok.is(tok::kw_sizeof) || Tok.is(tok::kw___alignof)
+ || Tok.is(tok::kw_alignof)) &&
+ "Not a sizeof/alignof expression!");
+ Token OpTok = Tok;
+ ConsumeToken();
+
+ bool isCastExpr;
+ TypeTy *CastTy;
+ SourceRange CastRange;
+ OwningExprResult Operand = ParseExprAfterTypeofSizeofAlignof(OpTok,
+ isCastExpr,
+ CastTy,
+ CastRange);
+
+ if (isCastExpr)
+ return Actions.ActOnSizeOfAlignOfExpr(OpTok.getLocation(),
+ OpTok.is(tok::kw_sizeof),
+ /*isType=*/true, CastTy,
+ CastRange);
+
+ // If we get here, the operand to the sizeof/alignof was an expresion.
+ if (!Operand.isInvalid())
+ Operand = Actions.ActOnSizeOfAlignOfExpr(OpTok.getLocation(),
+ OpTok.is(tok::kw_sizeof),
+ /*isType=*/false,
+ Operand.release(), CastRange);
+ return move(Operand);
+}
+
+/// ParseBuiltinPrimaryExpression
+///
+/// primary-expression: [C99 6.5.1]
+/// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')'
+/// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')'
+/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ','
+/// assign-expr ')'
+/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
+///
+/// [GNU] offsetof-member-designator:
+/// [GNU] identifier
+/// [GNU] offsetof-member-designator '.' identifier
+/// [GNU] offsetof-member-designator '[' expression ']'
+///
+Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() {
+ OwningExprResult Res(Actions);
+ const IdentifierInfo *BuiltinII = Tok.getIdentifierInfo();
+
+ tok::TokenKind T = Tok.getKind();
+ SourceLocation StartLoc = ConsumeToken(); // Eat the builtin identifier.
+
+ // All of these start with an open paren.
+ if (Tok.isNot(tok::l_paren))
+ return ExprError(Diag(Tok, diag::err_expected_lparen_after_id)
+ << BuiltinII);
+
+ SourceLocation LParenLoc = ConsumeParen();
+ // TODO: Build AST.
+
+ switch (T) {
+ default: assert(0 && "Not a builtin primary expression!");
+ case tok::kw___builtin_va_arg: {
+ OwningExprResult Expr(ParseAssignmentExpression());
+ if (Expr.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
+ return ExprError();
+
+ TypeResult Ty = ParseTypeName();
+
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_expected_rparen);
+ return ExprError();
+ }
+ if (Ty.isInvalid())
+ Res = ExprError();
+ else
+ Res = Actions.ActOnVAArg(StartLoc, move(Expr), Ty.get(), ConsumeParen());
+ break;
+ }
+ case tok::kw___builtin_offsetof: {
+ SourceLocation TypeLoc = Tok.getLocation();
+ TypeResult Ty = ParseTypeName();
+ if (Ty.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
+ return ExprError();
+
+ // We must have at least one identifier here.
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ // Keep track of the various subcomponents we see.
+ llvm::SmallVector<Action::OffsetOfComponent, 4> Comps;
+
+ Comps.push_back(Action::OffsetOfComponent());
+ Comps.back().isBrackets = false;
+ Comps.back().U.IdentInfo = Tok.getIdentifierInfo();
+ Comps.back().LocStart = Comps.back().LocEnd = ConsumeToken();
+
+ // FIXME: This loop leaks the index expressions on error.
+ while (1) {
+ if (Tok.is(tok::period)) {
+ // offsetof-member-designator: offsetof-member-designator '.' identifier
+ Comps.push_back(Action::OffsetOfComponent());
+ Comps.back().isBrackets = false;
+ Comps.back().LocStart = ConsumeToken();
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+ Comps.back().U.IdentInfo = Tok.getIdentifierInfo();
+ Comps.back().LocEnd = ConsumeToken();
+
+ } else if (Tok.is(tok::l_square)) {
+ // offsetof-member-designator: offsetof-member-design '[' expression ']'
+ Comps.push_back(Action::OffsetOfComponent());
+ Comps.back().isBrackets = true;
+ Comps.back().LocStart = ConsumeBracket();
+ Res = ParseExpression();
+ if (Res.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return move(Res);
+ }
+ Comps.back().U.E = Res.release();
+
+ Comps.back().LocEnd =
+ MatchRHSPunctuation(tok::r_square, Comps.back().LocStart);
+ } else if (Tok.is(tok::r_paren)) {
+ if (Ty.isInvalid())
+ Res = ExprError();
+ else
+ Res = Actions.ActOnBuiltinOffsetOf(CurScope, StartLoc, TypeLoc,
+ Ty.get(), &Comps[0],
+ Comps.size(), ConsumeParen());
+ break;
+ } else {
+ // Error occurred.
+ return ExprError();
+ }
+ }
+ break;
+ }
+ case tok::kw___builtin_choose_expr: {
+ OwningExprResult Cond(ParseAssignmentExpression());
+ if (Cond.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return move(Cond);
+ }
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
+ return ExprError();
+
+ OwningExprResult Expr1(ParseAssignmentExpression());
+ if (Expr1.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return move(Expr1);
+ }
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
+ return ExprError();
+
+ OwningExprResult Expr2(ParseAssignmentExpression());
+ if (Expr2.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return move(Expr2);
+ }
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_expected_rparen);
+ return ExprError();
+ }
+ Res = Actions.ActOnChooseExpr(StartLoc, move(Cond), move(Expr1),
+ move(Expr2), ConsumeParen());
+ break;
+ }
+ case tok::kw___builtin_types_compatible_p:
+ TypeResult Ty1 = ParseTypeName();
+
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
+ return ExprError();
+
+ TypeResult Ty2 = ParseTypeName();
+
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_expected_rparen);
+ return ExprError();
+ }
+
+ if (Ty1.isInvalid() || Ty2.isInvalid())
+ Res = ExprError();
+ else
+ Res = Actions.ActOnTypesCompatibleExpr(StartLoc, Ty1.get(), Ty2.get(),
+ ConsumeParen());
+ break;
+ }
+
+ // These can be followed by postfix-expr pieces because they are
+ // primary-expressions.
+ return ParsePostfixExpressionSuffix(move(Res));
+}
+
+/// ParseParenExpression - This parses the unit that starts with a '(' token,
+/// based on what is allowed by ExprType. The actual thing parsed is returned
+/// in ExprType. If stopIfCastExpr is true, it will only return the parsed type,
+/// not the parsed cast-expression.
+///
+/// primary-expression: [C99 6.5.1]
+/// '(' expression ')'
+/// [GNU] '(' compound-statement ')' (if !ParenExprOnly)
+/// postfix-expression: [C99 6.5.2]
+/// '(' type-name ')' '{' initializer-list '}'
+/// '(' type-name ')' '{' initializer-list ',' '}'
+/// cast-expression: [C99 6.5.4]
+/// '(' type-name ')' cast-expression
+///
+Parser::OwningExprResult
+Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
+ TypeTy *&CastTy, SourceLocation &RParenLoc) {
+ assert(Tok.is(tok::l_paren) && "Not a paren expr!");
+ GreaterThanIsOperatorScope G(GreaterThanIsOperator, true);
+ SourceLocation OpenLoc = ConsumeParen();
+ OwningExprResult Result(Actions, true);
+ bool isAmbiguousTypeId;
+ CastTy = 0;
+
+ if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) {
+ Diag(Tok, diag::ext_gnu_statement_expr);
+ OwningStmtResult Stmt(ParseCompoundStatement(true));
+ ExprType = CompoundStmt;
+
+ // If the substmt parsed correctly, build the AST node.
+ if (!Stmt.isInvalid() && Tok.is(tok::r_paren))
+ Result = Actions.ActOnStmtExpr(OpenLoc, move(Stmt), Tok.getLocation());
+
+ } else if (ExprType >= CompoundLiteral &&
+ isTypeIdInParens(isAmbiguousTypeId)) {
+
+ // Otherwise, this is a compound literal expression or cast expression.
+
+ // In C++, if the type-id is ambiguous we disambiguate based on context.
+ // If stopIfCastExpr is true the context is a typeof/sizeof/alignof
+ // in which case we should treat it as type-id.
+ // if stopIfCastExpr is false, we need to determine the context past the
+ // parens, so we defer to ParseCXXAmbiguousParenExpression for that.
+ if (isAmbiguousTypeId && !stopIfCastExpr)
+ return ParseCXXAmbiguousParenExpression(ExprType, CastTy,
+ OpenLoc, RParenLoc);
+
+ TypeResult Ty = ParseTypeName();
+
+ // Match the ')'.
+ if (Tok.is(tok::r_paren))
+ RParenLoc = ConsumeParen();
+ else
+ MatchRHSPunctuation(tok::r_paren, OpenLoc);
+
+ if (Tok.is(tok::l_brace)) {
+ ExprType = CompoundLiteral;
+ return ParseCompoundLiteralExpression(Ty.get(), OpenLoc, RParenLoc);
+ }
+
+ if (ExprType == CastExpr) {
+ // We parsed '(' type-name ')' and the thing after it wasn't a '{'.
+
+ if (Ty.isInvalid())
+ return ExprError();
+
+ CastTy = Ty.get();
+
+ if (stopIfCastExpr) {
+ // Note that this doesn't parse the subsequent cast-expression, it just
+ // returns the parsed type to the callee.
+ return OwningExprResult(Actions);
+ }
+
+ // Parse the cast-expression that follows it next.
+ // TODO: For cast expression with CastTy.
+ Result = ParseCastExpression(false);
+ if (!Result.isInvalid())
+ Result = Actions.ActOnCastExpr(OpenLoc, CastTy, RParenLoc,move(Result));
+ return move(Result);
+ }
+
+ Diag(Tok, diag::err_expected_lbrace_in_compound_literal);
+ return ExprError();
+ } else {
+ Result = ParseExpression();
+ ExprType = SimpleExpr;
+ if (!Result.isInvalid() && Tok.is(tok::r_paren))
+ Result = Actions.ActOnParenExpr(OpenLoc, Tok.getLocation(), move(Result));
+ }
+
+ // Match the ')'.
+ if (Result.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ if (Tok.is(tok::r_paren))
+ RParenLoc = ConsumeParen();
+ else
+ MatchRHSPunctuation(tok::r_paren, OpenLoc);
+
+ return move(Result);
+}
+
+/// ParseCompoundLiteralExpression - We have parsed the parenthesized type-name
+/// and we are at the left brace.
+///
+/// postfix-expression: [C99 6.5.2]
+/// '(' type-name ')' '{' initializer-list '}'
+/// '(' type-name ')' '{' initializer-list ',' '}'
+///
+Parser::OwningExprResult
+Parser::ParseCompoundLiteralExpression(TypeTy *Ty,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+ assert(Tok.is(tok::l_brace) && "Not a compound literal!");
+ if (!getLang().C99) // Compound literals don't exist in C90.
+ Diag(LParenLoc, diag::ext_c99_compound_literal);
+ OwningExprResult Result = ParseInitializer();
+ if (!Result.isInvalid() && Ty)
+ return Actions.ActOnCompoundLiteral(LParenLoc, Ty, RParenLoc, move(Result));
+ return move(Result);
+}
+
+/// ParseStringLiteralExpression - This handles the various token types that
+/// form string literals, and also handles string concatenation [C99 5.1.1.2,
+/// translation phase #6].
+///
+/// primary-expression: [C99 6.5.1]
+/// string-literal
+Parser::OwningExprResult Parser::ParseStringLiteralExpression() {
+ assert(isTokenStringLiteral() && "Not a string literal!");
+
+ // String concat. Note that keywords like __func__ and __FUNCTION__ are not
+ // considered to be strings for concatenation purposes.
+ llvm::SmallVector<Token, 4> StringToks;
+
+ do {
+ StringToks.push_back(Tok);
+ ConsumeStringToken();
+ } while (isTokenStringLiteral());
+
+ // Pass the set of string tokens, ready for concatenation, to the actions.
+ return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size());
+}
+
+/// ParseExpressionList - Used for C/C++ (argument-)expression-list.
+///
+/// argument-expression-list:
+/// assignment-expression
+/// argument-expression-list , assignment-expression
+///
+/// [C++] expression-list:
+/// [C++] assignment-expression
+/// [C++] expression-list , assignment-expression
+///
+bool Parser::ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs) {
+ while (1) {
+ OwningExprResult Expr(ParseAssignmentExpression());
+ if (Expr.isInvalid())
+ return true;
+
+ Exprs.push_back(Expr.release());
+
+ if (Tok.isNot(tok::comma))
+ return false;
+ // Move to the next argument, remember where the comma was.
+ CommaLocs.push_back(ConsumeToken());
+ }
+}
+
+/// ParseBlockId - Parse a block-id, which roughly looks like int (int x).
+///
+/// [clang] block-id:
+/// [clang] specifier-qualifier-list block-declarator
+///
+void Parser::ParseBlockId() {
+ // Parse the specifier-qualifier-list piece.
+ DeclSpec DS;
+ ParseSpecifierQualifierList(DS);
+
+ // Parse the block-declarator.
+ Declarator DeclaratorInfo(DS, Declarator::BlockLiteralContext);
+ ParseDeclarator(DeclaratorInfo);
+
+ // We do this for: ^ __attribute__((noreturn)) {, as DS has the attributes.
+ DeclaratorInfo.AddAttributes(DS.TakeAttributes(),
+ SourceLocation());
+
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ DeclaratorInfo.AddAttributes(AttrList, Loc);
+ }
+
+ // Inform sema that we are starting a block.
+ Actions.ActOnBlockArguments(DeclaratorInfo, CurScope);
+}
+
+/// ParseBlockLiteralExpression - Parse a block literal, which roughly looks
+/// like ^(int x){ return x+1; }
+///
+/// block-literal:
+/// [clang] '^' block-args[opt] compound-statement
+/// [clang] '^' block-id compound-statement
+/// [clang] block-args:
+/// [clang] '(' parameter-list ')'
+///
+Parser::OwningExprResult Parser::ParseBlockLiteralExpression() {
+ assert(Tok.is(tok::caret) && "block literal starts with ^");
+ SourceLocation CaretLoc = ConsumeToken();
+
+ PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), CaretLoc,
+ "block literal parsing");
+
+ // Enter a scope to hold everything within the block. This includes the
+ // argument decls, decls within the compound expression, etc. This also
+ // allows determining whether a variable reference inside the block is
+ // within or outside of the block.
+ ParseScope BlockScope(this, Scope::BlockScope | Scope::FnScope |
+ Scope::BreakScope | Scope::ContinueScope |
+ Scope::DeclScope);
+
+ // Inform sema that we are starting a block.
+ Actions.ActOnBlockStart(CaretLoc, CurScope);
+
+ // Parse the return type if present.
+ DeclSpec DS;
+ Declarator ParamInfo(DS, Declarator::BlockLiteralContext);
+ // FIXME: Since the return type isn't actually parsed, it can't be used to
+ // fill ParamInfo with an initial valid range, so do it manually.
+ ParamInfo.SetSourceRange(SourceRange(Tok.getLocation(), Tok.getLocation()));
+
+ // If this block has arguments, parse them. There is no ambiguity here with
+ // the expression case, because the expression case requires a parameter list.
+ if (Tok.is(tok::l_paren)) {
+ ParseParenDeclarator(ParamInfo);
+ // Parse the pieces after the identifier as if we had "int(...)".
+ // SetIdentifier sets the source range end, but in this case we're past
+ // that location.
+ SourceLocation Tmp = ParamInfo.getSourceRange().getEnd();
+ ParamInfo.SetIdentifier(0, CaretLoc);
+ ParamInfo.SetRangeEnd(Tmp);
+ if (ParamInfo.isInvalidType()) {
+ // If there was an error parsing the arguments, they may have
+ // tried to use ^(x+y) which requires an argument list. Just
+ // skip the whole block literal.
+ Actions.ActOnBlockError(CaretLoc, CurScope);
+ return ExprError();
+ }
+
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ ParamInfo.AddAttributes(AttrList, Loc);
+ }
+
+ // Inform sema that we are starting a block.
+ Actions.ActOnBlockArguments(ParamInfo, CurScope);
+ } else if (!Tok.is(tok::l_brace)) {
+ ParseBlockId();
+ } else {
+ // Otherwise, pretend we saw (void).
+ ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false,
+ SourceLocation(),
+ 0, 0, 0,
+ false, SourceLocation(),
+ false, 0, 0, 0,
+ CaretLoc, ParamInfo),
+ CaretLoc);
+
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ ParamInfo.AddAttributes(AttrList, Loc);
+ }
+
+ // Inform sema that we are starting a block.
+ Actions.ActOnBlockArguments(ParamInfo, CurScope);
+ }
+
+
+ OwningExprResult Result(Actions, true);
+ if (!Tok.is(tok::l_brace)) {
+ // Saw something like: ^expr
+ Diag(Tok, diag::err_expected_expression);
+ Actions.ActOnBlockError(CaretLoc, CurScope);
+ return ExprError();
+ }
+
+ OwningStmtResult Stmt(ParseCompoundStatementBody());
+ if (!Stmt.isInvalid())
+ Result = Actions.ActOnBlockStmtExpr(CaretLoc, move(Stmt), CurScope);
+ else
+ Actions.ActOnBlockError(CaretLoc, CurScope);
+ return move(Result);
+}
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
new file mode 100644
index 0000000..681c6ad
--- /dev/null
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -0,0 +1,1166 @@
+//===--- ParseExprCXX.cpp - C++ Expression Parsing ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Expression parsing implementation for C++.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/DeclSpec.h"
+using namespace clang;
+
+/// ParseOptionalCXXScopeSpecifier - Parse global scope or
+/// nested-name-specifier if present. Returns true if a nested-name-specifier
+/// was parsed from the token stream. Note that this routine will not parse
+/// ::new or ::delete, it will just leave them in the token stream.
+///
+/// '::'[opt] nested-name-specifier
+/// '::'
+///
+/// nested-name-specifier:
+/// type-name '::'
+/// namespace-name '::'
+/// nested-name-specifier identifier '::'
+/// nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
+///
+bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
+ assert(getLang().CPlusPlus &&
+ "Call sites of this function should be guarded by checking for C++");
+
+ if (Tok.is(tok::annot_cxxscope)) {
+ SS.setScopeRep(Tok.getAnnotationValue());
+ SS.setRange(Tok.getAnnotationRange());
+ ConsumeToken();
+ return true;
+ }
+
+ bool HasScopeSpecifier = false;
+
+ if (Tok.is(tok::coloncolon)) {
+ // ::new and ::delete aren't nested-name-specifiers.
+ tok::TokenKind NextKind = NextToken().getKind();
+ if (NextKind == tok::kw_new || NextKind == tok::kw_delete)
+ return false;
+
+ // '::' - Global scope qualifier.
+ SourceLocation CCLoc = ConsumeToken();
+ SS.setBeginLoc(CCLoc);
+ SS.setScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(CurScope, CCLoc));
+ SS.setEndLoc(CCLoc);
+ HasScopeSpecifier = true;
+ }
+
+ while (true) {
+ // nested-name-specifier:
+ // type-name '::'
+ // namespace-name '::'
+ // nested-name-specifier identifier '::'
+ if (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) {
+ // We have an identifier followed by a '::'. Lookup this name
+ // as the name in a nested-name-specifier.
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ SourceLocation IdLoc = ConsumeToken();
+ assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
+ SourceLocation CCLoc = ConsumeToken();
+
+ if (!HasScopeSpecifier) {
+ SS.setBeginLoc(IdLoc);
+ HasScopeSpecifier = true;
+ }
+
+ if (SS.isInvalid())
+ continue;
+
+ SS.setScopeRep(
+ Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, *II));
+ SS.setEndLoc(CCLoc);
+ continue;
+ }
+
+ // nested-name-specifier:
+ // type-name '::'
+ // nested-name-specifier 'template'[opt] simple-template-id '::'
+ if ((Tok.is(tok::identifier) && NextToken().is(tok::less)) ||
+ Tok.is(tok::kw_template)) {
+ // Parse the optional 'template' keyword, then make sure we have
+ // 'identifier <' after it.
+ if (Tok.is(tok::kw_template)) {
+ SourceLocation TemplateKWLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::identifier)) {
+ 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);
+ AnnotateTemplateIdToken(Template, TNK_Dependent_template_name,
+ &SS, TemplateKWLoc, false);
+ continue;
+ }
+
+ TemplateTy Template;
+ TemplateNameKind TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(),
+ CurScope, Template, &SS);
+ if (TNK) {
+ // We have found a template name, so annotate this this token
+ // with a template-id annotation. We do not permit the
+ // template-id to be translated into a type annotation,
+ // because some clients (e.g., the parsing of class template
+ // specializations) still want to see the original template-id
+ // token.
+ AnnotateTemplateIdToken(Template, TNK, &SS, SourceLocation(), false);
+ continue;
+ }
+ }
+
+ if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) {
+ // We have
+ //
+ // simple-template-id '::'
+ //
+ // So we need to check whether the simple-template-id is of the
+ // right kind (it should name a type or be dependent), and then
+ // convert it into a type within the nested-name-specifier.
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+
+ if (TemplateId->Kind == TNK_Type_template ||
+ TemplateId->Kind == TNK_Dependent_template_name) {
+ AnnotateTemplateIdTokenAsType(&SS);
+ SS.setScopeRep(0);
+
+ assert(Tok.is(tok::annot_typename) &&
+ "AnnotateTemplateIdTokenAsType isn't working");
+ Token TypeToken = Tok;
+ ConsumeToken();
+ assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
+ SourceLocation CCLoc = ConsumeToken();
+
+ if (!HasScopeSpecifier) {
+ SS.setBeginLoc(TypeToken.getLocation());
+ HasScopeSpecifier = true;
+ }
+
+ if (TypeToken.getAnnotationValue())
+ SS.setScopeRep(
+ Actions.ActOnCXXNestedNameSpecifier(CurScope, SS,
+ TypeToken.getAnnotationValue(),
+ TypeToken.getAnnotationRange(),
+ CCLoc));
+ else
+ SS.setScopeRep(0);
+ SS.setEndLoc(CCLoc);
+ continue;
+ } else
+ assert(false && "FIXME: Only type template names supported here");
+ }
+
+ // We don't have any tokens that form the beginning of a
+ // nested-name-specifier, so we're done.
+ break;
+ }
+
+ return HasScopeSpecifier;
+}
+
+/// ParseCXXIdExpression - Handle id-expression.
+///
+/// id-expression:
+/// unqualified-id
+/// qualified-id
+///
+/// unqualified-id:
+/// identifier
+/// operator-function-id
+/// conversion-function-id [TODO]
+/// '~' class-name [TODO]
+/// template-id [TODO]
+///
+/// qualified-id:
+/// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
+/// '::' identifier
+/// '::' operator-function-id
+/// '::' template-id [TODO]
+///
+/// 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:
+///
+/// '::' conversion-function-id
+/// '::' '~' class-name
+///
+/// This may cause a slight inconsistency on diagnostics:
+///
+/// class C {};
+/// namespace A {}
+/// void f() {
+/// :: A :: ~ C(); // Some Sema error about using destructor with a
+/// // namespace.
+/// :: ~ C(); // Some Parser error like 'unexpected ~'.
+/// }
+///
+/// We simplify the parser a bit and make it work like:
+///
+/// qualified-id:
+/// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
+/// '::' unqualified-id
+///
+/// That way Sema can handle and report similar errors for namespaces and the
+/// global scope.
+///
+/// The isAddressOfOperand parameter indicates that this id-expression is a
+/// direct operand of the address-of operator. This is, besides member contexts,
+/// the only place where a qualified-id naming a non-static class member may
+/// appear.
+///
+Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
+ // qualified-id:
+ // '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
+ // '::' unqualified-id
+ //
+ CXXScopeSpec SS;
+ ParseOptionalCXXScopeSpecifier(SS);
+
+ // unqualified-id:
+ // identifier
+ // operator-function-id
+ // conversion-function-id
+ // '~' class-name [TODO]
+ // template-id [TODO]
+ //
+ 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.
+ return ExprError();
+ }
+
+ } // switch.
+
+ assert(0 && "The switch was supposed to take care everything.");
+}
+
+/// ParseCXXCasts - This handles the various ways to cast expressions to another
+/// type.
+///
+/// postfix-expression: [C++ 5.2p1]
+/// 'dynamic_cast' '<' type-name '>' '(' expression ')'
+/// 'static_cast' '<' type-name '>' '(' expression ')'
+/// 'reinterpret_cast' '<' type-name '>' '(' expression ')'
+/// 'const_cast' '<' type-name '>' '(' expression ')'
+///
+Parser::OwningExprResult Parser::ParseCXXCasts() {
+ tok::TokenKind Kind = Tok.getKind();
+ const char *CastName = 0; // For error messages
+
+ switch (Kind) {
+ default: assert(0 && "Unknown C++ cast!"); abort();
+ case tok::kw_const_cast: CastName = "const_cast"; break;
+ case tok::kw_dynamic_cast: CastName = "dynamic_cast"; break;
+ case tok::kw_reinterpret_cast: CastName = "reinterpret_cast"; break;
+ case tok::kw_static_cast: CastName = "static_cast"; break;
+ }
+
+ SourceLocation OpLoc = ConsumeToken();
+ SourceLocation LAngleBracketLoc = Tok.getLocation();
+
+ if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName))
+ return ExprError();
+
+ TypeResult CastTy = ParseTypeName();
+ SourceLocation RAngleBracketLoc = Tok.getLocation();
+
+ if (ExpectAndConsume(tok::greater, diag::err_expected_greater))
+ return ExprError(Diag(LAngleBracketLoc, diag::note_matching) << "<");
+
+ SourceLocation LParenLoc = Tok.getLocation(), RParenLoc;
+
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, CastName))
+ return ExprError();
+
+ OwningExprResult Result = ParseExpression();
+
+ // Match the ')'.
+ if (Result.isInvalid())
+ SkipUntil(tok::r_paren);
+
+ if (Tok.is(tok::r_paren))
+ RParenLoc = ConsumeParen();
+ else
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ if (!Result.isInvalid() && !CastTy.isInvalid())
+ Result = Actions.ActOnCXXNamedCast(OpLoc, Kind,
+ LAngleBracketLoc, CastTy.get(),
+ RAngleBracketLoc,
+ LParenLoc, move(Result), RParenLoc);
+
+ return move(Result);
+}
+
+/// ParseCXXTypeid - This handles the C++ typeid expression.
+///
+/// postfix-expression: [C++ 5.2p1]
+/// 'typeid' '(' expression ')'
+/// 'typeid' '(' type-id ')'
+///
+Parser::OwningExprResult Parser::ParseCXXTypeid() {
+ assert(Tok.is(tok::kw_typeid) && "Not 'typeid'!");
+
+ SourceLocation OpLoc = ConsumeToken();
+ SourceLocation LParenLoc = Tok.getLocation();
+ SourceLocation RParenLoc;
+
+ // typeid expressions are always parenthesized.
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
+ "typeid"))
+ return ExprError();
+
+ OwningExprResult Result(Actions);
+
+ if (isTypeIdInParens()) {
+ TypeResult Ty = ParseTypeName();
+
+ // Match the ')'.
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ if (Ty.isInvalid())
+ return ExprError();
+
+ Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/true,
+ Ty.get(), RParenLoc);
+ } else {
+ Result = ParseExpression();
+
+ // Match the ')'.
+ if (Result.isInvalid())
+ SkipUntil(tok::r_paren);
+ else {
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/false,
+ Result.release(), RParenLoc);
+ }
+ }
+
+ return move(Result);
+}
+
+/// ParseCXXBoolLiteral - This handles the C++ Boolean literals.
+///
+/// boolean-literal: [C++ 2.13.5]
+/// 'true'
+/// 'false'
+Parser::OwningExprResult Parser::ParseCXXBoolLiteral() {
+ tok::TokenKind Kind = Tok.getKind();
+ return Actions.ActOnCXXBoolLiteral(ConsumeToken(), Kind);
+}
+
+/// ParseThrowExpression - This handles the C++ throw expression.
+///
+/// throw-expression: [C++ 15]
+/// 'throw' assignment-expression[opt]
+Parser::OwningExprResult Parser::ParseThrowExpression() {
+ assert(Tok.is(tok::kw_throw) && "Not throw!");
+ SourceLocation ThrowLoc = ConsumeToken(); // Eat the throw token.
+
+ // If the current token isn't the start of an assignment-expression,
+ // then the expression is not present. This handles things like:
+ // "C ? throw : (void)42", which is crazy but legal.
+ switch (Tok.getKind()) { // FIXME: move this predicate somewhere common.
+ case tok::semi:
+ case tok::r_paren:
+ case tok::r_square:
+ case tok::r_brace:
+ case tok::colon:
+ case tok::comma:
+ return Actions.ActOnCXXThrow(ThrowLoc, ExprArg(Actions));
+
+ default:
+ OwningExprResult Expr(ParseAssignmentExpression());
+ if (Expr.isInvalid()) return move(Expr);
+ return Actions.ActOnCXXThrow(ThrowLoc, move(Expr));
+ }
+}
+
+/// ParseCXXThis - This handles the C++ 'this' pointer.
+///
+/// C++ 9.3.2: In the body of a non-static member function, the keyword this is
+/// a non-lvalue expression whose value is the address of the object for which
+/// the function is called.
+Parser::OwningExprResult Parser::ParseCXXThis() {
+ assert(Tok.is(tok::kw_this) && "Not 'this'!");
+ SourceLocation ThisLoc = ConsumeToken();
+ return Actions.ActOnCXXThis(ThisLoc);
+}
+
+/// ParseCXXTypeConstructExpression - Parse construction of a specified type.
+/// Can be interpreted either as function-style casting ("int(x)")
+/// or class type construction ("ClassType(x,y,z)")
+/// or creation of a value-initialized type ("int()").
+///
+/// postfix-expression: [C++ 5.2p1]
+/// simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
+/// typename-specifier '(' expression-list[opt] ')' [TODO]
+///
+Parser::OwningExprResult
+Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ TypeTy *TypeRep = Actions.ActOnTypeName(CurScope, DeclaratorInfo).get();
+
+ assert(Tok.is(tok::l_paren) && "Expected '('!");
+ SourceLocation LParenLoc = ConsumeParen();
+
+ ExprVector Exprs(Actions);
+ CommaLocsTy CommaLocs;
+
+ if (Tok.isNot(tok::r_paren)) {
+ if (ParseExpressionList(Exprs, CommaLocs)) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+ }
+
+ // Match the ')'.
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&&
+ "Unexpected number of commas!");
+ return Actions.ActOnCXXTypeConstructExpr(DS.getSourceRange(), TypeRep,
+ LParenLoc, move_arg(Exprs),
+ CommaLocs.data(), RParenLoc);
+}
+
+/// ParseCXXCondition - if/switch/while/for condition expression.
+///
+/// condition:
+/// expression
+/// type-specifier-seq declarator '=' assignment-expression
+/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
+/// '=' assignment-expression
+///
+Parser::OwningExprResult Parser::ParseCXXCondition() {
+ if (!isCXXConditionDeclaration())
+ return ParseExpression(); // expression
+
+ SourceLocation StartLoc = Tok.getLocation();
+
+ // type-specifier-seq
+ DeclSpec DS;
+ ParseSpecifierQualifierList(DS);
+
+ // declarator
+ Declarator DeclaratorInfo(DS, Declarator::ConditionContext);
+ ParseDeclarator(DeclaratorInfo);
+
+ // simple-asm-expr[opt]
+ if (Tok.is(tok::kw_asm)) {
+ SourceLocation Loc;
+ OwningExprResult AsmLabel(ParseSimpleAsm(&Loc));
+ if (AsmLabel.isInvalid()) {
+ SkipUntil(tok::semi);
+ return ExprError();
+ }
+ DeclaratorInfo.setAsmLabel(AsmLabel.release());
+ DeclaratorInfo.SetRangeEnd(Loc);
+ }
+
+ // If attributes are present, parse them.
+ if (Tok.is(tok::kw___attribute)) {
+ SourceLocation Loc;
+ AttributeList *AttrList = ParseAttributes(&Loc);
+ DeclaratorInfo.AddAttributes(AttrList, Loc);
+ }
+
+ // '=' assignment-expression
+ if (Tok.isNot(tok::equal))
+ return ExprError(Diag(Tok, diag::err_expected_equal_after_declarator));
+ SourceLocation EqualLoc = ConsumeToken();
+ OwningExprResult AssignExpr(ParseAssignmentExpression());
+ if (AssignExpr.isInvalid())
+ return ExprError();
+
+ return Actions.ActOnCXXConditionDeclarationExpr(CurScope, StartLoc,
+ DeclaratorInfo,EqualLoc,
+ move(AssignExpr));
+}
+
+/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
+/// This should only be called when the current token is known to be part of
+/// simple-type-specifier.
+///
+/// simple-type-specifier:
+/// '::'[opt] nested-name-specifier[opt] type-name
+/// '::'[opt] nested-name-specifier 'template' simple-template-id [TODO]
+/// char
+/// wchar_t
+/// bool
+/// short
+/// int
+/// long
+/// signed
+/// unsigned
+/// float
+/// double
+/// void
+/// [GNU] typeof-specifier
+/// [C++0x] auto [TODO]
+///
+/// type-name:
+/// class-name
+/// enum-name
+/// typedef-name
+///
+void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
+ DS.SetRangeStart(Tok.getLocation());
+ const char *PrevSpec;
+ SourceLocation Loc = Tok.getLocation();
+
+ switch (Tok.getKind()) {
+ case tok::identifier: // foo::bar
+ case tok::coloncolon: // ::foo::bar
+ assert(0 && "Annotation token should already be formed!");
+ default:
+ assert(0 && "Not a simple-type-specifier token!");
+ abort();
+
+ // type-name
+ case tok::annot_typename: {
+ DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
+ Tok.getAnnotationValue());
+ break;
+ }
+
+ // builtin types
+ case tok::kw_short:
+ DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec);
+ break;
+ case tok::kw_long:
+ DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec);
+ break;
+ case tok::kw_signed:
+ DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec);
+ break;
+ case tok::kw_unsigned:
+ DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec);
+ break;
+ case tok::kw_void:
+ DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec);
+ break;
+ case tok::kw_char:
+ DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec);
+ break;
+ case tok::kw_int:
+ DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec);
+ break;
+ case tok::kw_float:
+ DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec);
+ break;
+ case tok::kw_double:
+ DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec);
+ break;
+ case tok::kw_wchar_t:
+ DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec);
+ break;
+ case tok::kw_bool:
+ DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec);
+ break;
+
+ // GNU typeof support.
+ case tok::kw_typeof:
+ ParseTypeofSpecifier(DS);
+ DS.Finish(Diags, PP);
+ return;
+ }
+ if (Tok.is(tok::annot_typename))
+ DS.SetRangeEnd(Tok.getAnnotationEndLoc());
+ else
+ DS.SetRangeEnd(Tok.getLocation());
+ ConsumeToken();
+ DS.Finish(Diags, PP);
+}
+
+/// ParseCXXTypeSpecifierSeq - Parse a C++ type-specifier-seq (C++
+/// [dcl.name]), which is a non-empty sequence of type-specifiers,
+/// e.g., "const short int". Note that the DeclSpec is *not* finished
+/// by parsing the type-specifier-seq, because these sequences are
+/// typically followed by some form of declarator. Returns true and
+/// emits diagnostics if this is not a type-specifier-seq, false
+/// otherwise.
+///
+/// type-specifier-seq: [C++ 8.1]
+/// type-specifier type-specifier-seq[opt]
+///
+bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
+ DS.SetRangeStart(Tok.getLocation());
+ const char *PrevSpec = 0;
+ int isInvalid = 0;
+
+ // Parse one or more of the type specifiers.
+ if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec)) {
+ Diag(Tok, diag::err_operator_missing_type_specifier);
+ return true;
+ }
+
+ while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec)) ;
+
+ return false;
+}
+
+/// TryParseOperatorFunctionId - Attempts to parse a C++ overloaded
+/// operator name (C++ [over.oper]). If successful, returns the
+/// predefined identifier that corresponds to that overloaded
+/// operator. Otherwise, returns NULL and does not consume any tokens.
+///
+/// operator-function-id: [C++ 13.5]
+/// 'operator' operator
+///
+/// operator: one of
+/// new delete new[] delete[]
+/// + - * / % ^ & | ~
+/// ! = < > += -= *= /= %=
+/// ^= &= |= << >> >>= <<= == !=
+/// <= >= && || ++ -- , ->* ->
+/// () []
+OverloadedOperatorKind
+Parser::TryParseOperatorFunctionId(SourceLocation *EndLoc) {
+ assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
+ SourceLocation Loc;
+
+ OverloadedOperatorKind Op = OO_None;
+ switch (NextToken().getKind()) {
+ case tok::kw_new:
+ ConsumeToken(); // 'operator'
+ Loc = ConsumeToken(); // 'new'
+ if (Tok.is(tok::l_square)) {
+ ConsumeBracket(); // '['
+ Loc = Tok.getLocation();
+ ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
+ Op = OO_Array_New;
+ } else {
+ Op = OO_New;
+ }
+ if (EndLoc)
+ *EndLoc = Loc;
+ return Op;
+
+ case tok::kw_delete:
+ ConsumeToken(); // 'operator'
+ Loc = ConsumeToken(); // 'delete'
+ if (Tok.is(tok::l_square)) {
+ ConsumeBracket(); // '['
+ Loc = Tok.getLocation();
+ ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
+ Op = OO_Array_Delete;
+ } else {
+ Op = OO_Delete;
+ }
+ if (EndLoc)
+ *EndLoc = Loc;
+ return Op;
+
+#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
+ case tok::Token: Op = OO_##Name; break;
+#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly)
+#include "clang/Basic/OperatorKinds.def"
+
+ case tok::l_paren:
+ ConsumeToken(); // 'operator'
+ ConsumeParen(); // '('
+ Loc = Tok.getLocation();
+ ExpectAndConsume(tok::r_paren, diag::err_expected_rparen); // ')'
+ if (EndLoc)
+ *EndLoc = Loc;
+ return OO_Call;
+
+ case tok::l_square:
+ ConsumeToken(); // 'operator'
+ ConsumeBracket(); // '['
+ Loc = Tok.getLocation();
+ ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
+ if (EndLoc)
+ *EndLoc = Loc;
+ return OO_Subscript;
+
+ default:
+ return OO_None;
+ }
+
+ ConsumeToken(); // 'operator'
+ Loc = ConsumeAnyToken(); // the operator itself
+ if (EndLoc)
+ *EndLoc = Loc;
+ return Op;
+}
+
+/// ParseConversionFunctionId - Parse a C++ conversion-function-id,
+/// which expresses the name of a user-defined conversion operator
+/// (C++ [class.conv.fct]p1). Returns the type that this operator is
+/// specifying a conversion for, or NULL if there was an error.
+///
+/// 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]
+Parser::TypeTy *Parser::ParseConversionFunctionId(SourceLocation *EndLoc) {
+ assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
+ ConsumeToken(); // 'operator'
+
+ // Parse the type-specifier-seq.
+ DeclSpec DS;
+ if (ParseCXXTypeSpecifierSeq(DS))
+ return 0;
+
+ // Parse the conversion-declarator, which is merely a sequence of
+ // ptr-operators.
+ Declarator D(DS, Declarator::TypeNameContext);
+ ParseDeclaratorInternal(D, /*DirectDeclParser=*/0);
+ if (EndLoc)
+ *EndLoc = D.getSourceRange().getEnd();
+
+ // Finish up the type.
+ Action::TypeResult Result = Actions.ActOnTypeName(CurScope, D);
+ if (Result.isInvalid())
+ return 0;
+ else
+ return Result.get();
+}
+
+/// ParseCXXNewExpression - Parse a C++ new-expression. New is used to allocate
+/// memory in a typesafe manner and call constructors.
+///
+/// This method is called to parse the new expression after the optional :: has
+/// been already parsed. If the :: was present, "UseGlobal" is true and "Start"
+/// is its location. Otherwise, "Start" is the location of the 'new' token.
+///
+/// new-expression:
+/// '::'[opt] 'new' new-placement[opt] new-type-id
+/// new-initializer[opt]
+/// '::'[opt] 'new' new-placement[opt] '(' type-id ')'
+/// new-initializer[opt]
+///
+/// new-placement:
+/// '(' expression-list ')'
+///
+/// new-type-id:
+/// type-specifier-seq new-declarator[opt]
+///
+/// new-declarator:
+/// ptr-operator new-declarator[opt]
+/// direct-new-declarator
+///
+/// new-initializer:
+/// '(' expression-list[opt] ')'
+/// [C++0x] braced-init-list [TODO]
+///
+Parser::OwningExprResult
+Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
+ assert(Tok.is(tok::kw_new) && "expected 'new' token");
+ ConsumeToken(); // Consume 'new'
+
+ // A '(' now can be a new-placement or the '(' wrapping the type-id in the
+ // second form of new-expression. It can't be a new-type-id.
+
+ ExprVector PlacementArgs(Actions);
+ SourceLocation PlacementLParen, PlacementRParen;
+
+ bool ParenTypeId;
+ DeclSpec DS;
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ if (Tok.is(tok::l_paren)) {
+ // If it turns out to be a placement, we change the type location.
+ PlacementLParen = ConsumeParen();
+ if (ParseExpressionListOrTypeId(PlacementArgs, DeclaratorInfo)) {
+ SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ return ExprError();
+ }
+
+ PlacementRParen = MatchRHSPunctuation(tok::r_paren, PlacementLParen);
+ if (PlacementRParen.isInvalid()) {
+ SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ return ExprError();
+ }
+
+ if (PlacementArgs.empty()) {
+ // Reset the placement locations. There was no placement.
+ PlacementLParen = PlacementRParen = SourceLocation();
+ ParenTypeId = true;
+ } else {
+ // We still need the type.
+ if (Tok.is(tok::l_paren)) {
+ SourceLocation LParen = ConsumeParen();
+ ParseSpecifierQualifierList(DS);
+ DeclaratorInfo.SetSourceRange(DS.getSourceRange());
+ ParseDeclarator(DeclaratorInfo);
+ MatchRHSPunctuation(tok::r_paren, LParen);
+ ParenTypeId = true;
+ } else {
+ if (ParseCXXTypeSpecifierSeq(DS))
+ DeclaratorInfo.setInvalidType(true);
+ else {
+ DeclaratorInfo.SetSourceRange(DS.getSourceRange());
+ ParseDeclaratorInternal(DeclaratorInfo,
+ &Parser::ParseDirectNewDeclarator);
+ }
+ ParenTypeId = false;
+ }
+ }
+ } else {
+ // A new-type-id is a simplified type-id, where essentially the
+ // direct-declarator is replaced by a direct-new-declarator.
+ if (ParseCXXTypeSpecifierSeq(DS))
+ DeclaratorInfo.setInvalidType(true);
+ else {
+ DeclaratorInfo.SetSourceRange(DS.getSourceRange());
+ ParseDeclaratorInternal(DeclaratorInfo,
+ &Parser::ParseDirectNewDeclarator);
+ }
+ ParenTypeId = false;
+ }
+ if (DeclaratorInfo.isInvalidType()) {
+ SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ return ExprError();
+ }
+
+ ExprVector ConstructorArgs(Actions);
+ SourceLocation ConstructorLParen, ConstructorRParen;
+
+ if (Tok.is(tok::l_paren)) {
+ ConstructorLParen = ConsumeParen();
+ if (Tok.isNot(tok::r_paren)) {
+ CommaLocsTy CommaLocs;
+ if (ParseExpressionList(ConstructorArgs, CommaLocs)) {
+ SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ return ExprError();
+ }
+ }
+ ConstructorRParen = MatchRHSPunctuation(tok::r_paren, ConstructorLParen);
+ if (ConstructorRParen.isInvalid()) {
+ SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ return ExprError();
+ }
+ }
+
+ return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen,
+ move_arg(PlacementArgs), PlacementRParen,
+ ParenTypeId, DeclaratorInfo, ConstructorLParen,
+ move_arg(ConstructorArgs), ConstructorRParen);
+}
+
+/// ParseDirectNewDeclarator - Parses a direct-new-declarator. Intended to be
+/// passed to ParseDeclaratorInternal.
+///
+/// direct-new-declarator:
+/// '[' expression ']'
+/// direct-new-declarator '[' constant-expression ']'
+///
+void Parser::ParseDirectNewDeclarator(Declarator &D) {
+ // Parse the array dimensions.
+ bool first = true;
+ while (Tok.is(tok::l_square)) {
+ SourceLocation LLoc = ConsumeBracket();
+ OwningExprResult Size(first ? ParseExpression()
+ : ParseConstantExpression());
+ if (Size.isInvalid()) {
+ // Recover
+ SkipUntil(tok::r_square);
+ return;
+ }
+ first = false;
+
+ SourceLocation RLoc = MatchRHSPunctuation(tok::r_square, LLoc);
+ D.AddTypeInfo(DeclaratorChunk::getArray(0, /*static=*/false, /*star=*/false,
+ Size.release(), LLoc),
+ RLoc);
+
+ if (RLoc.isInvalid())
+ return;
+ }
+}
+
+/// ParseExpressionListOrTypeId - Parse either an expression-list or a type-id.
+/// This ambiguity appears in the syntax of the C++ new operator.
+///
+/// new-expression:
+/// '::'[opt] 'new' new-placement[opt] '(' type-id ')'
+/// new-initializer[opt]
+///
+/// new-placement:
+/// '(' expression-list ')'
+///
+bool Parser::ParseExpressionListOrTypeId(ExprListTy &PlacementArgs,
+ Declarator &D) {
+ // The '(' was already consumed.
+ if (isTypeIdInParens()) {
+ ParseSpecifierQualifierList(D.getMutableDeclSpec());
+ D.SetSourceRange(D.getDeclSpec().getSourceRange());
+ ParseDeclarator(D);
+ return D.isInvalidType();
+ }
+
+ // It's not a type, it has to be an expression list.
+ // Discard the comma locations - ActOnCXXNew has enough parameters.
+ CommaLocsTy CommaLocs;
+ return ParseExpressionList(PlacementArgs, CommaLocs);
+}
+
+/// ParseCXXDeleteExpression - Parse a C++ delete-expression. Delete is used
+/// to free memory allocated by new.
+///
+/// This method is called to parse the 'delete' expression after the optional
+/// '::' has been already parsed. If the '::' was present, "UseGlobal" is true
+/// and "Start" is its location. Otherwise, "Start" is the location of the
+/// 'delete' token.
+///
+/// delete-expression:
+/// '::'[opt] 'delete' cast-expression
+/// '::'[opt] 'delete' '[' ']' cast-expression
+Parser::OwningExprResult
+Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) {
+ assert(Tok.is(tok::kw_delete) && "Expected 'delete' keyword");
+ ConsumeToken(); // Consume 'delete'
+
+ // Array delete?
+ bool ArrayDelete = false;
+ if (Tok.is(tok::l_square)) {
+ ArrayDelete = true;
+ SourceLocation LHS = ConsumeBracket();
+ SourceLocation RHS = MatchRHSPunctuation(tok::r_square, LHS);
+ if (RHS.isInvalid())
+ return ExprError();
+ }
+
+ OwningExprResult Operand(ParseCastExpression(false));
+ if (Operand.isInvalid())
+ return move(Operand);
+
+ return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, move(Operand));
+}
+
+static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind)
+{
+ switch(kind) {
+ default: assert(false && "Not a known unary type trait.");
+ case tok::kw___has_nothrow_assign: return UTT_HasNothrowAssign;
+ case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy;
+ case tok::kw___has_nothrow_constructor: return UTT_HasNothrowConstructor;
+ case tok::kw___has_trivial_assign: return UTT_HasTrivialAssign;
+ case tok::kw___has_trivial_copy: return UTT_HasTrivialCopy;
+ case tok::kw___has_trivial_constructor: return UTT_HasTrivialConstructor;
+ case tok::kw___has_trivial_destructor: return UTT_HasTrivialDestructor;
+ case tok::kw___has_virtual_destructor: return UTT_HasVirtualDestructor;
+ case tok::kw___is_abstract: return UTT_IsAbstract;
+ case tok::kw___is_class: return UTT_IsClass;
+ case tok::kw___is_empty: return UTT_IsEmpty;
+ case tok::kw___is_enum: return UTT_IsEnum;
+ case tok::kw___is_pod: return UTT_IsPOD;
+ case tok::kw___is_polymorphic: return UTT_IsPolymorphic;
+ case tok::kw___is_union: return UTT_IsUnion;
+ }
+}
+
+/// ParseUnaryTypeTrait - Parse the built-in unary type-trait
+/// pseudo-functions that allow implementation of the TR1/C++0x type traits
+/// templates.
+///
+/// primary-expression:
+/// [GNU] unary-type-trait '(' type-id ')'
+///
+Parser::OwningExprResult Parser::ParseUnaryTypeTrait()
+{
+ UnaryTypeTrait UTT = UnaryTypeTraitFromTokKind(Tok.getKind());
+ SourceLocation Loc = ConsumeToken();
+
+ SourceLocation LParen = Tok.getLocation();
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen))
+ return ExprError();
+
+ // FIXME: Error reporting absolutely sucks! If the this fails to parse a type
+ // there will be cryptic errors about mismatched parentheses and missing
+ // specifiers.
+ TypeResult Ty = ParseTypeName();
+
+ SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen);
+
+ if (Ty.isInvalid())
+ return ExprError();
+
+ return Actions.ActOnUnaryTypeTrait(UTT, Loc, LParen, Ty.get(), RParen);
+}
+
+/// ParseCXXAmbiguousParenExpression - We have parsed the left paren of a
+/// parenthesized ambiguous type-id. This uses tentative parsing to disambiguate
+/// based on the context past the parens.
+Parser::OwningExprResult
+Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
+ TypeTy *&CastTy,
+ SourceLocation LParenLoc,
+ SourceLocation &RParenLoc) {
+ assert(getLang().CPlusPlus && "Should only be called for C++!");
+ assert(ExprType == CastExpr && "Compound literals are not ambiguous!");
+ assert(isTypeIdInParens() && "Not a type-id!");
+
+ OwningExprResult Result(Actions, true);
+ CastTy = 0;
+
+ // We need to disambiguate a very ugly part of the C++ syntax:
+ //
+ // (T())x; - type-id
+ // (T())*x; - type-id
+ // (T())/x; - expression
+ // (T()); - expression
+ //
+ // The bad news is that we cannot use the specialized tentative parser, since
+ // it can only verify that the thing inside the parens can be parsed as
+ // type-id, it is not useful for determining the context past the parens.
+ //
+ // The good news is that the parser can disambiguate this part without
+ // making any unnecessary Action calls.
+ //
+ // It uses a scheme similar to parsing inline methods. The parenthesized
+ // tokens are cached, the context that follows is determined (possibly by
+ // parsing a cast-expression), and then we re-introduce the cached tokens
+ // into the token stream and parse them appropriately.
+
+ ParenParseOption ParseAs;
+ CachedTokens Toks;
+
+ // Store the tokens of the parentheses. We will parse them after we determine
+ // the context that follows them.
+ if (!ConsumeAndStoreUntil(tok::r_paren, tok::unknown, Toks, tok::semi)) {
+ // We didn't find the ')' we expected.
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ return ExprError();
+ }
+
+ if (Tok.is(tok::l_brace)) {
+ ParseAs = CompoundLiteral;
+ } else {
+ bool NotCastExpr;
+ // FIXME: Special-case ++ and --: "(S())++;" is not a cast-expression
+ if (Tok.is(tok::l_paren) && NextToken().is(tok::r_paren)) {
+ NotCastExpr = true;
+ } else {
+ // Try parsing the cast-expression that may follow.
+ // If it is not a cast-expression, NotCastExpr will be true and no token
+ // will be consumed.
+ Result = ParseCastExpression(false/*isUnaryExpression*/,
+ false/*isAddressofOperand*/,
+ NotCastExpr);
+ }
+
+ // If we parsed a cast-expression, it's really a type-id, otherwise it's
+ // an expression.
+ ParseAs = NotCastExpr ? SimpleExpr : CastExpr;
+ }
+
+ // The current token should go after the cached tokens.
+ Toks.push_back(Tok);
+ // Re-enter the stored parenthesized tokens into the token stream, so we may
+ // parse them now.
+ PP.EnterTokenStream(Toks.data(), Toks.size(),
+ true/*DisableMacroExpansion*/, false/*OwnsTokens*/);
+ // Drop the current token and bring the first cached one. It's the same token
+ // as when we entered this function.
+ ConsumeAnyToken();
+
+ if (ParseAs >= CompoundLiteral) {
+ TypeResult Ty = ParseTypeName();
+
+ // Match the ')'.
+ if (Tok.is(tok::r_paren))
+ RParenLoc = ConsumeParen();
+ else
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ if (ParseAs == CompoundLiteral) {
+ ExprType = CompoundLiteral;
+ return ParseCompoundLiteralExpression(Ty.get(), LParenLoc, RParenLoc);
+ }
+
+ // We parsed '(' type-id ')' and the thing after it wasn't a '{'.
+ assert(ParseAs == CastExpr);
+
+ if (Ty.isInvalid())
+ return ExprError();
+
+ CastTy = Ty.get();
+
+ // Result is what ParseCastExpression returned earlier.
+ if (!Result.isInvalid())
+ Result = Actions.ActOnCastExpr(LParenLoc, CastTy, RParenLoc,move(Result));
+ return move(Result);
+ }
+
+ // Not a compound literal, and not followed by a cast-expression.
+ assert(ParseAs == SimpleExpr);
+
+ ExprType = SimpleExpr;
+ Result = ParseExpression();
+ if (!Result.isInvalid() && Tok.is(tok::r_paren))
+ Result = Actions.ActOnParenExpr(LParenLoc, Tok.getLocation(), move(Result));
+
+ // Match the ')'.
+ if (Result.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ if (Tok.is(tok::r_paren))
+ RParenLoc = ConsumeParen();
+ else
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ return move(Result);
+}
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
new file mode 100644
index 0000000..bbc2124
--- /dev/null
+++ b/lib/Parse/ParseInit.cpp
@@ -0,0 +1,308 @@
+//===--- ParseInit.cpp - Initializer Parsing ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements initializer parsing as specified by C99 6.7.8.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Designator.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "llvm/ADT/SmallString.h"
+using namespace clang;
+
+
+/// MayBeDesignationStart - Return true if this token might be the start of a
+/// designator. If we can tell it is impossible that it is a designator, return
+/// false.
+static bool MayBeDesignationStart(tok::TokenKind K, Preprocessor &PP) {
+ switch (K) {
+ default: return false;
+ case tok::period: // designator: '.' identifier
+ case tok::l_square: // designator: array-designator
+ return true;
+ case tok::identifier: // designation: identifier ':'
+ return PP.LookAhead(0).is(tok::colon);
+ }
+}
+
+/// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production
+/// checking to see if the token stream starts with a designator.
+///
+/// designation:
+/// designator-list '='
+/// [GNU] array-designator
+/// [GNU] identifier ':'
+///
+/// designator-list:
+/// designator
+/// designator-list designator
+///
+/// designator:
+/// array-designator
+/// '.' identifier
+///
+/// array-designator:
+/// '[' constant-expression ']'
+/// [GNU] '[' constant-expression '...' constant-expression ']'
+///
+/// NOTE: [OBC] allows '[ objc-receiver objc-message-args ]' as an
+/// initializer (because it is an expression). We need to consider this case
+/// when parsing array designators.
+///
+Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
+
+ // If this is the old-style GNU extension:
+ // designation ::= identifier ':'
+ // Handle it as a field designator. Otherwise, this must be the start of a
+ // normal expression.
+ if (Tok.is(tok::identifier)) {
+ const IdentifierInfo *FieldName = Tok.getIdentifierInfo();
+
+ std::string NewSyntax(".");
+ NewSyntax += FieldName->getName();
+ NewSyntax += " = ";
+
+ SourceLocation NameLoc = ConsumeToken(); // Eat the identifier.
+
+ assert(Tok.is(tok::colon) && "MayBeDesignationStart not working properly!");
+ SourceLocation ColonLoc = ConsumeToken();
+
+ Diag(Tok, diag::ext_gnu_old_style_field_designator)
+ << CodeModificationHint::CreateReplacement(SourceRange(NameLoc,
+ ColonLoc),
+ NewSyntax);
+
+ Designation D;
+ D.AddDesignator(Designator::getField(FieldName, SourceLocation(), NameLoc));
+ return Actions.ActOnDesignatedInitializer(D, ColonLoc, true,
+ ParseInitializer());
+ }
+
+ // Desig - This is initialized when we see our first designator. We may have
+ // an objc message send with no designator, so we don't want to create this
+ // eagerly.
+ Designation Desig;
+
+ // Parse each designator in the designator list until we find an initializer.
+ while (Tok.is(tok::period) || Tok.is(tok::l_square)) {
+ if (Tok.is(tok::period)) {
+ // designator: '.' identifier
+ SourceLocation DotLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok.getLocation(), diag::err_expected_field_designator);
+ return ExprError();
+ }
+
+ Desig.AddDesignator(Designator::getField(Tok.getIdentifierInfo(), DotLoc,
+ Tok.getLocation()));
+ ConsumeToken(); // Eat the identifier.
+ continue;
+ }
+
+ // We must have either an array designator now or an objc message send.
+ assert(Tok.is(tok::l_square) && "Unexpected token!");
+
+ // Handle the two forms of array designator:
+ // array-designator: '[' constant-expression ']'
+ // array-designator: '[' constant-expression '...' constant-expression ']'
+ //
+ // Also, we have to handle the case where the expression after the
+ // designator an an objc message send: '[' objc-message-expr ']'.
+ // Interesting cases are:
+ // [foo bar] -> objc message send
+ // [foo] -> array designator
+ // [foo ... bar] -> array designator
+ // [4][foo bar] -> obsolete GNU designation with objc message send.
+ //
+ SourceLocation StartLoc = ConsumeBracket();
+
+ // If Objective-C is enabled and this is a typename or other identifier
+ // receiver, parse this as a message send expression.
+ if (getLang().ObjC1 && isTokObjCMessageIdentifierReceiver()) {
+ // If we have exactly one array designator, this used the GNU
+ // 'designation: array-designator' extension, otherwise there should be no
+ // designators at all!
+ if (Desig.getNumDesignators() == 1 &&
+ (Desig.getDesignator(0).isArrayDesignator() ||
+ Desig.getDesignator(0).isArrayRangeDesignator()))
+ Diag(StartLoc, diag::ext_gnu_missing_equal_designator);
+ else if (Desig.getNumDesignators() > 0)
+ Diag(Tok, diag::err_expected_equal_designator);
+
+ IdentifierInfo *Name = Tok.getIdentifierInfo();
+ SourceLocation NameLoc = ConsumeToken();
+ return ParseAssignmentExprWithObjCMessageExprStart(
+ StartLoc, NameLoc, Name, ExprArg(Actions));
+ }
+
+ // Note that we parse this as an assignment expression, not a constant
+ // expression (allowing *=, =, etc) to handle the objc case. Sema needs
+ // to validate that the expression is a constant.
+ OwningExprResult Idx(ParseAssignmentExpression());
+ if (Idx.isInvalid()) {
+ SkipUntil(tok::r_square);
+ return move(Idx);
+ }
+
+ // Given an expression, we could either have a designator (if the next
+ // tokens are '...' or ']' or an objc message send. If this is an objc
+ // message send, handle it now. An objc-message send is the start of
+ // an assignment-expression production.
+ if (getLang().ObjC1 && Tok.isNot(tok::ellipsis) &&
+ Tok.isNot(tok::r_square)) {
+
+ // If we have exactly one array designator, this used the GNU
+ // 'designation: array-designator' extension, otherwise there should be no
+ // designators at all!
+ if (Desig.getNumDesignators() == 1 &&
+ (Desig.getDesignator(0).isArrayDesignator() ||
+ Desig.getDesignator(0).isArrayRangeDesignator()))
+ Diag(StartLoc, diag::ext_gnu_missing_equal_designator);
+ else if (Desig.getNumDesignators() > 0)
+ Diag(Tok, diag::err_expected_equal_designator);
+
+ return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
+ SourceLocation(),
+ 0, move(Idx));
+ }
+
+ // If this is a normal array designator, remember it.
+ if (Tok.isNot(tok::ellipsis)) {
+ Desig.AddDesignator(Designator::getArray(Idx.release(), StartLoc));
+ } else {
+ // Handle the gnu array range extension.
+ Diag(Tok, diag::ext_gnu_array_range);
+ SourceLocation EllipsisLoc = ConsumeToken();
+
+ OwningExprResult RHS(ParseConstantExpression());
+ if (RHS.isInvalid()) {
+ SkipUntil(tok::r_square);
+ return move(RHS);
+ }
+ Desig.AddDesignator(Designator::getArrayRange(Idx.release(),
+ RHS.release(),
+ StartLoc, EllipsisLoc));
+ }
+
+ SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
+ Desig.getDesignator(Desig.getNumDesignators() - 1).setRBracketLoc(EndLoc);
+ }
+
+ // Okay, we're done with the designator sequence. We know that there must be
+ // at least one designator, because the only case we can get into this method
+ // without a designator is when we have an objc message send. That case is
+ // handled and returned from above.
+ assert(!Desig.empty() && "Designator is empty?");
+
+ // Handle a normal designator sequence end, which is an equal.
+ if (Tok.is(tok::equal)) {
+ SourceLocation EqualLoc = ConsumeToken();
+ return Actions.ActOnDesignatedInitializer(Desig, EqualLoc, false,
+ ParseInitializer());
+ }
+
+ // We read some number of designators and found something that isn't an = or
+ // an initializer. If we have exactly one array designator, this
+ // is the GNU 'designation: array-designator' extension. Otherwise, it is a
+ // parse error.
+ if (Desig.getNumDesignators() == 1 &&
+ (Desig.getDesignator(0).isArrayDesignator() ||
+ Desig.getDesignator(0).isArrayRangeDesignator())) {
+ Diag(Tok, diag::ext_gnu_missing_equal_designator)
+ << CodeModificationHint::CreateInsertion(Tok.getLocation(), "= ");
+ return Actions.ActOnDesignatedInitializer(Desig, Tok.getLocation(),
+ true, ParseInitializer());
+ }
+
+ Diag(Tok, diag::err_expected_equal_designator);
+ return ExprError();
+}
+
+
+/// ParseBraceInitializer - Called when parsing an initializer that has a
+/// leading open brace.
+///
+/// initializer: [C99 6.7.8]
+/// '{' initializer-list '}'
+/// '{' initializer-list ',' '}'
+/// [GNU] '{' '}'
+///
+/// initializer-list:
+/// designation[opt] initializer
+/// initializer-list ',' designation[opt] initializer
+///
+Parser::OwningExprResult Parser::ParseBraceInitializer() {
+ SourceLocation LBraceLoc = ConsumeBrace();
+
+ /// InitExprs - This is the actual list of expressions contained in the
+ /// initializer.
+ ExprVector InitExprs(Actions);
+
+ if (Tok.is(tok::r_brace)) {
+ // Empty initializers are a C++ feature and a GNU extension to C.
+ if (!getLang().CPlusPlus)
+ Diag(LBraceLoc, diag::ext_gnu_empty_initializer);
+ // Match the '}'.
+ return Actions.ActOnInitList(LBraceLoc, Action::MultiExprArg(Actions),
+ ConsumeBrace());
+ }
+
+ bool InitExprsOk = true;
+
+ while (1) {
+ // Parse: designation[opt] initializer
+
+ // If we know that this cannot be a designation, just parse the nested
+ // initializer directly.
+ OwningExprResult SubElt(Actions);
+ if (MayBeDesignationStart(Tok.getKind(), PP))
+ SubElt = ParseInitializerWithPotentialDesignator();
+ else
+ SubElt = ParseInitializer();
+
+ // If we couldn't parse the subelement, bail out.
+ if (!SubElt.isInvalid()) {
+ InitExprs.push_back(SubElt.release());
+ } else {
+ InitExprsOk = false;
+
+ // We have two ways to try to recover from this error: if the code looks
+ // gramatically ok (i.e. we have a comma coming up) try to continue
+ // parsing the rest of the initializer. This allows us to emit
+ // diagnostics for later elements that we find. If we don't see a comma,
+ // assume there is a parse error, and just skip to recover.
+ // FIXME: This comment doesn't sound right. If there is a r_brace
+ // immediately, it can't be an error, since there is no other way of
+ // leaving this loop except through this if.
+ if (Tok.isNot(tok::comma)) {
+ SkipUntil(tok::r_brace, false, true);
+ break;
+ }
+ }
+
+ // If we don't have a comma continued list, we're done.
+ if (Tok.isNot(tok::comma)) break;
+
+ // TODO: save comma locations if some client cares.
+ ConsumeToken();
+
+ // Handle trailing comma.
+ if (Tok.is(tok::r_brace)) break;
+ }
+ if (InitExprsOk && Tok.is(tok::r_brace))
+ return Actions.ActOnInitList(LBraceLoc, move_arg(InitExprs),
+ ConsumeBrace());
+
+ // Match the '}'.
+ MatchRHSPunctuation(tok::r_brace, LBraceLoc);
+ return ExprError(); // an error occurred.
+}
+
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
new file mode 100644
index 0000000..3014f95
--- /dev/null
+++ b/lib/Parse/ParseObjc.cpp
@@ -0,0 +1,1708 @@
+//===--- ParseObjC.cpp - Objective C Parsing ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Objective-C portions of the Parser interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "llvm/ADT/SmallVector.h"
+using namespace clang;
+
+
+/// ParseObjCAtDirectives - Handle parts of the external-declaration production:
+/// external-declaration: [C99 6.9]
+/// [OBJC] objc-class-definition
+/// [OBJC] objc-class-declaration
+/// [OBJC] objc-alias-declaration
+/// [OBJC] objc-protocol-definition
+/// [OBJC] objc-method-definition
+/// [OBJC] '@' 'end'
+Parser::DeclPtrTy Parser::ParseObjCAtDirectives() {
+ SourceLocation AtLoc = ConsumeToken(); // the "@"
+
+ switch (Tok.getObjCKeywordID()) {
+ case tok::objc_class:
+ return ParseObjCAtClassDeclaration(AtLoc);
+ case tok::objc_interface:
+ return ParseObjCAtInterfaceDeclaration(AtLoc);
+ case tok::objc_protocol:
+ return ParseObjCAtProtocolDeclaration(AtLoc);
+ case tok::objc_implementation:
+ return ParseObjCAtImplementationDeclaration(AtLoc);
+ case tok::objc_end:
+ return ParseObjCAtEndDeclaration(AtLoc);
+ case tok::objc_compatibility_alias:
+ return ParseObjCAtAliasDeclaration(AtLoc);
+ case tok::objc_synthesize:
+ return ParseObjCPropertySynthesize(AtLoc);
+ case tok::objc_dynamic:
+ return ParseObjCPropertyDynamic(AtLoc);
+ default:
+ Diag(AtLoc, diag::err_unexpected_at);
+ SkipUntil(tok::semi);
+ return DeclPtrTy();
+ }
+}
+
+///
+/// objc-class-declaration:
+/// '@' 'class' identifier-list ';'
+///
+Parser::DeclPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
+ ConsumeToken(); // the identifier "class"
+ llvm::SmallVector<IdentifierInfo *, 8> ClassNames;
+
+ while (1) {
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::semi);
+ return DeclPtrTy();
+ }
+ ClassNames.push_back(Tok.getIdentifierInfo());
+ ConsumeToken();
+
+ if (Tok.isNot(tok::comma))
+ break;
+
+ ConsumeToken();
+ }
+
+ // Consume the ';'.
+ if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class"))
+ return DeclPtrTy();
+
+ return Actions.ActOnForwardClassDeclaration(atLoc,
+ &ClassNames[0], ClassNames.size());
+}
+
+///
+/// objc-interface:
+/// objc-class-interface-attributes[opt] objc-class-interface
+/// objc-category-interface
+///
+/// objc-class-interface:
+/// '@' 'interface' identifier objc-superclass[opt]
+/// objc-protocol-refs[opt]
+/// objc-class-instance-variables[opt]
+/// objc-interface-decl-list
+/// @end
+///
+/// objc-category-interface:
+/// '@' 'interface' identifier '(' identifier[opt] ')'
+/// objc-protocol-refs[opt]
+/// objc-interface-decl-list
+/// @end
+///
+/// objc-superclass:
+/// ':' identifier
+///
+/// objc-class-interface-attributes:
+/// __attribute__((visibility("default")))
+/// __attribute__((visibility("hidden")))
+/// __attribute__((deprecated))
+/// __attribute__((unavailable))
+/// __attribute__((objc_exception)) - used by NSException on 64-bit
+///
+Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
+ SourceLocation atLoc, AttributeList *attrList) {
+ assert(Tok.isObjCAtKeyword(tok::objc_interface) &&
+ "ParseObjCAtInterfaceDeclaration(): Expected @interface");
+ ConsumeToken(); // the "interface" identifier
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident); // missing class or category name.
+ return DeclPtrTy();
+ }
+ // We have a class or category name - consume it.
+ IdentifierInfo *nameId = Tok.getIdentifierInfo();
+ SourceLocation nameLoc = ConsumeToken();
+
+ if (Tok.is(tok::l_paren)) { // we have a category.
+ SourceLocation lparenLoc = ConsumeParen();
+ SourceLocation categoryLoc, rparenLoc;
+ IdentifierInfo *categoryId = 0;
+
+ // For ObjC2, the category name is optional (not an error).
+ if (Tok.is(tok::identifier)) {
+ categoryId = Tok.getIdentifierInfo();
+ categoryLoc = ConsumeToken();
+ } else if (!getLang().ObjC2) {
+ Diag(Tok, diag::err_expected_ident); // missing category name.
+ return DeclPtrTy();
+ }
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_expected_rparen);
+ SkipUntil(tok::r_paren, false); // don't stop at ';'
+ return DeclPtrTy();
+ }
+ rparenLoc = ConsumeParen();
+
+ // Next, we need to check for any protocol references.
+ SourceLocation EndProtoLoc;
+ llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs;
+ if (Tok.is(tok::less) &&
+ ParseObjCProtocolReferences(ProtocolRefs, true, EndProtoLoc))
+ return DeclPtrTy();
+
+ if (attrList) // categories don't support attributes.
+ Diag(Tok, diag::err_objc_no_attributes_on_category);
+
+ DeclPtrTy CategoryType =
+ Actions.ActOnStartCategoryInterface(atLoc,
+ nameId, nameLoc,
+ categoryId, categoryLoc,
+ ProtocolRefs.data(),
+ ProtocolRefs.size(),
+ EndProtoLoc);
+
+ ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword);
+ return CategoryType;
+ }
+ // Parse a class interface.
+ IdentifierInfo *superClassId = 0;
+ SourceLocation superClassLoc;
+
+ if (Tok.is(tok::colon)) { // a super class is specified.
+ ConsumeToken();
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident); // missing super class name.
+ return DeclPtrTy();
+ }
+ superClassId = Tok.getIdentifierInfo();
+ superClassLoc = ConsumeToken();
+ }
+ // Next, we need to check for any protocol references.
+ llvm::SmallVector<Action::DeclPtrTy, 8> ProtocolRefs;
+ SourceLocation EndProtoLoc;
+ if (Tok.is(tok::less) &&
+ ParseObjCProtocolReferences(ProtocolRefs, true, EndProtoLoc))
+ return DeclPtrTy();
+
+ DeclPtrTy ClsType =
+ Actions.ActOnStartClassInterface(atLoc, nameId, nameLoc,
+ superClassId, superClassLoc,
+ ProtocolRefs.data(), ProtocolRefs.size(),
+ EndProtoLoc, attrList);
+
+ if (Tok.is(tok::l_brace))
+ ParseObjCClassInstanceVariables(ClsType, atLoc);
+
+ ParseObjCInterfaceDeclList(ClsType, tok::objc_interface);
+ return ClsType;
+}
+
+/// objc-interface-decl-list:
+/// empty
+/// objc-interface-decl-list objc-property-decl [OBJC2]
+/// objc-interface-decl-list objc-method-requirement [OBJC2]
+/// objc-interface-decl-list objc-method-proto ';'
+/// objc-interface-decl-list declaration
+/// objc-interface-decl-list ';'
+///
+/// objc-method-requirement: [OBJC2]
+/// @required
+/// @optional
+///
+void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
+ tok::ObjCKeywordKind contextKey) {
+ llvm::SmallVector<DeclPtrTy, 32> allMethods;
+ llvm::SmallVector<DeclPtrTy, 16> allProperties;
+ llvm::SmallVector<DeclGroupPtrTy, 8> allTUVariables;
+ tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword;
+
+ SourceLocation AtEndLoc;
+
+ while (1) {
+ // If this is a method prototype, parse it.
+ if (Tok.is(tok::minus) || Tok.is(tok::plus)) {
+ DeclPtrTy methodPrototype =
+ ParseObjCMethodPrototype(interfaceDecl, MethodImplKind);
+ allMethods.push_back(methodPrototype);
+ // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for
+ // method definitions.
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after_method_proto,
+ "", tok::semi);
+ continue;
+ }
+
+ // Ignore excess semicolons.
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ continue;
+ }
+
+ // If we got to the end of the file, exit the loop.
+ if (Tok.is(tok::eof))
+ break;
+
+ // If we don't have an @ directive, parse it as a function definition.
+ if (Tok.isNot(tok::at)) {
+ // The code below does not consume '}'s because it is afraid of eating the
+ // end of a namespace. Because of the way this code is structured, an
+ // erroneous r_brace would cause an infinite loop if not handled here.
+ if (Tok.is(tok::r_brace))
+ break;
+
+ // FIXME: as the name implies, this rule allows function definitions.
+ // We could pass a flag or check for functions during semantic analysis.
+ allTUVariables.push_back(ParseDeclarationOrFunctionDefinition());
+ continue;
+ }
+
+ // Otherwise, we have an @ directive, eat the @.
+ SourceLocation AtLoc = ConsumeToken(); // the "@"
+ tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
+
+ if (DirectiveKind == tok::objc_end) { // @end -> terminate list
+ AtEndLoc = AtLoc;
+ break;
+ }
+
+ // Eat the identifier.
+ ConsumeToken();
+
+ switch (DirectiveKind) {
+ default:
+ // FIXME: If someone forgets an @end on a protocol, this loop will
+ // continue to eat up tons of stuff and spew lots of nonsense errors. It
+ // would probably be better to bail out if we saw an @class or @interface
+ // or something like that.
+ Diag(AtLoc, diag::err_objc_illegal_interface_qual);
+ // Skip until we see an '@' or '}' or ';'.
+ SkipUntil(tok::r_brace, tok::at);
+ break;
+
+ case tok::objc_required:
+ case tok::objc_optional:
+ // This is only valid on protocols.
+ // FIXME: Should this check for ObjC2 being enabled?
+ if (contextKey != tok::objc_protocol)
+ Diag(AtLoc, diag::err_objc_directive_only_in_protocol);
+ else
+ MethodImplKind = DirectiveKind;
+ break;
+
+ case tok::objc_property:
+ if (!getLang().ObjC2)
+ Diag(AtLoc, diag::err_objc_propertoes_require_objc2);
+
+ ObjCDeclSpec OCDS;
+ // Parse property attribute list, if any.
+ if (Tok.is(tok::l_paren))
+ ParseObjCPropertyAttribute(OCDS);
+
+ // Parse all the comma separated declarators.
+ DeclSpec DS;
+ llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators;
+ ParseStructDeclaration(DS, FieldDeclarators);
+
+ 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;
+ }
+ }
+
+ // We break out of the big loop in two cases: when we see @end or when we see
+ // EOF. In the former case, eat the @end. In the later case, emit an error.
+ if (Tok.isObjCAtKeyword(tok::objc_end))
+ ConsumeToken(); // the "end" identifier
+ else
+ Diag(Tok, diag::err_objc_missing_end);
+
+ // Insert collected methods declarations into the @interface object.
+ // This passes in an invalid SourceLocation for AtEndLoc when EOF is hit.
+ Actions.ActOnAtEnd(AtEndLoc, interfaceDecl,
+ allMethods.data(), allMethods.size(),
+ allProperties.data(), allProperties.size(),
+ allTUVariables.data(), allTUVariables.size());
+}
+
+/// Parse property attribute declarations.
+///
+/// property-attr-decl: '(' property-attrlist ')'
+/// property-attrlist:
+/// property-attribute
+/// property-attrlist ',' property-attribute
+/// property-attribute:
+/// getter '=' identifier
+/// setter '=' identifier ':'
+/// readonly
+/// readwrite
+/// assign
+/// retain
+/// copy
+/// nonatomic
+///
+void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
+ assert(Tok.getKind() == tok::l_paren);
+ SourceLocation LHSLoc = ConsumeParen(); // consume '('
+
+ while (1) {
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+
+ // If this is not an identifier at all, bail out early.
+ if (II == 0) {
+ MatchRHSPunctuation(tok::r_paren, LHSLoc);
+ return;
+ }
+
+ SourceLocation AttrName = ConsumeToken(); // consume last attribute name
+
+ if (II->isStr("readonly"))
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readonly);
+ else if (II->isStr("assign"))
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_assign);
+ else if (II->isStr("readwrite"))
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readwrite);
+ else if (II->isStr("retain"))
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_retain);
+ else if (II->isStr("copy"))
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_copy);
+ else if (II->isStr("nonatomic"))
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nonatomic);
+ else if (II->isStr("getter") || II->isStr("setter")) {
+ // getter/setter require extra treatment.
+ if (ExpectAndConsume(tok::equal, diag::err_objc_expected_equal, "",
+ tok::r_paren))
+ return;
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::r_paren);
+ return;
+ }
+
+ if (II->getName()[0] == 's') {
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter);
+ DS.setSetterName(Tok.getIdentifierInfo());
+ ConsumeToken(); // consume method name
+
+ if (ExpectAndConsume(tok::colon, diag::err_expected_colon, "",
+ tok::r_paren))
+ return;
+ } else {
+ DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter);
+ DS.setGetterName(Tok.getIdentifierInfo());
+ ConsumeToken(); // consume method name
+ }
+ } else {
+ Diag(AttrName, diag::err_objc_expected_property_attr) << II;
+ SkipUntil(tok::r_paren);
+ return;
+ }
+
+ if (Tok.isNot(tok::comma))
+ break;
+
+ ConsumeToken();
+ }
+
+ MatchRHSPunctuation(tok::r_paren, LHSLoc);
+}
+
+/// objc-method-proto:
+/// objc-instance-method objc-method-decl objc-method-attributes[opt]
+/// objc-class-method objc-method-decl objc-method-attributes[opt]
+///
+/// objc-instance-method: '-'
+/// objc-class-method: '+'
+///
+/// objc-method-attributes: [OBJC2]
+/// __attribute__((deprecated))
+///
+Parser::DeclPtrTy Parser::ParseObjCMethodPrototype(DeclPtrTy IDecl,
+ tok::ObjCKeywordKind MethodImplKind) {
+ assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-");
+
+ tok::TokenKind methodType = Tok.getKind();
+ SourceLocation mLoc = ConsumeToken();
+
+ DeclPtrTy MDecl = ParseObjCMethodDecl(mLoc, methodType, IDecl,MethodImplKind);
+ // Since this rule is used for both method declarations and definitions,
+ // the caller is (optionally) responsible for consuming the ';'.
+ return MDecl;
+}
+
+/// objc-selector:
+/// identifier
+/// one of
+/// enum struct union if else while do for switch case default
+/// break continue return goto asm sizeof typeof __alignof
+/// unsigned long const short volatile signed restrict _Complex
+/// in out inout bycopy byref oneway int char float double void _Bool
+///
+IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) {
+ switch (Tok.getKind()) {
+ default:
+ return 0;
+ case tok::identifier:
+ case tok::kw_asm:
+ case tok::kw_auto:
+ case tok::kw_bool:
+ case tok::kw_break:
+ case tok::kw_case:
+ case tok::kw_catch:
+ case tok::kw_char:
+ case tok::kw_class:
+ case tok::kw_const:
+ case tok::kw_const_cast:
+ case tok::kw_continue:
+ case tok::kw_default:
+ case tok::kw_delete:
+ case tok::kw_do:
+ case tok::kw_double:
+ case tok::kw_dynamic_cast:
+ case tok::kw_else:
+ case tok::kw_enum:
+ case tok::kw_explicit:
+ case tok::kw_export:
+ case tok::kw_extern:
+ case tok::kw_false:
+ case tok::kw_float:
+ case tok::kw_for:
+ case tok::kw_friend:
+ case tok::kw_goto:
+ case tok::kw_if:
+ case tok::kw_inline:
+ case tok::kw_int:
+ case tok::kw_long:
+ case tok::kw_mutable:
+ case tok::kw_namespace:
+ case tok::kw_new:
+ case tok::kw_operator:
+ case tok::kw_private:
+ case tok::kw_protected:
+ case tok::kw_public:
+ case tok::kw_register:
+ case tok::kw_reinterpret_cast:
+ case tok::kw_restrict:
+ case tok::kw_return:
+ case tok::kw_short:
+ case tok::kw_signed:
+ case tok::kw_sizeof:
+ case tok::kw_static:
+ case tok::kw_static_cast:
+ case tok::kw_struct:
+ case tok::kw_switch:
+ case tok::kw_template:
+ case tok::kw_this:
+ case tok::kw_throw:
+ case tok::kw_true:
+ case tok::kw_try:
+ case tok::kw_typedef:
+ case tok::kw_typeid:
+ case tok::kw_typename:
+ case tok::kw_typeof:
+ case tok::kw_union:
+ case tok::kw_unsigned:
+ case tok::kw_using:
+ case tok::kw_virtual:
+ case tok::kw_void:
+ case tok::kw_volatile:
+ case tok::kw_wchar_t:
+ case tok::kw_while:
+ case tok::kw__Bool:
+ case tok::kw__Complex:
+ case tok::kw___alignof:
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ SelectorLoc = ConsumeToken();
+ return II;
+ }
+}
+
+/// objc-for-collection-in: 'in'
+///
+bool Parser::isTokIdentifier_in() const {
+ // FIXME: May have to do additional look-ahead to only allow for
+ // valid tokens following an 'in'; such as an identifier, unary operators,
+ // '[' etc.
+ return (getLang().ObjC2 && Tok.is(tok::identifier) &&
+ Tok.getIdentifierInfo() == ObjCTypeQuals[objc_in]);
+}
+
+/// ParseObjCTypeQualifierList - This routine parses the objective-c's type
+/// qualifier list and builds their bitmask representation in the input
+/// argument.
+///
+/// objc-type-qualifiers:
+/// objc-type-qualifier
+/// objc-type-qualifiers objc-type-qualifier
+///
+void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS) {
+ while (1) {
+ if (Tok.isNot(tok::identifier))
+ return;
+
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ for (unsigned i = 0; i != objc_NumQuals; ++i) {
+ if (II != ObjCTypeQuals[i])
+ continue;
+
+ ObjCDeclSpec::ObjCDeclQualifier Qual;
+ switch (i) {
+ default: assert(0 && "Unknown decl qualifier");
+ case objc_in: Qual = ObjCDeclSpec::DQ_In; break;
+ case objc_out: Qual = ObjCDeclSpec::DQ_Out; break;
+ case objc_inout: Qual = ObjCDeclSpec::DQ_Inout; break;
+ case objc_oneway: Qual = ObjCDeclSpec::DQ_Oneway; break;
+ case objc_bycopy: Qual = ObjCDeclSpec::DQ_Bycopy; break;
+ case objc_byref: Qual = ObjCDeclSpec::DQ_Byref; break;
+ }
+ DS.setObjCDeclQualifier(Qual);
+ ConsumeToken();
+ II = 0;
+ break;
+ }
+
+ // If this wasn't a recognized qualifier, bail out.
+ if (II) return;
+ }
+}
+
+/// objc-type-name:
+/// '(' objc-type-qualifiers[opt] type-name ')'
+/// '(' objc-type-qualifiers[opt] ')'
+///
+Parser::TypeTy *Parser::ParseObjCTypeName(ObjCDeclSpec &DS) {
+ assert(Tok.is(tok::l_paren) && "expected (");
+
+ SourceLocation LParenLoc = ConsumeParen();
+ SourceLocation TypeStartLoc = Tok.getLocation();
+
+ // Parse type qualifiers, in, inout, etc.
+ ParseObjCTypeQualifierList(DS);
+
+ TypeTy *Ty = 0;
+ if (isTypeSpecifierQualifier()) {
+ TypeResult TypeSpec = ParseTypeName();
+ if (!TypeSpec.isInvalid())
+ Ty = TypeSpec.get();
+ }
+
+ if (Tok.is(tok::r_paren))
+ ConsumeParen();
+ else if (Tok.getLocation() == TypeStartLoc) {
+ // If we didn't eat any tokens, then this isn't a type.
+ Diag(Tok, diag::err_expected_type);
+ SkipUntil(tok::r_paren);
+ } else {
+ // Otherwise, we found *something*, but didn't get a ')' in the right
+ // place. Emit an error then return what we have as the type.
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ }
+ return Ty;
+}
+
+/// objc-method-decl:
+/// objc-selector
+/// objc-keyword-selector objc-parmlist[opt]
+/// objc-type-name objc-selector
+/// objc-type-name objc-keyword-selector objc-parmlist[opt]
+///
+/// objc-keyword-selector:
+/// objc-keyword-decl
+/// objc-keyword-selector objc-keyword-decl
+///
+/// objc-keyword-decl:
+/// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier
+/// objc-selector ':' objc-keyword-attributes[opt] identifier
+/// ':' objc-type-name objc-keyword-attributes[opt] identifier
+/// ':' objc-keyword-attributes[opt] identifier
+///
+/// objc-parmlist:
+/// objc-parms objc-ellipsis[opt]
+///
+/// objc-parms:
+/// objc-parms , parameter-declaration
+///
+/// objc-ellipsis:
+/// , ...
+///
+/// objc-keyword-attributes: [OBJC2]
+/// __attribute__((unused))
+///
+Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
+ tok::TokenKind mType,
+ DeclPtrTy IDecl,
+ tok::ObjCKeywordKind MethodImplKind) {
+ // Parse the return type if present.
+ TypeTy *ReturnType = 0;
+ ObjCDeclSpec DSRet;
+ if (Tok.is(tok::l_paren))
+ ReturnType = ParseObjCTypeName(DSRet);
+
+ SourceLocation selLoc;
+ IdentifierInfo *SelIdent = ParseObjCSelectorPiece(selLoc);
+
+ // An unnamed colon is valid.
+ if (!SelIdent && Tok.isNot(tok::colon)) { // missing selector name.
+ Diag(Tok, diag::err_expected_selector_for_method)
+ << SourceRange(mLoc, Tok.getLocation());
+ // Skip until we get a ; or {}.
+ SkipUntil(tok::r_brace);
+ return DeclPtrTy();
+ }
+
+ llvm::SmallVector<Declarator, 8> CargNames;
+ if (Tok.isNot(tok::colon)) {
+ // If attributes exist after the method, parse them.
+ AttributeList *MethodAttrs = 0;
+ if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
+ MethodAttrs = ParseAttributes();
+
+ Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
+ return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
+ mType, IDecl, DSRet, ReturnType, Sel,
+ 0, CargNames, MethodAttrs,
+ MethodImplKind);
+ }
+
+ llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
+ llvm::SmallVector<Action::ObjCArgInfo, 12> ArgInfos;
+
+ while (1) {
+ Action::ObjCArgInfo ArgInfo;
+
+ // Each iteration parses a single keyword argument.
+ if (Tok.isNot(tok::colon)) {
+ Diag(Tok, diag::err_expected_colon);
+ break;
+ }
+ ConsumeToken(); // Eat the ':'.
+
+ ArgInfo.Type = 0;
+ if (Tok.is(tok::l_paren)) // Parse the argument type if present.
+ ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec);
+
+ // If attributes exist before the argument name, parse them.
+ ArgInfo.ArgAttrs = 0;
+ if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
+ ArgInfo.ArgAttrs = ParseAttributes();
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident); // missing argument name.
+ break;
+ }
+
+ ArgInfo.Name = Tok.getIdentifierInfo();
+ ArgInfo.NameLoc = Tok.getLocation();
+ ConsumeToken(); // Eat the identifier.
+
+ ArgInfos.push_back(ArgInfo);
+ KeyIdents.push_back(SelIdent);
+
+ // Check for another keyword selector.
+ SourceLocation Loc;
+ SelIdent = ParseObjCSelectorPiece(Loc);
+ if (!SelIdent && Tok.isNot(tok::colon))
+ break;
+ // We have a selector or a colon, continue parsing.
+ }
+
+ bool isVariadic = false;
+
+ // Parse the (optional) parameter list.
+ while (Tok.is(tok::comma)) {
+ ConsumeToken();
+ if (Tok.is(tok::ellipsis)) {
+ isVariadic = true;
+ ConsumeToken();
+ break;
+ }
+ DeclSpec DS;
+ ParseDeclarationSpecifiers(DS);
+ // Parse the declarator.
+ Declarator ParmDecl(DS, Declarator::PrototypeContext);
+ ParseDeclarator(ParmDecl);
+ CargNames.push_back(ParmDecl);
+ }
+
+ // FIXME: Add support for optional parmameter list...
+ // If attributes exist after the method, parse them.
+ AttributeList *MethodAttrs = 0;
+ if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
+ MethodAttrs = ParseAttributes();
+
+ Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(),
+ &KeyIdents[0]);
+ return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
+ mType, IDecl, DSRet, ReturnType, Sel,
+ &ArgInfos[0], CargNames, MethodAttrs,
+ MethodImplKind, isVariadic);
+}
+
+/// objc-protocol-refs:
+/// '<' identifier-list '>'
+///
+bool Parser::
+ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &Protocols,
+ bool WarnOnDeclarations, SourceLocation &EndLoc) {
+ assert(Tok.is(tok::less) && "expected <");
+
+ ConsumeToken(); // the "<"
+
+ llvm::SmallVector<IdentifierLocPair, 8> ProtocolIdents;
+
+ while (1) {
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::greater);
+ return true;
+ }
+ ProtocolIdents.push_back(std::make_pair(Tok.getIdentifierInfo(),
+ Tok.getLocation()));
+ ConsumeToken();
+
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken();
+ }
+
+ // Consume the '>'.
+ if (Tok.isNot(tok::greater)) {
+ Diag(Tok, diag::err_expected_greater);
+ return true;
+ }
+
+ EndLoc = ConsumeAnyToken();
+
+ // Convert the list of protocols identifiers into a list of protocol decls.
+ Actions.FindProtocolDeclaration(WarnOnDeclarations,
+ &ProtocolIdents[0], ProtocolIdents.size(),
+ Protocols);
+ return false;
+}
+
+/// objc-class-instance-variables:
+/// '{' objc-instance-variable-decl-list[opt] '}'
+///
+/// objc-instance-variable-decl-list:
+/// objc-visibility-spec
+/// objc-instance-variable-decl ';'
+/// ';'
+/// objc-instance-variable-decl-list objc-visibility-spec
+/// objc-instance-variable-decl-list objc-instance-variable-decl ';'
+/// objc-instance-variable-decl-list ';'
+///
+/// objc-visibility-spec:
+/// @private
+/// @protected
+/// @public
+/// @package [OBJC2]
+///
+/// objc-instance-variable-decl:
+/// struct-declaration
+///
+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);
+
+ SourceLocation LBraceLoc = ConsumeBrace(); // the "{"
+
+ tok::ObjCKeywordKind visibility = tok::objc_protected;
+ // While we still have something to read, read the instance variables.
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ // Each iteration of this loop reads one objc-instance-variable-decl.
+
+ // Check for extraneous top-level semicolon.
+ if (Tok.is(tok::semi)) {
+ Diag(Tok, diag::ext_extra_struct_semi);
+ ConsumeToken();
+ continue;
+ }
+
+ // Set the default visibility to private.
+ if (Tok.is(tok::at)) { // parse objc-visibility-spec
+ ConsumeToken(); // eat the @ sign
+ switch (Tok.getObjCKeywordID()) {
+ case tok::objc_private:
+ case tok::objc_public:
+ case tok::objc_protected:
+ case tok::objc_package:
+ visibility = Tok.getObjCKeywordID();
+ ConsumeToken();
+ continue;
+ default:
+ Diag(Tok, diag::err_objc_illegal_visibility_spec);
+ continue;
+ }
+ }
+
+ // 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(),
+ FD.D, FD.BitfieldSize, visibility);
+ AllIvarDecls.push_back(Field);
+ }
+
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ } else {
+ Diag(Tok, diag::err_expected_semi_decl_list);
+ // Skip to end of block or statement
+ SkipUntil(tok::r_brace, true, true);
+ }
+ }
+ SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
+ // Call ActOnFields() even if we don't have any decls. This is useful
+ // for code rewriting tools that need to be aware of the empty list.
+ Actions.ActOnFields(CurScope, atLoc, interfaceDecl,
+ AllIvarDecls.data(), AllIvarDecls.size(),
+ LBraceLoc, RBraceLoc, 0);
+ return;
+}
+
+/// objc-protocol-declaration:
+/// objc-protocol-definition
+/// objc-protocol-forward-reference
+///
+/// objc-protocol-definition:
+/// @protocol identifier
+/// objc-protocol-refs[opt]
+/// objc-interface-decl-list
+/// @end
+///
+/// objc-protocol-forward-reference:
+/// @protocol identifier-list ';'
+///
+/// "@protocol identifier ;" should be resolved as "@protocol
+/// identifier-list ;": objc-interface-decl-list may not start with a
+/// semicolon in the first alternative if objc-protocol-refs are omitted.
+Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
+ AttributeList *attrList) {
+ assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&
+ "ParseObjCAtProtocolDeclaration(): Expected @protocol");
+ ConsumeToken(); // the "protocol" identifier
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident); // missing protocol name.
+ return DeclPtrTy();
+ }
+ // Save the protocol name, then consume it.
+ IdentifierInfo *protocolName = Tok.getIdentifierInfo();
+ SourceLocation nameLoc = ConsumeToken();
+
+ if (Tok.is(tok::semi)) { // forward declaration of one protocol.
+ IdentifierLocPair ProtoInfo(protocolName, nameLoc);
+ ConsumeToken();
+ return Actions.ActOnForwardProtocolDeclaration(AtLoc, &ProtoInfo, 1,
+ attrList);
+ }
+
+ if (Tok.is(tok::comma)) { // list of forward declarations.
+ llvm::SmallVector<IdentifierLocPair, 8> ProtocolRefs;
+ ProtocolRefs.push_back(std::make_pair(protocolName, nameLoc));
+
+ // Parse the list of forward declarations.
+ while (1) {
+ ConsumeToken(); // the ','
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::semi);
+ return DeclPtrTy();
+ }
+ ProtocolRefs.push_back(IdentifierLocPair(Tok.getIdentifierInfo(),
+ Tok.getLocation()));
+ ConsumeToken(); // the identifier
+
+ if (Tok.isNot(tok::comma))
+ break;
+ }
+ // Consume the ';'.
+ if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol"))
+ return DeclPtrTy();
+
+ return Actions.ActOnForwardProtocolDeclaration(AtLoc,
+ &ProtocolRefs[0],
+ ProtocolRefs.size(),
+ attrList);
+ }
+
+ // Last, and definitely not least, parse a protocol declaration.
+ SourceLocation EndProtoLoc;
+
+ llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs;
+ if (Tok.is(tok::less) &&
+ ParseObjCProtocolReferences(ProtocolRefs, false, EndProtoLoc))
+ return DeclPtrTy();
+
+ DeclPtrTy ProtoType =
+ Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc,
+ ProtocolRefs.data(),
+ ProtocolRefs.size(),
+ EndProtoLoc, attrList);
+ ParseObjCInterfaceDeclList(ProtoType, tok::objc_protocol);
+ return ProtoType;
+}
+
+/// objc-implementation:
+/// objc-class-implementation-prologue
+/// objc-category-implementation-prologue
+///
+/// objc-class-implementation-prologue:
+/// @implementation identifier objc-superclass[opt]
+/// objc-class-instance-variables[opt]
+///
+/// objc-category-implementation-prologue:
+/// @implementation identifier ( identifier )
+Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration(
+ SourceLocation atLoc) {
+ assert(Tok.isObjCAtKeyword(tok::objc_implementation) &&
+ "ParseObjCAtImplementationDeclaration(): Expected @implementation");
+ ConsumeToken(); // the "implementation" identifier
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident); // missing class or category name.
+ return DeclPtrTy();
+ }
+ // We have a class or category name - consume it.
+ IdentifierInfo *nameId = Tok.getIdentifierInfo();
+ SourceLocation nameLoc = ConsumeToken(); // consume class or category name
+
+ if (Tok.is(tok::l_paren)) {
+ // we have a category implementation.
+ SourceLocation lparenLoc = ConsumeParen();
+ SourceLocation categoryLoc, rparenLoc;
+ IdentifierInfo *categoryId = 0;
+
+ if (Tok.is(tok::identifier)) {
+ categoryId = Tok.getIdentifierInfo();
+ categoryLoc = ConsumeToken();
+ } else {
+ Diag(Tok, diag::err_expected_ident); // missing category name.
+ return DeclPtrTy();
+ }
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_expected_rparen);
+ SkipUntil(tok::r_paren, false); // don't stop at ';'
+ return DeclPtrTy();
+ }
+ rparenLoc = ConsumeParen();
+ DeclPtrTy ImplCatType = Actions.ActOnStartCategoryImplementation(
+ atLoc, nameId, nameLoc, categoryId,
+ categoryLoc);
+ ObjCImpDecl = ImplCatType;
+ return DeclPtrTy();
+ }
+ // We have a class implementation
+ SourceLocation superClassLoc;
+ IdentifierInfo *superClassId = 0;
+ if (Tok.is(tok::colon)) {
+ // We have a super class
+ ConsumeToken();
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident); // missing super class name.
+ return DeclPtrTy();
+ }
+ superClassId = Tok.getIdentifierInfo();
+ superClassLoc = ConsumeToken(); // Consume super class name
+ }
+ DeclPtrTy ImplClsType = Actions.ActOnStartClassImplementation(
+ atLoc, nameId, nameLoc,
+ superClassId, superClassLoc);
+
+ if (Tok.is(tok::l_brace)) // we have ivars
+ ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/, atLoc);
+ ObjCImpDecl = ImplClsType;
+
+ return DeclPtrTy();
+}
+
+Parser::DeclPtrTy Parser::ParseObjCAtEndDeclaration(SourceLocation atLoc) {
+ assert(Tok.isObjCAtKeyword(tok::objc_end) &&
+ "ParseObjCAtEndDeclaration(): Expected @end");
+ DeclPtrTy Result = ObjCImpDecl;
+ ConsumeToken(); // the "end" identifier
+ if (ObjCImpDecl) {
+ Actions.ActOnAtEnd(atLoc, ObjCImpDecl);
+ ObjCImpDecl = DeclPtrTy();
+ }
+ else
+ Diag(atLoc, diag::warn_expected_implementation); // missing @implementation
+ return Result;
+}
+
+/// compatibility-alias-decl:
+/// @compatibility_alias alias-name class-name ';'
+///
+Parser::DeclPtrTy Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) {
+ assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) &&
+ "ParseObjCAtAliasDeclaration(): Expected @compatibility_alias");
+ ConsumeToken(); // consume compatibility_alias
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ return DeclPtrTy();
+ }
+ IdentifierInfo *aliasId = Tok.getIdentifierInfo();
+ SourceLocation aliasLoc = ConsumeToken(); // consume alias-name
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ return DeclPtrTy();
+ }
+ IdentifierInfo *classId = Tok.getIdentifierInfo();
+ SourceLocation classLoc = ConsumeToken(); // consume class-name;
+ if (Tok.isNot(tok::semi)) {
+ Diag(Tok, diag::err_expected_semi_after) << "@compatibility_alias";
+ return DeclPtrTy();
+ }
+ return Actions.ActOnCompatiblityAlias(atLoc, aliasId, aliasLoc,
+ classId, classLoc);
+}
+
+/// property-synthesis:
+/// @synthesize property-ivar-list ';'
+///
+/// property-ivar-list:
+/// property-ivar
+/// property-ivar-list ',' property-ivar
+///
+/// property-ivar:
+/// identifier
+/// identifier '=' identifier
+///
+Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
+ assert(Tok.isObjCAtKeyword(tok::objc_synthesize) &&
+ "ParseObjCPropertyDynamic(): Expected '@synthesize'");
+ SourceLocation loc = ConsumeToken(); // consume synthesize
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ return DeclPtrTy();
+ }
+
+ while (Tok.is(tok::identifier)) {
+ IdentifierInfo *propertyIvar = 0;
+ IdentifierInfo *propertyId = Tok.getIdentifierInfo();
+ SourceLocation propertyLoc = ConsumeToken(); // consume property name
+ if (Tok.is(tok::equal)) {
+ // property '=' ivar-name
+ ConsumeToken(); // consume '='
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ break;
+ }
+ propertyIvar = Tok.getIdentifierInfo();
+ ConsumeToken(); // consume ivar-name
+ }
+ Actions.ActOnPropertyImplDecl(atLoc, propertyLoc, true, ObjCImpDecl,
+ propertyId, propertyIvar);
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken(); // consume ','
+ }
+ if (Tok.isNot(tok::semi))
+ Diag(Tok, diag::err_expected_semi_after) << "@synthesize";
+ return DeclPtrTy();
+}
+
+/// property-dynamic:
+/// @dynamic property-list
+///
+/// property-list:
+/// identifier
+/// property-list ',' identifier
+///
+Parser::DeclPtrTy Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
+ assert(Tok.isObjCAtKeyword(tok::objc_dynamic) &&
+ "ParseObjCPropertyDynamic(): Expected '@dynamic'");
+ SourceLocation loc = ConsumeToken(); // consume dynamic
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ return DeclPtrTy();
+ }
+ while (Tok.is(tok::identifier)) {
+ IdentifierInfo *propertyId = Tok.getIdentifierInfo();
+ SourceLocation propertyLoc = ConsumeToken(); // consume property name
+ Actions.ActOnPropertyImplDecl(atLoc, propertyLoc, false, ObjCImpDecl,
+ propertyId, 0);
+
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken(); // consume ','
+ }
+ if (Tok.isNot(tok::semi))
+ Diag(Tok, diag::err_expected_semi_after) << "@dynamic";
+ return DeclPtrTy();
+}
+
+/// objc-throw-statement:
+/// throw expression[opt];
+///
+Parser::OwningStmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) {
+ OwningExprResult Res(Actions);
+ ConsumeToken(); // consume throw
+ if (Tok.isNot(tok::semi)) {
+ Res = ParseExpression();
+ if (Res.isInvalid()) {
+ SkipUntil(tok::semi);
+ return StmtError();
+ }
+ }
+ ConsumeToken(); // consume ';'
+ return Actions.ActOnObjCAtThrowStmt(atLoc, move(Res), CurScope);
+}
+
+/// objc-synchronized-statement:
+/// @synchronized '(' expression ')' compound-statement
+///
+Parser::OwningStmtResult
+Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
+ ConsumeToken(); // consume synchronized
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << "@synchronized";
+ return StmtError();
+ }
+ ConsumeParen(); // '('
+ OwningExprResult Res(ParseExpression());
+ if (Res.isInvalid()) {
+ SkipUntil(tok::semi);
+ return StmtError();
+ }
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_expected_lbrace);
+ return StmtError();
+ }
+ ConsumeParen(); // ')'
+ if (Tok.isNot(tok::l_brace)) {
+ Diag(Tok, diag::err_expected_lbrace);
+ return StmtError();
+ }
+ // Enter a scope to hold everything within the compound stmt. Compound
+ // statements can always hold declarations.
+ ParseScope BodyScope(this, Scope::DeclScope);
+
+ OwningStmtResult SynchBody(ParseCompoundStatementBody());
+
+ BodyScope.Exit();
+ if (SynchBody.isInvalid())
+ SynchBody = Actions.ActOnNullStmt(Tok.getLocation());
+ return Actions.ActOnObjCAtSynchronizedStmt(atLoc, move(Res), move(SynchBody));
+}
+
+/// objc-try-catch-statement:
+/// @try compound-statement objc-catch-list[opt]
+/// @try compound-statement objc-catch-list[opt] @finally compound-statement
+///
+/// objc-catch-list:
+/// @catch ( parameter-declaration ) compound-statement
+/// objc-catch-list @catch ( catch-parameter-declaration ) compound-statement
+/// catch-parameter-declaration:
+/// parameter-declaration
+/// '...' [OBJC2]
+///
+Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
+ bool catch_or_finally_seen = false;
+
+ ConsumeToken(); // consume try
+ if (Tok.isNot(tok::l_brace)) {
+ Diag(Tok, diag::err_expected_lbrace);
+ return StmtError();
+ }
+ OwningStmtResult CatchStmts(Actions);
+ OwningStmtResult FinallyStmt(Actions);
+ ParseScope TryScope(this, Scope::DeclScope);
+ OwningStmtResult TryBody(ParseCompoundStatementBody());
+ TryScope.Exit();
+ if (TryBody.isInvalid())
+ TryBody = Actions.ActOnNullStmt(Tok.getLocation());
+
+ while (Tok.is(tok::at)) {
+ // At this point, we need to lookahead to determine if this @ is the start
+ // of an @catch or @finally. We don't want to consume the @ token if this
+ // is an @try or @encode or something else.
+ Token AfterAt = GetLookAheadToken(1);
+ if (!AfterAt.isObjCAtKeyword(tok::objc_catch) &&
+ !AfterAt.isObjCAtKeyword(tok::objc_finally))
+ break;
+
+ SourceLocation AtCatchFinallyLoc = ConsumeToken();
+ if (Tok.isObjCAtKeyword(tok::objc_catch)) {
+ DeclPtrTy FirstPart;
+ ConsumeToken(); // consume catch
+ if (Tok.is(tok::l_paren)) {
+ ConsumeParen();
+ ParseScope CatchScope(this, Scope::DeclScope|Scope::AtCatchScope);
+ if (Tok.isNot(tok::ellipsis)) {
+ DeclSpec DS;
+ ParseDeclarationSpecifiers(DS);
+ // For some odd reason, the name of the exception variable is
+ // optional. As a result, we need to use "PrototypeContext", because
+ // we must accept either 'declarator' or 'abstract-declarator' here.
+ Declarator ParmDecl(DS, Declarator::PrototypeContext);
+ ParseDeclarator(ParmDecl);
+
+ // Inform the actions module about the parameter declarator, so it
+ // gets added to the current scope.
+ FirstPart = Actions.ActOnParamDeclarator(CurScope, ParmDecl);
+ } else
+ ConsumeToken(); // consume '...'
+
+ SourceLocation RParenLoc;
+
+ if (Tok.is(tok::r_paren))
+ RParenLoc = ConsumeParen();
+ else // Skip over garbage, until we get to ')'. Eat the ')'.
+ SkipUntil(tok::r_paren, true, false);
+
+ OwningStmtResult CatchBody(Actions, true);
+ if (Tok.is(tok::l_brace))
+ CatchBody = ParseCompoundStatementBody();
+ else
+ Diag(Tok, diag::err_expected_lbrace);
+ if (CatchBody.isInvalid())
+ CatchBody = Actions.ActOnNullStmt(Tok.getLocation());
+ CatchStmts = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc,
+ RParenLoc, FirstPart, move(CatchBody),
+ move(CatchStmts));
+ } else {
+ Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after)
+ << "@catch clause";
+ return StmtError();
+ }
+ catch_or_finally_seen = true;
+ } else {
+ assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?");
+ ConsumeToken(); // consume finally
+ ParseScope FinallyScope(this, Scope::DeclScope);
+
+ OwningStmtResult FinallyBody(Actions, true);
+ if (Tok.is(tok::l_brace))
+ FinallyBody = ParseCompoundStatementBody();
+ else
+ Diag(Tok, diag::err_expected_lbrace);
+ if (FinallyBody.isInvalid())
+ FinallyBody = Actions.ActOnNullStmt(Tok.getLocation());
+ FinallyStmt = Actions.ActOnObjCAtFinallyStmt(AtCatchFinallyLoc,
+ move(FinallyBody));
+ catch_or_finally_seen = true;
+ break;
+ }
+ }
+ if (!catch_or_finally_seen) {
+ Diag(atLoc, diag::err_missing_catch_finally);
+ return StmtError();
+ }
+ return Actions.ActOnObjCAtTryStmt(atLoc, move(TryBody), move(CatchStmts),
+ move(FinallyStmt));
+}
+
+/// objc-method-def: objc-method-proto ';'[opt] '{' body '}'
+///
+Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() {
+ DeclPtrTy MDecl = ParseObjCMethodPrototype(ObjCImpDecl);
+
+ PrettyStackTraceActionsDecl CrashInfo(MDecl, Tok.getLocation(), Actions,
+ PP.getSourceManager(),
+ "parsing Objective-C method");
+
+ // parse optional ';'
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+
+ // We should have an opening brace now.
+ if (Tok.isNot(tok::l_brace)) {
+ Diag(Tok, diag::err_expected_method_body);
+
+ // Skip over garbage, until we get to '{'. Don't eat the '{'.
+ SkipUntil(tok::l_brace, true, true);
+
+ // If we didn't find the '{', bail out.
+ if (Tok.isNot(tok::l_brace))
+ return DeclPtrTy();
+ }
+ SourceLocation BraceLoc = Tok.getLocation();
+
+ // Enter a scope for the method body.
+ ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
+
+ // Tell the actions module that we have entered a method definition with the
+ // specified Declarator for the method.
+ Actions.ActOnStartOfObjCMethodDef(CurScope, MDecl);
+
+ OwningStmtResult FnBody(ParseCompoundStatementBody());
+
+ // If the function body could not be parsed, make a bogus compoundstmt.
+ if (FnBody.isInvalid())
+ FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc,
+ MultiStmtArg(Actions), false);
+
+ // TODO: Pass argument information.
+ Actions.ActOnFinishFunctionBody(MDecl, move(FnBody));
+
+ // Leave the function body scope.
+ BodyScope.Exit();
+
+ return MDecl;
+}
+
+Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) {
+ if (Tok.isObjCAtKeyword(tok::objc_try)) {
+ return ParseObjCTryStmt(AtLoc);
+ } else if (Tok.isObjCAtKeyword(tok::objc_throw))
+ return ParseObjCThrowStmt(AtLoc);
+ else if (Tok.isObjCAtKeyword(tok::objc_synchronized))
+ return ParseObjCSynchronizedStmt(AtLoc);
+ OwningExprResult Res(ParseExpressionWithLeadingAt(AtLoc));
+ if (Res.isInvalid()) {
+ // If the expression is invalid, skip ahead to the next semicolon. Not
+ // doing this opens us up to the possibility of infinite loops if
+ // ParseExpression does not consume any tokens.
+ SkipUntil(tok::semi);
+ return StmtError();
+ }
+ // Otherwise, eat the semicolon.
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
+ return Actions.ActOnExprStmt(Actions.FullExpr(Res));
+}
+
+Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
+ switch (Tok.getKind()) {
+ case tok::string_literal: // primary-expression: string-literal
+ case tok::wide_string_literal:
+ return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc));
+ default:
+ if (Tok.getIdentifierInfo() == 0)
+ return ExprError(Diag(AtLoc, diag::err_unexpected_at));
+
+ switch (Tok.getIdentifierInfo()->getObjCKeywordID()) {
+ case tok::objc_encode:
+ return ParsePostfixExpressionSuffix(ParseObjCEncodeExpression(AtLoc));
+ case tok::objc_protocol:
+ return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression(AtLoc));
+ case tok::objc_selector:
+ return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc));
+ default:
+ return ExprError(Diag(AtLoc, diag::err_unexpected_at));
+ }
+ }
+}
+
+/// objc-message-expr:
+/// '[' objc-receiver objc-message-args ']'
+///
+/// objc-receiver:
+/// expression
+/// class-name
+/// type-name
+Parser::OwningExprResult Parser::ParseObjCMessageExpression() {
+ assert(Tok.is(tok::l_square) && "'[' expected");
+ SourceLocation LBracLoc = ConsumeBracket(); // consume '['
+
+ // Parse receiver
+ if (isTokObjCMessageIdentifierReceiver()) {
+ IdentifierInfo *ReceiverName = Tok.getIdentifierInfo();
+ if (ReceiverName != Ident_super || GetLookAheadToken(1).isNot(tok::period)) {
+ SourceLocation NameLoc = ConsumeToken();
+ return ParseObjCMessageExpressionBody(LBracLoc, NameLoc, ReceiverName,
+ ExprArg(Actions));
+ }
+ }
+
+ OwningExprResult Res(ParseExpression());
+ if (Res.isInvalid()) {
+ SkipUntil(tok::r_square);
+ return move(Res);
+ }
+
+ return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
+ 0, move(Res));
+}
+
+/// ParseObjCMessageExpressionBody - Having parsed "'[' objc-receiver", parse
+/// the rest of a message expression.
+///
+/// objc-message-args:
+/// objc-selector
+/// objc-keywordarg-list
+///
+/// objc-keywordarg-list:
+/// objc-keywordarg
+/// objc-keywordarg-list objc-keywordarg
+///
+/// objc-keywordarg:
+/// selector-name[opt] ':' objc-keywordexpr
+///
+/// objc-keywordexpr:
+/// nonempty-expr-list
+///
+/// nonempty-expr-list:
+/// assignment-expression
+/// nonempty-expr-list , assignment-expression
+///
+Parser::OwningExprResult
+Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
+ SourceLocation NameLoc,
+ IdentifierInfo *ReceiverName,
+ ExprArg ReceiverExpr) {
+ // Parse objc-selector
+ SourceLocation Loc;
+ IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc);
+
+ SourceLocation SelectorLoc = Loc;
+
+ llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
+ ExprVector KeyExprs(Actions);
+
+ if (Tok.is(tok::colon)) {
+ while (1) {
+ // Each iteration parses a single keyword argument.
+ KeyIdents.push_back(selIdent);
+
+ if (Tok.isNot(tok::colon)) {
+ Diag(Tok, diag::err_expected_colon);
+ // We must manually skip to a ']', otherwise the expression skipper will
+ // stop at the ']' when it skips to the ';'. We want it to skip beyond
+ // the enclosing expression.
+ SkipUntil(tok::r_square);
+ return ExprError();
+ }
+
+ ConsumeToken(); // Eat the ':'.
+ /// Parse the expression after ':'
+ OwningExprResult Res(ParseAssignmentExpression());
+ if (Res.isInvalid()) {
+ // We must manually skip to a ']', otherwise the expression skipper will
+ // stop at the ']' when it skips to the ';'. We want it to skip beyond
+ // the enclosing expression.
+ SkipUntil(tok::r_square);
+ return move(Res);
+ }
+
+ // We have a valid expression.
+ KeyExprs.push_back(Res.release());
+
+ // Check for another keyword selector.
+ selIdent = ParseObjCSelectorPiece(Loc);
+ if (!selIdent && Tok.isNot(tok::colon))
+ break;
+ // We have a selector or a colon, continue parsing.
+ }
+ // Parse the, optional, argument list, comma separated.
+ while (Tok.is(tok::comma)) {
+ ConsumeToken(); // Eat the ','.
+ /// Parse the expression after ','
+ OwningExprResult Res(ParseAssignmentExpression());
+ if (Res.isInvalid()) {
+ // We must manually skip to a ']', otherwise the expression skipper will
+ // stop at the ']' when it skips to the ';'. We want it to skip beyond
+ // the enclosing expression.
+ SkipUntil(tok::r_square);
+ return move(Res);
+ }
+
+ // We have a valid expression.
+ KeyExprs.push_back(Res.release());
+ }
+ } else if (!selIdent) {
+ Diag(Tok, diag::err_expected_ident); // missing selector name.
+
+ // We must manually skip to a ']', otherwise the expression skipper will
+ // stop at the ']' when it skips to the ';'. We want it to skip beyond
+ // the enclosing expression.
+ SkipUntil(tok::r_square);
+ return ExprError();
+ }
+
+ if (Tok.isNot(tok::r_square)) {
+ Diag(Tok, diag::err_expected_rsquare);
+ // We must manually skip to a ']', otherwise the expression skipper will
+ // stop at the ']' when it skips to the ';'. We want it to skip beyond
+ // the enclosing expression.
+ SkipUntil(tok::r_square);
+ return ExprError();
+ }
+
+ SourceLocation RBracLoc = ConsumeBracket(); // consume ']'
+
+ unsigned nKeys = KeyIdents.size();
+ if (nKeys == 0)
+ KeyIdents.push_back(selIdent);
+ Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]);
+
+ // We've just parsed a keyword message.
+ if (ReceiverName)
+ return Owned(Actions.ActOnClassMessage(CurScope, ReceiverName, Sel,
+ LBracLoc, NameLoc, SelectorLoc,
+ RBracLoc,
+ KeyExprs.take(), KeyExprs.size()));
+ return Owned(Actions.ActOnInstanceMessage(ReceiverExpr.release(), Sel,
+ LBracLoc, SelectorLoc, RBracLoc,
+ KeyExprs.take(), KeyExprs.size()));
+}
+
+Parser::OwningExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
+ OwningExprResult Res(ParseStringLiteralExpression());
+ if (Res.isInvalid()) return move(Res);
+
+ // @"foo" @"bar" is a valid concatenated string. Eat any subsequent string
+ // expressions. At this point, we know that the only valid thing that starts
+ // with '@' is an @"".
+ llvm::SmallVector<SourceLocation, 4> AtLocs;
+ ExprVector AtStrings(Actions);
+ AtLocs.push_back(AtLoc);
+ AtStrings.push_back(Res.release());
+
+ while (Tok.is(tok::at)) {
+ AtLocs.push_back(ConsumeToken()); // eat the @.
+
+ // Invalid unless there is a string literal.
+ if (!isTokenStringLiteral())
+ return ExprError(Diag(Tok, diag::err_objc_concat_string));
+
+ OwningExprResult Lit(ParseStringLiteralExpression());
+ if (Lit.isInvalid())
+ return move(Lit);
+
+ AtStrings.push_back(Lit.release());
+ }
+
+ return Owned(Actions.ParseObjCStringLiteral(&AtLocs[0], AtStrings.take(),
+ AtStrings.size()));
+}
+
+/// objc-encode-expression:
+/// @encode ( type-name )
+Parser::OwningExprResult
+Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) {
+ assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!");
+
+ SourceLocation EncLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::l_paren))
+ return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@encode");
+
+ SourceLocation LParenLoc = ConsumeParen();
+
+ TypeResult Ty = ParseTypeName();
+
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ if (Ty.isInvalid())
+ return ExprError();
+
+ return Owned(Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, LParenLoc,
+ Ty.get(), RParenLoc));
+}
+
+/// objc-protocol-expression
+/// @protocol ( protocol-name )
+Parser::OwningExprResult
+Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
+ SourceLocation ProtoLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::l_paren))
+ return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@protocol");
+
+ SourceLocation LParenLoc = ConsumeParen();
+
+ if (Tok.isNot(tok::identifier))
+ return ExprError(Diag(Tok, diag::err_expected_ident));
+
+ IdentifierInfo *protocolId = Tok.getIdentifierInfo();
+ ConsumeToken();
+
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ return Owned(Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc,
+ LParenLoc, RParenLoc));
+}
+
+/// objc-selector-expression
+/// @selector '(' objc-keyword-selector ')'
+Parser::OwningExprResult
+Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
+ SourceLocation SelectorLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::l_paren))
+ return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@selector");
+
+ llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
+ SourceLocation LParenLoc = ConsumeParen();
+ SourceLocation sLoc;
+ IdentifierInfo *SelIdent = ParseObjCSelectorPiece(sLoc);
+ if (!SelIdent && Tok.isNot(tok::colon)) // missing selector name.
+ return ExprError(Diag(Tok, diag::err_expected_ident));
+
+ KeyIdents.push_back(SelIdent);
+ unsigned nColons = 0;
+ if (Tok.isNot(tok::r_paren)) {
+ while (1) {
+ if (Tok.isNot(tok::colon))
+ return ExprError(Diag(Tok, diag::err_expected_colon));
+
+ nColons++;
+ ConsumeToken(); // Eat the ':'.
+ if (Tok.is(tok::r_paren))
+ break;
+ // Check for another keyword selector.
+ SourceLocation Loc;
+ SelIdent = ParseObjCSelectorPiece(Loc);
+ KeyIdents.push_back(SelIdent);
+ if (!SelIdent && Tok.isNot(tok::colon))
+ break;
+ }
+ }
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]);
+ return Owned(Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc,
+ LParenLoc, RParenLoc));
+ }
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
new file mode 100644
index 0000000..94695e4
--- /dev/null
+++ b/lib/Parse/ParsePragma.cpp
@@ -0,0 +1,182 @@
+//===--- ParsePragma.cpp - Language specific pragma parsing ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the language specific #pragma handlers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ParsePragma.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/Action.h"
+#include "clang/Parse/Parser.h"
+using namespace clang;
+
+// #pragma pack(...) comes in the following delicious flavors:
+// pack '(' [integer] ')'
+// pack '(' 'show' ')'
+// pack '(' ('push' | 'pop') [',' identifier] [, integer] ')'
+void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) {
+ // FIXME: Should we be expanding macros here? My guess is no.
+ SourceLocation PackLoc = PackTok.getLocation();
+
+ Token Tok;
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "pack";
+ return;
+ }
+
+ Action::PragmaPackKind Kind = Action::PPK_Default;
+ IdentifierInfo *Name = 0;
+ Action::OwningExprResult Alignment(Actions);
+ SourceLocation LParenLoc = Tok.getLocation();
+ PP.Lex(Tok);
+ if (Tok.is(tok::numeric_constant)) {
+ Alignment = Actions.ActOnNumericConstant(Tok);
+ if (Alignment.isInvalid())
+ return;
+
+ PP.Lex(Tok);
+ } else if (Tok.is(tok::identifier)) {
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (II->isStr("show")) {
+ Kind = Action::PPK_Show;
+ PP.Lex(Tok);
+ } else {
+ if (II->isStr("push")) {
+ Kind = Action::PPK_Push;
+ } else if (II->isStr("pop")) {
+ Kind = Action::PPK_Pop;
+ } else {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_invalid_action);
+ return;
+ }
+ PP.Lex(Tok);
+
+ if (Tok.is(tok::comma)) {
+ PP.Lex(Tok);
+
+ if (Tok.is(tok::numeric_constant)) {
+ Alignment = Actions.ActOnNumericConstant(Tok);
+ if (Alignment.isInvalid())
+ return;
+
+ PP.Lex(Tok);
+ } else if (Tok.is(tok::identifier)) {
+ Name = Tok.getIdentifierInfo();
+ PP.Lex(Tok);
+
+ if (Tok.is(tok::comma)) {
+ PP.Lex(Tok);
+
+ if (Tok.isNot(tok::numeric_constant)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed);
+ return;
+ }
+
+ Alignment = Actions.ActOnNumericConstant(Tok);
+ if (Alignment.isInvalid())
+ return;
+
+ PP.Lex(Tok);
+ }
+ } else {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed);
+ return;
+ }
+ }
+ }
+ }
+
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) << "pack";
+ return;
+ }
+
+ SourceLocation RParenLoc = Tok.getLocation();
+ Actions.ActOnPragmaPack(Kind, Name, Alignment.release(), PackLoc,
+ LParenLoc, RParenLoc);
+}
+
+// #pragma unused(identifier)
+void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, Token &UnusedTok) {
+ // FIXME: Should we be expanding macros here? My guess is no.
+ SourceLocation UnusedLoc = UnusedTok.getLocation();
+
+ // Lex the left '('.
+ Token Tok;
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "unused";
+ return;
+ }
+ SourceLocation LParenLoc = Tok.getLocation();
+
+ // Lex the declaration reference(s).
+ llvm::SmallVector<Action::ExprTy*, 5> Ex;
+ SourceLocation RParenLoc;
+ bool LexID = true;
+
+ while (true) {
+ PP.Lex(Tok);
+
+ if (LexID) {
+ if (Tok.is(tok::identifier)) {
+ Action::OwningExprResult Name =
+ Actions.ActOnIdentifierExpr(parser.CurScope, Tok.getLocation(),
+ *Tok.getIdentifierInfo(), false);
+
+ if (Name.isInvalid()) {
+ if (!Ex.empty())
+ Action::MultiExprArg Release(Actions, &Ex[0], Ex.size());
+ return;
+ }
+
+ Ex.push_back(Name.release());
+ LexID = false;
+ continue;
+ }
+
+ // Illegal token! Release the parsed expressions (if any) and emit
+ // a warning.
+ if (!Ex.empty())
+ Action::MultiExprArg Release(Actions, &Ex[0], Ex.size());
+
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_var);
+ return;
+ }
+
+ // We are execting a ')' or a ','.
+ if (Tok.is(tok::comma)) {
+ LexID = true;
+ continue;
+ }
+
+ if (Tok.is(tok::r_paren)) {
+ RParenLoc = Tok.getLocation();
+ break;
+ }
+
+ // Illegal token! Release the parsed expressions (if any) and emit
+ // a warning.
+ if (!Ex.empty())
+ Action::MultiExprArg Release(Actions, &Ex[0], Ex.size());
+
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_punc);
+ return;
+ }
+
+ // Verify that we have a location for the right parenthesis.
+ assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'");
+ assert(!Ex.empty() && "Valid '#pragma unused' must have arguments");
+
+ // Perform the action to handle the pragma.
+ Actions.ActOnPragmaUnused(&Ex[0], Ex.size(), UnusedLoc, LParenLoc, RParenLoc);
+}
diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h
new file mode 100644
index 0000000..31b2a5f
--- /dev/null
+++ b/lib/Parse/ParsePragma.h
@@ -0,0 +1,44 @@
+//===---- ParserPragmas.h - Language specific pragmas -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines #pragma handlers for language specific pragmas.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PARSE_PARSEPRAGMA_H
+#define LLVM_CLANG_PARSE_PARSEPRAGMA_H
+
+#include "clang/Lex/Pragma.h"
+
+namespace clang {
+ class Action;
+ class Parser;
+
+class PragmaPackHandler : public PragmaHandler {
+ Action &Actions;
+public:
+ PragmaPackHandler(const IdentifierInfo *N, Action &A) : PragmaHandler(N),
+ Actions(A) {}
+
+ virtual void HandlePragma(Preprocessor &PP, Token &FirstToken);
+};
+
+class PragmaUnusedHandler : public PragmaHandler {
+ Action &Actions;
+ Parser &parser;
+public:
+ PragmaUnusedHandler(const IdentifierInfo *N, Action &A, Parser& p)
+ : PragmaHandler(N), Actions(A), parser(p) {}
+
+ virtual void HandlePragma(Preprocessor &PP, Token &FirstToken);
+};
+
+} // end namespace clang
+
+#endif
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
new file mode 100644
index 0000000..758b662
--- /dev/null
+++ b/lib/Parse/ParseStmt.cpp
@@ -0,0 +1,1435 @@
+//===--- ParseStmt.cpp - Statement and Block Parser -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Statement and Block portions of the Parser
+// interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "ExtensionRAIIObject.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/PrettyStackTrace.h"
+#include "clang/Basic/SourceManager.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// C99 6.8: Statements and Blocks.
+//===----------------------------------------------------------------------===//
+
+/// ParseStatementOrDeclaration - Read 'statement' or 'declaration'.
+/// StatementOrDeclaration:
+/// statement
+/// declaration
+///
+/// statement:
+/// labeled-statement
+/// compound-statement
+/// expression-statement
+/// selection-statement
+/// iteration-statement
+/// jump-statement
+/// [C++] declaration-statement
+/// [C++] try-block
+/// [OBC] objc-throw-statement
+/// [OBC] objc-try-catch-statement
+/// [OBC] objc-synchronized-statement
+/// [GNU] asm-statement
+/// [OMP] openmp-construct [TODO]
+///
+/// labeled-statement:
+/// identifier ':' statement
+/// 'case' constant-expression ':' statement
+/// 'default' ':' statement
+///
+/// selection-statement:
+/// if-statement
+/// switch-statement
+///
+/// iteration-statement:
+/// while-statement
+/// do-statement
+/// for-statement
+///
+/// expression-statement:
+/// expression[opt] ';'
+///
+/// jump-statement:
+/// 'goto' identifier ';'
+/// 'continue' ';'
+/// 'break' ';'
+/// 'return' expression[opt] ';'
+/// [GNU] 'goto' '*' expression ';'
+///
+/// [OBC] objc-throw-statement:
+/// [OBC] '@' 'throw' expression ';'
+/// [OBC] '@' 'throw' ';'
+///
+Parser::OwningStmtResult
+Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
+ const char *SemiError = 0;
+ OwningStmtResult Res(Actions);
+
+ // Cases in this switch statement should fall through if the parser expects
+ // the token to end in a semicolon (in which case SemiError should be set),
+ // or they directly 'return;' if not.
+ tok::TokenKind Kind = Tok.getKind();
+ SourceLocation AtLoc;
+ switch (Kind) {
+ case tok::at: // May be a @try or @throw statement
+ {
+ AtLoc = ConsumeToken(); // consume @
+ return ParseObjCAtStatement(AtLoc);
+ }
+
+ case tok::identifier:
+ if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement
+ // identifier ':' statement
+ return ParseLabeledStatement();
+ }
+ // PASS THROUGH.
+
+ default: {
+ if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
+ SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
+ DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext, DeclEnd);
+ return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
+ }
+
+ if (Tok.is(tok::r_brace)) {
+ Diag(Tok, diag::err_expected_statement);
+ return StmtError();
+ }
+
+ // expression[opt] ';'
+ OwningExprResult Expr(ParseExpression());
+ if (Expr.isInvalid()) {
+ // If the expression is invalid, skip ahead to the next semicolon. Not
+ // doing this opens us up to the possibility of infinite loops if
+ // ParseExpression does not consume any tokens.
+ SkipUntil(tok::semi);
+ return StmtError();
+ }
+ // Otherwise, eat the semicolon.
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
+ return Actions.ActOnExprStmt(Actions.FullExpr(Expr));
+ }
+
+ case tok::kw_case: // C99 6.8.1: labeled-statement
+ return ParseCaseStatement();
+ case tok::kw_default: // C99 6.8.1: labeled-statement
+ return ParseDefaultStatement();
+
+ case tok::l_brace: // C99 6.8.2: compound-statement
+ return ParseCompoundStatement();
+ case tok::semi: // C99 6.8.3p3: expression[opt] ';'
+ return Actions.ActOnNullStmt(ConsumeToken());
+
+ case tok::kw_if: // C99 6.8.4.1: if-statement
+ return ParseIfStatement();
+ case tok::kw_switch: // C99 6.8.4.2: switch-statement
+ return ParseSwitchStatement();
+
+ case tok::kw_while: // C99 6.8.5.1: while-statement
+ return ParseWhileStatement();
+ case tok::kw_do: // C99 6.8.5.2: do-statement
+ Res = ParseDoStatement();
+ SemiError = "do/while loop";
+ break;
+ case tok::kw_for: // C99 6.8.5.3: for-statement
+ return ParseForStatement();
+
+ case tok::kw_goto: // C99 6.8.6.1: goto-statement
+ Res = ParseGotoStatement();
+ SemiError = "goto statement";
+ break;
+ case tok::kw_continue: // C99 6.8.6.2: continue-statement
+ Res = ParseContinueStatement();
+ SemiError = "continue statement";
+ break;
+ case tok::kw_break: // C99 6.8.6.3: break-statement
+ Res = ParseBreakStatement();
+ SemiError = "break statement";
+ break;
+ case tok::kw_return: // C99 6.8.6.4: return-statement
+ Res = ParseReturnStatement();
+ SemiError = "return statement";
+ break;
+
+ case tok::kw_asm: {
+ bool msAsm = false;
+ Res = ParseAsmStatement(msAsm);
+ if (msAsm) return move(Res);
+ SemiError = "asm statement";
+ break;
+ }
+
+ case tok::kw_try: // C++ 15: try-block
+ return ParseCXXTryBlock();
+ }
+
+ // If we reached this code, the statement must end in a semicolon.
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ } else if (!Res.isInvalid()) {
+ Diag(Tok, diag::err_expected_semi_after) << SemiError;
+ // Skip until we see a } or ;, but don't eat it.
+ SkipUntil(tok::r_brace, true, true);
+ }
+ return move(Res);
+}
+
+/// ParseLabeledStatement - We have an identifier and a ':' after it.
+///
+/// labeled-statement:
+/// identifier ':' statement
+/// [GNU] identifier ':' attributes[opt] statement
+///
+Parser::OwningStmtResult Parser::ParseLabeledStatement() {
+ assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() &&
+ "Not an identifier!");
+
+ Token IdentTok = Tok; // Save the whole token.
+ ConsumeToken(); // eat the identifier.
+
+ assert(Tok.is(tok::colon) && "Not a label!");
+
+ // identifier ':' statement
+ SourceLocation ColonLoc = ConsumeToken();
+
+ // Read label attributes, if present.
+ Action::AttrTy *AttrList = 0;
+ if (Tok.is(tok::kw___attribute))
+ // TODO: save these somewhere.
+ AttrList = ParseAttributes();
+
+ OwningStmtResult SubStmt(ParseStatement());
+
+ // Broken substmt shouldn't prevent the label from being added to the AST.
+ if (SubStmt.isInvalid())
+ SubStmt = Actions.ActOnNullStmt(ColonLoc);
+
+ return Actions.ActOnLabelStmt(IdentTok.getLocation(),
+ IdentTok.getIdentifierInfo(),
+ ColonLoc, move(SubStmt));
+}
+
+/// ParseCaseStatement
+/// labeled-statement:
+/// 'case' constant-expression ':' statement
+/// [GNU] 'case' constant-expression '...' constant-expression ':' statement
+///
+Parser::OwningStmtResult Parser::ParseCaseStatement() {
+ assert(Tok.is(tok::kw_case) && "Not a case stmt!");
+
+ // It is very very common for code to contain many case statements recursively
+ // nested, as in (but usually without indentation):
+ // case 1:
+ // case 2:
+ // case 3:
+ // case 4:
+ // case 5: etc.
+ //
+ // Parsing this naively works, but is both inefficient and can cause us to run
+ // out of stack space in our recursive descent parser. As a special case,
+ // flatten this recursion into an iterative loop. This is complex and gross,
+ // but all the grossness is constrained to ParseCaseStatement (and some
+ // wierdness in the actions), so this is just local grossness :).
+
+ // TopLevelCase - This is the highest level we have parsed. 'case 1' in the
+ // example above.
+ OwningStmtResult TopLevelCase(Actions, true);
+
+ // DeepestParsedCaseStmt - This is the deepest statement we have parsed, which
+ // gets updated each time a new case is parsed, and whose body is unset so
+ // far. When parsing 'case 4', this is the 'case 3' node.
+ StmtTy *DeepestParsedCaseStmt = 0;
+
+ // While we have case statements, eat and stack them.
+ do {
+ SourceLocation CaseLoc = ConsumeToken(); // eat the 'case'.
+
+ OwningExprResult LHS(ParseConstantExpression());
+ if (LHS.isInvalid()) {
+ SkipUntil(tok::colon);
+ return StmtError();
+ }
+
+ // GNU case range extension.
+ SourceLocation DotDotDotLoc;
+ OwningExprResult RHS(Actions);
+ if (Tok.is(tok::ellipsis)) {
+ Diag(Tok, diag::ext_gnu_case_range);
+ DotDotDotLoc = ConsumeToken();
+
+ RHS = ParseConstantExpression();
+ if (RHS.isInvalid()) {
+ SkipUntil(tok::colon);
+ return StmtError();
+ }
+ }
+
+ if (Tok.isNot(tok::colon)) {
+ Diag(Tok, diag::err_expected_colon_after) << "'case'";
+ SkipUntil(tok::colon);
+ return StmtError();
+ }
+
+ SourceLocation ColonLoc = ConsumeToken();
+
+ OwningStmtResult Case =
+ Actions.ActOnCaseStmt(CaseLoc, move(LHS), DotDotDotLoc,
+ move(RHS), ColonLoc);
+
+ // If we had a sema error parsing this case, then just ignore it and
+ // continue parsing the sub-stmt.
+ if (Case.isInvalid()) {
+ if (TopLevelCase.isInvalid()) // No parsed case stmts.
+ return ParseStatement();
+ // Otherwise, just don't add it as a nested case.
+ } else {
+ // If this is the first case statement we parsed, it becomes TopLevelCase.
+ // Otherwise we link it into the current chain.
+ StmtTy *NextDeepest = Case.get();
+ if (TopLevelCase.isInvalid())
+ TopLevelCase = move(Case);
+ else
+ Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, move(Case));
+ DeepestParsedCaseStmt = NextDeepest;
+ }
+
+ // Handle all case statements.
+ } while (Tok.is(tok::kw_case));
+
+ assert(!TopLevelCase.isInvalid() && "Should have parsed at least one case!");
+
+ // If we found a non-case statement, start by parsing it.
+ OwningStmtResult SubStmt(Actions);
+
+ if (Tok.isNot(tok::r_brace)) {
+ SubStmt = ParseStatement();
+ } else {
+ // Nicely diagnose the common error "switch (X) { case 4: }", which is
+ // not valid.
+ // FIXME: add insertion hint.
+ Diag(Tok, diag::err_label_end_of_compound_statement);
+ SubStmt = true;
+ }
+
+ // Broken sub-stmt shouldn't prevent forming the case statement properly.
+ if (SubStmt.isInvalid())
+ SubStmt = Actions.ActOnNullStmt(SourceLocation());
+
+ // Install the body into the most deeply-nested case.
+ Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, move(SubStmt));
+
+ // Return the top level parsed statement tree.
+ return move(TopLevelCase);
+}
+
+/// ParseDefaultStatement
+/// labeled-statement:
+/// 'default' ':' statement
+/// Note that this does not parse the 'statement' at the end.
+///
+Parser::OwningStmtResult Parser::ParseDefaultStatement() {
+ assert(Tok.is(tok::kw_default) && "Not a default stmt!");
+ SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'.
+
+ if (Tok.isNot(tok::colon)) {
+ Diag(Tok, diag::err_expected_colon_after) << "'default'";
+ SkipUntil(tok::colon);
+ return StmtError();
+ }
+
+ SourceLocation ColonLoc = ConsumeToken();
+
+ // Diagnose the common error "switch (X) {... default: }", which is not valid.
+ if (Tok.is(tok::r_brace)) {
+ Diag(Tok, diag::err_label_end_of_compound_statement);
+ return StmtError();
+ }
+
+ OwningStmtResult SubStmt(ParseStatement());
+ if (SubStmt.isInvalid())
+ return StmtError();
+
+ return Actions.ActOnDefaultStmt(DefaultLoc, ColonLoc,
+ move(SubStmt), CurScope);
+}
+
+
+/// ParseCompoundStatement - Parse a "{}" block.
+///
+/// compound-statement: [C99 6.8.2]
+/// { block-item-list[opt] }
+/// [GNU] { label-declarations block-item-list } [TODO]
+///
+/// block-item-list:
+/// block-item
+/// block-item-list block-item
+///
+/// block-item:
+/// declaration
+/// [GNU] '__extension__' declaration
+/// statement
+/// [OMP] openmp-directive [TODO]
+///
+/// [GNU] label-declarations:
+/// [GNU] label-declaration
+/// [GNU] label-declarations label-declaration
+///
+/// [GNU] label-declaration:
+/// [GNU] '__label__' identifier-list ';'
+///
+/// [OMP] openmp-directive: [TODO]
+/// [OMP] barrier-directive
+/// [OMP] flush-directive
+///
+Parser::OwningStmtResult Parser::ParseCompoundStatement(bool isStmtExpr) {
+ assert(Tok.is(tok::l_brace) && "Not a compount stmt!");
+
+ // Enter a scope to hold everything within the compound stmt. Compound
+ // statements can always hold declarations.
+ ParseScope CompoundScope(this, Scope::DeclScope);
+
+ // Parse the statements in the body.
+ return ParseCompoundStatementBody(isStmtExpr);
+}
+
+
+/// ParseCompoundStatementBody - Parse a sequence of statements and invoke the
+/// ActOnCompoundStmt action. This expects the '{' to be the current token, and
+/// consume the '}' at the end of the block. It does not manipulate the scope
+/// stack.
+Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
+ PrettyStackTraceLoc CrashInfo(PP.getSourceManager(),
+ Tok.getLocation(),
+ "in compound statement ('{}')");
+
+ SourceLocation LBraceLoc = ConsumeBrace(); // eat the '{'.
+
+ // TODO: "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are
+ // only allowed at the start of a compound stmt regardless of the language.
+
+ typedef StmtVector StmtsTy;
+ StmtsTy Stmts(Actions);
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ OwningStmtResult R(Actions);
+ if (Tok.isNot(tok::kw___extension__)) {
+ R = ParseStatementOrDeclaration(false);
+ } else {
+ // __extension__ can start declarations and it can also be a unary
+ // operator for expressions. Consume multiple __extension__ markers here
+ // until we can determine which is which.
+ // FIXME: This loses extension expressions in the AST!
+ SourceLocation ExtLoc = ConsumeToken();
+ while (Tok.is(tok::kw___extension__))
+ ConsumeToken();
+
+ // If this is the start of a declaration, parse it as such.
+ if (isDeclarationStatement()) {
+ // __extension__ silences extension warnings in the subdeclaration.
+ // FIXME: Save the __extension__ on the decl as a node somehow?
+ ExtensionRAIIObject O(Diags);
+
+ SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
+ DeclGroupPtrTy Res = ParseDeclaration(Declarator::BlockContext,DeclEnd);
+ R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd);
+ } else {
+ // Otherwise this was a unary __extension__ marker.
+ OwningExprResult Res(ParseExpressionWithLeadingExtension(ExtLoc));
+
+ if (Res.isInvalid()) {
+ SkipUntil(tok::semi);
+ continue;
+ }
+
+ // Eat the semicolon at the end of stmt and convert the expr into a
+ // statement.
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
+ R = Actions.ActOnExprStmt(Actions.FullExpr(Res));
+ }
+ }
+
+ if (R.isUsable())
+ Stmts.push_back(R.release());
+ }
+
+ // We broke out of the while loop because we found a '}' or EOF.
+ if (Tok.isNot(tok::r_brace)) {
+ Diag(Tok, diag::err_expected_rbrace);
+ return StmtError();
+ }
+
+ SourceLocation RBraceLoc = ConsumeBrace();
+ return Actions.ActOnCompoundStmt(LBraceLoc, RBraceLoc, move_arg(Stmts),
+ isStmtExpr);
+}
+
+/// ParseParenExprOrCondition:
+/// [C ] '(' expression ')'
+/// [C++] '(' condition ')' [not allowed if OnlyAllowCondition=true]
+///
+/// This function parses and performs error recovery on the specified condition
+/// or expression (depending on whether we're in C++ or C mode). This function
+/// goes out of its way to recover well. It returns true if there was a parser
+/// error (the right paren couldn't be found), which indicates that the caller
+/// should try to recover harder. It returns false if the condition is
+/// successfully parsed. Note that a successful parse can still have semantic
+/// errors in the condition.
+bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp,
+ bool OnlyAllowCondition) {
+ SourceLocation LParenLoc = ConsumeParen();
+
+ if (getLang().CPlusPlus)
+ CondExp = ParseCXXCondition();
+ else
+ CondExp = ParseExpression();
+
+ // If the parser was confused by the condition and we don't have a ')', try to
+ // recover by skipping ahead to a semi and bailing out. If condexp is
+ // semantically invalid but we have well formed code, keep going.
+ if (CondExp.isInvalid() && Tok.isNot(tok::r_paren)) {
+ SkipUntil(tok::semi);
+ // Skipping may have stopped if it found the containing ')'. If so, we can
+ // continue parsing the if statement.
+ if (Tok.isNot(tok::r_paren))
+ return true;
+ }
+
+ // Otherwise the condition is valid or the rparen is present.
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ return false;
+}
+
+
+/// ParseIfStatement
+/// if-statement: [C99 6.8.4.1]
+/// 'if' '(' expression ')' statement
+/// 'if' '(' expression ')' statement 'else' statement
+/// [C++] 'if' '(' condition ')' statement
+/// [C++] 'if' '(' condition ')' statement 'else' statement
+///
+Parser::OwningStmtResult Parser::ParseIfStatement() {
+ assert(Tok.is(tok::kw_if) && "Not an if stmt!");
+ SourceLocation IfLoc = ConsumeToken(); // eat the 'if'.
+
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << "if";
+ SkipUntil(tok::semi);
+ return StmtError();
+ }
+
+ bool C99orCXX = getLang().C99 || getLang().CPlusPlus;
+
+ // C99 6.8.4p3 - In C99, the if statement is a block. This is not
+ // the case for C90.
+ //
+ // C++ 6.4p3:
+ // A name introduced by a declaration in a condition is in scope from its
+ // point of declaration until the end of the substatements controlled by the
+ // condition.
+ // C++ 3.3.2p4:
+ // Names declared in the for-init-statement, and in the condition of if,
+ // while, for, and switch statements are local to the if, while, for, or
+ // switch statement (including the controlled statement).
+ //
+ ParseScope IfScope(this, Scope::DeclScope | Scope::ControlScope, C99orCXX);
+
+ // Parse the condition.
+ OwningExprResult CondExp(Actions);
+ if (ParseParenExprOrCondition(CondExp))
+ return StmtError();
+
+ // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if
+ // there is no compound stmt. C90 does not have this clause. We only do this
+ // if the body isn't a compound statement to avoid push/pop in common cases.
+ //
+ // C++ 6.4p1:
+ // The substatement in a selection-statement (each substatement, in the else
+ // form of the if statement) implicitly defines a local scope.
+ //
+ // For C++ we create a scope for the condition and a new scope for
+ // substatements because:
+ // -When the 'then' scope exits, we want the condition declaration to still be
+ // active for the 'else' scope too.
+ // -Sema will detect name clashes by considering declarations of a
+ // 'ControlScope' as part of its direct subscope.
+ // -If we wanted the condition and substatement to be in the same scope, we
+ // would have to notify ParseStatement not to create a new scope. It's
+ // simpler to let it create a new scope.
+ //
+ ParseScope InnerScope(this, Scope::DeclScope,
+ C99orCXX && Tok.isNot(tok::l_brace));
+
+ // Read the 'then' stmt.
+ SourceLocation ThenStmtLoc = Tok.getLocation();
+ OwningStmtResult ThenStmt(ParseStatement());
+
+ // Pop the 'if' scope if needed.
+ InnerScope.Exit();
+
+ // If it has an else, parse it.
+ SourceLocation ElseLoc;
+ SourceLocation ElseStmtLoc;
+ OwningStmtResult ElseStmt(Actions);
+
+ if (Tok.is(tok::kw_else)) {
+ ElseLoc = ConsumeToken();
+
+ // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if
+ // there is no compound stmt. C90 does not have this clause. We only do
+ // this if the body isn't a compound statement to avoid push/pop in common
+ // cases.
+ //
+ // C++ 6.4p1:
+ // The substatement in a selection-statement (each substatement, in the else
+ // form of the if statement) implicitly defines a local scope.
+ //
+ ParseScope InnerScope(this, Scope::DeclScope,
+ C99orCXX && Tok.isNot(tok::l_brace));
+
+ bool WithinElse = CurScope->isWithinElse();
+ CurScope->setWithinElse(true);
+ ElseStmtLoc = Tok.getLocation();
+ ElseStmt = ParseStatement();
+ CurScope->setWithinElse(WithinElse);
+
+ // Pop the 'else' scope if needed.
+ InnerScope.Exit();
+ }
+
+ IfScope.Exit();
+
+ // If the condition was invalid, discard the if statement. We could recover
+ // better by replacing it with a valid expr, but don't do that yet.
+ if (CondExp.isInvalid())
+ return StmtError();
+
+ // If the then or else stmt is invalid and the other is valid (and present),
+ // make turn the invalid one into a null stmt to avoid dropping the other
+ // part. If both are invalid, return error.
+ if ((ThenStmt.isInvalid() && ElseStmt.isInvalid()) ||
+ (ThenStmt.isInvalid() && ElseStmt.get() == 0) ||
+ (ThenStmt.get() == 0 && ElseStmt.isInvalid())) {
+ // Both invalid, or one is invalid and other is non-present: return error.
+ return StmtError();
+ }
+
+ // Now if either are invalid, replace with a ';'.
+ if (ThenStmt.isInvalid())
+ ThenStmt = Actions.ActOnNullStmt(ThenStmtLoc);
+ if (ElseStmt.isInvalid())
+ ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc);
+
+ return Actions.ActOnIfStmt(IfLoc, Actions.FullExpr(CondExp), move(ThenStmt),
+ ElseLoc, move(ElseStmt));
+}
+
+/// ParseSwitchStatement
+/// switch-statement:
+/// 'switch' '(' expression ')' statement
+/// [C++] 'switch' '(' condition ')' statement
+Parser::OwningStmtResult Parser::ParseSwitchStatement() {
+ assert(Tok.is(tok::kw_switch) && "Not a switch stmt!");
+ SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'.
+
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << "switch";
+ SkipUntil(tok::semi);
+ return StmtError();
+ }
+
+ bool C99orCXX = getLang().C99 || getLang().CPlusPlus;
+
+ // C99 6.8.4p3 - In C99, the switch statement is a block. This is
+ // not the case for C90. Start the switch scope.
+ //
+ // C++ 6.4p3:
+ // A name introduced by a declaration in a condition is in scope from its
+ // point of declaration until the end of the substatements controlled by the
+ // condition.
+ // C++ 3.3.2p4:
+ // Names declared in the for-init-statement, and in the condition of if,
+ // while, for, and switch statements are local to the if, while, for, or
+ // switch statement (including the controlled statement).
+ //
+ unsigned ScopeFlags = Scope::BreakScope;
+ if (C99orCXX)
+ ScopeFlags |= Scope::DeclScope | Scope::ControlScope;
+ ParseScope SwitchScope(this, ScopeFlags);
+
+ // Parse the condition.
+ OwningExprResult Cond(Actions);
+ if (ParseParenExprOrCondition(Cond))
+ return StmtError();
+
+ OwningStmtResult Switch(Actions);
+ if (!Cond.isInvalid())
+ Switch = Actions.ActOnStartOfSwitchStmt(move(Cond));
+
+ // C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if
+ // there is no compound stmt. C90 does not have this clause. We only do this
+ // if the body isn't a compound statement to avoid push/pop in common cases.
+ //
+ // C++ 6.4p1:
+ // The substatement in a selection-statement (each substatement, in the else
+ // form of the if statement) implicitly defines a local scope.
+ //
+ // See comments in ParseIfStatement for why we create a scope for the
+ // condition and a new scope for substatement in C++.
+ //
+ ParseScope InnerScope(this, Scope::DeclScope,
+ C99orCXX && Tok.isNot(tok::l_brace));
+
+ // Read the body statement.
+ OwningStmtResult Body(ParseStatement());
+
+ // Pop the body scope if needed.
+ InnerScope.Exit();
+
+ if (Body.isInvalid()) {
+ Body = Actions.ActOnNullStmt(Tok.getLocation());
+ // FIXME: Remove the case statement list from the Switch statement.
+ }
+
+ SwitchScope.Exit();
+
+ if (Cond.isInvalid())
+ return StmtError();
+
+ return Actions.ActOnFinishSwitchStmt(SwitchLoc, move(Switch), move(Body));
+}
+
+/// ParseWhileStatement
+/// while-statement: [C99 6.8.5.1]
+/// 'while' '(' expression ')' statement
+/// [C++] 'while' '(' condition ')' statement
+Parser::OwningStmtResult Parser::ParseWhileStatement() {
+ assert(Tok.is(tok::kw_while) && "Not a while stmt!");
+ SourceLocation WhileLoc = Tok.getLocation();
+ ConsumeToken(); // eat the 'while'.
+
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << "while";
+ SkipUntil(tok::semi);
+ return StmtError();
+ }
+
+ bool C99orCXX = getLang().C99 || getLang().CPlusPlus;
+
+ // C99 6.8.5p5 - In C99, the while statement is a block. This is not
+ // the case for C90. Start the loop scope.
+ //
+ // C++ 6.4p3:
+ // A name introduced by a declaration in a condition is in scope from its
+ // point of declaration until the end of the substatements controlled by the
+ // condition.
+ // C++ 3.3.2p4:
+ // Names declared in the for-init-statement, and in the condition of if,
+ // while, for, and switch statements are local to the if, while, for, or
+ // switch statement (including the controlled statement).
+ //
+ unsigned ScopeFlags;
+ if (C99orCXX)
+ ScopeFlags = Scope::BreakScope | Scope::ContinueScope |
+ Scope::DeclScope | Scope::ControlScope;
+ else
+ ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
+ ParseScope WhileScope(this, ScopeFlags);
+
+ // Parse the condition.
+ OwningExprResult Cond(Actions);
+ if (ParseParenExprOrCondition(Cond))
+ return StmtError();
+
+ // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if
+ // there is no compound stmt. C90 does not have this clause. We only do this
+ // if the body isn't a compound statement to avoid push/pop in common cases.
+ //
+ // C++ 6.5p2:
+ // The substatement in an iteration-statement implicitly defines a local scope
+ // which is entered and exited each time through the loop.
+ //
+ // See comments in ParseIfStatement for why we create a scope for the
+ // condition and a new scope for substatement in C++.
+ //
+ ParseScope InnerScope(this, Scope::DeclScope,
+ C99orCXX && Tok.isNot(tok::l_brace));
+
+ // Read the body statement.
+ OwningStmtResult Body(ParseStatement());
+
+ // Pop the body scope if needed.
+ InnerScope.Exit();
+ WhileScope.Exit();
+
+ if (Cond.isInvalid() || Body.isInvalid())
+ return StmtError();
+
+ return Actions.ActOnWhileStmt(WhileLoc, Actions.FullExpr(Cond), move(Body));
+}
+
+/// ParseDoStatement
+/// do-statement: [C99 6.8.5.2]
+/// 'do' statement 'while' '(' expression ')' ';'
+/// Note: this lets the caller parse the end ';'.
+Parser::OwningStmtResult Parser::ParseDoStatement() {
+ assert(Tok.is(tok::kw_do) && "Not a do stmt!");
+ SourceLocation DoLoc = ConsumeToken(); // eat the 'do'.
+
+ // C99 6.8.5p5 - In C99, the do statement is a block. This is not
+ // the case for C90. Start the loop scope.
+ unsigned ScopeFlags;
+ if (getLang().C99)
+ ScopeFlags = Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope;
+ else
+ ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
+
+ ParseScope DoScope(this, ScopeFlags);
+
+ // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if
+ // there is no compound stmt. C90 does not have this clause. We only do this
+ // if the body isn't a compound statement to avoid push/pop in common cases.
+ //
+ // C++ 6.5p2:
+ // The substatement in an iteration-statement implicitly defines a local scope
+ // which is entered and exited each time through the loop.
+ //
+ ParseScope InnerScope(this, Scope::DeclScope,
+ (getLang().C99 || getLang().CPlusPlus) &&
+ Tok.isNot(tok::l_brace));
+
+ // Read the body statement.
+ OwningStmtResult Body(ParseStatement());
+
+ // Pop the body scope if needed.
+ InnerScope.Exit();
+
+ if (Tok.isNot(tok::kw_while)) {
+ if (!Body.isInvalid()) {
+ Diag(Tok, diag::err_expected_while);
+ Diag(DoLoc, diag::note_matching) << "do";
+ SkipUntil(tok::semi, false, true);
+ }
+ return StmtError();
+ }
+ SourceLocation WhileLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << "do/while";
+ SkipUntil(tok::semi, false, true);
+ return StmtError();
+ }
+
+ // Parse the parenthesized condition.
+ OwningExprResult Cond(Actions);
+ ParseParenExprOrCondition(Cond, true);
+
+ DoScope.Exit();
+
+ if (Cond.isInvalid() || Body.isInvalid())
+ return StmtError();
+
+ return Actions.ActOnDoStmt(DoLoc, move(Body), WhileLoc, move(Cond));
+}
+
+/// ParseForStatement
+/// for-statement: [C99 6.8.5.3]
+/// 'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement
+/// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement
+/// [C++] 'for' '(' for-init-statement condition[opt] ';' expression[opt] ')'
+/// [C++] statement
+/// [OBJC2] 'for' '(' declaration 'in' expr ')' statement
+/// [OBJC2] 'for' '(' expr 'in' expr ')' statement
+///
+/// [C++] for-init-statement:
+/// [C++] expression-statement
+/// [C++] simple-declaration
+///
+Parser::OwningStmtResult Parser::ParseForStatement() {
+ assert(Tok.is(tok::kw_for) && "Not a for stmt!");
+ SourceLocation ForLoc = ConsumeToken(); // eat the 'for'.
+
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << "for";
+ SkipUntil(tok::semi);
+ return StmtError();
+ }
+
+ bool C99orCXXorObjC = getLang().C99 || getLang().CPlusPlus || getLang().ObjC1;
+
+ // C99 6.8.5p5 - In C99, the for statement is a block. This is not
+ // the case for C90. Start the loop scope.
+ //
+ // C++ 6.4p3:
+ // A name introduced by a declaration in a condition is in scope from its
+ // point of declaration until the end of the substatements controlled by the
+ // condition.
+ // C++ 3.3.2p4:
+ // Names declared in the for-init-statement, and in the condition of if,
+ // while, for, and switch statements are local to the if, while, for, or
+ // switch statement (including the controlled statement).
+ // C++ 6.5.3p1:
+ // Names declared in the for-init-statement are in the same declarative-region
+ // as those declared in the condition.
+ //
+ unsigned ScopeFlags;
+ if (C99orCXXorObjC)
+ ScopeFlags = Scope::BreakScope | Scope::ContinueScope |
+ Scope::DeclScope | Scope::ControlScope;
+ else
+ ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
+
+ ParseScope ForScope(this, ScopeFlags);
+
+ SourceLocation LParenLoc = ConsumeParen();
+ OwningExprResult Value(Actions);
+
+ bool ForEach = false;
+ OwningStmtResult FirstPart(Actions);
+ OwningExprResult SecondPart(Actions), ThirdPart(Actions);
+
+ // Parse the first part of the for specifier.
+ if (Tok.is(tok::semi)) { // for (;
+ // no first part, eat the ';'.
+ ConsumeToken();
+ } else if (isSimpleDeclaration()) { // for (int X = 4;
+ // Parse declaration, which eats the ';'.
+ if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode?
+ Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
+
+ SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
+ DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd,
+ false);
+ FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
+
+ if (Tok.is(tok::semi)) { // for (int x = 4;
+ ConsumeToken();
+ } else if ((ForEach = isTokIdentifier_in())) {
+ // ObjC: for (id x in expr)
+ ConsumeToken(); // consume 'in'
+ SecondPart = ParseExpression();
+ } else {
+ Diag(Tok, diag::err_expected_semi_for);
+ SkipUntil(tok::semi);
+ }
+ } else {
+ Value = ParseExpression();
+
+ // Turn the expression into a stmt.
+ if (!Value.isInvalid())
+ FirstPart = Actions.ActOnExprStmt(Actions.FullExpr(Value));
+
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ } else if ((ForEach = isTokIdentifier_in())) {
+ ConsumeToken(); // consume 'in'
+ SecondPart = ParseExpression();
+ } else {
+ if (!Value.isInvalid()) Diag(Tok, diag::err_expected_semi_for);
+ SkipUntil(tok::semi);
+ }
+ }
+ if (!ForEach) {
+ assert(!SecondPart.get() && "Shouldn't have a second expression yet.");
+ // Parse the second part of the for specifier.
+ if (Tok.is(tok::semi)) { // for (...;;
+ // no second part.
+ } else {
+ SecondPart =getLang().CPlusPlus ? ParseCXXCondition() : ParseExpression();
+ }
+
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ } else {
+ if (!SecondPart.isInvalid()) Diag(Tok, diag::err_expected_semi_for);
+ SkipUntil(tok::semi);
+ }
+
+ // Parse the third part of the for specifier.
+ if (Tok.isNot(tok::r_paren)) // for (...;...;)
+ ThirdPart = ParseExpression();
+ }
+ // Match the ')'.
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if
+ // there is no compound stmt. C90 does not have this clause. We only do this
+ // if the body isn't a compound statement to avoid push/pop in common cases.
+ //
+ // C++ 6.5p2:
+ // The substatement in an iteration-statement implicitly defines a local scope
+ // which is entered and exited each time through the loop.
+ //
+ // See comments in ParseIfStatement for why we create a scope for
+ // for-init-statement/condition and a new scope for substatement in C++.
+ //
+ ParseScope InnerScope(this, Scope::DeclScope,
+ C99orCXXorObjC && Tok.isNot(tok::l_brace));
+
+ // Read the body statement.
+ OwningStmtResult Body(ParseStatement());
+
+ // Pop the body scope if needed.
+ InnerScope.Exit();
+
+ // Leave the for-scope.
+ ForScope.Exit();
+
+ if (Body.isInvalid())
+ return StmtError();
+
+ if (!ForEach)
+ return Actions.ActOnForStmt(ForLoc, LParenLoc, move(FirstPart),
+ move(SecondPart), move(ThirdPart),
+ RParenLoc, move(Body));
+
+ return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc,
+ move(FirstPart),
+ move(SecondPart),
+ RParenLoc, move(Body));
+}
+
+/// ParseGotoStatement
+/// jump-statement:
+/// 'goto' identifier ';'
+/// [GNU] 'goto' '*' expression ';'
+///
+/// Note: this lets the caller parse the end ';'.
+///
+Parser::OwningStmtResult Parser::ParseGotoStatement() {
+ assert(Tok.is(tok::kw_goto) && "Not a goto stmt!");
+ SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'.
+
+ OwningStmtResult Res(Actions);
+ if (Tok.is(tok::identifier)) {
+ Res = Actions.ActOnGotoStmt(GotoLoc, Tok.getLocation(),
+ Tok.getIdentifierInfo());
+ ConsumeToken();
+ } else if (Tok.is(tok::star)) {
+ // GNU indirect goto extension.
+ Diag(Tok, diag::ext_gnu_indirect_goto);
+ SourceLocation StarLoc = ConsumeToken();
+ OwningExprResult R(ParseExpression());
+ if (R.isInvalid()) { // Skip to the semicolon, but don't consume it.
+ SkipUntil(tok::semi, false, true);
+ return StmtError();
+ }
+ Res = Actions.ActOnIndirectGotoStmt(GotoLoc, StarLoc, move(R));
+ } else {
+ Diag(Tok, diag::err_expected_ident);
+ return StmtError();
+ }
+
+ return move(Res);
+}
+
+/// ParseContinueStatement
+/// jump-statement:
+/// 'continue' ';'
+///
+/// Note: this lets the caller parse the end ';'.
+///
+Parser::OwningStmtResult Parser::ParseContinueStatement() {
+ SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'.
+ return Actions.ActOnContinueStmt(ContinueLoc, CurScope);
+}
+
+/// ParseBreakStatement
+/// jump-statement:
+/// 'break' ';'
+///
+/// Note: this lets the caller parse the end ';'.
+///
+Parser::OwningStmtResult Parser::ParseBreakStatement() {
+ SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'.
+ return Actions.ActOnBreakStmt(BreakLoc, CurScope);
+}
+
+/// ParseReturnStatement
+/// jump-statement:
+/// 'return' expression[opt] ';'
+Parser::OwningStmtResult Parser::ParseReturnStatement() {
+ assert(Tok.is(tok::kw_return) && "Not a return stmt!");
+ SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'.
+
+ OwningExprResult R(Actions);
+ if (Tok.isNot(tok::semi)) {
+ R = ParseExpression();
+ if (R.isInvalid()) { // Skip to the semicolon, but don't consume it.
+ SkipUntil(tok::semi, false, true);
+ return StmtError();
+ }
+ }
+ return Actions.ActOnReturnStmt(ReturnLoc, Actions.FullExpr(R));
+}
+
+/// FuzzyParseMicrosoftAsmStatement. When -fms-extensions is enabled, this
+/// routine is called to skip/ignore tokens that comprise the MS asm statement.
+Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() {
+ if (Tok.is(tok::l_brace)) {
+ unsigned short savedBraceCount = BraceCount;
+ do {
+ ConsumeAnyToken();
+ } while (BraceCount > savedBraceCount && Tok.isNot(tok::eof));
+ } else {
+ // From the MS website: If used without braces, the __asm keyword means
+ // that the rest of the line is an assembly-language statement.
+ SourceManager &SrcMgr = PP.getSourceManager();
+ SourceLocation TokLoc = Tok.getLocation();
+ unsigned LineNo = SrcMgr.getInstantiationLineNumber(TokLoc);
+ do {
+ ConsumeAnyToken();
+ TokLoc = Tok.getLocation();
+ } while ((SrcMgr.getInstantiationLineNumber(TokLoc) == LineNo) &&
+ Tok.isNot(tok::r_brace) && Tok.isNot(tok::semi) &&
+ Tok.isNot(tok::eof));
+ }
+ return Actions.ActOnNullStmt(Tok.getLocation());
+}
+
+/// ParseAsmStatement - Parse a GNU extended asm statement.
+/// asm-statement:
+/// gnu-asm-statement
+/// ms-asm-statement
+///
+/// [GNU] gnu-asm-statement:
+/// 'asm' type-qualifier[opt] '(' asm-argument ')' ';'
+///
+/// [GNU] asm-argument:
+/// asm-string-literal
+/// asm-string-literal ':' asm-operands[opt]
+/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
+/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
+/// ':' asm-clobbers
+///
+/// [GNU] asm-clobbers:
+/// asm-string-literal
+/// asm-clobbers ',' asm-string-literal
+///
+/// [MS] ms-asm-statement:
+/// '__asm' assembly-instruction ';'[opt]
+/// '__asm' '{' assembly-instruction-list '}' ';'[opt]
+///
+/// [MS] assembly-instruction-list:
+/// assembly-instruction ';'[opt]
+/// assembly-instruction-list ';' assembly-instruction ';'[opt]
+///
+Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) {
+ assert(Tok.is(tok::kw_asm) && "Not an asm stmt");
+ SourceLocation AsmLoc = ConsumeToken();
+
+ if (getLang().Microsoft && Tok.isNot(tok::l_paren) && !isTypeQualifier()) {
+ msAsm = true;
+ return FuzzyParseMicrosoftAsmStatement();
+ }
+ DeclSpec DS;
+ SourceLocation Loc = Tok.getLocation();
+ ParseTypeQualifierListOpt(DS);
+
+ // GNU asms accept, but warn, about type-qualifiers other than volatile.
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
+ Diag(Loc, diag::w_asm_qualifier_ignored) << "const";
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
+ Diag(Loc, diag::w_asm_qualifier_ignored) << "restrict";
+
+ // Remember if this was a volatile asm.
+ bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile;
+ bool isSimple = false;
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << "asm";
+ SkipUntil(tok::r_paren);
+ return StmtError();
+ }
+ Loc = ConsumeParen();
+
+ OwningExprResult AsmString(ParseAsmStringLiteral());
+ if (AsmString.isInvalid())
+ return StmtError();
+
+ llvm::SmallVector<std::string, 4> Names;
+ ExprVector Constraints(Actions);
+ ExprVector Exprs(Actions);
+ ExprVector Clobbers(Actions);
+
+ unsigned NumInputs = 0, NumOutputs = 0;
+
+ SourceLocation RParenLoc;
+ if (Tok.is(tok::r_paren)) {
+ // We have a simple asm expression
+ isSimple = true;
+
+ RParenLoc = ConsumeParen();
+ } else {
+ // Parse Outputs, if present.
+ if (ParseAsmOperandsOpt(Names, Constraints, Exprs))
+ return StmtError();
+
+ NumOutputs = Names.size();
+
+ // Parse Inputs, if present.
+ if (ParseAsmOperandsOpt(Names, Constraints, Exprs))
+ return StmtError();
+
+ assert(Names.size() == Constraints.size() &&
+ Constraints.size() == Exprs.size()
+ && "Input operand size mismatch!");
+
+ NumInputs = Names.size() - NumOutputs;
+
+ // Parse the clobbers, if present.
+ if (Tok.is(tok::colon)) {
+ ConsumeToken();
+
+ // Parse the asm-string list for clobbers.
+ while (1) {
+ OwningExprResult Clobber(ParseAsmStringLiteral());
+
+ if (Clobber.isInvalid())
+ break;
+
+ Clobbers.push_back(Clobber.release());
+
+ if (Tok.isNot(tok::comma)) break;
+ ConsumeToken();
+ }
+ }
+
+ RParenLoc = MatchRHSPunctuation(tok::r_paren, Loc);
+ }
+
+ return Actions.ActOnAsmStmt(AsmLoc, isSimple, isVolatile,
+ NumOutputs, NumInputs, Names.data(),
+ move_arg(Constraints), move_arg(Exprs),
+ move(AsmString), move_arg(Clobbers),
+ RParenLoc);
+}
+
+/// ParseAsmOperands - Parse the asm-operands production as used by
+/// asm-statement. We also parse a leading ':' token. If the leading colon is
+/// not present, we do not parse anything.
+///
+/// [GNU] asm-operands:
+/// asm-operand
+/// asm-operands ',' asm-operand
+///
+/// [GNU] asm-operand:
+/// asm-string-literal '(' expression ')'
+/// '[' identifier ']' asm-string-literal '(' expression ')'
+///
+bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names,
+ llvm::SmallVectorImpl<ExprTy*> &Constraints,
+ llvm::SmallVectorImpl<ExprTy*> &Exprs) {
+ // Only do anything if this operand is present.
+ if (Tok.isNot(tok::colon)) return false;
+ ConsumeToken();
+
+ // 'asm-operands' isn't present?
+ if (!isTokenStringLiteral() && Tok.isNot(tok::l_square))
+ return false;
+
+ while (1) {
+ // Read the [id] if present.
+ if (Tok.is(tok::l_square)) {
+ SourceLocation Loc = ConsumeBracket();
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected_ident);
+ SkipUntil(tok::r_paren);
+ return true;
+ }
+
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ ConsumeToken();
+
+ Names.push_back(std::string(II->getName(), II->getLength()));
+ MatchRHSPunctuation(tok::r_square, Loc);
+ } else
+ Names.push_back(std::string());
+
+ OwningExprResult Constraint(ParseAsmStringLiteral());
+ if (Constraint.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return true;
+ }
+ Constraints.push_back(Constraint.release());
+
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << "asm operand";
+ SkipUntil(tok::r_paren);
+ return true;
+ }
+
+ // Read the parenthesized expression.
+ SourceLocation OpenLoc = ConsumeParen();
+ OwningExprResult Res(ParseExpression());
+ MatchRHSPunctuation(tok::r_paren, OpenLoc);
+ if (Res.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return true;
+ }
+ Exprs.push_back(Res.release());
+ // Eat the comma and continue parsing if it exists.
+ if (Tok.isNot(tok::comma)) return false;
+ ConsumeToken();
+ }
+
+ return true;
+}
+
+Parser::DeclPtrTy Parser::ParseFunctionStatementBody(DeclPtrTy Decl) {
+ assert(Tok.is(tok::l_brace));
+ SourceLocation LBraceLoc = Tok.getLocation();
+
+ PrettyStackTraceActionsDecl CrashInfo(Decl, LBraceLoc, Actions,
+ PP.getSourceManager(),
+ "parsing function body");
+
+ // Do not enter a scope for the brace, as the arguments are in the same scope
+ // (the function body) as the body itself. Instead, just read the statement
+ // list and put it into a CompoundStmt for safe keeping.
+ OwningStmtResult FnBody(ParseCompoundStatementBody());
+
+ // If the function body could not be parsed, make a bogus compoundstmt.
+ if (FnBody.isInvalid())
+ FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
+ MultiStmtArg(Actions), false);
+
+ return Actions.ActOnFinishFunctionBody(Decl, move(FnBody));
+}
+
+/// ParseFunctionTryBlock - Parse a C++ function-try-block.
+///
+/// function-try-block:
+/// 'try' ctor-initializer[opt] compound-statement handler-seq
+///
+Parser::DeclPtrTy Parser::ParseFunctionTryBlock(DeclPtrTy Decl) {
+ assert(Tok.is(tok::kw_try) && "Expected 'try'");
+ SourceLocation TryLoc = ConsumeToken();
+
+ PrettyStackTraceActionsDecl CrashInfo(Decl, TryLoc, Actions,
+ PP.getSourceManager(),
+ "parsing function try block");
+
+ // Constructor initializer list?
+ if (Tok.is(tok::colon))
+ ParseConstructorInitializer(Decl);
+
+ SourceLocation LBraceLoc = Tok.getLocation();
+ OwningStmtResult FnBody(ParseCXXTryBlockCommon(TryLoc));
+ // If we failed to parse the try-catch, we just give the function an empty
+ // compound statement as the body.
+ if (FnBody.isInvalid())
+ FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc,
+ MultiStmtArg(Actions), false);
+
+ return Actions.ActOnFinishFunctionBody(Decl, move(FnBody));
+}
+
+/// ParseCXXTryBlock - Parse a C++ try-block.
+///
+/// try-block:
+/// 'try' compound-statement handler-seq
+///
+Parser::OwningStmtResult Parser::ParseCXXTryBlock() {
+ assert(Tok.is(tok::kw_try) && "Expected 'try'");
+
+ SourceLocation TryLoc = ConsumeToken();
+ return ParseCXXTryBlockCommon(TryLoc);
+}
+
+/// ParseCXXTryBlockCommon - Parse the common part of try-block and
+/// function-try-block.
+///
+/// try-block:
+/// 'try' compound-statement handler-seq
+///
+/// function-try-block:
+/// 'try' ctor-initializer[opt] compound-statement handler-seq
+///
+/// handler-seq:
+/// handler handler-seq[opt]
+///
+Parser::OwningStmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
+ if (Tok.isNot(tok::l_brace))
+ return StmtError(Diag(Tok, diag::err_expected_lbrace));
+ OwningStmtResult TryBlock(ParseCompoundStatement());
+ if (TryBlock.isInvalid())
+ return move(TryBlock);
+
+ StmtVector Handlers(Actions);
+ if (Tok.isNot(tok::kw_catch))
+ return StmtError(Diag(Tok, diag::err_expected_catch));
+ while (Tok.is(tok::kw_catch)) {
+ OwningStmtResult Handler(ParseCXXCatchBlock());
+ if (!Handler.isInvalid())
+ Handlers.push_back(Handler.release());
+ }
+ // Don't bother creating the full statement if we don't have any usable
+ // handlers.
+ if (Handlers.empty())
+ return StmtError();
+
+ return Actions.ActOnCXXTryBlock(TryLoc, move(TryBlock), move_arg(Handlers));
+}
+
+/// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the standard
+///
+/// handler:
+/// 'catch' '(' exception-declaration ')' compound-statement
+///
+/// exception-declaration:
+/// type-specifier-seq declarator
+/// type-specifier-seq abstract-declarator
+/// type-specifier-seq
+/// '...'
+///
+Parser::OwningStmtResult Parser::ParseCXXCatchBlock() {
+ assert(Tok.is(tok::kw_catch) && "Expected 'catch'");
+
+ SourceLocation CatchLoc = ConsumeToken();
+
+ SourceLocation LParenLoc = Tok.getLocation();
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen))
+ return StmtError();
+
+ // C++ 3.3.2p3:
+ // The name in a catch exception-declaration is local to the handler and
+ // shall not be redeclared in the outermost block of the handler.
+ ParseScope CatchScope(this, Scope::DeclScope | Scope::ControlScope);
+
+ // exception-declaration is equivalent to '...' or a parameter-declaration
+ // without default arguments.
+ DeclPtrTy ExceptionDecl;
+ if (Tok.isNot(tok::ellipsis)) {
+ DeclSpec DS;
+ if (ParseCXXTypeSpecifierSeq(DS))
+ return StmtError();
+ Declarator ExDecl(DS, Declarator::CXXCatchContext);
+ ParseDeclarator(ExDecl);
+ ExceptionDecl = Actions.ActOnExceptionDeclarator(CurScope, ExDecl);
+ } else
+ ConsumeToken();
+
+ if (MatchRHSPunctuation(tok::r_paren, LParenLoc).isInvalid())
+ return StmtError();
+
+ if (Tok.isNot(tok::l_brace))
+ return StmtError(Diag(Tok, diag::err_expected_lbrace));
+
+ OwningStmtResult Block(ParseCompoundStatement());
+ if (Block.isInvalid())
+ return move(Block);
+
+ return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, move(Block));
+}
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
new file mode 100644
index 0000000..2a79b99
--- /dev/null
+++ b/lib/Parse/ParseTemplate.cpp
@@ -0,0 +1,812 @@
+//===--- ParseTemplate.cpp - Template Parsing -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements parsing of C++ templates.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+using namespace clang;
+
+/// \brief Parse a template declaration, explicit instantiation, or
+/// explicit specialization.
+Parser::DeclPtrTy
+Parser::ParseDeclarationStartingWithTemplate(unsigned Context,
+ SourceLocation &DeclEnd,
+ AccessSpecifier AS) {
+ if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less))
+ return ParseExplicitInstantiation(ConsumeToken(), DeclEnd);
+
+ return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS);
+}
+
+/// \brief Parse a template declaration or an explicit specialization.
+///
+/// Template declarations include one or more template parameter lists
+/// and either the function or class template declaration. Explicit
+/// specializations contain one or more 'template < >' prefixes
+/// followed by a (possibly templated) declaration. Since the
+/// syntactic form of both features is nearly identical, we parse all
+/// of the template headers together and let semantic analysis sort
+/// the declarations from the explicit specializations.
+///
+/// template-declaration: [C++ temp]
+/// 'export'[opt] 'template' '<' template-parameter-list '>' declaration
+///
+/// explicit-specialization: [ C++ temp.expl.spec]
+/// 'template' '<' '>' declaration
+Parser::DeclPtrTy
+Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
+ SourceLocation &DeclEnd,
+ AccessSpecifier AS) {
+ assert((Tok.is(tok::kw_export) || Tok.is(tok::kw_template)) &&
+ "Token does not start a template declaration.");
+
+ // Enter template-parameter scope.
+ ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
+
+ // Parse multiple levels of template headers within this template
+ // parameter scope, e.g.,
+ //
+ // template<typename T>
+ // template<typename U>
+ // class A<T>::B { ... };
+ //
+ // We parse multiple levels non-recursively so that we can build a
+ // single data structure containing all of the template parameter
+ // lists to easily differentiate between the case above and:
+ //
+ // template<typename T>
+ // class A {
+ // template<typename U> class B;
+ // };
+ //
+ // In the first case, the action for declaring A<T>::B receives
+ // both template parameter lists. In the second case, the action for
+ // defining A<T>::B receives just the inner template parameter list
+ // (and retrieves the outer template parameter list from its
+ // context).
+ bool isSpecialiation = true;
+ TemplateParameterLists ParamLists;
+ do {
+ // Consume the 'export', if any.
+ SourceLocation ExportLoc;
+ if (Tok.is(tok::kw_export)) {
+ ExportLoc = ConsumeToken();
+ }
+
+ // Consume the 'template', which should be here.
+ SourceLocation TemplateLoc;
+ if (Tok.is(tok::kw_template)) {
+ TemplateLoc = ConsumeToken();
+ } else {
+ Diag(Tok.getLocation(), diag::err_expected_template);
+ return DeclPtrTy();
+ }
+
+ // Parse the '<' template-parameter-list '>'
+ SourceLocation LAngleLoc, RAngleLoc;
+ TemplateParameterList TemplateParams;
+ ParseTemplateParameters(ParamLists.size(), TemplateParams, LAngleLoc,
+ RAngleLoc);
+
+ if (!TemplateParams.empty())
+ isSpecialiation = false;
+
+ ParamLists.push_back(
+ Actions.ActOnTemplateParameterList(ParamLists.size(), ExportLoc,
+ TemplateLoc, LAngleLoc,
+ TemplateParams.data(),
+ TemplateParams.size(), RAngleLoc));
+ } while (Tok.is(tok::kw_export) || Tok.is(tok::kw_template));
+
+ // Parse the actual template declaration.
+ return ParseSingleDeclarationAfterTemplate(Context,
+ ParsedTemplateInfo(&ParamLists,
+ isSpecialiation),
+ DeclEnd, AS);
+}
+
+/// \brief Parse a single declaration that declares a template,
+/// template specialization, or explicit instantiation of a template.
+///
+/// \param TemplateParams if non-NULL, the template parameter lists
+/// that preceded this declaration. In this case, the declaration is a
+/// template declaration, out-of-line definition of a template, or an
+/// explicit template specialization. When NULL, the declaration is an
+/// explicit template instantiation.
+///
+/// \param TemplateLoc when TemplateParams is NULL, the location of
+/// the 'template' keyword that indicates that we have an explicit
+/// template instantiation.
+///
+/// \param DeclEnd will receive the source location of the last token
+/// within this declaration.
+///
+/// \param AS the access specifier associated with this
+/// declaration. Will be AS_none for namespace-scope declarations.
+///
+/// \returns the new declaration.
+Parser::DeclPtrTy
+Parser::ParseSingleDeclarationAfterTemplate(
+ unsigned Context,
+ const ParsedTemplateInfo &TemplateInfo,
+ SourceLocation &DeclEnd,
+ AccessSpecifier AS) {
+ assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
+ "Template information required");
+
+ // Parse the declaration specifiers.
+ DeclSpec DS;
+ // FIXME: Pass TemplateLoc through for explicit template instantiations
+ ParseDeclarationSpecifiers(DS, TemplateInfo, AS);
+
+ if (Tok.is(tok::semi)) {
+ DeclEnd = ConsumeToken();
+ return Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ }
+
+ // Parse the declarator.
+ Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context);
+ 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 DeclPtrTy();
+ }
+
+ // If we have a declaration or declarator list, handle it.
+ if (isDeclarationAfterDeclarator()) {
+ // Parse this declaration.
+ DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo);
+
+ if (Tok.is(tok::comma)) {
+ Diag(Tok, diag::err_multiple_template_declarators)
+ << (int)TemplateInfo.Kind;
+ SkipUntil(tok::semi, true, false);
+ return ThisDecl;
+ }
+
+ // Eat the semi colon after the declaration.
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_declation);
+ return ThisDecl;
+ }
+
+ 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 DeclPtrTy();
+ }
+ return ParseFunctionDefinition(DeclaratorInfo);
+ }
+
+ if (DeclaratorInfo.isFunctionDeclarator())
+ Diag(Tok, diag::err_expected_fn_body);
+ else
+ Diag(Tok, diag::err_invalid_token_after_toplevel_declarator);
+ SkipUntil(tok::semi);
+ return DeclPtrTy();
+}
+
+/// ParseTemplateParameters - Parses a template-parameter-list enclosed in
+/// angle brackets. Depth is the depth of this template-parameter-list, which
+/// is the number of template headers directly enclosing this template header.
+/// TemplateParams is the current list of template parameters we're building.
+/// The template parameter we parse will be added to this list. LAngleLoc and
+/// RAngleLoc will receive the positions of the '<' and '>', respectively,
+/// that enclose this template parameter list.
+bool Parser::ParseTemplateParameters(unsigned Depth,
+ TemplateParameterList &TemplateParams,
+ SourceLocation &LAngleLoc,
+ SourceLocation &RAngleLoc) {
+ // Get the template parameter list.
+ if(!Tok.is(tok::less)) {
+ Diag(Tok.getLocation(), diag::err_expected_less_after) << "template";
+ return false;
+ }
+ LAngleLoc = ConsumeToken();
+
+ // Try to parse the template parameter list.
+ if (Tok.is(tok::greater))
+ RAngleLoc = ConsumeToken();
+ else if(ParseTemplateParameterList(Depth, TemplateParams)) {
+ if(!Tok.is(tok::greater)) {
+ Diag(Tok.getLocation(), diag::err_expected_greater);
+ return false;
+ }
+ RAngleLoc = ConsumeToken();
+ }
+ return true;
+}
+
+/// ParseTemplateParameterList - Parse a template parameter list. If
+/// the parsing fails badly (i.e., closing bracket was left out), this
+/// will try to put the token stream in a reasonable position (closing
+/// a statement, etc.) and return false.
+///
+/// template-parameter-list: [C++ temp]
+/// template-parameter
+/// template-parameter-list ',' template-parameter
+bool
+Parser::ParseTemplateParameterList(unsigned Depth,
+ TemplateParameterList &TemplateParams) {
+ while(1) {
+ if (DeclPtrTy TmpParam
+ = ParseTemplateParameter(Depth, TemplateParams.size())) {
+ TemplateParams.push_back(TmpParam);
+ } else {
+ // If we failed to parse a template parameter, skip until we find
+ // a comma or closing brace.
+ SkipUntil(tok::comma, tok::greater, true, true);
+ }
+
+ // Did we find a comma or the end of the template parmeter list?
+ if(Tok.is(tok::comma)) {
+ ConsumeToken();
+ } else if(Tok.is(tok::greater)) {
+ // Don't consume this... that's done by template parser.
+ break;
+ } else {
+ // Somebody probably forgot to close the template. Skip ahead and
+ // try to get out of the expression. This error is currently
+ // subsumed by whatever goes on in ParseTemplateParameter.
+ // TODO: This could match >>, and it would be nice to avoid those
+ // silly errors with template <vec<T>>.
+ // Diag(Tok.getLocation(), diag::err_expected_comma_greater);
+ SkipUntil(tok::greater, true, true);
+ return false;
+ }
+ }
+ return true;
+}
+
+/// ParseTemplateParameter - Parse a template-parameter (C++ [temp.param]).
+///
+/// template-parameter: [C++ temp.param]
+/// type-parameter
+/// parameter-declaration
+///
+/// type-parameter: (see below)
+/// 'class' identifier[opt]
+/// 'class' identifier[opt] '=' type-id
+/// 'typename' identifier[opt]
+/// 'typename' identifier[opt] '=' type-id
+/// 'template' '<' template-parameter-list '>' 'class' identifier[opt]
+/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression
+Parser::DeclPtrTy
+Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
+ if(Tok.is(tok::kw_class) ||
+ (Tok.is(tok::kw_typename) &&
+ // FIXME: Next token has not been annotated!
+ NextToken().isNot(tok::annot_typename))) {
+ return ParseTypeParameter(Depth, Position);
+ }
+
+ if(Tok.is(tok::kw_template))
+ return ParseTemplateTemplateParameter(Depth, Position);
+
+ // If it's none of the above, then it must be a parameter declaration.
+ // NOTE: This will pick up errors in the closure of the template parameter
+ // list (e.g., template < ; Check here to implement >> style closures.
+ return ParseNonTypeTemplateParameter(Depth, Position);
+}
+
+/// ParseTypeParameter - Parse a template type parameter (C++ [temp.param]).
+/// Other kinds of template parameters are parsed in
+/// ParseTemplateTemplateParameter and ParseNonTypeTemplateParameter.
+///
+/// type-parameter: [C++ temp.param]
+/// 'class' identifier[opt]
+/// 'class' identifier[opt] '=' type-id
+/// 'typename' identifier[opt]
+/// 'typename' identifier[opt] '=' type-id
+Parser::DeclPtrTy Parser::ParseTypeParameter(unsigned Depth, unsigned Position){
+ assert((Tok.is(tok::kw_class) || Tok.is(tok::kw_typename)) &&
+ "A type-parameter starts with 'class' or 'typename'");
+
+ // Consume the 'class' or 'typename' keyword.
+ bool TypenameKeyword = Tok.is(tok::kw_typename);
+ SourceLocation KeyLoc = ConsumeToken();
+
+ // Grab the template parameter name (if given)
+ SourceLocation NameLoc;
+ IdentifierInfo* ParamName = 0;
+ if(Tok.is(tok::identifier)) {
+ ParamName = Tok.getIdentifierInfo();
+ NameLoc = ConsumeToken();
+ } else if(Tok.is(tok::equal) || Tok.is(tok::comma) ||
+ Tok.is(tok::greater)) {
+ // Unnamed template parameter. Don't have to do anything here, just
+ // don't consume this token.
+ } else {
+ Diag(Tok.getLocation(), diag::err_expected_ident);
+ return DeclPtrTy();
+ }
+
+ DeclPtrTy TypeParam = Actions.ActOnTypeParameter(CurScope, TypenameKeyword,
+ KeyLoc, ParamName, NameLoc,
+ Depth, Position);
+
+ // Grab a default type id (if given).
+ if(Tok.is(tok::equal)) {
+ SourceLocation EqualLoc = ConsumeToken();
+ SourceLocation DefaultLoc = Tok.getLocation();
+ TypeResult DefaultType = ParseTypeName();
+ if (!DefaultType.isInvalid())
+ Actions.ActOnTypeParameterDefault(TypeParam, EqualLoc, DefaultLoc,
+ DefaultType.get());
+ }
+
+ return TypeParam;
+}
+
+/// ParseTemplateTemplateParameter - Handle the parsing of template
+/// template parameters.
+///
+/// type-parameter: [C++ temp.param]
+/// 'template' '<' template-parameter-list '>' 'class' identifier[opt]
+/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression
+Parser::DeclPtrTy
+Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
+ assert(Tok.is(tok::kw_template) && "Expected 'template' keyword");
+
+ // Handle the template <...> part.
+ SourceLocation TemplateLoc = ConsumeToken();
+ TemplateParameterList TemplateParams;
+ SourceLocation LAngleLoc, RAngleLoc;
+ {
+ ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
+ if(!ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc,
+ RAngleLoc)) {
+ return DeclPtrTy();
+ }
+ }
+
+ // Generate a meaningful error if the user forgot to put class before the
+ // identifier, comma, or greater.
+ if(!Tok.is(tok::kw_class)) {
+ Diag(Tok.getLocation(), diag::err_expected_class_before)
+ << PP.getSpelling(Tok);
+ return DeclPtrTy();
+ }
+ SourceLocation ClassLoc = ConsumeToken();
+
+ // Get the identifier, if given.
+ SourceLocation NameLoc;
+ IdentifierInfo* ParamName = 0;
+ if(Tok.is(tok::identifier)) {
+ ParamName = Tok.getIdentifierInfo();
+ NameLoc = ConsumeToken();
+ } else if(Tok.is(tok::equal) || Tok.is(tok::comma) || Tok.is(tok::greater)) {
+ // Unnamed template parameter. Don't have to do anything here, just
+ // don't consume this token.
+ } else {
+ Diag(Tok.getLocation(), diag::err_expected_ident);
+ return DeclPtrTy();
+ }
+
+ TemplateParamsTy *ParamList =
+ Actions.ActOnTemplateParameterList(Depth, SourceLocation(),
+ TemplateLoc, LAngleLoc,
+ &TemplateParams[0],
+ TemplateParams.size(),
+ RAngleLoc);
+
+ Parser::DeclPtrTy Param
+ = Actions.ActOnTemplateTemplateParameter(CurScope, TemplateLoc,
+ ParamList, ParamName,
+ NameLoc, Depth, Position);
+
+ // Get the a default value, if given.
+ if (Tok.is(tok::equal)) {
+ SourceLocation EqualLoc = ConsumeToken();
+ OwningExprResult DefaultExpr = ParseCXXIdExpression();
+ if (DefaultExpr.isInvalid())
+ return Param;
+ else if (Param)
+ Actions.ActOnTemplateTemplateParameterDefault(Param, EqualLoc,
+ move(DefaultExpr));
+ }
+
+ return Param;
+}
+
+/// ParseNonTypeTemplateParameter - Handle the parsing of non-type
+/// template parameters (e.g., in "template<int Size> class array;").
+///
+/// template-parameter:
+/// ...
+/// parameter-declaration
+///
+/// NOTE: It would be ideal to simply call out to ParseParameterDeclaration(),
+/// but that didn't work out to well. Instead, this tries to recrate the basic
+/// parsing of parameter declarations, but tries to constrain it for template
+/// parameters.
+/// FIXME: We need to make a ParseParameterDeclaration that works for
+/// non-type template parameters and normal function parameters.
+Parser::DeclPtrTy
+Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
+ SourceLocation StartLoc = Tok.getLocation();
+
+ // Parse the declaration-specifiers (i.e., the type).
+ // FIXME: The type should probably be restricted in some way... Not all
+ // declarators (parts of declarators?) are accepted for parameters.
+ DeclSpec DS;
+ ParseDeclarationSpecifiers(DS);
+
+ // Parse this as a typename.
+ Declarator ParamDecl(DS, Declarator::TemplateParamContext);
+ ParseDeclarator(ParamDecl);
+ if (DS.getTypeSpecType() == DeclSpec::TST_unspecified && !DS.getTypeRep()) {
+ // This probably shouldn't happen - and it's more of a Sema thing, but
+ // basically we didn't parse the type name because we couldn't associate
+ // it with an AST node. we should just skip to the comma or greater.
+ // TODO: This is currently a placeholder for some kind of Sema Error.
+ Diag(Tok.getLocation(), diag::err_parse_error);
+ SkipUntil(tok::comma, tok::greater, true, true);
+ return DeclPtrTy();
+ }
+
+ // Create the parameter.
+ DeclPtrTy Param = Actions.ActOnNonTypeTemplateParameter(CurScope, ParamDecl,
+ Depth, Position);
+
+ // If there is a default value, parse it.
+ if (Tok.is(tok::equal)) {
+ SourceLocation EqualLoc = ConsumeToken();
+
+ // C++ [temp.param]p15:
+ // When parsing a default template-argument for a non-type
+ // template-parameter, the first non-nested > is taken as the
+ // end of the template-parameter-list rather than a greater-than
+ // operator.
+ GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
+
+ OwningExprResult DefaultArg = ParseAssignmentExpression();
+ if (DefaultArg.isInvalid())
+ SkipUntil(tok::comma, tok::greater, true, true);
+ else if (Param)
+ Actions.ActOnNonTypeTemplateParameterDefault(Param, EqualLoc,
+ move(DefaultArg));
+ }
+
+ return Param;
+}
+
+/// \brief Parses a template-id that after the template name has
+/// already been parsed.
+///
+/// This routine takes care of parsing the enclosed template argument
+/// list ('<' template-parameter-list [opt] '>') and placing the
+/// results into a form that can be transferred to semantic analysis.
+///
+/// \param Template the template declaration produced by isTemplateName
+///
+/// \param TemplateNameLoc the source location of the template name
+///
+/// \param SS if non-NULL, the nested-name-specifier preceding the
+/// template name.
+///
+/// \param ConsumeLastToken if true, then we will consume the last
+/// token that forms the template-id. Otherwise, we will leave the
+/// last token in the stream (e.g., so that it can be replaced with an
+/// annotation token).
+bool
+Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
+ SourceLocation TemplateNameLoc,
+ const CXXScopeSpec *SS,
+ bool ConsumeLastToken,
+ SourceLocation &LAngleLoc,
+ TemplateArgList &TemplateArgs,
+ TemplateArgIsTypeList &TemplateArgIsType,
+ TemplateArgLocationList &TemplateArgLocations,
+ SourceLocation &RAngleLoc) {
+ assert(Tok.is(tok::less) && "Must have already parsed the template-name");
+
+ // Consume the '<'.
+ LAngleLoc = ConsumeToken();
+
+ // Parse the optional template-argument-list.
+ bool Invalid = false;
+ {
+ GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
+ if (Tok.isNot(tok::greater))
+ Invalid = ParseTemplateArgumentList(TemplateArgs, TemplateArgIsType,
+ TemplateArgLocations);
+
+ if (Invalid) {
+ // Try to find the closing '>'.
+ SkipUntil(tok::greater, true, !ConsumeLastToken);
+
+ return true;
+ }
+ }
+
+ if (Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater))
+ return true;
+
+ // Determine the location of the '>' or '>>'. Only consume this
+ // token if the caller asked us to.
+ RAngleLoc = Tok.getLocation();
+
+ if (Tok.is(tok::greatergreater)) {
+ if (!getLang().CPlusPlus0x) {
+ const char *ReplaceStr = "> >";
+ if (NextToken().is(tok::greater) || NextToken().is(tok::greatergreater))
+ ReplaceStr = "> > ";
+
+ Diag(Tok.getLocation(), diag::err_two_right_angle_brackets_need_space)
+ << CodeModificationHint::CreateReplacement(
+ SourceRange(Tok.getLocation()), ReplaceStr);
+ }
+
+ Tok.setKind(tok::greater);
+ if (!ConsumeLastToken) {
+ // Since we're not supposed to consume the '>>' token, we need
+ // to insert a second '>' token after the first.
+ PP.EnterToken(Tok);
+ }
+ } else if (ConsumeLastToken)
+ ConsumeToken();
+
+ return false;
+}
+
+/// \brief Replace the tokens that form a simple-template-id with an
+/// annotation token containing the complete template-id.
+///
+/// The first token in the stream must be the name of a template that
+/// is followed by a '<'. This routine will parse the complete
+/// simple-template-id and replace the tokens with a single annotation
+/// token with one of two different kinds: if the template-id names a
+/// type (and \p AllowTypeAnnotation is true), the annotation token is
+/// a type annotation that includes the optional nested-name-specifier
+/// (\p SS). Otherwise, the annotation token is a template-id
+/// annotation that does not include the optional
+/// nested-name-specifier.
+///
+/// \param Template the declaration of the template named by the first
+/// token (an identifier), as returned from \c Action::isTemplateName().
+///
+/// \param TemplateNameKind the kind of template that \p Template
+/// refers to, as returned from \c Action::isTemplateName().
+///
+/// \param SS if non-NULL, the nested-name-specifier that precedes
+/// this template name.
+///
+/// \param TemplateKWLoc if valid, specifies that this template-id
+/// annotation was preceded by the 'template' keyword and gives the
+/// location of that keyword. If invalid (the default), then this
+/// template-id was not preceded by a 'template' keyword.
+///
+/// \param AllowTypeAnnotation if true (the default), then a
+/// simple-template-id that refers to a class template, template
+/// template parameter, or other template that produces a type will be
+/// replaced with a type annotation token. Otherwise, the
+/// simple-template-id is always replaced with a template-id
+/// annotation token.
+void Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
+ const CXXScopeSpec *SS,
+ SourceLocation TemplateKWLoc,
+ bool AllowTypeAnnotation) {
+ assert(getLang().CPlusPlus && "Can only annotate template-ids in C++");
+ assert(Template && Tok.is(tok::identifier) && NextToken().is(tok::less) &&
+ "Parser isn't at the beginning of a template-id");
+
+ // Consume the template-name.
+ IdentifierInfo *Name = Tok.getIdentifierInfo();
+ SourceLocation TemplateNameLoc = ConsumeToken();
+
+ // Parse the enclosed template argument list.
+ SourceLocation LAngleLoc, RAngleLoc;
+ TemplateArgList TemplateArgs;
+ TemplateArgIsTypeList TemplateArgIsType;
+ TemplateArgLocationList TemplateArgLocations;
+ bool Invalid = ParseTemplateIdAfterTemplateName(Template, TemplateNameLoc,
+ SS, false, LAngleLoc,
+ TemplateArgs,
+ TemplateArgIsType,
+ TemplateArgLocations,
+ RAngleLoc);
+
+ ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(),
+ TemplateArgIsType.data(),
+ TemplateArgs.size());
+
+ if (Invalid) // FIXME: How to recover from a broken template-id?
+ return;
+
+ // Build the annotation token.
+ if (TNK == TNK_Type_template && AllowTypeAnnotation) {
+ Action::TypeResult Type
+ = Actions.ActOnTemplateIdType(Template, TemplateNameLoc,
+ LAngleLoc, TemplateArgsPtr,
+ &TemplateArgLocations[0],
+ RAngleLoc);
+ if (Type.isInvalid()) // FIXME: better recovery?
+ return;
+
+ Tok.setKind(tok::annot_typename);
+ Tok.setAnnotationValue(Type.get());
+ if (SS && SS->isNotEmpty())
+ Tok.setLocation(SS->getBeginLoc());
+ else if (TemplateKWLoc.isValid())
+ Tok.setLocation(TemplateKWLoc);
+ else
+ Tok.setLocation(TemplateNameLoc);
+ } else {
+ // Build a template-id annotation token that can be processed
+ // later.
+ Tok.setKind(tok::annot_template_id);
+ TemplateIdAnnotation *TemplateId
+ = TemplateIdAnnotation::Allocate(TemplateArgs.size());
+ TemplateId->TemplateNameLoc = TemplateNameLoc;
+ TemplateId->Name = Name;
+ 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];
+ }
+ Tok.setAnnotationValue(TemplateId);
+ if (TemplateKWLoc.isValid())
+ Tok.setLocation(TemplateKWLoc);
+ else
+ Tok.setLocation(TemplateNameLoc);
+
+ TemplateArgsPtr.release();
+ }
+
+ // Common fields for the annotation token
+ Tok.setAnnotationEndLoc(RAngleLoc);
+
+ // In case the tokens were cached, have Preprocessor replace them with the
+ // annotation token.
+ PP.AnnotateCachedTokens(Tok);
+}
+
+/// \brief Replaces a template-id annotation token with a type
+/// annotation token.
+///
+/// If there was a failure when forming the type from the template-id,
+/// a type annotation token will still be created, but will have a
+/// NULL type pointer to signify an error.
+void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) {
+ assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens");
+
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ assert((TemplateId->Kind == TNK_Type_template ||
+ TemplateId->Kind == TNK_Dependent_template_name) &&
+ "Only works for type and dependent templates");
+
+ ASTTemplateArgsPtr TemplateArgsPtr(Actions,
+ TemplateId->getTemplateArgs(),
+ TemplateId->getTemplateArgIsType(),
+ TemplateId->NumArgs);
+
+ Action::TypeResult Type
+ = Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc,
+ TemplateArgsPtr,
+ TemplateId->getTemplateArgLocations(),
+ TemplateId->RAngleLoc);
+ // Create the new "type" annotation token.
+ Tok.setKind(tok::annot_typename);
+ Tok.setAnnotationValue(Type.isInvalid()? 0 : Type.get());
+ if (SS && SS->isNotEmpty()) // it was a C++ qualified type name.
+ Tok.setLocation(SS->getBeginLoc());
+
+ // We might be backtracking, in which case we need to replace the
+ // template-id annotation token with the type annotation within the
+ // set of cached tokens. That way, we won't try to form the same
+ // class template specialization again.
+ PP.ReplaceLastTokenWithAnnotation(Tok);
+ TemplateId->Destroy();
+}
+
+/// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]).
+///
+/// template-argument: [C++ 14.2]
+/// assignment-expression
+/// type-id
+/// id-expression
+void *Parser::ParseTemplateArgument(bool &ArgIsType) {
+ // C++ [temp.arg]p2:
+ // In a template-argument, an ambiguity between a type-id and an
+ // expression is resolved to a type-id, regardless of the form of
+ // the corresponding template-parameter.
+ //
+ // Therefore, we initially try to parse a type-id.
+ if (isCXXTypeId(TypeIdAsTemplateArgument)) {
+ ArgIsType = true;
+ TypeResult TypeArg = ParseTypeName();
+ if (TypeArg.isInvalid())
+ return 0;
+ return TypeArg.get();
+ }
+
+ OwningExprResult ExprArg = ParseAssignmentExpression();
+ if (ExprArg.isInvalid() || !ExprArg.get())
+ return 0;
+
+ ArgIsType = false;
+ return ExprArg.release();
+}
+
+/// ParseTemplateArgumentList - Parse a C++ template-argument-list
+/// (C++ [temp.names]). Returns true if there was an error.
+///
+/// template-argument-list: [C++ 14.2]
+/// template-argument
+/// template-argument-list ',' template-argument
+bool
+Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs,
+ TemplateArgIsTypeList &TemplateArgIsType,
+ TemplateArgLocationList &TemplateArgLocations) {
+ while (true) {
+ bool IsType = false;
+ SourceLocation Loc = Tok.getLocation();
+ void *Arg = ParseTemplateArgument(IsType);
+ if (Arg) {
+ TemplateArgs.push_back(Arg);
+ TemplateArgIsType.push_back(IsType);
+ TemplateArgLocations.push_back(Loc);
+ } else {
+ SkipUntil(tok::comma, tok::greater, true, true);
+ return true;
+ }
+
+ // If the next token is a comma, consume it and keep reading
+ // arguments.
+ if (Tok.isNot(tok::comma)) break;
+
+ // Consume the comma.
+ ConsumeToken();
+ }
+
+ return Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater);
+}
+
+/// \brief Parse a C++ explicit template instantiation
+/// (C++ [temp.explicit]).
+///
+/// explicit-instantiation:
+/// 'template' declaration
+Parser::DeclPtrTy
+Parser::ParseExplicitInstantiation(SourceLocation TemplateLoc,
+ SourceLocation &DeclEnd) {
+ return ParseSingleDeclarationAfterTemplate(Declarator::FileContext,
+ ParsedTemplateInfo(TemplateLoc),
+ DeclEnd, AS_none);
+}
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
new file mode 100644
index 0000000..81696d6
--- /dev/null
+++ b/lib/Parse/ParseTentative.cpp
@@ -0,0 +1,920 @@
+//===--- ParseTentative.cpp - Ambiguity Resolution Parsing ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the tentative parsing portions of the Parser
+// interfaces, for ambiguity resolution.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/ParseDiagnostic.h"
+using namespace clang;
+
+/// isCXXDeclarationStatement - C++-specialized function that disambiguates
+/// between a declaration or an expression statement, when parsing function
+/// bodies. Returns true for declaration, false for expression.
+///
+/// declaration-statement:
+/// block-declaration
+///
+/// block-declaration:
+/// simple-declaration
+/// asm-definition
+/// namespace-alias-definition
+/// using-declaration
+/// using-directive
+/// [C++0x] static_assert-declaration
+///
+/// asm-definition:
+/// 'asm' '(' string-literal ')' ';'
+///
+/// namespace-alias-definition:
+/// 'namespace' identifier = qualified-namespace-specifier ';'
+///
+/// using-declaration:
+/// 'using' typename[opt] '::'[opt] nested-name-specifier
+/// unqualified-id ';'
+/// 'using' '::' unqualified-id ;
+///
+/// using-directive:
+/// 'using' 'namespace' '::'[opt] nested-name-specifier[opt]
+/// namespace-name ';'
+///
+bool Parser::isCXXDeclarationStatement() {
+ switch (Tok.getKind()) {
+ // asm-definition
+ case tok::kw_asm:
+ // namespace-alias-definition
+ case tok::kw_namespace:
+ // using-declaration
+ // using-directive
+ case tok::kw_using:
+ return true;
+ case tok::kw_static_assert:
+ // static_assert-declaration
+ return true;
+ default:
+ // simple-declaration
+ return isCXXSimpleDeclaration();
+ }
+}
+
+/// isCXXSimpleDeclaration - C++-specialized function that disambiguates
+/// between a simple-declaration or an expression-statement.
+/// If during the disambiguation process a parsing error is encountered,
+/// the function returns true to let the declaration parsing code handle it.
+/// Returns false if the statement is disambiguated as expression.
+///
+/// simple-declaration:
+/// decl-specifier-seq init-declarator-list[opt] ';'
+///
+bool Parser::isCXXSimpleDeclaration() {
+ // C++ 6.8p1:
+ // There is an ambiguity in the grammar involving expression-statements and
+ // declarations: An expression-statement with a function-style explicit type
+ // conversion (5.2.3) as its leftmost subexpression can be indistinguishable
+ // from a declaration where the first declarator starts with a '('. In those
+ // cases the statement is a declaration. [Note: To disambiguate, the whole
+ // statement might have to be examined to determine if it is an
+ // expression-statement or a declaration].
+
+ // C++ 6.8p3:
+ // The disambiguation is purely syntactic; that is, the meaning of the names
+ // occurring in such a statement, beyond whether they are type-names or not,
+ // is not generally used in or changed by the disambiguation. Class
+ // templates are instantiated as necessary to determine if a qualified name
+ // is a type-name. Disambiguation precedes parsing, and a statement
+ // disambiguated as a declaration may be an ill-formed declaration.
+
+ // We don't have to parse all of the decl-specifier-seq part. There's only
+ // an ambiguity if the first decl-specifier is
+ // simple-type-specifier/typename-specifier followed by a '(', which may
+ // indicate a function-style cast expression.
+ // isCXXDeclarationSpecifier will return TPResult::Ambiguous() only in such
+ // a case.
+
+ TPResult TPR = isCXXDeclarationSpecifier();
+ if (TPR != TPResult::Ambiguous())
+ return TPR != TPResult::False(); // Returns true for TPResult::True() or
+ // TPResult::Error().
+
+ // FIXME: Add statistics about the number of ambiguous statements encountered
+ // and how they were resolved (number of declarations+number of expressions).
+
+ // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
+ // We need tentative parsing...
+
+ TentativeParsingAction PA(*this);
+
+ TPR = TryParseSimpleDeclaration();
+ SourceLocation TentativeParseLoc = Tok.getLocation();
+
+ PA.Revert();
+
+ // In case of an error, let the declaration parsing code handle it.
+ if (TPR == TPResult::Error())
+ return true;
+
+ // Declarations take precedence over expressions.
+ if (TPR == TPResult::Ambiguous())
+ TPR = TPResult::True();
+
+ assert(TPR == TPResult::True() || TPR == TPResult::False());
+ return TPR == TPResult::True();
+}
+
+/// simple-declaration:
+/// decl-specifier-seq init-declarator-list[opt] ';'
+///
+Parser::TPResult Parser::TryParseSimpleDeclaration() {
+ // We know that we have a simple-type-specifier/typename-specifier followed
+ // by a '('.
+ assert(isCXXDeclarationSpecifier() == TPResult::Ambiguous());
+
+ if (Tok.is(tok::kw_typeof))
+ TryParseTypeofSpecifier();
+ else
+ ConsumeToken();
+
+ assert(Tok.is(tok::l_paren) && "Expected '('");
+
+ TPResult TPR = TryParseInitDeclaratorList();
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+
+ if (Tok.isNot(tok::semi))
+ return TPResult::False();
+
+ return TPResult::Ambiguous();
+}
+
+/// init-declarator-list:
+/// init-declarator
+/// init-declarator-list ',' init-declarator
+///
+/// init-declarator:
+/// declarator initializer[opt]
+/// [GNU] declarator simple-asm-expr[opt] attributes[opt] initializer[opt]
+///
+/// initializer:
+/// '=' initializer-clause
+/// '(' expression-list ')'
+///
+/// initializer-clause:
+/// assignment-expression
+/// '{' initializer-list ','[opt] '}'
+/// '{' '}'
+///
+Parser::TPResult Parser::TryParseInitDeclaratorList() {
+ // GCC only examines the first declarator for disambiguation:
+ // i.e:
+ // int(x), ++x; // GCC regards it as ill-formed declaration.
+ //
+ // Comeau and MSVC will regard the above statement as correct expression.
+ // Clang examines all of the declarators and also regards the above statement
+ // as correct expression.
+
+ while (1) {
+ // declarator
+ TPResult TPR = TryParseDeclarator(false/*mayBeAbstract*/);
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+
+ // [GNU] simple-asm-expr[opt] attributes[opt]
+ if (Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
+ return TPResult::True();
+
+ // initializer[opt]
+ if (Tok.is(tok::l_paren)) {
+ // Parse through the parens.
+ ConsumeParen();
+ if (!SkipUntil(tok::r_paren))
+ return TPResult::Error();
+ } else if (Tok.is(tok::equal)) {
+ // MSVC won't examine the rest of declarators if '=' is encountered, it
+ // will conclude that it is a declaration.
+ // Comeau and Clang will examine the rest of declarators.
+ // Note that "int(x) = {0}, ++x;" will be interpreted as ill-formed
+ // expression.
+ //
+ // Parse through the initializer-clause.
+ SkipUntil(tok::comma, true/*StopAtSemi*/, true/*DontConsume*/);
+ }
+
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken(); // the comma.
+ }
+
+ return TPResult::Ambiguous();
+}
+
+/// isCXXConditionDeclaration - Disambiguates between a declaration or an
+/// expression for a condition of a if/switch/while/for statement.
+/// If during the disambiguation process a parsing error is encountered,
+/// the function returns true to let the declaration parsing code handle it.
+///
+/// condition:
+/// expression
+/// type-specifier-seq declarator '=' assignment-expression
+/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
+/// '=' assignment-expression
+///
+bool Parser::isCXXConditionDeclaration() {
+ TPResult TPR = isCXXDeclarationSpecifier();
+ if (TPR != TPResult::Ambiguous())
+ return TPR != TPResult::False(); // Returns true for TPResult::True() or
+ // TPResult::Error().
+
+ // FIXME: Add statistics about the number of ambiguous statements encountered
+ // and how they were resolved (number of declarations+number of expressions).
+
+ // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
+ // We need tentative parsing...
+
+ TentativeParsingAction PA(*this);
+
+ // type-specifier-seq
+ if (Tok.is(tok::kw_typeof))
+ TryParseTypeofSpecifier();
+ else
+ ConsumeToken();
+ assert(Tok.is(tok::l_paren) && "Expected '('");
+
+ // declarator
+ TPR = TryParseDeclarator(false/*mayBeAbstract*/);
+
+ // In case of an error, let the declaration parsing code handle it.
+ if (TPR == TPResult::Error())
+ TPR = TPResult::True();
+
+ if (TPR == TPResult::Ambiguous()) {
+ // '='
+ // [GNU] simple-asm-expr[opt] attributes[opt]
+ if (Tok.is(tok::equal) ||
+ Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
+ TPR = TPResult::True();
+ else
+ TPR = TPResult::False();
+ }
+
+ PA.Revert();
+
+ assert(TPR == TPResult::True() || TPR == TPResult::False());
+ return TPR == TPResult::True();
+}
+
+ /// \brief Determine whether the next set of tokens contains a type-id.
+ ///
+ /// The context parameter states what context we're parsing right
+ /// now, which affects how this routine copes with the token
+ /// following the type-id. If the context is TypeIdInParens, we have
+ /// already parsed the '(' and we will cease lookahead when we hit
+ /// the corresponding ')'. If the context is
+ /// TypeIdAsTemplateArgument, we've already parsed the '<' or ','
+ /// before this template argument, and will cease lookahead when we
+ /// hit a '>', '>>' (in C++0x), or ','. Returns true for a type-id
+ /// and false for an expression. If during the disambiguation
+ /// process a parsing error is encountered, the function returns
+ /// true to let the declaration parsing code handle it.
+ ///
+ /// type-id:
+ /// type-specifier-seq abstract-declarator[opt]
+ ///
+bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
+
+ isAmbiguous = false;
+
+ // C++ 8.2p2:
+ // The ambiguity arising from the similarity between a function-style cast and
+ // a type-id can occur in different contexts. The ambiguity appears as a
+ // choice between a function-style cast expression and a declaration of a
+ // type. The resolution is that any construct that could possibly be a type-id
+ // in its syntactic context shall be considered a type-id.
+
+ TPResult TPR = isCXXDeclarationSpecifier();
+ if (TPR != TPResult::Ambiguous())
+ return TPR != TPResult::False(); // Returns true for TPResult::True() or
+ // TPResult::Error().
+
+ // FIXME: Add statistics about the number of ambiguous statements encountered
+ // and how they were resolved (number of declarations+number of expressions).
+
+ // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
+ // We need tentative parsing...
+
+ TentativeParsingAction PA(*this);
+
+ // type-specifier-seq
+ if (Tok.is(tok::kw_typeof))
+ TryParseTypeofSpecifier();
+ else
+ ConsumeToken();
+ assert(Tok.is(tok::l_paren) && "Expected '('");
+
+ // declarator
+ TPR = TryParseDeclarator(true/*mayBeAbstract*/, false/*mayHaveIdentifier*/);
+
+ // In case of an error, let the declaration parsing code handle it.
+ if (TPR == TPResult::Error())
+ TPR = TPResult::True();
+
+ if (TPR == TPResult::Ambiguous()) {
+ // We are supposed to be inside parens, so if after the abstract declarator
+ // we encounter a ')' this is a type-id, otherwise it's an expression.
+ if (Context == TypeIdInParens && Tok.is(tok::r_paren)) {
+ TPR = TPResult::True();
+ isAmbiguous = true;
+
+ // We are supposed to be inside a template argument, so if after
+ // the abstract declarator we encounter a '>', '>>' (in C++0x), or
+ // ',', this is a type-id. Otherwise, it's an expression.
+ } else if (Context == TypeIdAsTemplateArgument &&
+ (Tok.is(tok::greater) || Tok.is(tok::comma) ||
+ (getLang().CPlusPlus0x && Tok.is(tok::greatergreater)))) {
+ TPR = TPResult::True();
+ isAmbiguous = true;
+
+ } else
+ TPR = TPResult::False();
+ }
+
+ PA.Revert();
+
+ assert(TPR == TPResult::True() || TPR == TPResult::False());
+ return TPR == TPResult::True();
+}
+
+/// declarator:
+/// direct-declarator
+/// ptr-operator declarator
+///
+/// direct-declarator:
+/// declarator-id
+/// direct-declarator '(' parameter-declaration-clause ')'
+/// cv-qualifier-seq[opt] exception-specification[opt]
+/// direct-declarator '[' constant-expression[opt] ']'
+/// '(' declarator ')'
+/// [GNU] '(' attributes declarator ')'
+///
+/// abstract-declarator:
+/// ptr-operator abstract-declarator[opt]
+/// direct-abstract-declarator
+///
+/// direct-abstract-declarator:
+/// direct-abstract-declarator[opt]
+/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
+/// exception-specification[opt]
+/// direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
+/// '(' abstract-declarator ')'
+///
+/// ptr-operator:
+/// '*' cv-qualifier-seq[opt]
+/// '&'
+/// [C++0x] '&&' [TODO]
+/// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt]
+///
+/// cv-qualifier-seq:
+/// cv-qualifier cv-qualifier-seq[opt]
+///
+/// cv-qualifier:
+/// 'const'
+/// 'volatile'
+///
+/// declarator-id:
+/// id-expression
+///
+/// id-expression:
+/// unqualified-id
+/// qualified-id [TODO]
+///
+/// unqualified-id:
+/// identifier
+/// operator-function-id [TODO]
+/// conversion-function-id [TODO]
+/// '~' class-name [TODO]
+/// template-id [TODO]
+///
+Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
+ bool mayHaveIdentifier) {
+ // declarator:
+ // direct-declarator
+ // ptr-operator declarator
+
+ while (1) {
+ if (Tok.is(tok::coloncolon) || Tok.is(tok::identifier))
+ TryAnnotateCXXScopeToken();
+
+ if (Tok.is(tok::star) || Tok.is(tok::amp) || Tok.is(tok::caret) ||
+ (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) {
+ // ptr-operator
+ ConsumeToken();
+ while (Tok.is(tok::kw_const) ||
+ Tok.is(tok::kw_volatile) ||
+ Tok.is(tok::kw_restrict))
+ ConsumeToken();
+ } else {
+ break;
+ }
+ }
+
+ // direct-declarator:
+ // direct-abstract-declarator:
+
+ if (Tok.is(tok::identifier) && mayHaveIdentifier) {
+ // declarator-id
+ ConsumeToken();
+ } else if (Tok.is(tok::l_paren)) {
+ ConsumeParen();
+ if (mayBeAbstract &&
+ (Tok.is(tok::r_paren) || // 'int()' is a function.
+ Tok.is(tok::ellipsis) || // 'int(...)' is a function.
+ isDeclarationSpecifier())) { // 'int(int)' is a function.
+ // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
+ // exception-specification[opt]
+ TPResult TPR = TryParseFunctionDeclarator();
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+ } else {
+ // '(' declarator ')'
+ // '(' attributes declarator ')'
+ // '(' abstract-declarator ')'
+ if (Tok.is(tok::kw___attribute))
+ return TPResult::True(); // attributes indicate declaration
+ TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier);
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+ if (Tok.isNot(tok::r_paren))
+ return TPResult::False();
+ ConsumeParen();
+ }
+ } else if (!mayBeAbstract) {
+ return TPResult::False();
+ }
+
+ while (1) {
+ TPResult TPR(TPResult::Ambiguous());
+
+ if (Tok.is(tok::l_paren)) {
+ // Check whether we have a function declarator or a possible ctor-style
+ // initializer that follows the declarator. Note that ctor-style
+ // initializers are not possible in contexts where abstract declarators
+ // are allowed.
+ if (!mayBeAbstract && !isCXXFunctionDeclarator(false/*warnIfAmbiguous*/))
+ break;
+
+ // direct-declarator '(' parameter-declaration-clause ')'
+ // cv-qualifier-seq[opt] exception-specification[opt]
+ ConsumeParen();
+ TPR = TryParseFunctionDeclarator();
+ } else if (Tok.is(tok::l_square)) {
+ // direct-declarator '[' constant-expression[opt] ']'
+ // direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
+ TPR = TryParseBracketDeclarator();
+ } else {
+ break;
+ }
+
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+ }
+
+ return TPResult::Ambiguous();
+}
+
+/// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a declaration
+/// specifier, TPResult::False() if it is not, TPResult::Ambiguous() if it could
+/// be either a decl-specifier or a function-style cast, and TPResult::Error()
+/// if a parsing error was found and reported.
+///
+/// decl-specifier:
+/// storage-class-specifier
+/// type-specifier
+/// function-specifier
+/// 'friend'
+/// 'typedef'
+/// [GNU] attributes declaration-specifiers[opt]
+///
+/// storage-class-specifier:
+/// 'register'
+/// 'static'
+/// 'extern'
+/// 'mutable'
+/// 'auto'
+/// [GNU] '__thread'
+///
+/// function-specifier:
+/// 'inline'
+/// 'virtual'
+/// 'explicit'
+///
+/// typedef-name:
+/// identifier
+///
+/// type-specifier:
+/// simple-type-specifier
+/// class-specifier
+/// enum-specifier
+/// elaborated-type-specifier
+/// typename-specifier
+/// cv-qualifier
+///
+/// simple-type-specifier:
+/// '::'[opt] nested-name-specifier[opt] type-name
+/// '::'[opt] nested-name-specifier 'template'
+/// simple-template-id [TODO]
+/// 'char'
+/// 'wchar_t'
+/// 'bool'
+/// 'short'
+/// 'int'
+/// 'long'
+/// 'signed'
+/// 'unsigned'
+/// 'float'
+/// 'double'
+/// 'void'
+/// [GNU] typeof-specifier
+/// [GNU] '_Complex'
+/// [C++0x] 'auto' [TODO]
+///
+/// type-name:
+/// class-name
+/// enum-name
+/// typedef-name
+///
+/// elaborated-type-specifier:
+/// class-key '::'[opt] nested-name-specifier[opt] identifier
+/// class-key '::'[opt] nested-name-specifier[opt] 'template'[opt]
+/// simple-template-id
+/// 'enum' '::'[opt] nested-name-specifier[opt] identifier
+///
+/// enum-name:
+/// identifier
+///
+/// enum-specifier:
+/// 'enum' identifier[opt] '{' enumerator-list[opt] '}'
+/// 'enum' identifier[opt] '{' enumerator-list ',' '}'
+///
+/// class-specifier:
+/// class-head '{' member-specification[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]
+///
+/// class-key:
+/// 'class'
+/// 'struct'
+/// 'union'
+///
+/// cv-qualifier:
+/// 'const'
+/// 'volatile'
+/// [GNU] restrict
+///
+Parser::TPResult Parser::isCXXDeclarationSpecifier() {
+ switch (Tok.getKind()) {
+ case tok::identifier: // foo::bar
+ case tok::kw_typename: // typename T::type
+ // Annotate typenames and C++ scope specifiers. If we get one, just
+ // recurse to handle whatever we get.
+ if (TryAnnotateTypeOrScopeToken())
+ return isCXXDeclarationSpecifier();
+ // Otherwise, not a typename.
+ return TPResult::False();
+
+ case tok::coloncolon: // ::foo::bar
+ if (NextToken().is(tok::kw_new) || // ::new
+ NextToken().is(tok::kw_delete)) // ::delete
+ return TPResult::False();
+
+ // Annotate typenames and C++ scope specifiers. If we get one, just
+ // recurse to handle whatever we get.
+ if (TryAnnotateTypeOrScopeToken())
+ return isCXXDeclarationSpecifier();
+ // Otherwise, not a typename.
+ return TPResult::False();
+
+ // decl-specifier:
+ // storage-class-specifier
+ // type-specifier
+ // function-specifier
+ // 'friend'
+ // 'typedef'
+
+ case tok::kw_friend:
+ case tok::kw_typedef:
+ // storage-class-specifier
+ case tok::kw_register:
+ case tok::kw_static:
+ case tok::kw_extern:
+ case tok::kw_mutable:
+ case tok::kw_auto:
+ case tok::kw___thread:
+ // function-specifier
+ case tok::kw_inline:
+ case tok::kw_virtual:
+ case tok::kw_explicit:
+
+ // type-specifier:
+ // simple-type-specifier
+ // class-specifier
+ // enum-specifier
+ // elaborated-type-specifier
+ // typename-specifier
+ // cv-qualifier
+
+ // class-specifier
+ // elaborated-type-specifier
+ case tok::kw_class:
+ case tok::kw_struct:
+ case tok::kw_union:
+ // enum-specifier
+ case tok::kw_enum:
+ // cv-qualifier
+ case tok::kw_const:
+ case tok::kw_volatile:
+
+ // GNU
+ case tok::kw_restrict:
+ case tok::kw__Complex:
+ case tok::kw___attribute:
+ return TPResult::True();
+
+ // Microsoft
+ case tok::kw___declspec:
+ case tok::kw___cdecl:
+ case tok::kw___stdcall:
+ case tok::kw___fastcall:
+ return PP.getLangOptions().Microsoft ? TPResult::True() : TPResult::False();
+
+ // The ambiguity resides in a simple-type-specifier/typename-specifier
+ // followed by a '('. The '(' could either be the start of:
+ //
+ // direct-declarator:
+ // '(' declarator ')'
+ //
+ // direct-abstract-declarator:
+ // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
+ // exception-specification[opt]
+ // '(' abstract-declarator ')'
+ //
+ // or part of a function-style cast expression:
+ //
+ // simple-type-specifier '(' expression-list[opt] ')'
+ //
+
+ // simple-type-specifier:
+
+ case tok::kw_char:
+ case tok::kw_wchar_t:
+ case tok::kw_bool:
+ case tok::kw_short:
+ case tok::kw_int:
+ case tok::kw_long:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_void:
+ case tok::annot_typename:
+ if (NextToken().is(tok::l_paren))
+ return TPResult::Ambiguous();
+
+ return TPResult::True();
+
+ // GNU typeof support.
+ case tok::kw_typeof: {
+ if (NextToken().isNot(tok::l_paren))
+ return TPResult::True();
+
+ TentativeParsingAction PA(*this);
+
+ TPResult TPR = TryParseTypeofSpecifier();
+ bool isFollowedByParen = Tok.is(tok::l_paren);
+
+ PA.Revert();
+
+ if (TPR == TPResult::Error())
+ return TPResult::Error();
+
+ if (isFollowedByParen)
+ return TPResult::Ambiguous();
+
+ return TPResult::True();
+ }
+
+ default:
+ return TPResult::False();
+ }
+}
+
+/// [GNU] typeof-specifier:
+/// 'typeof' '(' expressions ')'
+/// 'typeof' '(' type-name ')'
+///
+Parser::TPResult Parser::TryParseTypeofSpecifier() {
+ assert(Tok.is(tok::kw_typeof) && "Expected 'typeof'!");
+ ConsumeToken();
+
+ assert(Tok.is(tok::l_paren) && "Expected '('");
+ // Parse through the parens after 'typeof'.
+ ConsumeParen();
+ if (!SkipUntil(tok::r_paren))
+ return TPResult::Error();
+
+ return TPResult::Ambiguous();
+}
+
+Parser::TPResult Parser::TryParseDeclarationSpecifier() {
+ TPResult TPR = isCXXDeclarationSpecifier();
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+
+ if (Tok.is(tok::kw_typeof))
+ TryParseTypeofSpecifier();
+ else
+ ConsumeToken();
+
+ assert(Tok.is(tok::l_paren) && "Expected '('!");
+ return TPResult::Ambiguous();
+}
+
+/// isCXXFunctionDeclarator - Disambiguates between a function declarator or
+/// a constructor-style initializer, when parsing declaration statements.
+/// Returns true for function declarator and false for constructor-style
+/// initializer.
+/// If during the disambiguation process a parsing error is encountered,
+/// the function returns true to let the declaration parsing code handle it.
+///
+/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
+/// exception-specification[opt]
+///
+bool Parser::isCXXFunctionDeclarator(bool warnIfAmbiguous) {
+
+ // C++ 8.2p1:
+ // The ambiguity arising from the similarity between a function-style cast and
+ // a declaration mentioned in 6.8 can also occur in the context of a
+ // declaration. In that context, the choice is between a function declaration
+ // with a redundant set of parentheses around a parameter name and an object
+ // declaration with a function-style cast as the initializer. Just as for the
+ // ambiguities mentioned in 6.8, the resolution is to consider any construct
+ // that could possibly be a declaration a declaration.
+
+ TentativeParsingAction PA(*this);
+
+ ConsumeParen();
+ TPResult TPR = TryParseParameterDeclarationClause();
+ if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren))
+ TPR = TPResult::False();
+
+ SourceLocation TPLoc = Tok.getLocation();
+ PA.Revert();
+
+ // In case of an error, let the declaration parsing code handle it.
+ if (TPR == TPResult::Error())
+ return true;
+
+ if (TPR == TPResult::Ambiguous()) {
+ // Function declarator has precedence over constructor-style initializer.
+ // Emit a warning just in case the author intended a variable definition.
+ if (warnIfAmbiguous)
+ Diag(Tok, diag::warn_parens_disambiguated_as_function_decl)
+ << SourceRange(Tok.getLocation(), TPLoc);
+ return true;
+ }
+
+ return TPR == TPResult::True();
+}
+
+/// parameter-declaration-clause:
+/// parameter-declaration-list[opt] '...'[opt]
+/// parameter-declaration-list ',' '...'
+///
+/// parameter-declaration-list:
+/// parameter-declaration
+/// parameter-declaration-list ',' parameter-declaration
+///
+/// parameter-declaration:
+/// decl-specifier-seq declarator
+/// decl-specifier-seq declarator '=' assignment-expression
+/// decl-specifier-seq abstract-declarator[opt]
+/// decl-specifier-seq abstract-declarator[opt] '=' assignment-expression
+///
+Parser::TPResult Parser::TryParseParameterDeclarationClause() {
+
+ if (Tok.is(tok::r_paren))
+ return TPResult::True();
+
+ // parameter-declaration-list[opt] '...'[opt]
+ // parameter-declaration-list ',' '...'
+ //
+ // parameter-declaration-list:
+ // parameter-declaration
+ // parameter-declaration-list ',' parameter-declaration
+ //
+ while (1) {
+ // '...'[opt]
+ if (Tok.is(tok::ellipsis)) {
+ ConsumeToken();
+ return TPResult::True(); // '...' is a sign of a function declarator.
+ }
+
+ // decl-specifier-seq
+ TPResult TPR = TryParseDeclarationSpecifier();
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+
+ // declarator
+ // abstract-declarator[opt]
+ TPR = TryParseDeclarator(true/*mayBeAbstract*/);
+ if (TPR != TPResult::Ambiguous())
+ return TPR;
+
+ if (Tok.is(tok::equal)) {
+ // '=' assignment-expression
+ // Parse through assignment-expression.
+ tok::TokenKind StopToks[3] ={ tok::comma, tok::ellipsis, tok::r_paren };
+ if (!SkipUntil(StopToks, 3, true/*StopAtSemi*/, true/*DontConsume*/))
+ return TPResult::Error();
+ }
+
+ if (Tok.is(tok::ellipsis)) {
+ ConsumeToken();
+ return TPResult::True(); // '...' is a sign of a function declarator.
+ }
+
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken(); // the comma.
+ }
+
+ return TPResult::Ambiguous();
+}
+
+/// TryParseFunctionDeclarator - We parsed a '(' and we want to try to continue
+/// parsing as a function declarator.
+/// If TryParseFunctionDeclarator fully parsed the function declarator, it will
+/// return TPResult::Ambiguous(), otherwise it will return either False() or
+/// Error().
+///
+/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
+/// exception-specification[opt]
+///
+/// exception-specification:
+/// 'throw' '(' type-id-list[opt] ')'
+///
+Parser::TPResult Parser::TryParseFunctionDeclarator() {
+
+ // The '(' is already parsed.
+
+ TPResult TPR = TryParseParameterDeclarationClause();
+ if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren))
+ TPR = TPResult::False();
+
+ if (TPR == TPResult::False() || TPR == TPResult::Error())
+ return TPR;
+
+ // Parse through the parens.
+ if (!SkipUntil(tok::r_paren))
+ return TPResult::Error();
+
+ // cv-qualifier-seq
+ while (Tok.is(tok::kw_const) ||
+ Tok.is(tok::kw_volatile) ||
+ Tok.is(tok::kw_restrict) )
+ ConsumeToken();
+
+ // exception-specification
+ if (Tok.is(tok::kw_throw)) {
+ ConsumeToken();
+ if (Tok.isNot(tok::l_paren))
+ return TPResult::Error();
+
+ // Parse through the parens after 'throw'.
+ ConsumeParen();
+ if (!SkipUntil(tok::r_paren))
+ return TPResult::Error();
+ }
+
+ return TPResult::Ambiguous();
+}
+
+/// '[' constant-expression[opt] ']'
+///
+Parser::TPResult Parser::TryParseBracketDeclarator() {
+ ConsumeBracket();
+ if (!SkipUntil(tok::r_square))
+ return TPResult::Error();
+
+ return TPResult::Ambiguous();
+}
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
new file mode 100644
index 0000000..1c2e8a6
--- /dev/null
+++ b/lib/Parse/Parser.cpp
@@ -0,0 +1,996 @@
+//===--- Parser.cpp - C Language Family Parser ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Parser interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+#include "llvm/Support/raw_ostream.h"
+#include "ExtensionRAIIObject.h"
+#include "ParsePragma.h"
+using namespace clang;
+
+Parser::Parser(Preprocessor &pp, Action &actions)
+ : CrashInfo(*this), PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
+ GreaterThanIsOperator(true) {
+ Tok.setKind(tok::eof);
+ CurScope = 0;
+ NumCachedScopes = 0;
+ ParenCount = BracketCount = BraceCount = 0;
+ ObjCImpDecl = DeclPtrTy();
+
+ // Add #pragma handlers. These are removed and destroyed in the
+ // destructor.
+ PackHandler.reset(new
+ PragmaPackHandler(&PP.getIdentifierTable().get("pack"), actions));
+ PP.AddPragmaHandler(0, PackHandler.get());
+
+ UnusedHandler.reset(new
+ PragmaUnusedHandler(&PP.getIdentifierTable().get("unused"), actions,
+ *this));
+ PP.AddPragmaHandler(0, UnusedHandler.get());
+}
+
+/// If a crash happens while the parser is active, print out a line indicating
+/// what the current token is.
+void PrettyStackTraceParserEntry::print(llvm::raw_ostream &OS) const {
+ const Token &Tok = P.getCurToken();
+ if (Tok.is(tok::eof)) {
+ OS << "<eof> parser at end of file\n";
+ return;
+ }
+
+ if (Tok.getLocation().isInvalid()) {
+ OS << "<unknown> parser at unknown location\n";
+ return;
+ }
+
+ const Preprocessor &PP = P.getPreprocessor();
+ Tok.getLocation().print(OS, PP.getSourceManager());
+ OS << ": current parser token '" << PP.getSpelling(Tok) << "'\n";
+}
+
+
+DiagnosticBuilder Parser::Diag(SourceLocation Loc, unsigned DiagID) {
+ return Diags.Report(FullSourceLoc(Loc, PP.getSourceManager()), DiagID);
+}
+
+DiagnosticBuilder Parser::Diag(const Token &Tok, unsigned DiagID) {
+ return Diag(Tok.getLocation(), DiagID);
+}
+
+/// \brief Emits a diagnostic suggesting parentheses surrounding a
+/// given range.
+///
+/// \param Loc The location where we'll emit the diagnostic.
+/// \param Loc The kind of diagnostic to emit.
+/// \param ParenRange Source range enclosing code that should be parenthesized.
+void Parser::SuggestParentheses(SourceLocation Loc, unsigned DK,
+ SourceRange ParenRange) {
+ SourceLocation EndLoc = PP.getLocForEndOfToken(ParenRange.getEnd());
+ if (!ParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
+ // We can't display the parentheses, so just dig the
+ // warning/error and return.
+ Diag(Loc, DK);
+ return;
+ }
+
+ Diag(Loc, DK)
+ << CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(")
+ << CodeModificationHint::CreateInsertion(EndLoc, ")");
+}
+
+/// MatchRHSPunctuation - For punctuation with a LHS and RHS (e.g. '['/']'),
+/// this helper function matches and consumes the specified RHS token if
+/// present. If not present, it emits the specified diagnostic indicating
+/// that the parser failed to match the RHS of the token at LHSLoc. LHSName
+/// should be the name of the unmatched LHS token.
+SourceLocation Parser::MatchRHSPunctuation(tok::TokenKind RHSTok,
+ SourceLocation LHSLoc) {
+
+ if (Tok.is(RHSTok))
+ return ConsumeAnyToken();
+
+ SourceLocation R = Tok.getLocation();
+ const char *LHSName = "unknown";
+ diag::kind DID = diag::err_parse_error;
+ switch (RHSTok) {
+ default: break;
+ case tok::r_paren : LHSName = "("; DID = diag::err_expected_rparen; break;
+ case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace; break;
+ case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare; break;
+ case tok::greater: LHSName = "<"; DID = diag::err_expected_greater; break;
+ }
+ Diag(Tok, DID);
+ Diag(LHSLoc, diag::note_matching) << LHSName;
+ SkipUntil(RHSTok);
+ return R;
+}
+
+/// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the
+/// input. If so, it is consumed and false is returned.
+///
+/// If the input is malformed, this emits the specified diagnostic. Next, if
+/// SkipToTok is specified, it calls SkipUntil(SkipToTok). Finally, true is
+/// returned.
+bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID,
+ const char *Msg, tok::TokenKind SkipToTok) {
+ if (Tok.is(ExpectedTok)) {
+ ConsumeAnyToken();
+ return false;
+ }
+
+ const char *Spelling = 0;
+ SourceLocation EndLoc = PP.getLocForEndOfToken(PrevTokLocation);
+ if (EndLoc.isValid() &&
+ (Spelling = tok::getTokenSimpleSpelling(ExpectedTok))) {
+ // Show what code to insert to fix this problem.
+ Diag(EndLoc, DiagID)
+ << Msg
+ << CodeModificationHint::CreateInsertion(EndLoc, Spelling);
+ } else
+ Diag(Tok, DiagID) << Msg;
+
+ if (SkipToTok != tok::unknown)
+ SkipUntil(SkipToTok);
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Error recovery.
+//===----------------------------------------------------------------------===//
+
+/// SkipUntil - Read tokens until we get to the specified token, then consume
+/// it (unless DontConsume is true). Because we cannot guarantee that the
+/// token will ever occur, this skips to the next token, or to some likely
+/// good stopping point. If StopAtSemi is true, skipping will stop at a ';'
+/// character.
+///
+/// If SkipUntil finds the specified token, it returns true, otherwise it
+/// returns false.
+bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks,
+ bool StopAtSemi, bool DontConsume) {
+ // We always want this function to skip at least one token if the first token
+ // isn't T and if not at EOF.
+ bool isFirstTokenSkipped = true;
+ while (1) {
+ // If we found one of the tokens, stop and return true.
+ for (unsigned i = 0; i != NumToks; ++i) {
+ if (Tok.is(Toks[i])) {
+ if (DontConsume) {
+ // Noop, don't consume the token.
+ } else {
+ ConsumeAnyToken();
+ }
+ return true;
+ }
+ }
+
+ switch (Tok.getKind()) {
+ case tok::eof:
+ // Ran out of tokens.
+ return false;
+
+ case tok::l_paren:
+ // Recursively skip properly-nested parens.
+ ConsumeParen();
+ SkipUntil(tok::r_paren, false);
+ break;
+ case tok::l_square:
+ // Recursively skip properly-nested square brackets.
+ ConsumeBracket();
+ SkipUntil(tok::r_square, false);
+ break;
+ case tok::l_brace:
+ // Recursively skip properly-nested braces.
+ ConsumeBrace();
+ SkipUntil(tok::r_brace, false);
+ break;
+
+ // Okay, we found a ']' or '}' or ')', which we think should be balanced.
+ // Since the user wasn't looking for this token (if they were, it would
+ // already be handled), this isn't balanced. If there is a LHS token at a
+ // higher level, we will assume that this matches the unbalanced token
+ // and return it. Otherwise, this is a spurious RHS token, which we skip.
+ case tok::r_paren:
+ if (ParenCount && !isFirstTokenSkipped)
+ return false; // Matches something.
+ ConsumeParen();
+ break;
+ case tok::r_square:
+ if (BracketCount && !isFirstTokenSkipped)
+ return false; // Matches something.
+ ConsumeBracket();
+ break;
+ case tok::r_brace:
+ if (BraceCount && !isFirstTokenSkipped)
+ return false; // Matches something.
+ ConsumeBrace();
+ break;
+
+ case tok::string_literal:
+ case tok::wide_string_literal:
+ ConsumeStringToken();
+ break;
+ case tok::semi:
+ if (StopAtSemi)
+ return false;
+ // FALL THROUGH.
+ default:
+ // Skip this token.
+ ConsumeToken();
+ break;
+ }
+ isFirstTokenSkipped = false;
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Scope manipulation
+//===----------------------------------------------------------------------===//
+
+/// EnterScope - Start a new scope.
+void Parser::EnterScope(unsigned ScopeFlags) {
+ if (NumCachedScopes) {
+ Scope *N = ScopeCache[--NumCachedScopes];
+ N->Init(CurScope, ScopeFlags);
+ CurScope = N;
+ } else {
+ CurScope = new Scope(CurScope, ScopeFlags);
+ }
+}
+
+/// ExitScope - Pop a scope off the scope stack.
+void Parser::ExitScope() {
+ assert(CurScope && "Scope imbalance!");
+
+ // Inform the actions module that this scope is going away if there are any
+ // decls in it.
+ if (!CurScope->decl_empty())
+ Actions.ActOnPopScope(Tok.getLocation(), CurScope);
+
+ Scope *OldScope = CurScope;
+ CurScope = OldScope->getParent();
+
+ if (NumCachedScopes == ScopeCacheSize)
+ delete OldScope;
+ else
+ ScopeCache[NumCachedScopes++] = OldScope;
+}
+
+
+
+
+//===----------------------------------------------------------------------===//
+// C99 6.9: External Definitions.
+//===----------------------------------------------------------------------===//
+
+Parser::~Parser() {
+ // If we still have scopes active, delete the scope tree.
+ delete CurScope;
+
+ // Free the scope cache.
+ for (unsigned i = 0, e = NumCachedScopes; i != e; ++i)
+ delete ScopeCache[i];
+
+ // Remove the pragma handlers we installed.
+ PP.RemovePragmaHandler(0, PackHandler.get());
+ PackHandler.reset();
+ PP.RemovePragmaHandler(0, UnusedHandler.get());
+ UnusedHandler.reset();
+}
+
+/// Initialize - Warm up the parser.
+///
+void Parser::Initialize() {
+ // Prime the lexer look-ahead.
+ ConsumeToken();
+
+ // Create the translation unit scope. Install it as the current scope.
+ assert(CurScope == 0 && "A scope is already active?");
+ EnterScope(Scope::DeclScope);
+ Actions.ActOnTranslationUnitScope(Tok.getLocation(), CurScope);
+
+ if (Tok.is(tok::eof) &&
+ !getLang().CPlusPlus) // Empty source file is an extension in C
+ Diag(Tok, diag::ext_empty_source_file);
+
+ // Initialization for Objective-C context sensitive keywords recognition.
+ // Referenced in Parser::ParseObjCTypeQualifierList.
+ if (getLang().ObjC1) {
+ ObjCTypeQuals[objc_in] = &PP.getIdentifierTable().get("in");
+ ObjCTypeQuals[objc_out] = &PP.getIdentifierTable().get("out");
+ ObjCTypeQuals[objc_inout] = &PP.getIdentifierTable().get("inout");
+ ObjCTypeQuals[objc_oneway] = &PP.getIdentifierTable().get("oneway");
+ ObjCTypeQuals[objc_bycopy] = &PP.getIdentifierTable().get("bycopy");
+ ObjCTypeQuals[objc_byref] = &PP.getIdentifierTable().get("byref");
+ }
+
+ Ident_super = &PP.getIdentifierTable().get("super");
+}
+
+/// ParseTopLevelDecl - Parse one top-level declaration, return whatever the
+/// action tells us to. This returns true if the EOF was encountered.
+bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
+ Result = DeclGroupPtrTy();
+ if (Tok.is(tok::eof)) {
+ Actions.ActOnEndOfTranslationUnit();
+ return true;
+ }
+
+ Result = ParseExternalDeclaration();
+ return false;
+}
+
+/// ParseTranslationUnit:
+/// translation-unit: [C99 6.9]
+/// external-declaration
+/// translation-unit external-declaration
+void Parser::ParseTranslationUnit() {
+ Initialize();
+
+ DeclGroupPtrTy Res;
+ while (!ParseTopLevelDecl(Res))
+ /*parse them all*/;
+
+ ExitScope();
+ assert(CurScope == 0 && "Scope imbalance!");
+}
+
+/// ParseExternalDeclaration:
+///
+/// external-declaration: [C99 6.9], declaration: [C++ dcl.dcl]
+/// function-definition
+/// declaration
+/// [EXT] ';'
+/// [GNU] asm-definition
+/// [GNU] __extension__ external-declaration
+/// [OBJC] objc-class-definition
+/// [OBJC] objc-class-declaration
+/// [OBJC] objc-alias-declaration
+/// [OBJC] objc-protocol-definition
+/// [OBJC] objc-method-definition
+/// [OBJC] @end
+/// [C++] linkage-specification
+/// [GNU] asm-definition:
+/// simple-asm-expr ';'
+///
+Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() {
+ DeclPtrTy SingleDecl;
+ switch (Tok.getKind()) {
+ case tok::semi:
+ Diag(Tok, diag::ext_top_level_semi)
+ << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation()));
+ ConsumeToken();
+ // TODO: Invoke action for top-level semicolon.
+ return DeclGroupPtrTy();
+ case tok::r_brace:
+ Diag(Tok, diag::err_expected_external_declaration);
+ ConsumeBrace();
+ return DeclGroupPtrTy();
+ case tok::eof:
+ Diag(Tok, diag::err_expected_external_declaration);
+ return DeclGroupPtrTy();
+ case tok::kw___extension__: {
+ // __extension__ silences extension warnings in the subexpression.
+ ExtensionRAIIObject O(Diags); // Use RAII to do this.
+ ConsumeToken();
+ return ParseExternalDeclaration();
+ }
+ case tok::kw_asm: {
+ OwningExprResult Result(ParseSimpleAsm());
+
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
+ "top-level asm block");
+
+ if (Result.isInvalid())
+ return DeclGroupPtrTy();
+ SingleDecl = Actions.ActOnFileScopeAsmDecl(Tok.getLocation(), move(Result));
+ break;
+ }
+ case tok::at:
+ // @ is not a legal token unless objc is enabled, no need to check for ObjC.
+ /// FIXME: ParseObjCAtDirectives should return a DeclGroup for things like
+ /// @class foo, bar;
+ SingleDecl = ParseObjCAtDirectives();
+ break;
+ case tok::minus:
+ case tok::plus:
+ if (!getLang().ObjC1) {
+ Diag(Tok, diag::err_expected_external_declaration);
+ ConsumeToken();
+ return DeclGroupPtrTy();
+ }
+ SingleDecl = ParseObjCMethodDefinition();
+ break;
+ case tok::kw_using:
+ case tok::kw_namespace:
+ case tok::kw_typedef:
+ case tok::kw_template:
+ case tok::kw_export: // As in 'export template'
+ case tok::kw_static_assert:
+ // A function definition cannot start with a these keywords.
+ {
+ SourceLocation DeclEnd;
+ return ParseDeclaration(Declarator::FileContext, DeclEnd);
+ }
+ default:
+ // We can't tell whether this is a function-definition or declaration yet.
+ return ParseDeclarationOrFunctionDefinition();
+ }
+
+ // This routine returns a DeclGroup, if the thing we parsed only contains a
+ // single decl, convert it now.
+ return Actions.ConvertDeclToDeclGroup(SingleDecl);
+}
+
+/// \brief Determine whether the current token, if it occurs after a
+/// declarator, continues a declaration or declaration list.
+bool Parser::isDeclarationAfterDeclarator() {
+ return Tok.is(tok::equal) || // int X()= -> not a function def
+ Tok.is(tok::comma) || // int X(), -> not a function def
+ Tok.is(tok::semi) || // int X(); -> not a function def
+ Tok.is(tok::kw_asm) || // int X() __asm__ -> not a function def
+ Tok.is(tok::kw___attribute) || // int X() __attr__ -> not a function def
+ (getLang().CPlusPlus &&
+ Tok.is(tok::l_paren)); // int X(0) -> not a function def [C++]
+}
+
+/// \brief Determine whether the current token, if it occurs after a
+/// declarator, indicates the start of a function definition.
+bool Parser::isStartOfFunctionDefinition() {
+ return Tok.is(tok::l_brace) || // int X() {}
+ (!getLang().CPlusPlus &&
+ isDeclarationSpecifier()) || // int X(f) int f; {}
+ (getLang().CPlusPlus &&
+ (Tok.is(tok::colon) || // X() : Base() {} (used for ctors)
+ Tok.is(tok::kw_try))); // X() try { ... }
+}
+
+/// ParseDeclarationOrFunctionDefinition - Parse either a function-definition or
+/// a declaration. We can't tell which we have until we read up to the
+/// compound-statement in function-definition. TemplateParams, if
+/// non-NULL, provides the template parameters when we're parsing a
+/// C++ template-declaration.
+///
+/// function-definition: [C99 6.9.1]
+/// decl-specs declarator declaration-list[opt] compound-statement
+/// [C90] function-definition: [C99 6.7.1] - implicit int result
+/// [C90] decl-specs[opt] declarator declaration-list[opt] compound-statement
+///
+/// declaration: [C99 6.7]
+/// declaration-specifiers init-declarator-list[opt] ';'
+/// [!C99] init-declarator-list ';' [TODO: warn in c99 mode]
+/// [OMP] threadprivate-directive [TODO]
+///
+Parser::DeclGroupPtrTy
+Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) {
+ // Parse the common declaration-specifiers piece.
+ DeclSpec DS;
+ ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS);
+
+ // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
+ // declaration-specifiers init-declarator-list[opt] ';'
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
+ return Actions.ConvertDeclToDeclGroup(TheDecl);
+ }
+
+ // ObjC2 allows prefix attributes on class interfaces and protocols.
+ // FIXME: This still needs better diagnostics. We should only accept
+ // attributes here, no types, etc.
+ if (getLang().ObjC2 && Tok.is(tok::at)) {
+ SourceLocation AtLoc = ConsumeToken(); // the "@"
+ if (!Tok.isObjCAtKeyword(tok::objc_interface) &&
+ !Tok.isObjCAtKeyword(tok::objc_protocol)) {
+ Diag(Tok, diag::err_objc_unexpected_attr);
+ SkipUntil(tok::semi); // FIXME: better skip?
+ return DeclGroupPtrTy();
+ }
+ const char *PrevSpec = 0;
+ if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec))
+ Diag(AtLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
+
+ DeclPtrTy TheDecl;
+ if (Tok.isObjCAtKeyword(tok::objc_protocol))
+ TheDecl = ParseObjCAtProtocolDeclaration(AtLoc, DS.getAttributes());
+ else
+ TheDecl = ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes());
+ return Actions.ConvertDeclToDeclGroup(TheDecl);
+ }
+
+ // If the declspec consisted only of 'extern' and we have a string
+ // literal following it, this must be a C++ linkage specifier like
+ // 'extern "C"'.
+ if (Tok.is(tok::string_literal) && getLang().CPlusPlus &&
+ DS.getStorageClassSpec() == DeclSpec::SCS_extern &&
+ DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) {
+ 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_declation);
+ 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();
+}
+
+/// ParseFunctionDefinition - We parsed and verified that the specified
+/// Declarator is well formed. If this is a K&R-style function, read the
+/// parameters declaration-list, then start the compound-statement.
+///
+/// function-definition: [C99 6.9.1]
+/// decl-specs declarator declaration-list[opt] compound-statement
+/// [C90] function-definition: [C99 6.7.1] - implicit int result
+/// [C90] decl-specs[opt] declarator declaration-list[opt] compound-statement
+/// [C++] function-definition: [C++ 8.4]
+/// decl-specifier-seq[opt] declarator ctor-initializer[opt]
+/// function-body
+/// [C++] function-definition: [C++ 8.4]
+/// decl-specifier-seq[opt] declarator function-try-block
+///
+Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D) {
+ const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0);
+ assert(FnTypeInfo.Kind == DeclaratorChunk::Function &&
+ "This isn't a function declarator!");
+ const DeclaratorChunk::FunctionTypeInfo &FTI = FnTypeInfo.Fun;
+
+ // If this is C90 and the declspecs were completely missing, fudge in an
+ // implicit int. We do this here because this is the only place where
+ // declaration-specifiers are completely optional in the grammar.
+ if (getLang().ImplicitInt && D.getDeclSpec().isEmpty()) {
+ const char *PrevSpec;
+ D.getMutableDeclSpec().SetTypeSpecType(DeclSpec::TST_int,
+ D.getIdentifierLoc(),
+ PrevSpec);
+ D.SetRangeBegin(D.getDeclSpec().getSourceRange().getBegin());
+ }
+
+ // If this declaration was formed with a K&R-style identifier list for the
+ // arguments, parse declarations for all of the args next.
+ // int foo(a,b) int a; float b; {}
+ if (!FTI.hasPrototype && FTI.NumArgs != 0)
+ ParseKNRParamDeclarations(D);
+
+ // We should have either an opening brace or, in a C++ constructor,
+ // we may have a colon.
+ if (Tok.isNot(tok::l_brace) && Tok.isNot(tok::colon) &&
+ Tok.isNot(tok::kw_try)) {
+ Diag(Tok, diag::err_expected_fn_body);
+
+ // Skip over garbage, until we get to '{'. Don't eat the '{'.
+ SkipUntil(tok::l_brace, true, true);
+
+ // If we didn't find the '{', bail out.
+ if (Tok.isNot(tok::l_brace))
+ return DeclPtrTy();
+ }
+
+ // Enter a scope for the function body.
+ ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
+
+ // Tell the actions module that we have entered a function definition with the
+ // specified Declarator for the function.
+ DeclPtrTy Res = Actions.ActOnStartOfFunctionDef(CurScope, D);
+
+ if (Tok.is(tok::kw_try))
+ return ParseFunctionTryBlock(Res);
+
+ // If we have a colon, then we're probably parsing a C++
+ // ctor-initializer.
+ if (Tok.is(tok::colon))
+ ParseConstructorInitializer(Res);
+
+ return ParseFunctionStatementBody(Res);
+}
+
+/// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides
+/// types for a function with a K&R-style identifier list for arguments.
+void Parser::ParseKNRParamDeclarations(Declarator &D) {
+ // We know that the top-level of this declarator is a function.
+ DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
+
+ // Enter function-declaration scope, limiting any declarators to the
+ // function prototype scope, including parameter declarators.
+ ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope);
+
+ // Read all the argument declarations.
+ while (isDeclarationSpecifier()) {
+ SourceLocation DSStart = Tok.getLocation();
+
+ // Parse the common declaration-specifiers piece.
+ DeclSpec DS;
+ ParseDeclarationSpecifiers(DS);
+
+ // C99 6.9.1p6: 'each declaration in the declaration list shall have at
+ // least one declarator'.
+ // NOTE: GCC just makes this an ext-warn. It's not clear what it does with
+ // the declarations though. It's trivial to ignore them, really hard to do
+ // anything else with them.
+ if (Tok.is(tok::semi)) {
+ Diag(DSStart, diag::err_declaration_does_not_declare_param);
+ ConsumeToken();
+ continue;
+ }
+
+ // C99 6.9.1p6: Declarations shall contain no storage-class specifiers other
+ // than register.
+ if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified &&
+ DS.getStorageClassSpec() != DeclSpec::SCS_register) {
+ Diag(DS.getStorageClassSpecLoc(),
+ diag::err_invalid_storage_class_in_func_decl);
+ DS.ClearStorageClassSpecs();
+ }
+ if (DS.isThreadSpecified()) {
+ Diag(DS.getThreadSpecLoc(),
+ diag::err_invalid_storage_class_in_func_decl);
+ DS.ClearStorageClassSpecs();
+ }
+
+ // Parse the first declarator attached to this declspec.
+ Declarator ParmDeclarator(DS, Declarator::KNRTypeListContext);
+ ParseDeclarator(ParmDeclarator);
+
+ // Handle the full declarator list.
+ while (1) {
+ Action::AttrTy *AttrList;
+ // If attributes are present, parse them.
+ if (Tok.is(tok::kw___attribute))
+ // FIXME: attach attributes too.
+ AttrList = ParseAttributes();
+
+ // Ask the actions module to compute the type for this declarator.
+ Action::DeclPtrTy Param =
+ Actions.ActOnParamDeclarator(CurScope, ParmDeclarator);
+
+ if (Param &&
+ // A missing identifier has already been diagnosed.
+ ParmDeclarator.getIdentifier()) {
+
+ // Scan the argument list looking for the correct param to apply this
+ // type.
+ for (unsigned i = 0; ; ++i) {
+ // C99 6.9.1p6: those declarators shall declare only identifiers from
+ // the identifier list.
+ if (i == FTI.NumArgs) {
+ Diag(ParmDeclarator.getIdentifierLoc(), diag::err_no_matching_param)
+ << ParmDeclarator.getIdentifier();
+ break;
+ }
+
+ if (FTI.ArgInfo[i].Ident == ParmDeclarator.getIdentifier()) {
+ // Reject redefinitions of parameters.
+ if (FTI.ArgInfo[i].Param) {
+ Diag(ParmDeclarator.getIdentifierLoc(),
+ diag::err_param_redefinition)
+ << ParmDeclarator.getIdentifier();
+ } else {
+ FTI.ArgInfo[i].Param = Param;
+ }
+ break;
+ }
+ }
+ }
+
+ // 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.
+ ParmDeclarator.clear();
+ ParseDeclarator(ParmDeclarator);
+ }
+
+ if (Tok.is(tok::semi)) {
+ ConsumeToken();
+ } else {
+ Diag(Tok, diag::err_parse_error);
+ // Skip to end of block or statement
+ SkipUntil(tok::semi, true);
+ if (Tok.is(tok::semi))
+ ConsumeToken();
+ }
+ }
+
+ // The actions module must verify that all arguments were declared.
+ Actions.ActOnFinishKNRParamDeclarations(CurScope, D, Tok.getLocation());
+}
+
+
+/// ParseAsmStringLiteral - This is just a normal string-literal, but is not
+/// allowed to be a wide string, and is not subject to character translation.
+///
+/// [GNU] asm-string-literal:
+/// string-literal
+///
+Parser::OwningExprResult Parser::ParseAsmStringLiteral() {
+ if (!isTokenStringLiteral()) {
+ Diag(Tok, diag::err_expected_string_literal);
+ return ExprError();
+ }
+
+ OwningExprResult Res(ParseStringLiteralExpression());
+ if (Res.isInvalid()) return move(Res);
+
+ // TODO: Diagnose: wide string literal in 'asm'
+
+ return move(Res);
+}
+
+/// ParseSimpleAsm
+///
+/// [GNU] simple-asm-expr:
+/// 'asm' '(' asm-string-literal ')'
+///
+Parser::OwningExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
+ assert(Tok.is(tok::kw_asm) && "Not an asm!");
+ SourceLocation Loc = ConsumeToken();
+
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << "asm";
+ return ExprError();
+ }
+
+ Loc = ConsumeParen();
+
+ OwningExprResult Result(ParseAsmStringLiteral());
+
+ if (Result.isInvalid()) {
+ SkipUntil(tok::r_paren, true, true);
+ if (EndLoc)
+ *EndLoc = Tok.getLocation();
+ ConsumeAnyToken();
+ } else {
+ Loc = MatchRHSPunctuation(tok::r_paren, Loc);
+ if (EndLoc)
+ *EndLoc = Loc;
+ }
+
+ return move(Result);
+}
+
+/// TryAnnotateTypeOrScopeToken - If the current token position is on a
+/// typename (possibly qualified in C++) or a C++ scope specifier not followed
+/// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens
+/// with a single annotation token representing the typename or C++ scope
+/// respectively.
+/// This simplifies handling of C++ scope specifiers and allows efficient
+/// backtracking without the need to re-parse and resolve nested-names and
+/// typenames.
+/// It will mainly be called when we expect to treat identifiers as typenames
+/// (if they are typenames). For example, in C we do not expect identifiers
+/// inside expressions to be treated as typenames so it will not be called
+/// for expressions in C.
+/// The benefit for C/ObjC is that a typename will be annotated and
+/// Actions.getTypeName will not be needed to be called again (e.g. getTypeName
+/// will not be called twice, once to check whether we have a declaration
+/// specifier, and another one to get the actual type inside
+/// ParseDeclarationSpecifiers).
+///
+/// This returns true if the token was annotated.
+///
+/// Note that this routine emits an error if you call it with ::new or ::delete
+/// as the current tokens, so only call it in contexts where these are invalid.
+bool Parser::TryAnnotateTypeOrScopeToken() {
+ assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon)
+ || Tok.is(tok::kw_typename)) &&
+ "Cannot be a type or scope token!");
+
+ if (Tok.is(tok::kw_typename)) {
+ // Parse a C++ typename-specifier, e.g., "typename T::type".
+ //
+ // typename-specifier:
+ // 'typename' '::' [opt] nested-name-specifier identifier
+ // 'typename' '::' [opt] nested-name-specifier template [opt]
+ // simple-template-id
+ SourceLocation TypenameLoc = ConsumeToken();
+ CXXScopeSpec SS;
+ bool HadNestedNameSpecifier = ParseOptionalCXXScopeSpecifier(SS);
+ if (!HadNestedNameSpecifier) {
+ Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename);
+ return false;
+ }
+
+ TypeResult Ty;
+ if (Tok.is(tok::identifier)) {
+ // FIXME: check whether the next token is '<', first!
+ Ty = Actions.ActOnTypenameType(TypenameLoc, SS, *Tok.getIdentifierInfo(),
+ Tok.getLocation());
+ } else if (Tok.is(tok::annot_template_id)) {
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ if (TemplateId->Kind == TNK_Function_template) {
+ Diag(Tok, diag::err_typename_refers_to_non_type_template)
+ << Tok.getAnnotationRange();
+ return false;
+ }
+
+ AnnotateTemplateIdTokenAsType(0);
+ assert(Tok.is(tok::annot_typename) &&
+ "AnnotateTemplateIdTokenAsType isn't working properly");
+ if (Tok.getAnnotationValue())
+ Ty = Actions.ActOnTypenameType(TypenameLoc, SS, SourceLocation(),
+ Tok.getAnnotationValue());
+ else
+ Ty = true;
+ } else {
+ Diag(Tok, diag::err_expected_type_name_after_typename)
+ << SS.getRange();
+ return false;
+ }
+
+ Tok.setKind(tok::annot_typename);
+ Tok.setAnnotationValue(Ty.isInvalid()? 0 : Ty.get());
+ Tok.setAnnotationEndLoc(Tok.getLocation());
+ Tok.setLocation(TypenameLoc);
+ PP.AnnotateCachedTokens(Tok);
+ return true;
+ }
+
+ CXXScopeSpec SS;
+ if (getLang().CPlusPlus)
+ ParseOptionalCXXScopeSpecifier(SS);
+
+ if (Tok.is(tok::identifier)) {
+ // Determine whether the identifier is a type name.
+ if (TypeTy *Ty = Actions.getTypeName(*Tok.getIdentifierInfo(),
+ Tok.getLocation(), CurScope, &SS)) {
+ // This is a typename. Replace the current token in-place with an
+ // annotation type token.
+ Tok.setKind(tok::annot_typename);
+ Tok.setAnnotationValue(Ty);
+ Tok.setAnnotationEndLoc(Tok.getLocation());
+ if (SS.isNotEmpty()) // it was a C++ qualified type name.
+ Tok.setLocation(SS.getBeginLoc());
+
+ // In case the tokens were cached, have Preprocessor replace
+ // them with the annotation token.
+ PP.AnnotateCachedTokens(Tok);
+ return true;
+ }
+
+ if (!getLang().CPlusPlus) {
+ // If we're in C, we can't have :: tokens at all (the lexer won't return
+ // them). If the identifier is not a type, then it can't be scope either,
+ // just early exit.
+ return false;
+ }
+
+ // If this is a template-id, annotate with a template-id or type token.
+ if (NextToken().is(tok::less)) {
+ TemplateTy Template;
+ if (TemplateNameKind TNK
+ = Actions.isTemplateName(*Tok.getIdentifierInfo(),
+ CurScope, Template, &SS))
+ AnnotateTemplateIdToken(Template, TNK, &SS);
+ }
+
+ // The current token, which is either an identifier or a
+ // template-id, is not part of the annotation. Fall through to
+ // push that token back into the stream and complete the C++ scope
+ // specifier annotation.
+ }
+
+ if (Tok.is(tok::annot_template_id)) {
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ if (TemplateId->Kind == TNK_Type_template) {
+ // A template-id that refers to a type was parsed into a
+ // template-id annotation in a context where we weren't allowed
+ // to produce a type annotation token. Update the template-id
+ // annotation token to a type annotation token now.
+ AnnotateTemplateIdTokenAsType(&SS);
+ return true;
+ }
+ }
+
+ if (SS.isEmpty())
+ return false;
+
+ // A C++ scope specifier that isn't followed by a typename.
+ // Push the current token back into the token stream (or revert it if it is
+ // cached) and use an annotation scope token for current token.
+ if (PP.isBacktrackEnabled())
+ PP.RevertCachedTokens(1);
+ else
+ PP.EnterToken(Tok);
+ Tok.setKind(tok::annot_cxxscope);
+ Tok.setAnnotationValue(SS.getScopeRep());
+ Tok.setAnnotationRange(SS.getRange());
+
+ // In case the tokens were cached, have Preprocessor replace them with the
+ // annotation token.
+ PP.AnnotateCachedTokens(Tok);
+ return true;
+}
+
+/// TryAnnotateScopeToken - Like TryAnnotateTypeOrScopeToken but only
+/// annotates C++ scope specifiers and template-ids. This returns
+/// true if the token was annotated.
+///
+/// Note that this routine emits an error if you call it with ::new or ::delete
+/// as the current tokens, so only call it in contexts where these are invalid.
+bool Parser::TryAnnotateCXXScopeToken() {
+ assert(getLang().CPlusPlus &&
+ "Call sites of this function should be guarded by checking for C++");
+ assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) &&
+ "Cannot be a type or scope token!");
+
+ CXXScopeSpec SS;
+ if (!ParseOptionalCXXScopeSpecifier(SS))
+ return Tok.is(tok::annot_template_id);
+
+ // Push the current token back into the token stream (or revert it if it is
+ // cached) and use an annotation scope token for current token.
+ if (PP.isBacktrackEnabled())
+ PP.RevertCachedTokens(1);
+ else
+ PP.EnterToken(Tok);
+ Tok.setKind(tok::annot_cxxscope);
+ Tok.setAnnotationValue(SS.getScopeRep());
+ Tok.setAnnotationRange(SS.getRange());
+
+ // In case the tokens were cached, have Preprocessor replace them with the
+ // annotation token.
+ PP.AnnotateCachedTokens(Tok);
+ return true;
+}
OpenPOWER on IntegriCloud