diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Parse')
19 files changed, 18228 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/Parse/AttributeList.cpp b/contrib/llvm/tools/clang/lib/Parse/AttributeList.cpp new file mode 100644 index 0000000..1ebff22 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Parse/AttributeList.cpp @@ -0,0 +1,129 @@ +//===--- 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" +#include "llvm/ADT/StringSwitch.h" +using namespace clang; + +AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc, + IdentifierInfo *sName, SourceLocation sLoc, + IdentifierInfo *pName, SourceLocation pLoc, + ActionBase::ExprTy **ExprList, unsigned numArgs, + AttributeList *n, bool declspec, bool cxx0x) + : AttrName(aName), AttrLoc(aLoc), ScopeName(sName), ScopeLoc(sLoc), + ParmName(pName), ParmLoc(pLoc), NumArgs(numArgs), Next(n), + DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), Invalid(false) { + + 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) { + llvm::StringRef AttrName = Name->getName(); + + // Normalize the attribute name, __foo__ becomes foo. + if (AttrName.startswith("__") && AttrName.endswith("__")) + AttrName = AttrName.substr(2, AttrName.size() - 4); + + return llvm::StringSwitch<AttributeList::Kind>(AttrName) + .Case("weak", AT_weak) + .Case("weakref", AT_weakref) + .Case("pure", AT_pure) + .Case("mode", AT_mode) + .Case("used", AT_used) + .Case("alias", AT_alias) + .Case("align", AT_aligned) + .Case("final", AT_final) + .Case("cdecl", AT_cdecl) + .Case("const", AT_const) + .Case("blocks", AT_blocks) + .Case("format", AT_format) + .Case("hiding", AT_hiding) + .Case("malloc", AT_malloc) + .Case("packed", AT_packed) + .Case("unused", AT_unused) + .Case("aligned", AT_aligned) + .Case("cleanup", AT_cleanup) + .Case("nodebug", AT_nodebug) + .Case("nonnull", AT_nonnull) + .Case("nothrow", AT_nothrow) + .Case("objc_gc", AT_objc_gc) + .Case("regparm", AT_regparm) + .Case("section", AT_section) + .Case("stdcall", AT_stdcall) + .Case("annotate", AT_annotate) + .Case("fastcall", AT_fastcall) + .Case("ibaction", AT_IBAction) + .Case("iboutlet", AT_IBOutlet) + .Case("iboutletcollection", AT_IBOutletCollection) + .Case("noreturn", AT_noreturn) + .Case("noinline", AT_noinline) + .Case("override", AT_override) + .Case("sentinel", AT_sentinel) + .Case("NSObject", AT_nsobject) + .Case("dllimport", AT_dllimport) + .Case("dllexport", AT_dllexport) + .Case("may_alias", IgnoredAttribute) // FIXME: TBAA + .Case("base_check", AT_base_check) + .Case("deprecated", AT_deprecated) + .Case("visibility", AT_visibility) + .Case("destructor", AT_destructor) + .Case("format_arg", AT_format_arg) + .Case("gnu_inline", AT_gnu_inline) + .Case("weak_import", AT_weak_import) + .Case("vector_size", AT_vector_size) + .Case("constructor", AT_constructor) + .Case("unavailable", AT_unavailable) + .Case("overloadable", AT_overloadable) + .Case("address_space", AT_address_space) + .Case("always_inline", AT_always_inline) + .Case("returns_twice", IgnoredAttribute) + .Case("vec_type_hint", IgnoredAttribute) + .Case("objc_exception", AT_objc_exception) + .Case("ext_vector_type", AT_ext_vector_type) + .Case("transparent_union", AT_transparent_union) + .Case("analyzer_noreturn", AT_analyzer_noreturn) + .Case("warn_unused_result", AT_warn_unused_result) + .Case("carries_dependency", AT_carries_dependency) + .Case("ns_returns_not_retained", AT_ns_returns_not_retained) + .Case("ns_returns_retained", AT_ns_returns_retained) + .Case("cf_returns_not_retained", AT_cf_returns_not_retained) + .Case("cf_returns_retained", AT_cf_returns_retained) + .Case("reqd_work_group_size", AT_reqd_wg_size) + .Case("no_instrument_function", AT_no_instrument_function) + .Case("thiscall", AT_thiscall) + .Case("__cdecl", AT_cdecl) + .Case("__stdcall", AT_stdcall) + .Case("__fastcall", AT_fastcall) + .Case("__thiscall", AT_thiscall) + .Default(UnknownAttribute); +} diff --git a/contrib/llvm/tools/clang/lib/Parse/CMakeLists.txt b/contrib/llvm/tools/clang/lib/Parse/CMakeLists.txt new file mode 100644 index 0000000..bec1c6e --- /dev/null +++ b/contrib/llvm/tools/clang/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 + ParseStmt.cpp + ParseTemplate.cpp + ParseTentative.cpp + Parser.cpp + ) + +add_dependencies(clangParse ClangDiagnosticParse) diff --git a/contrib/llvm/tools/clang/lib/Parse/DeclSpec.cpp b/contrib/llvm/tools/clang/lib/Parse/DeclSpec.cpp new file mode 100644 index 0000000..5dc08b3 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Parse/DeclSpec.cpp @@ -0,0 +1,556 @@ +//===--- 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/Parse/Template.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/LangOptions.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/ErrorHandling.h" +#include <cstring> +using namespace clang; + + +static DiagnosticBuilder Diag(Diagnostic &D, SourceLocation Loc, + SourceManager &SrcMgr, unsigned DiagID) { + return D.Report(FullSourceLoc(Loc, SrcMgr), DiagID); +} + + +void UnqualifiedId::setTemplateId(TemplateIdAnnotation *TemplateId) { + assert(TemplateId && "NULL template-id annotation?"); + Kind = IK_TemplateId; + this->TemplateId = TemplateId; + StartLocation = TemplateId->TemplateNameLoc; + EndLocation = TemplateId->RAngleLoc; +} + +void UnqualifiedId::setConstructorTemplateId(TemplateIdAnnotation *TemplateId) { + assert(TemplateId && "NULL template-id annotation?"); + Kind = IK_ConstructorTemplateId; + this->TemplateId = TemplateId; + StartLocation = TemplateId->TemplateNameLoc; + EndLocation = TemplateId->RAngleLoc; +} + +/// 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 LPLoc, + SourceLocation RPLoc, + Declarator &TheDeclarator) { + DeclaratorChunk I; + I.Kind = Function; + I.Loc = LPLoc; + I.EndLoc = RPLoc; + 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; +} + +template <class T> static bool BadSpecifier(T TNew, T TPrev, + const char *&PrevSpec, + unsigned &DiagID) { + PrevSpec = DeclSpec::getSpecifierName(TPrev); + DiagID = (TNew == TPrev ? diag::ext_duplicate_declspec + : diag::err_invalid_decl_spec_combination); + return true; +} + +const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) { + switch (S) { + 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"; + } + llvm_unreachable("Unknown typespec!"); +} + +const char *DeclSpec::getSpecifierName(TSW W) { + switch (W) { + case TSW_unspecified: return "unspecified"; + case TSW_short: return "short"; + case TSW_long: return "long"; + case TSW_longlong: return "long long"; + } + llvm_unreachable("Unknown typespec!"); +} + +const char *DeclSpec::getSpecifierName(TSC C) { + switch (C) { + case TSC_unspecified: return "unspecified"; + case TSC_imaginary: return "imaginary"; + case TSC_complex: return "complex"; + } + llvm_unreachable("Unknown typespec!"); +} + + +const char *DeclSpec::getSpecifierName(TSS S) { + switch (S) { + case TSS_unspecified: return "unspecified"; + case TSS_signed: return "signed"; + case TSS_unsigned: return "unsigned"; + } + llvm_unreachable("Unknown typespec!"); +} + +const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { + switch (T) { + 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_char16: return "char16_t"; + case DeclSpec::TST_char32: return "char32_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"; + case DeclSpec::TST_auto: return "auto"; + case DeclSpec::TST_decltype: return "(decltype)"; + case DeclSpec::TST_error: return "(error)"; + } + llvm_unreachable("Unknown typespec!"); +} + +const char *DeclSpec::getSpecifierName(TQ T) { + switch (T) { + case DeclSpec::TQ_unspecified: return "unspecified"; + case DeclSpec::TQ_const: return "const"; + case DeclSpec::TQ_restrict: return "restrict"; + case DeclSpec::TQ_volatile: return "volatile"; + } + llvm_unreachable("Unknown typespec!"); +} + +bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc, + const char *&PrevSpec, + unsigned &DiagID) { + if (StorageClassSpec != SCS_unspecified) + return BadSpecifier(S, (SCS)StorageClassSpec, PrevSpec, DiagID); + StorageClassSpec = S; + StorageClassSpecLoc = Loc; + assert((unsigned)S == StorageClassSpec && "SCS constants overflow bitfield"); + return false; +} + +bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc, + const char *&PrevSpec, + unsigned &DiagID) { + if (SCS_thread_specified) { + PrevSpec = "__thread"; + DiagID = diag::ext_duplicate_declspec; + 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, + unsigned &DiagID) { + if (TypeSpecWidth != TSW_unspecified && + // Allow turning long -> long long. + (W != TSW_longlong || TypeSpecWidth != TSW_long)) + return BadSpecifier(W, (TSW)TypeSpecWidth, PrevSpec, DiagID); + TypeSpecWidth = W; + TSWLoc = Loc; + if (TypeAltiVecVector && ((TypeSpecWidth == TSW_long) || (TypeSpecWidth == TSW_longlong))) { + PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); + DiagID = diag::warn_vector_long_decl_spec_combination; + return true; + } + return false; +} + +bool DeclSpec::SetTypeSpecComplex(TSC C, SourceLocation Loc, + const char *&PrevSpec, + unsigned &DiagID) { + if (TypeSpecComplex != TSC_unspecified) + return BadSpecifier(C, (TSC)TypeSpecComplex, PrevSpec, DiagID); + TypeSpecComplex = C; + TSCLoc = Loc; + return false; +} + +bool DeclSpec::SetTypeSpecSign(TSS S, SourceLocation Loc, + const char *&PrevSpec, + unsigned &DiagID) { + if (TypeSpecSign != TSS_unspecified) + return BadSpecifier(S, (TSS)TypeSpecSign, PrevSpec, DiagID); + TypeSpecSign = S; + TSSLoc = Loc; + return false; +} + +bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, + const char *&PrevSpec, + unsigned &DiagID, + void *Rep, bool Owned) { + if (TypeSpecType != TST_unspecified) { + PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); + DiagID = diag::err_invalid_decl_spec_combination; + return true; + } + TypeSpecType = T; + TypeRep = Rep; + TSTLoc = Loc; + TypeSpecOwned = Owned; + if (TypeAltiVecVector && (TypeSpecType == TST_double)) { + PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); + DiagID = diag::err_invalid_vector_double_decl_spec_combination; + return true; + } + return false; +} + +bool DeclSpec::SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID) { + if (TypeSpecType != TST_unspecified) { + PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); + DiagID = diag::err_invalid_vector_decl_spec_combination; + return true; + } + TypeAltiVecVector = isAltiVecVector; + AltiVecLoc = Loc; + return false; +} + +bool DeclSpec::SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID) { + if (!TypeAltiVecVector || (TypeSpecType != TST_unspecified)) { + PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); + DiagID = diag::err_invalid_pixel_decl_spec_combination; + return true; + } + TypeSpecType = TST_int; + TypeSpecSign = TSS_unsigned; + TypeSpecWidth = TSW_short; + TypeAltiVecPixel = isAltiVecPixel; + TSTLoc = Loc; + return false; +} + +bool DeclSpec::SetTypeSpecError() { + TypeSpecType = TST_error; + TypeRep = 0; + TSTLoc = SourceLocation(); + return false; +} + +bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, const LangOptions &Lang) { + // Duplicates turn into warnings pre-C99. + if ((TypeQualifiers & T) && !Lang.C99) + return BadSpecifier(T, T, PrevSpec, DiagID); + 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, + unsigned &DiagID) { + // 'inline inline' is ok. + FS_inline_specified = true; + FS_inlineLoc = Loc; + return false; +} + +bool DeclSpec::SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID) { + // 'virtual virtual' is ok. + FS_virtual_specified = true; + FS_virtualLoc = Loc; + return false; +} + +bool DeclSpec::SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID) { + // 'explicit explicit' is ok. + FS_explicit_specified = true; + FS_explicitLoc = Loc; + return false; +} + +bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID) { + if (Friend_specified) { + PrevSpec = "friend"; + DiagID = diag::ext_duplicate_declspec; + return true; + } + + Friend_specified = true; + FriendLoc = Loc; + return false; +} + +bool DeclSpec::SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID) { + // 'constexpr constexpr' is ok. + Constexpr_specified = true; + ConstexprLoc = Loc; + return false; +} + +void DeclSpec::setProtocolQualifiers(const ActionBase::DeclPtrTy *Protos, + unsigned NP, + SourceLocation *ProtoLocs, + SourceLocation LAngleLoc) { + if (NP == 0) return; + ProtocolQualifiers = new ActionBase::DeclPtrTy[NP]; + ProtocolLocs = new SourceLocation[NP]; + memcpy((void*)ProtocolQualifiers, Protos, sizeof(ActionBase::DeclPtrTy)*NP); + memcpy(ProtocolLocs, ProtoLocs, sizeof(SourceLocation)*NP); + NumProtocolQualifiers = NP; + ProtocolLAngleLoc = LAngleLoc; +} + +void DeclSpec::SaveWrittenBuiltinSpecs() { + writtenBS.Sign = getTypeSpecSign(); + writtenBS.Width = getTypeSpecWidth(); + writtenBS.Type = getTypeSpecType(); + // Search the list of attributes for the presence of a mode attribute. + writtenBS.ModeAttr = false; + AttributeList* attrs = getAttributes(); + while (attrs) { + if (attrs->getKind() == AttributeList::AT_mode) { + writtenBS.ModeAttr = true; + break; + } + attrs = attrs->getNext(); + } +} + +/// 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) { + // Before possibly changing their values, save specs as written. + SaveWrittenBuiltinSpecs(); + SaveStorageSpecifierAsWritten(); + + // 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) + << FixItHint::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; + } + } + + // C++ [class.friend]p6: + // No storage-class-specifier shall appear in the decl-specifier-seq + // of a friend declaration. + if (isFriendSpecified() && getStorageClassSpec()) { + DeclSpec::SCS SC = getStorageClassSpec(); + const char *SpecName = getSpecifierName(SC); + + SourceLocation SCLoc = getStorageClassSpecLoc(); + SourceLocation SCEndLoc = SCLoc.getFileLocWithOffset(strlen(SpecName)); + + Diag(D, SCLoc, SrcMgr, diag::err_friend_storage_spec) + << SpecName + << FixItHint::CreateRemoval(SourceRange(SCLoc, SCEndLoc)); + + ClearStorageClassSpecs(); + } + + + // 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; +} + +void UnqualifiedId::clear() { + if (Kind == IK_TemplateId) + TemplateId->Destroy(); + + Kind = IK_Identifier; + Identifier = 0; + StartLocation = SourceLocation(); + EndLocation = SourceLocation(); +} + +void UnqualifiedId::setOperatorFunctionId(SourceLocation OperatorLoc, + OverloadedOperatorKind Op, + SourceLocation SymbolLocations[3]) { + Kind = IK_OperatorFunctionId; + StartLocation = OperatorLoc; + EndLocation = OperatorLoc; + OperatorFunctionId.Operator = Op; + for (unsigned I = 0; I != 3; ++I) { + OperatorFunctionId.SymbolLocations[I] = SymbolLocations[I].getRawEncoding(); + + if (SymbolLocations[I].isValid()) + EndLocation = SymbolLocations[I]; + } +} diff --git a/contrib/llvm/tools/clang/lib/Parse/Makefile b/contrib/llvm/tools/clang/lib/Parse/Makefile new file mode 100644 index 0000000..6a5540f --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Parse/Makefile @@ -0,0 +1,21 @@ +##===- 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 + +CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include + +include $(LEVEL)/Makefile.common + diff --git a/contrib/llvm/tools/clang/lib/Parse/MinimalAction.cpp b/contrib/llvm/tools/clang/lib/Parse/MinimalAction.cpp new file mode 100644 index 0000000..b720516 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Parse/MinimalAction.cpp @@ -0,0 +1,281 @@ +//===--- 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() {} + +Action::ObjCMessageKind Action::getObjCMessageKind(Scope *S, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool IsSuper, + bool HasTrailingDot, + TypeTy *&ReceiverType) { + ReceiverType = 0; + + if (IsSuper && !HasTrailingDot && S->isInObjcMethodScope()) + return ObjCSuperMessage; + + if (TypeTy *TyName = getTypeName(*Name, NameLoc, S)) { + DeclSpec DS; + const char *PrevSpec = 0; + unsigned DiagID = 0; + if (!DS.SetTypeSpecType(DeclSpec::TST_typename, NameLoc, PrevSpec, + DiagID, TyName)) { + DS.SetRangeEnd(NameLoc); + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + TypeResult Ty = ActOnTypeName(S, DeclaratorInfo); + if (!Ty.isInvalid()) + ReceiverType = Ty.get(); + } + return ObjCClassMessage; + } + + return ObjCInstanceMessage; +} + +// Defined out-of-line here because of dependecy on AttributeList +Action::DeclPtrTy Action::ActOnUsingDirective(Scope *CurScope, + SourceLocation UsingLoc, + SourceLocation NamespcLoc, + 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(); +} + +// Defined out-of-line here because of dependency on AttributeList +Action::DeclPtrTy Action::ActOnUsingDeclaration(Scope *CurScope, + AccessSpecifier AS, + bool HasUsingKeyword, + SourceLocation UsingLoc, + CXXScopeSpec &SS, + UnqualifiedId &Name, + AttributeList *AttrList, + bool IsTypeName, + SourceLocation TypenameLoc) { + + // 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, CXXScopeSpec *SS, + bool isClassName, TypeTy *ObjectType) { + 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(Scope *S, + CXXScopeSpec &SS, + UnqualifiedId &Name, + TypeTy *ObjectType, + bool EnteringScope, + TemplateTy &TemplateDecl, + bool &MemberOfUnknownSpecialization) { + MemberOfUnknownSpecialization = false; + 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, + const SourceLocation *ProtoLocs, + 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, + SourceLocation *IdentLocs, + 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/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp new file mode 100644 index 0000000..5405c0c --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -0,0 +1,333 @@ +//===--- 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, + const ParsedTemplateInfo &TemplateInfo) { + 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'!"); + + Action::MultiTemplateParamsArg TemplateParams(Actions, + TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0, + TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0); + + DeclPtrTy FnD; + if (D.getDeclSpec().isFriendSpecified()) + // FIXME: Friend templates + FnD = Actions.ActOnFriendFunctionDecl(CurScope, D, true, + move(TemplateParams)); + else // FIXME: pass template information through + FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, + move(TemplateParams), 0, 0, + /*IsDefinition*/true); + + HandleMemberFunctionDefaultArgs(D, FnD); + + // Consume the tokens and store them for later parsing. + + getCurrentClass().MethodDefs.push_back(LexedMethod(FnD)); + getCurrentClass().MethodDefs.back().TemplateScope + = CurScope->isTemplateParamScope(); + 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, Toks)) { + // 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, Toks, /*StopAtSemi=*/false); + + // 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, Toks, /*StopAtSemi=*/false); + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); + } + } + + 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); + + // The current scope is still active if we're the top-level class. + // Otherwise we'll need to push and enter a new scope. + bool HasClassScope = !Class.TopLevelClass; + ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, + HasClassScope); + if (HasClassScope) + Actions.ActOnStartDelayedMemberDeclarations(CurScope, Class.TagOrTemplate); + + for (; !Class.MethodDecls.empty(); Class.MethodDecls.pop_front()) { + LateParsedMethodDeclaration &LM = Class.MethodDecls.front(); + + // If this is a member template, introduce the template parameter scope. + ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); + if (LM.TemplateScope) + Actions.ActOnReenterTemplateScope(CurScope, LM.Method); + + // 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) { + // Save the current token position. + SourceLocation origLoc = Tok.getLocation(); + + // 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)); + + assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, + Tok.getLocation()) && + "ParseAssignmentExpression went over the default arg tokens!"); + // There could be leftover tokens (e.g. because of an error). + // Skip through until we reach the original token position. + while (Tok.getLocation() != origLoc) + ConsumeAnyToken(); + + 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]); + + if (HasClassScope) + Actions.ActOnFinishDelayedMemberDeclarations(CurScope, Class.TagOrTemplate); +} + +/// 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(); + + // If this is a member template, introduce the template parameter scope. + ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); + if (LM.TemplateScope) + Actions.ActOnReenterTemplateScope(CurScope, LM.D); + + // Save the current token position. + SourceLocation origLoc = Tok.getLocation(); + + 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.data(), 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); + assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, + Tok.getLocation()) && + "ParseFunctionTryBlock went over the cached tokens!"); + assert(Tok.getLocation() == origLoc && + "ParseFunctionTryBlock left tokens in the token stream!"); + continue; + } + if (Tok.is(tok::colon)) { + ParseConstructorInitializer(LM.D); + + // Error recovery. + if (!Tok.is(tok::l_brace)) { + Actions.ActOnFinishFunctionBody(LM.D, Action::StmtArg(Actions)); + continue; + } + } else + Actions.ActOnDefaultCtorInitializers(LM.D); + + ParseFunctionStatementBody(LM.D); + assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, + Tok.getLocation()) && + "We consumed more than the cached tokens!"); + assert(Tok.getLocation() == origLoc && + "Tokens were left in the token stream!"); + } + + 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 StopAtSemi is true, then we will stop early at a ';' character. +/// 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, + bool StopAtSemi, 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; + } + + 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, Toks, /*StopAtSemi=*/false); + break; + case tok::l_square: + // Recursively consume properly-nested square brackets. + Toks.push_back(Tok); + ConsumeBracket(); + ConsumeAndStoreUntil(tok::r_square, Toks, /*StopAtSemi=*/false); + break; + case tok::l_brace: + // Recursively consume properly-nested braces. + Toks.push_back(Tok); + ConsumeBrace(); + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/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 && !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; + case tok::semi: + if (StopAtSemi) + return false; + // FALL THROUGH. + default: + // consume this token. + Toks.push_back(Tok); + ConsumeToken(); + break; + } + isFirstTokenConsumed = false; + } +} diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp new file mode 100644 index 0000000..3e7d4a1 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp @@ -0,0 +1,3468 @@ +//===--- 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 "clang/Parse/Template.h" +#include "RAIIObjectsForParser.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); +} + +/// ParseGNUAttributes - 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::ParseGNUAttributes(SourceLocation *EndLoc) { + assert(Tok.is(tok::kw___attribute) && "Not a GNU 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 "parameterized" 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, 0, 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, 0, + AttrNameLoc, ParmName, ParmLoc, + ArgExprs.take(), ArgExprs.size(), + CurrAttr); + } + } + } else { // not an identifier + switch (Tok.getKind()) { + case tok::r_paren: + // parse a possibly empty comma separated list of expressions + // __attribute__(( nonnull() )) + ConsumeParen(); // ignore the right paren loc for now + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0, CurrAttr); + break; + case tok::kw_char: + case tok::kw_wchar_t: + case tok::kw_char16_t: + case tok::kw_char32_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_typeof: + // If it's a builtin type name, eat it and expect a rparen + // __attribute__(( vec_type_hint(char) )) + ConsumeToken(); + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0, CurrAttr); + if (Tok.is(tok::r_paren)) + ConsumeParen(); + break; + default: + // __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, + AttrNameLoc, 0, SourceLocation(), ArgExprs.take(), + ArgExprs.size(), + CurrAttr); + } + break; + } + } + } else { + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, 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; +} + +/// ParseMicrosoftDeclSpec - Parse an __declspec construct +/// +/// [MS] decl-specifier: +/// __declspec ( extended-decl-modifier-seq ) +/// +/// [MS] extended-decl-modifier-seq: +/// extended-decl-modifier[opt] +/// extended-decl-modifier extended-decl-modifier-seq + +AttributeList* Parser::ParseMicrosoftDeclSpec(AttributeList *CurrAttr) { + assert(Tok.is(tok::kw___declspec) && "Not a declspec!"); + + ConsumeToken(); + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, + "declspec")) { + SkipUntil(tok::r_paren, true); // skip until ) or ; + return CurrAttr; + } + while (Tok.getIdentifierInfo()) { + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + SourceLocation AttrNameLoc = ConsumeToken(); + if (Tok.is(tok::l_paren)) { + ConsumeParen(); + // FIXME: This doesn't parse __declspec(property(get=get_func_name)) + // correctly. + OwningExprResult ArgExpr(ParseAssignmentExpression()); + if (!ArgExpr.isInvalid()) { + ExprTy* ExprList = ArgExpr.take(); + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, + SourceLocation(), &ExprList, 1, + CurrAttr, true); + } + if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) + SkipUntil(tok::r_paren, false); + } else { + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0, CurrAttr, true); + } + } + if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) + SkipUntil(tok::r_paren, false); + return CurrAttr; +} + +AttributeList* Parser::ParseMicrosoftTypeAttributes(AttributeList *CurrAttr) { + // Treat these like attributes + // FIXME: Allow Sema to distinguish between these and real attributes! + while (Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___stdcall) || + Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___cdecl) || + Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64)) { + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + SourceLocation AttrNameLoc = ConsumeToken(); + if (Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64)) + // FIXME: Support these properly! + continue; + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, + SourceLocation(), 0, 0, CurrAttr, true); + } + return CurrAttr; +} + +/// 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 +/// [C++0x] static_assert-declaration +/// others... [FIXME] +/// +Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context, + SourceLocation &DeclEnd, + CXX0XAttributeList Attr) { + DeclPtrTy SingleDecl; + switch (Tok.getKind()) { + case tok::kw_template: + case tok::kw_export: + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; + SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd); + break; + case tok::kw_namespace: + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; + SingleDecl = ParseNamespace(Context, DeclEnd); + break; + case tok::kw_using: + SingleDecl = ParseUsingDirectiveOrDeclaration(Context, DeclEnd, Attr); + break; + case tok::kw_static_assert: + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; + SingleDecl = ParseStaticAssertDeclaration(DeclEnd); + break; + default: + return ParseSimpleDeclaration(Context, DeclEnd, Attr.AttrList, true); + } + + // 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. If it is true, it checks for and eats it. +Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context, + SourceLocation &DeclEnd, + AttributeList *Attr, + bool RequireSemi) { + // Parse the common declaration-specifiers piece. + ParsingDeclSpec DS(*this); + if (Attr) + DS.AddAttributes(Attr); + ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, + getDeclSpecContextFromDeclaratorContext(Context)); + + // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" + // declaration-specifiers init-declarator-list[opt] ';' + if (Tok.is(tok::semi)) { + if (RequireSemi) ConsumeToken(); + DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, AS_none, + DS); + DS.complete(TheDecl); + return Actions.ConvertDeclToDeclGroup(TheDecl); + } + + return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd); +} + +/// ParseDeclGroup - Having concluded that this is either a function +/// definition or a group of object declarations, actually parse the +/// result. +Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, + unsigned Context, + bool AllowFunctionDefinitions, + SourceLocation *DeclEnd) { + // Parse the first declarator. + ParsingDeclarator D(*this, DS, static_cast<Declarator::TheContext>(Context)); + ParseDeclarator(D); + + // Bail out if the first declarator didn't seem well-formed. + if (!D.hasName() && !D.mayOmitIdentifier()) { + // Skip until ; or }. + SkipUntil(tok::r_brace, true, true); + if (Tok.is(tok::semi)) + ConsumeToken(); + return DeclGroupPtrTy(); + } + + if (AllowFunctionDefinitions && D.isFunctionDeclarator()) { + if (isDeclarationAfterDeclarator()) { + // Fall though. We have to check this first, though, because + // __attribute__ might be the start of a function definition in + // (extended) K&R C. + } else if (isStartOfFunctionDefinition()) { + if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { + Diag(Tok, diag::err_function_declared_typedef); + + // Recover by treating the 'typedef' as spurious. + DS.ClearStorageClassSpecs(); + } + + DeclPtrTy TheDecl = ParseFunctionDefinition(D); + return Actions.ConvertDeclToDeclGroup(TheDecl); + } else { + Diag(Tok, diag::err_expected_fn_body); + SkipUntil(tok::semi); + return DeclGroupPtrTy(); + } + } + + llvm::SmallVector<DeclPtrTy, 8> DeclsInGroup; + DeclPtrTy FirstDecl = ParseDeclarationAfterDeclarator(D); + D.complete(FirstDecl); + if (FirstDecl.get()) + DeclsInGroup.push_back(FirstDecl); + + // If we don't have a comma, it is either the end of the list (a ';') or an + // error, bail out. + while (Tok.is(tok::comma)) { + // Consume the comma. + ConsumeToken(); + + // 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 = ParseGNUAttributes(&Loc); + D.AddAttributes(AttrList, Loc); + } + + ParseDeclarator(D); + + DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(D); + D.complete(ThisDecl); + if (ThisDecl.get()) + DeclsInGroup.push_back(ThisDecl); + } + + if (DeclEnd) + *DeclEnd = Tok.getLocation(); + + if (Context != Declarator::ForContext && + ExpectAndConsume(tok::semi, + Context == Declarator::FileContext + ? diag::err_invalid_token_after_toplevel_declarator + : diag::err_expected_semi_declaration)) { + SkipUntil(tok::r_brace, true, true); + if (Tok.is(tok::semi)) + ConsumeToken(); + } + + return Actions.FinalizeDeclaratorGroup(CurScope, DS, + DeclsInGroup.data(), + DeclsInGroup.size()); +} + +/// \brief Parse 'declaration' after parsing 'declaration-specifiers +/// 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, + const ParsedTemplateInfo &TemplateInfo) { + // 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 = ParseGNUAttributes(&Loc); + D.AddAttributes(AttrList, Loc); + } + + // Inform the current actions module that we just parsed this declarator. + DeclPtrTy ThisDecl; + switch (TemplateInfo.Kind) { + case ParsedTemplateInfo::NonTemplate: + ThisDecl = Actions.ActOnDeclarator(CurScope, D); + break; + + case ParsedTemplateInfo::Template: + case ParsedTemplateInfo::ExplicitSpecialization: + ThisDecl = Actions.ActOnTemplateDeclarator(CurScope, + Action::MultiTemplateParamsArg(Actions, + TemplateInfo.TemplateParams->data(), + TemplateInfo.TemplateParams->size()), + D); + break; + + case ParsedTemplateInfo::ExplicitInstantiation: { + Action::DeclResult ThisRes + = Actions.ActOnExplicitInstantiation(CurScope, + TemplateInfo.ExternLoc, + TemplateInfo.TemplateLoc, + D); + if (ThisRes.isInvalid()) { + SkipUntil(tok::semi, true, true); + return DeclPtrTy(); + } + + ThisDecl = ThisRes.get(); + break; + } + } + + // 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 { + if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { + EnterScope(0); + Actions.ActOnCXXEnterDeclInitializer(CurScope, ThisDecl); + } + + OwningExprResult Init(ParseInitializer()); + + if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { + Actions.ActOnCXXExitDeclInitializer(CurScope, ThisDecl); + ExitScope(); + } + + if (Init.isInvalid()) { + SkipUntil(tok::comma, true, true); + Actions.ActOnInitializerError(ThisDecl); + } else + Actions.AddInitializerToDecl(ThisDecl, move(Init)); + } + } else if (Tok.is(tok::l_paren)) { + // Parse C++ direct initializer: '(' expression-list ')' + SourceLocation LParenLoc = ConsumeParen(); + ExprVector Exprs(Actions); + CommaLocsTy CommaLocs; + + if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { + EnterScope(0); + Actions.ActOnCXXEnterDeclInitializer(CurScope, ThisDecl); + } + + if (ParseExpressionList(Exprs, CommaLocs)) { + SkipUntil(tok::r_paren); + + if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { + Actions.ActOnCXXExitDeclInitializer(CurScope, ThisDecl); + ExitScope(); + } + } else { + // Match the ')'. + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + + assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() && + "Unexpected number of commas!"); + + if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { + Actions.ActOnCXXExitDeclInitializer(CurScope, ThisDecl); + ExitScope(); + } + + Actions.AddCXXDirectInitializerToDecl(ThisDecl, LParenLoc, + move_arg(Exprs), + CommaLocs.data(), RParenLoc); + } + } else { + bool TypeContainsUndeducedAuto = + D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; + Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsUndeducedAuto); + } + + return ThisDecl; +} + +/// 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 << getLang().CPlusPlus + << FixItHint::CreateInsertion(Tok.getLocation(),TagName); + + // Parse this as a tag as if the missing tag were present. + if (TagKind == tok::kw_enum) + ParseEnumSpecifier(Loc, DS, TemplateInfo, AS); + else + ParseClassSpecifier(TagKind, Loc, DS, TemplateInfo, AS); + return true; + } + } + + // This is almost certainly an invalid type name. Let the action emit a + // diagnostic and attempt to recover. + Action::TypeTy *T = 0; + if (Actions.DiagnoseUnknownTypeName(*Tok.getIdentifierInfo(), Loc, + CurScope, SS, T)) { + // The action emitted a diagnostic, so we don't have to. + if (T) { + // The action has suggested that the type T could be used. Set that as + // the type in the declaration specifiers, consume the would-be type + // name token, and we're done. + const char *PrevSpec; + unsigned DiagID; + DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, T, + false); + DS.SetRangeEnd(Tok.getLocation()); + ConsumeToken(); + + // There may be other declaration specifiers after this. + return true; + } + + // Fall through; the action had no suggestion for us. + } else { + // The action did not emit a diagnostic, so emit one now. + SourceRange R; + if (SS) R = SS->getRange(); + Diag(Loc, diag::err_unknown_typename) << Tok.getIdentifierInfo() << R; + } + + // Mark this as an error. + const char *PrevSpec; + unsigned DiagID; + DS.SetTypeSpecType(DeclSpec::TST_error, Loc, PrevSpec, DiagID); + 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; +} + +/// \brief Determine the declaration specifier context from the declarator +/// context. +/// +/// \param Context the declarator context, which is one of the +/// Declarator::TheContext enumerator values. +Parser::DeclSpecContext +Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) { + if (Context == Declarator::MemberContext) + return DSC_class; + if (Context == Declarator::FileContext) + return DSC_top_level; + return DSC_normal; +} + +/// 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] +/// 'constexpr': [C++0x dcl.constexpr] + +/// +void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, + const ParsedTemplateInfo &TemplateInfo, + AccessSpecifier AS, + DeclSpecContext DSContext) { + if (Tok.is(tok::code_completion)) { + Action::CodeCompletionContext CCC = Action::CCC_Namespace; + if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) + CCC = DSContext == DSC_class? Action::CCC_MemberTemplate + : Action::CCC_Template; + else if (DSContext == DSC_class) + CCC = Action::CCC_Class; + else if (ObjCImpDecl) + CCC = Action::CCC_ObjCImplementation; + + Actions.CodeCompleteOrdinaryName(CurScope, CCC); + ConsumeCodeCompletionToken(); + } + + DS.SetRangeStart(Tok.getLocation()); + while (1) { + bool isInvalid = false; + const char *PrevSpec = 0; + unsigned DiagID = 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 + // C++ scope specifier. Annotate and loop, or bail out on error. + if (TryAnnotateCXXScopeToken(true)) { + if (!DS.hasTypeSpecifier()) + DS.SetTypeSpecError(); + goto DoneWithDeclSpec; + } + if (Tok.is(tok::coloncolon)) // ::new or ::delete + goto DoneWithDeclSpec; + continue; + + case tok::annot_cxxscope: { + if (DS.hasTypeSpecifier()) + goto DoneWithDeclSpec; + + CXXScopeSpec SS; + SS.setScopeRep(Tok.getAnnotationValue()); + SS.setRange(Tok.getAnnotationRange()); + + // 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> + + // C++ [class.qual]p2: + // In a lookup in which the constructor is an acceptable lookup + // result and the nested-name-specifier nominates a class C: + // + // - if the name specified after the + // nested-name-specifier, when looked up in C, is the + // injected-class-name of C (Clause 9), or + // + // - if the name specified after the nested-name-specifier + // is the same as the identifier or the + // simple-template-id's template-name in the last + // component of the nested-name-specifier, + // + // the name is instead considered to name the constructor of + // class C. + // + // Thus, if the template-name is actually the constructor + // name, then the code is ill-formed; this interpretation is + // reinforced by the NAD status of core issue 635. + TemplateIdAnnotation *TemplateId + = static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue()); + if ((DSContext == DSC_top_level || + (DSContext == DSC_class && DS.isFriendSpecified())) && + TemplateId->Name && + Actions.isCurrentClassName(*TemplateId->Name, CurScope, &SS)) { + if (isConstructorDeclarator()) { + // The user meant this to be an out-of-line constructor + // definition, but template arguments are not allowed + // there. Just allow this as a constructor; we'll + // complain about it later. + goto DoneWithDeclSpec; + } + + // The user meant this to name a type, but it actually names + // a constructor with some extraneous template + // arguments. Complain, then parse it as a type as the user + // intended. + Diag(TemplateId->TemplateNameLoc, + diag::err_out_of_line_template_id_names_constructor) + << TemplateId->Name; + } + + DS.getTypeSpecScope() = SS; + ConsumeToken(); // The C++ scope. + assert(Tok.is(tok::annot_template_id) && + "ParseOptionalCXXScopeSpecifier not working"); + AnnotateTemplateIdTokenAsType(&SS); + continue; + } + + if (Next.is(tok::annot_typename)) { + DS.getTypeSpecScope() = SS; + ConsumeToken(); // The C++ scope. + if (Tok.getAnnotationValue()) + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, + PrevSpec, DiagID, + Tok.getAnnotationValue()); + else + DS.SetTypeSpecError(); + DS.SetRangeEnd(Tok.getAnnotationEndLoc()); + ConsumeToken(); // The typename + } + + if (Next.isNot(tok::identifier)) + goto DoneWithDeclSpec; + + // If we're in a context where the identifier could be a class name, + // check whether this is a constructor declaration. + if ((DSContext == DSC_top_level || + (DSContext == DSC_class && DS.isFriendSpecified())) && + Actions.isCurrentClassName(*Next.getIdentifierInfo(), CurScope, + &SS)) { + if (isConstructorDeclarator()) + goto DoneWithDeclSpec; + + // As noted in C++ [class.qual]p2 (cited above), when the name + // of the class is qualified in a context where it could name + // a constructor, its a constructor name. However, we've + // looked at the declarator, and the user probably meant this + // to be a type. Complain that it isn't supposed to be treated + // as a type, then proceed to parse it as a type. + Diag(Next.getLocation(), diag::err_out_of_line_type_names_constructor) + << Next.getIdentifierInfo(); + } + + 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; + } + + DS.getTypeSpecScope() = SS; + ConsumeToken(); // The C++ scope. + + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, + DiagID, 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, + DiagID, Tok.getAnnotationValue()); + else + DS.SetTypeSpecError(); + + if (isInvalid) + break; + + 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 LAngleLoc, EndProtoLoc; + llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl; + llvm::SmallVector<SourceLocation, 8> ProtocolLocs; + ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, + LAngleLoc, EndProtoLoc); + DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), + ProtocolLocs.data(), LAngleLoc); + + 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) { + if (TryAnnotateCXXScopeToken(true)) { + if (!DS.hasTypeSpecifier()) + DS.SetTypeSpecError(); + goto DoneWithDeclSpec; + } + if (!Tok.is(tok::identifier)) + 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; + + // Check for need to substitute AltiVec keyword tokens. + if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid)) + break; + + // 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; + } + + // If we're in a context where the identifier could be a class name, + // check whether this is a constructor declaration. + if (getLang().CPlusPlus && DSContext == DSC_class && + Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope) && + isConstructorDeclarator()) + goto DoneWithDeclSpec; + + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, + DiagID, 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 LAngleLoc, EndProtoLoc; + llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl; + llvm::SmallVector<SourceLocation, 8> ProtocolLocs; + ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, + LAngleLoc, EndProtoLoc); + DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), + ProtocolLocs.data(), LAngleLoc); + + 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; + } + + // If we're in a context where the template-id could be a + // constructor name or specialization, check whether this is a + // constructor declaration. + if (getLang().CPlusPlus && DSContext == DSC_class && + Actions.isCurrentClassName(*TemplateId->Name, CurScope) && + isConstructorDeclarator()) + 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(ParseGNUAttributes()); + continue; + + // Microsoft declspec support. + case tok::kw___declspec: + DS.AddAttributes(ParseMicrosoftDeclSpec()); + continue; + + // Microsoft single token adornments. + case tok::kw___forceinline: + // FIXME: Add handling here! + break; + + case tok::kw___ptr64: + case tok::kw___w64: + case tok::kw___cdecl: + case tok::kw___stdcall: + case tok::kw___fastcall: + case tok::kw___thiscall: + DS.AddAttributes(ParseMicrosoftTypeAttributes()); + continue; + + // storage-class-specifier + case tok::kw_typedef: + isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Loc, PrevSpec, + DiagID); + break; + case tok::kw_extern: + if (DS.isThreadSpecified()) + Diag(Tok, diag::ext_thread_before) << "extern"; + isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_extern, Loc, PrevSpec, + DiagID); + break; + case tok::kw___private_extern__: + isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_private_extern, Loc, + PrevSpec, DiagID); + break; + case tok::kw_static: + if (DS.isThreadSpecified()) + Diag(Tok, diag::ext_thread_before) << "static"; + isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_static, Loc, PrevSpec, + DiagID); + break; + case tok::kw_auto: + if (getLang().CPlusPlus0x) + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, + DiagID); + else + isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec, + DiagID); + break; + case tok::kw_register: + isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, Loc, PrevSpec, + DiagID); + break; + case tok::kw_mutable: + isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_mutable, Loc, PrevSpec, + DiagID); + break; + case tok::kw___thread: + isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec, DiagID); + break; + + // function-specifier + case tok::kw_inline: + isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec, DiagID); + break; + case tok::kw_virtual: + isInvalid = DS.SetFunctionSpecVirtual(Loc, PrevSpec, DiagID); + break; + case tok::kw_explicit: + isInvalid = DS.SetFunctionSpecExplicit(Loc, PrevSpec, DiagID); + break; + + // friend + case tok::kw_friend: + if (DSContext == DSC_class) + isInvalid = DS.SetFriendSpec(Loc, PrevSpec, DiagID); + else { + PrevSpec = ""; // not actually used by the diagnostic + DiagID = diag::err_friend_invalid_in_context; + isInvalid = true; + } + break; + + // constexpr + case tok::kw_constexpr: + isInvalid = DS.SetConstexprSpec(Loc, PrevSpec, DiagID); + break; + + // type-specifier + case tok::kw_short: + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, + DiagID); + break; + case tok::kw_long: + if (DS.getTypeSpecWidth() != DeclSpec::TSW_long) + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec, + DiagID); + else + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, + DiagID); + break; + case tok::kw_signed: + isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, + DiagID); + break; + case tok::kw_unsigned: + isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec, + DiagID); + break; + case tok::kw__Complex: + isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec, + DiagID); + break; + case tok::kw__Imaginary: + isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec, + DiagID); + break; + case tok::kw_void: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, + DiagID); + break; + case tok::kw_char: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, + DiagID); + break; + case tok::kw_int: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, + DiagID); + break; + case tok::kw_float: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, + DiagID); + break; + case tok::kw_double: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, + DiagID); + break; + case tok::kw_wchar_t: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, + DiagID); + break; + case tok::kw_char16_t: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec, + DiagID); + break; + case tok::kw_char32_t: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec, + DiagID); + break; + case tok::kw_bool: + case tok::kw__Bool: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, + DiagID); + break; + case tok::kw__Decimal32: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec, + DiagID); + break; + case tok::kw__Decimal64: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec, + DiagID); + break; + case tok::kw__Decimal128: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec, + DiagID); + break; + case tok::kw___vector: + isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); + break; + case tok::kw___pixel: + isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID); + 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, TemplateInfo, AS); + continue; + + // cv-qualifier: + case tok::kw_const: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec, DiagID, + getLang()); + break; + case tok::kw_volatile: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID, + getLang()); + break; + case tok::kw_restrict: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID, + getLang()); + break; + + // C++ typename-specifier: + case tok::kw_typename: + if (TryAnnotateTypeOrScopeToken()) { + DS.SetTypeSpecError(); + goto DoneWithDeclSpec; + } + if (!Tok.is(tok::kw_typename)) + continue; + break; + + // GNU typeof support. + case tok::kw_typeof: + ParseTypeofSpecifier(DS); + continue; + + case tok::kw_decltype: + ParseDecltypeSpecifier(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 LAngleLoc, EndProtoLoc; + llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl; + llvm::SmallVector<SourceLocation, 8> ProtocolLocs; + ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, + LAngleLoc, EndProtoLoc); + DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), + ProtocolLocs.data(), LAngleLoc); + DS.SetRangeEnd(EndProtoLoc); + + Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id) + << FixItHint::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 wasn't legal, issue a diagnostic. + if (isInvalid) { + assert(PrevSpec && "Method did not return previous specifier!"); + assert(DiagID); + 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] +/// [C++0x] 'decltype' ( expression ) +/// [AltiVec] '__vector' +bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, + const char *&PrevSpec, + unsigned &DiagID, + const ParsedTemplateInfo &TemplateInfo, + bool SuppressDeclarations) { + SourceLocation Loc = Tok.getLocation(); + + switch (Tok.getKind()) { + case tok::identifier: // foo::bar + // If we already have a type specifier, this identifier is not a type. + if (DS.getTypeSpecType() != DeclSpec::TST_unspecified || + DS.getTypeSpecWidth() != DeclSpec::TSW_unspecified || + DS.getTypeSpecSign() != DeclSpec::TSS_unspecified) + return false; + // Check for need to substitute AltiVec keyword tokens. + if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid)) + break; + // Fall through. + 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 true; + if (Tok.is(tok::identifier)) + return false; + return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, + TemplateInfo, SuppressDeclarations); + 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 true; + return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, + TemplateInfo, SuppressDeclarations); + + // simple-type-specifier: + case tok::annot_typename: { + if (Tok.getAnnotationValue()) + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, + DiagID, 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 LAngleLoc, EndProtoLoc; + llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl; + llvm::SmallVector<SourceLocation, 8> ProtocolLocs; + ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, + LAngleLoc, EndProtoLoc); + DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), + ProtocolLocs.data(), LAngleLoc); + + DS.SetRangeEnd(EndProtoLoc); + return true; + } + + case tok::kw_short: + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, DiagID); + break; + case tok::kw_long: + if (DS.getTypeSpecWidth() != DeclSpec::TSW_long) + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec, + DiagID); + else + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, + DiagID); + break; + case tok::kw_signed: + isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID); + break; + case tok::kw_unsigned: + isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec, + DiagID); + break; + case tok::kw__Complex: + isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec, + DiagID); + break; + case tok::kw__Imaginary: + isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec, + DiagID); + break; + case tok::kw_void: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID); + break; + case tok::kw_char: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID); + break; + case tok::kw_int: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID); + break; + case tok::kw_float: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID); + break; + case tok::kw_double: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID); + break; + case tok::kw_wchar_t: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID); + break; + case tok::kw_char16_t: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec, DiagID); + break; + case tok::kw_char32_t: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec, DiagID); + break; + case tok::kw_bool: + case tok::kw__Bool: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID); + break; + case tok::kw__Decimal32: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec, + DiagID); + break; + case tok::kw__Decimal64: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec, + DiagID); + break; + case tok::kw__Decimal128: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec, + DiagID); + break; + case tok::kw___vector: + isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); + break; + case tok::kw___pixel: + isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID); + 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_none, + SuppressDeclarations); + return true; + } + + // enum-specifier: + case tok::kw_enum: + ConsumeToken(); + ParseEnumSpecifier(Loc, DS, TemplateInfo, AS_none); + return true; + + // cv-qualifier: + case tok::kw_const: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, + DiagID, getLang()); + break; + case tok::kw_volatile: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, + DiagID, getLang()); + break; + case tok::kw_restrict: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, + DiagID, getLang()); + break; + + // GNU typeof support. + case tok::kw_typeof: + ParseTypeofSpecifier(DS); + return true; + + // C++0x decltype support. + case tok::kw_decltype: + ParseDecltypeSpecifier(DS); + return true; + + // C++0x auto support. + case tok::kw_auto: + if (!getLang().CPlusPlus0x) + return false; + + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID); + break; + case tok::kw___ptr64: + case tok::kw___w64: + case tok::kw___cdecl: + case tok::kw___stdcall: + case tok::kw___fastcall: + case tok::kw___thiscall: + DS.AddAttributes(ParseMicrosoftTypeAttributes()); + 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. + 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, FieldCallback &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, AS_none, DS); + return; + } + + // Read struct-declarators until we find the semicolon. + bool FirstDeclarator = true; + while (1) { + ParsingDeclRAIIObject PD(*this); + FieldDeclarator DeclaratorInfo(DS); + + // Attributes are only allowed here on successive declarators. + if (!FirstDeclarator && Tok.is(tok::kw___attribute)) { + SourceLocation Loc; + AttributeList *AttrList = ParseGNUAttributes(&Loc); + DeclaratorInfo.D.AddAttributes(AttrList, Loc); + } + + /// struct-declarator: declarator + /// struct-declarator: declarator[opt] ':' constant-expression + if (Tok.isNot(tok::colon)) { + // Don't parse FOO:BAR as if it were a typo for FOO::BAR. + ColonProtectionRAIIObject X(*this); + 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 = ParseGNUAttributes(&Loc); + DeclaratorInfo.D.AddAttributes(AttrList, Loc); + } + + // We're done with this declarator; invoke the callback. + DeclPtrTy D = Fields.invoke(DeclaratorInfo); + PD.complete(D); + + // If we don't have a comma, it is either the end of the list (a ';') + // or an error, bail out. + if (Tok.isNot(tok::comma)) + return; + + // Consume the comma. + ConsumeToken(); + + FirstDeclarator = false; + } +} + +/// 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; + + // 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) + << FixItHint::CreateRemoval(Tok.getLocation()); + ConsumeToken(); + continue; + } + + // Parse all the comma separated declarators. + DeclSpec DS; + + if (!Tok.is(tok::at)) { + struct CFieldCallback : FieldCallback { + Parser &P; + DeclPtrTy TagDecl; + llvm::SmallVectorImpl<DeclPtrTy> &FieldDecls; + + CFieldCallback(Parser &P, DeclPtrTy TagDecl, + llvm::SmallVectorImpl<DeclPtrTy> &FieldDecls) : + P(P), TagDecl(TagDecl), FieldDecls(FieldDecls) {} + + virtual DeclPtrTy invoke(FieldDeclarator &FD) { + // Install the declarator into the current TagDecl. + DeclPtrTy Field = P.Actions.ActOnField(P.CurScope, TagDecl, + FD.D.getDeclSpec().getSourceRange().getBegin(), + FD.D, FD.BitfieldSize); + FieldDecls.push_back(Field); + return Field; + } + } Callback(*this, TagDecl, FieldDecls); + + ParseStructDeclaration(DS, Callback); + } else { // Handle @defs + ConsumeToken(); + if (!Tok.isObjCAtKeyword(tok::objc_defs)) { + Diag(Tok, diag::err_unexpected_at); + SkipUntil(tok::semi, 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); + 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)) { + ExpectAndConsume(tok::semi, diag::ext_expected_semi_decl_list); + break; + } else { + ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list); + // Skip to end of block or statement to avoid ext-warning on extra ';'. + SkipUntil(tok::r_brace, true, true); + // If we stopped at a ';', eat it. + if (Tok.is(tok::semi)) ConsumeToken(); + } + } + + SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); + + llvm::OwningPtr<AttributeList> AttrList; + // If attributes exist after struct contents, parse them. + if (Tok.is(tok::kw___attribute)) + AttrList.reset(ParseGNUAttributes()); + + Actions.ActOnFields(CurScope, + RecordLoc, TagDecl, FieldDecls.data(), FieldDecls.size(), + LBraceLoc, RBraceLoc, + AttrList.get()); + StructScope.Exit(); + Actions.ActOnTagFinishDefinition(CurScope, TagDecl, RBraceLoc); +} + + +/// 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, + const ParsedTemplateInfo &TemplateInfo, + AccessSpecifier AS) { + // Parse the tag portion of this. + if (Tok.is(tok::code_completion)) { + // Code completion for an enum name. + Actions.CodeCompleteTag(CurScope, DeclSpec::TST_enum); + ConsumeCodeCompletionToken(); + } + + llvm::OwningPtr<AttributeList> Attr; + // If attributes exist after tag, parse them. + if (Tok.is(tok::kw___attribute)) + Attr.reset(ParseGNUAttributes()); + + CXXScopeSpec &SS = DS.getTypeSpecScope(); + if (getLang().CPlusPlus) { + if (ParseOptionalCXXScopeSpecifier(SS, 0, false)) + return; + + if (SS.isSet() && 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::TagUseKind TUK; + if (Tok.is(tok::l_brace)) + TUK = Action::TUK_Definition; + else if (Tok.is(tok::semi)) + TUK = Action::TUK_Declaration; + else + TUK = Action::TUK_Reference; + + // enums cannot be templates, although they can be referenced from a + // template. + if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && + TUK != Action::TUK_Reference) { + Diag(Tok, diag::err_enum_template); + + // Skip the rest of this declarator, up until the comma or semicolon. + SkipUntil(tok::comma, true); + return; + } + + bool Owned = false; + bool IsDependent = false; + SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc; + const char *PrevSpec = 0; + unsigned DiagID; + DeclPtrTy TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TUK, + StartLoc, SS, Name, NameLoc, Attr.get(), + AS, + Action::MultiTemplateParamsArg(Actions), + Owned, IsDependent); + if (IsDependent) { + // This enum has a dependent nested-name-specifier. Handle it as a + // dependent tag. + if (!Name) { + DS.SetTypeSpecError(); + Diag(Tok, diag::err_expected_type_name_after_typename); + return; + } + + TypeResult Type = Actions.ActOnDependentTag(CurScope, DeclSpec::TST_enum, + TUK, SS, Name, StartLoc, + NameLoc); + if (Type.isInvalid()) { + DS.SetTypeSpecError(); + return; + } + + if (DS.SetTypeSpecType(DeclSpec::TST_typename, TSTLoc, PrevSpec, DiagID, + Type.get(), false)) + Diag(StartLoc, DiagID) << PrevSpec; + + return; + } + + if (!TagDecl.get()) { + // The action failed to produce an enumeration tag. If this is a + // definition, consume the entire definition. + if (Tok.is(tok::l_brace)) { + ConsumeBrace(); + SkipUntil(tok::r_brace); + } + + DS.SetTypeSpecError(); + return; + } + + if (Tok.is(tok::l_brace)) + ParseEnumBody(StartLoc, TagDecl); + + // FIXME: The DeclSpec should keep the locations of both the keyword and the + // name (if there is one). + if (DS.SetTypeSpecType(DeclSpec::TST_enum, TSTLoc, PrevSpec, DiagID, + TagDecl.getAs<void>(), Owned)) + Diag(StartLoc, DiagID) << 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 + << FixItHint::CreateRemoval(CommaLoc); + } + + // Eat the }. + SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); + + llvm::OwningPtr<AttributeList> Attr; + // If attributes exist after the identifier list, parse them. + if (Tok.is(tok::kw___attribute)) + Attr.reset(ParseGNUAttributes()); // FIXME: where do they do? + + Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl, + EnumConstantDecls.data(), EnumConstantDecls.size(), + CurScope, Attr.get()); + + EnumScope.Exit(); + Actions.ActOnTagFinishDefinition(CurScope, EnumDecl, RBraceLoc); +} + +/// 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; + } +} + +/// isKnownToBeTypeSpecifier - Return true if we know that the specified token +/// is definitely a type-specifier. Return false if it isn't part of a type +/// specifier or if we're not sure. +bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const { + switch (Tok.getKind()) { + default: return false; + // 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_char16_t: + case tok::kw_char32_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: + case tok::kw___vector: + + // 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: + + // typedef-name + case tok::annot_typename: + 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 + if (TryAltiVecVectorToken()) + return true; + // 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 true; + if (Tok.is(tok::identifier)) + return false; + return isTypeSpecifierQualifier(); + + case tok::coloncolon: // ::foo::bar + if (NextToken().is(tok::kw_new) || // ::new + NextToken().is(tok::kw_delete)) // ::delete + return false; + + if (TryAnnotateTypeOrScopeToken()) + return true; + return isTypeSpecifierQualifier(); + + // 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_char16_t: + case tok::kw_char32_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: + case tok::kw___vector: + + // 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: + case tok::kw___thiscall: + case tok::kw___w64: + case tok::kw___ptr64: + return true; + } +} + +/// 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; + if (TryAltiVecVectorToken()) + return true; + // 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 true; + if (Tok.is(tok::identifier)) + return false; + return isDeclarationSpecifier(); + + 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 true; + return isDeclarationSpecifier(); + + // 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_char16_t: + case tok::kw_char32_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: + case tok::kw___vector: + + // 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: + case tok::kw___thiscall: + case tok::kw___w64: + case tok::kw___ptr64: + case tok::kw___forceinline: + return true; + } +} + +bool Parser::isConstructorDeclarator() { + TentativeParsingAction TPA(*this); + + // Parse the C++ scope specifier. + CXXScopeSpec SS; + if (ParseOptionalCXXScopeSpecifier(SS, 0, true)) { + TPA.Revert(); + return false; + } + + // Parse the constructor name. + if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) { + // We already know that we have a constructor name; just consume + // the token. + ConsumeToken(); + } else { + TPA.Revert(); + return false; + } + + // Current class name must be followed by a left parentheses. + if (Tok.isNot(tok::l_paren)) { + TPA.Revert(); + return false; + } + ConsumeParen(); + + // A right parentheses or ellipsis signals that we have a constructor. + if (Tok.is(tok::r_paren) || Tok.is(tok::ellipsis)) { + TPA.Revert(); + return true; + } + + // If we need to, enter the specified scope. + DeclaratorScopeObj DeclScopeObj(*this, SS); + if (SS.isSet() && Actions.ShouldEnterDeclaratorScope(CurScope, SS)) + DeclScopeObj.EnterDeclaratorScope(); + + // Check whether the next token(s) are part of a declaration + // specifier, in which case we have the start of a parameter and, + // therefore, we know that this is a constructor. + bool IsConstructor = isDeclarationSpecifier(); + TPA.Revert(); + return IsConstructor; +} + +/// 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 ] +/// [C++0x] attribute-specifier[opt] is allowed before cv-qualifier-seq +/// if CXX0XAttributesAllowed = true +/// +void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed, + bool CXX0XAttributesAllowed) { + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { + SourceLocation Loc = Tok.getLocation(); + CXX0XAttributeList Attr = ParseCXX0XAttributes(); + if (CXX0XAttributesAllowed) + DS.AddAttributes(Attr.AttrList); + else + Diag(Loc, diag::err_attributes_not_allowed); + } + + while (1) { + bool isInvalid = false; + const char *PrevSpec = 0; + unsigned DiagID = 0; + SourceLocation Loc = Tok.getLocation(); + + switch (Tok.getKind()) { + case tok::kw_const: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, DiagID, + getLang()); + break; + case tok::kw_volatile: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID, + getLang()); + break; + case tok::kw_restrict: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID, + getLang()); + break; + case tok::kw___w64: + case tok::kw___ptr64: + case tok::kw___cdecl: + case tok::kw___stdcall: + case tok::kw___fastcall: + case tok::kw___thiscall: + if (GNUAttributesAllowed) { + DS.AddAttributes(ParseMicrosoftTypeAttributes()); + continue; + } + goto DoneWithTypeQuals; + case tok::kw___attribute: + if (GNUAttributesAllowed) { + DS.AddAttributes(ParseGNUAttributes()); + 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!"); + 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) { + if (Diags.hasAllExtensionsSilenced()) + D.setExtension(); + // 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; + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true); // ignore fail + + if (SS.isNotEmpty()) { + 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. + // [C++0x] Attributes on references are not allowed. + ParseTypeQualifierListOpt(DS, true, false); + 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 +/// +/// unqualified-id: [C++ 5.1] +/// identifier +/// operator-function-id +/// conversion-function-id +/// '~' class-name +/// template-id +/// +void Parser::ParseDirectDeclarator(Declarator &D) { + DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec()); + + if (getLang().CPlusPlus && D.mayHaveIdentifier()) { + // ParseDeclaratorInternal might already have parsed the scope. + if (D.getCXXScopeSpec().isEmpty()) { + ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0, + true); + } + + if (D.getCXXScopeSpec().isValid()) { + if (Actions.ShouldEnterDeclaratorScope(CurScope, D.getCXXScopeSpec())) + // Change the declaration context for name lookup, until this function + // is exited (and the declarator has been parsed). + DeclScopeObj.EnterDeclaratorScope(); + } + + if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) || + Tok.is(tok::annot_template_id) || Tok.is(tok::tilde)) { + // We found something that indicates the start of an unqualified-id. + // Parse that unqualified-id. + bool AllowConstructorName; + if (D.getDeclSpec().hasTypeSpecifier()) + AllowConstructorName = false; + else if (D.getCXXScopeSpec().isSet()) + AllowConstructorName = + (D.getContext() == Declarator::FileContext || + (D.getContext() == Declarator::MemberContext && + D.getDeclSpec().isFriendSpecified())); + else + AllowConstructorName = (D.getContext() == Declarator::MemberContext); + + if (ParseUnqualifiedId(D.getCXXScopeSpec(), + /*EnteringContext=*/true, + /*AllowDestructorName=*/true, + AllowConstructorName, + /*ObjectType=*/0, + D.getName()) || + // Once we're past the identifier, if the scope was bad, mark the + // whole declarator bad. + D.getCXXScopeSpec().isInvalid()) { + D.SetIdentifier(0, Tok.getLocation()); + D.setInvalidType(true); + } else { + // Parsed the unqualified-id; update range information and move along. + if (D.getSourceRange().getBegin().isInvalid()) + D.SetRangeBegin(D.getName().getSourceRange().getBegin()); + D.SetRangeEnd(D.getName().getSourceRange().getEnd()); + } + goto PastIdentifier; + } + } else if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) { + assert(!getLang().CPlusPlus && + "There's a C++-specific check for tok::identifier above"); + assert(Tok.getIdentifierInfo() && "Not an identifier?"); + D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeToken(); + goto PastIdentifier; + } + + if (Tok.is(tok::l_paren)) { + // direct-declarator: '(' declarator ')' + // direct-declarator: '(' attributes declarator ')' + // Example: 'char (*X)' or 'int (*XX)(void)' + ParseParenDeclarator(D); + + // If the declarator was parenthesized, we entered the declarator + // scope when parsing the parenthesized declarator, then exited + // the scope already. Re-enter the scope, if we need to. + if (D.getCXXScopeSpec().isSet()) { + if (Actions.ShouldEnterDeclaratorScope(CurScope, D.getCXXScopeSpec())) + // Change the declaration context for name lookup, until this function + // is exited (and the declarator has been parsed). + DeclScopeObj.EnterDeclaratorScope(); + } + } 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) << getLang().CPlusPlus; + 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?"); + + // Don't parse attributes unless we have an identifier. + if (D.getIdentifier() && getLang().CPlusPlus0x + && isCXX0XAttributeSpecifier(true)) { + SourceLocation AttrEndLoc; + CXX0XAttributeList Attr = ParseCXX0XAttributes(); + D.AddAttributes(Attr.AttrList, AttrEndLoc); + } + + 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. + // + llvm::OwningPtr<AttributeList> AttrList; + bool RequiresArg = false; + if (Tok.is(tok::kw___attribute)) { + AttrList.reset(ParseGNUAttributes()); + + // 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. + if (Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___stdcall) || + Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___fastcall) || + Tok.is(tok::kw___w64) || Tok.is(tok::kw___ptr64)) { + AttrList.reset(ParseMicrosoftTypeAttributes(AttrList.take())); + } + + // 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.take(), 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.take(), 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 ',' '...' +/// [C++] 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 RParenLoc = ConsumeParen(); // Eat the closing ')'. + SourceLocation EndLoc = RParenLoc; + + // 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()) + EndLoc = DS.getSourceRange().getEnd(); + + // Parse exception-specification[opt]. + if (Tok.is(tok::kw_throw)) { + hasExceptionSpec = true; + ThrowLoc = Tok.getLocation(); + ParseExceptionSpecification(EndLoc, 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, RParenLoc, D), + EndLoc); + 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) + && !TryAltiVecVectorToken()) { + if (TryAnnotateTypeOrScopeToken() || !Tok.is(tok::annot_typename)) { + // 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. Get the first + // identifier. + Token FirstTok = Tok; + ConsumeToken(); // eat the first identifier. + + // Identifier lists follow a really simple grammar: the identifiers can + // be followed *only* by a ", moreidentifiers" or ")". However, K&R + // identifier lists are really rare in the brave new modern world, and it + // is very common for someone to typo a type in a non-k&r style list. If + // we are presented with something like: "void foo(intptr x, float y)", + // we don't want to start parsing the function declarator as though it is + // a K&R style declarator just because intptr is an invalid type. + // + // To handle this, we check to see if the token after the first identifier + // is a "," or ")". Only if so, do we parse it as an identifier list. + if (Tok.is(tok::comma) || Tok.is(tok::r_paren)) + return ParseFunctionDeclaratorIdentifierList(LParenLoc, + FirstTok.getIdentifierInfo(), + FirstTok.getLocation(), D); + + // If we get here, the code is invalid. Push the first identifier back + // into the token stream and parse the first argument as an (invalid) + // normal argument declarator. + PP.EnterToken(Tok); + Tok = FirstTok; + } + } + + // 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. + // Just use the ParsingDeclaration "scope" of the declarator. + 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 = ParseGNUAttributes(&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, + /*StopAtSemi=*/true, + /*ConsumeFinalToken=*/false)) { + delete DefArgToks; + DefArgToks = 0; + Actions.ActOnParamDefaultArgumentError(Param); + } else + Actions.ActOnParamUnparsedDefaultArgument(Param, EqualLoc, + (*DefArgToks)[1].getLocation()); + } 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)) { + if (Tok.is(tok::ellipsis)) { + IsVariadic = true; + EllipsisLoc = ConsumeToken(); // Consume the ellipsis. + + if (!getLang().CPlusPlus) { + // We have ellipsis without a preceding ',', which is ill-formed + // in C. Complain and provide the fix. + Diag(EllipsisLoc, diag::err_missing_comma_before_ellipsis) + << FixItHint::CreateInsertion(EllipsisLoc, ", "); + } + } + + break; + } + + // Consume the comma. + ConsumeToken(); + } + + // Leave prototype scope. + PrototypeScope.Exit(); + + // If we have the closing ')', eat it. + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + SourceLocation EndLoc = RParenLoc; + + 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()) + EndLoc = DS.getSourceRange().getEnd(); + + // Parse exception-specification[opt]. + if (Tok.is(tok::kw_throw)) { + hasExceptionSpec = true; + ThrowLoc = Tok.getLocation(); + ParseExceptionSpecification(EndLoc, 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, RParenLoc, D), + EndLoc); +} + +/// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator +/// we found a K&R-style identifier list instead of a type argument list. The +/// first identifier has already been consumed, and the current token is the +/// token right after it. +/// +/// identifier-list: [C99 6.7.5] +/// identifier +/// identifier-list ',' identifier +/// +void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc, + IdentifierInfo *FirstIdent, + SourceLocation FirstIdentLoc, + 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(FirstIdentLoc, diag::ext_ident_list_in_param); + + // The first identifier was already read, and is known to be the first + // identifier in the list. Remember this identifier in ParamInfo. + ParamsSoFar.insert(FirstIdent); + ParamInfo.push_back(DeclaratorChunk::ParamInfo(FirstIdent, FirstIdentLoc, + DeclPtrTy())); + + 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, RLoc, 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); + //FIXME: Use these + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier(true)) { + Attr = ParseCXX0XAttributes(); + } + + // Remember that we parsed the empty array type. + OwningExprResult NumElements(Actions); + D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0, + StartLoc, EndLoc), + 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); + //FIXME: Use these + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { + Attr = ParseCXX0XAttributes(); + } + + // 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), + 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 constant-expression or assignment-expression now (depending + // on dialect). + if (getLang().CPlusPlus) + NumElements = ParseConstantExpression(); + else + 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); + + //FIXME: Use these + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { + Attr = ParseCXX0XAttributes(); + } + + // Remember that we parsed a array type, and remember its features. + D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(), + StaticLoc.isValid(), isStar, + NumElements.release(), + StartLoc, EndLoc), + 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(); + + const bool hasParens = Tok.is(tok::l_paren); + + bool isCastExpr; + TypeTy *CastTy; + SourceRange CastRange; + OwningExprResult Operand = ParseExprAfterTypeofSizeofAlignof(OpTok, + isCastExpr, + CastTy, + CastRange); + if (hasParens) + DS.setTypeofParensRange(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; + unsigned DiagID; + // Check for duplicate type specifiers (e.g. "int typeof(int)"). + if (DS.SetTypeSpecType(DeclSpec::TST_typeofType, StartLoc, PrevSpec, + DiagID, CastTy)) + Diag(StartLoc, DiagID) << PrevSpec; + return; + } + + // If we get here, the operand to the typeof was an expresion. + if (Operand.isInvalid()) { + DS.SetTypeSpecError(); + return; + } + + const char *PrevSpec = 0; + unsigned DiagID; + // Check for duplicate type specifiers (e.g. "int typeof(int)"). + if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec, + DiagID, Operand.release())) + Diag(StartLoc, DiagID) << PrevSpec; +} + + +/// TryAltiVecVectorTokenOutOfLine - Out of line body that should only be called +/// from TryAltiVecVectorToken. +bool Parser::TryAltiVecVectorTokenOutOfLine() { + Token Next = NextToken(); + switch (Next.getKind()) { + default: return false; + case tok::kw_short: + case tok::kw_long: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw_void: + case tok::kw_char: + case tok::kw_int: + case tok::kw_float: + case tok::kw_double: + case tok::kw_bool: + case tok::kw___pixel: + Tok.setKind(tok::kw___vector); + return true; + case tok::identifier: + if (Next.getIdentifierInfo() == Ident_pixel) { + Tok.setKind(tok::kw___vector); + return true; + } + return false; + } +} + +bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, + bool &isInvalid) { + if (Tok.getIdentifierInfo() == Ident_vector) { + Token Next = NextToken(); + switch (Next.getKind()) { + case tok::kw_short: + case tok::kw_long: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw_void: + case tok::kw_char: + case tok::kw_int: + case tok::kw_float: + case tok::kw_double: + case tok::kw_bool: + case tok::kw___pixel: + isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); + return true; + case tok::identifier: + if (Next.getIdentifierInfo() == Ident_pixel) { + isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); + return true; + } + break; + default: + break; + } + } else if (Tok.getIdentifierInfo() == Ident_pixel && + DS.isTypeAltiVecVector()) { + isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID); + return true; + } + return false; +} + diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp new file mode 100644 index 0000000..479c04c --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp @@ -0,0 +1,2016 @@ +//===--- 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/Basic/OperatorKinds.h" +#include "clang/Parse/Parser.h" +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/DeclSpec.h" +#include "clang/Parse/Scope.h" +#include "clang/Parse/Template.h" +#include "RAIIObjectsForParser.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'. + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteNamespaceDecl(CurScope); + ConsumeCodeCompletionToken(); + } + + SourceLocation IdentLoc; + IdentifierInfo *Ident = 0; + + Token attrTok; + + if (Tok.is(tok::identifier)) { + Ident = Tok.getIdentifierInfo(); + IdentLoc = ConsumeToken(); // eat the identifier. + } + + // Read label attributes, if present. + llvm::OwningPtr<AttributeList> AttrList; + if (Tok.is(tok::kw___attribute)) { + attrTok = Tok; + + // FIXME: save these somewhere. + AttrList.reset(ParseGNUAttributes()); + } + + if (Tok.is(tok::equal)) { + if (AttrList) + Diag(attrTok, diag::err_unexpected_namespace_attributes_alias); + + 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(); + + if (CurScope->isClassScope() || CurScope->isTemplateParamScope() || + CurScope->isInObjcMethodScope() || CurScope->getBlockParent() || + CurScope->getFnParent()) { + Diag(LBrace, diag::err_namespace_nonnamespace_scope); + SkipUntil(tok::r_brace, false); + return DeclPtrTy(); + } + + // Enter a scope for the namespace. + ParseScope NamespaceScope(this, Scope::DeclScope); + + DeclPtrTy NamespcDecl = + Actions.ActOnStartNamespaceDef(CurScope, IdentLoc, Ident, LBrace, + AttrList.get()); + + PrettyStackTraceActionsDecl CrashInfo(NamespcDecl, NamespaceLoc, Actions, + PP.getSourceManager(), + "parsing namespace"); + + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + Attr = ParseCXX0XAttributes(); + ParseExternalDeclaration(Attr); + } + + // 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 '='. + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteNamespaceAliasDecl(CurScope); + ConsumeCodeCompletionToken(); + } + + CXXScopeSpec SS; + // Parse (optional) nested-name-specifier. + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); + + 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(ParsingDeclSpec &DS, + unsigned Context) { + assert(Tok.is(tok::string_literal) && "Not a string literal!"); + llvm::SmallString<8> LangBuffer; + // LangBuffer is guaranteed to be big enough. + bool Invalid = false; + llvm::StringRef Lang = PP.getSpelling(Tok, LangBuffer, &Invalid); + if (Invalid) + return DeclPtrTy(); + + SourceLocation Loc = ConsumeStringToken(); + + ParseScope LinkageScope(this, Scope::DeclScope); + DeclPtrTy LinkageSpec + = Actions.ActOnStartLinkageSpecification(CurScope, + /*FIXME: */SourceLocation(), + Loc, Lang, + Tok.is(tok::l_brace)? Tok.getLocation() + : SourceLocation()); + + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { + Attr = ParseCXX0XAttributes(); + } + + if (Tok.isNot(tok::l_brace)) { + ParseDeclarationOrFunctionDefinition(DS, Attr.AttrList); + return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec, + SourceLocation()); + } + + DS.abort(); + + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; + + SourceLocation LBrace = ConsumeBrace(); + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + Attr = ParseCXX0XAttributes(); + ParseExternalDeclaration(Attr); + } + + 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, + CXX0XAttributeList Attr) { + assert(Tok.is(tok::kw_using) && "Not using token"); + + // Eat 'using'. + SourceLocation UsingLoc = ConsumeToken(); + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteUsing(CurScope); + ConsumeCodeCompletionToken(); + } + + if (Tok.is(tok::kw_namespace)) + // Next token after 'using' is 'namespace' so it must be using-directive + return ParseUsingDirective(Context, UsingLoc, DeclEnd, Attr.AttrList); + + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; + + // Otherwise, it must be using-declaration. + // Ignore illegal attributes (the caller should already have issued an error. + 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, + AttributeList *Attr) { + assert(Tok.is(tok::kw_namespace) && "Not 'namespace' token"); + + // Eat 'namespace'. + SourceLocation NamespcLoc = ConsumeToken(); + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteUsingDirective(CurScope); + ConsumeCodeCompletionToken(); + } + + CXXScopeSpec SS; + // Parse (optional) nested-name-specifier. + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); + + 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). + bool GNUAttr = false; + if (Tok.is(tok::kw___attribute)) { + GNUAttr = true; + Attr = addAttributeLists(Attr, ParseGNUAttributes()); + } + + // Eat ';'. + DeclEnd = Tok.getLocation(); + ExpectAndConsume(tok::semi, + GNUAttr ? diag::err_expected_semi_after_attribute_list : + diag::err_expected_semi_after_namespace_name, "", tok::semi); + + return Actions.ActOnUsingDirective(CurScope, UsingLoc, NamespcLoc, SS, + IdentLoc, NamespcName, Attr); +} + +/// 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 +/// 'using' :: unqualified-id +/// +Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, + SourceLocation UsingLoc, + SourceLocation &DeclEnd, + AccessSpecifier AS) { + CXXScopeSpec SS; + SourceLocation TypenameLoc; + bool IsTypeName; + + // Ignore optional 'typename'. + // FIXME: This is wrong; we should parse this as a typename-specifier. + if (Tok.is(tok::kw_typename)) { + TypenameLoc = Tok.getLocation(); + ConsumeToken(); + IsTypeName = true; + } + else + IsTypeName = false; + + // Parse nested-name-specifier. + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); + + // Check nested-name specifier. + if (SS.isInvalid()) { + SkipUntil(tok::semi); + return DeclPtrTy(); + } + + // Parse the unqualified-id. We allow parsing of both constructor and + // destructor names and allow the action module to diagnose any semantic + // errors. + UnqualifiedId Name; + if (ParseUnqualifiedId(SS, + /*EnteringContext=*/false, + /*AllowDestructorName=*/true, + /*AllowConstructorName=*/true, + /*ObjectType=*/0, + Name)) { + SkipUntil(tok::semi); + return DeclPtrTy(); + } + + // Parse (optional) attributes (most likely GNU strong-using extension). + llvm::OwningPtr<AttributeList> AttrList; + if (Tok.is(tok::kw___attribute)) + AttrList.reset(ParseGNUAttributes()); + + // Eat ';'. + DeclEnd = Tok.getLocation(); + ExpectAndConsume(tok::semi, diag::err_expected_semi_after, + AttrList ? "attributes list" : "using declaration", + tok::semi); + + return Actions.ActOnUsingDeclaration(CurScope, AS, true, UsingLoc, SS, Name, + AttrList.get(), IsTypeName, TypenameLoc); +} + +/// 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)); +} + +/// ParseDecltypeSpecifier - Parse a C++0x decltype specifier. +/// +/// 'decltype' ( expression ) +/// +void Parser::ParseDecltypeSpecifier(DeclSpec &DS) { + assert(Tok.is(tok::kw_decltype) && "Not a decltype specifier"); + + SourceLocation StartLoc = ConsumeToken(); + SourceLocation LParenLoc = Tok.getLocation(); + + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, + "decltype")) { + SkipUntil(tok::r_paren); + return; + } + + // Parse the expression + + // C++0x [dcl.type.simple]p4: + // The operand of the decltype specifier is an unevaluated operand. + EnterExpressionEvaluationContext Unevaluated(Actions, + Action::Unevaluated); + OwningExprResult Result = ParseExpression(); + if (Result.isInvalid()) { + SkipUntil(tok::r_paren); + return; + } + + // Match the ')' + SourceLocation RParenLoc; + if (Tok.is(tok::r_paren)) + RParenLoc = ConsumeParen(); + else + MatchRHSPunctuation(tok::r_paren, LParenLoc); + + if (RParenLoc.isInvalid()) + return; + + const char *PrevSpec = 0; + unsigned DiagID; + // Check for duplicate type specifiers (e.g. "int decltype(a)"). + if (DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec, + DiagID, Result.release())) + Diag(StartLoc, DiagID) << PrevSpec; +} + +/// 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, + 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 || + TemplateId->Kind == TNK_Dependent_template_name) { + 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; + } + + IdentifierInfo *Id = Tok.getIdentifierInfo(); + SourceLocation IdLoc = ConsumeToken(); + + if (Tok.is(tok::less)) { + // It looks the user intended to write a template-id here, but the + // template-name was wrong. Try to fix that. + TemplateNameKind TNK = TNK_Type_template; + TemplateTy Template; + if (!Actions.DiagnoseUnknownTemplateName(*Id, IdLoc, CurScope, + SS, Template, TNK)) { + Diag(IdLoc, diag::err_unknown_template_name) + << Id; + } + + if (!Template) + return true; + + // Form the template name + UnqualifiedId TemplateName; + TemplateName.setIdentifier(Id, IdLoc); + + // Parse the full template-id, then turn it into a type. + if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName, + SourceLocation(), true)) + return true; + if (TNK == TNK_Dependent_template_name) + AnnotateTemplateIdTokenAsType(SS); + + // If we didn't end up with a typename token, there's nothing more we + // can do. + if (Tok.isNot(tok::annot_typename)) + return true; + + // Retrieve the type from the annotation token, consume that token, and + // return. + EndLocation = Tok.getAnnotationEndLoc(); + TypeTy *Type = Tok.getAnnotationValue(); + ConsumeToken(); + return Type; + } + + // We have an identifier; check whether it is actually a type. + TypeTy *Type = Actions.getTypeName(*Id, IdLoc, CurScope, SS, true); + if (!Type) { + Diag(IdLoc, diag::err_expected_class_name); + return true; + } + + // Consume the identifier. + EndLocation = IdLoc; + 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. If SuppressDeclarations is true, we do know. +/// +/// 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, bool SuppressDeclarations){ + 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; + } + + if (Tok.is(tok::code_completion)) { + // Code completion for a struct, class, or union name. + Actions.CodeCompleteTag(CurScope, TagType); + ConsumeCodeCompletionToken(); + } + + AttributeList *AttrList = 0; + // If attributes exist after tag, parse them. + if (Tok.is(tok::kw___attribute)) + AttrList = ParseGNUAttributes(); + + // If declspecs exist after tag, parse them. + if (Tok.is(tok::kw___declspec)) + AttrList = ParseMicrosoftDeclSpec(AttrList); + + // If C++0x attributes exist here, parse them. + // FIXME: Are we consistent with the ordering of parsing of different + // styles of attributes? + if (isCXX0XAttributeSpecifier()) + AttrList = addAttributeLists(AttrList, ParseCXX0XAttributes().AttrList); + + if (TagType == DeclSpec::TST_struct && Tok.is(tok::kw___is_pod)) { + // GNU libstdc++ 4.2 uses __is_pod as the name of a struct template, but + // __is_pod is a keyword in GCC >= 4.3. Therefore, when we see the + // token sequence "struct __is_pod", make __is_pod into a normal + // identifier rather than a keyword, to allow libstdc++ 4.2 to work + // properly. + Tok.getIdentifierInfo()->setTokenID(tok::identifier); + Tok.setKind(tok::identifier); + } + + if (TagType == DeclSpec::TST_struct && Tok.is(tok::kw___is_empty)) { + // GNU libstdc++ 4.2 uses __is_empty as the name of a struct template, but + // __is_empty is a keyword in GCC >= 4.3. Therefore, when we see the + // token sequence "struct __is_empty", make __is_empty into a normal + // identifier rather than a keyword, to allow libstdc++ 4.2 to work + // properly. + Tok.getIdentifierInfo()->setTokenID(tok::identifier); + Tok.setKind(tok::identifier); + } + + // Parse the (optional) nested-name-specifier. + CXXScopeSpec &SS = DS.getTypeSpecScope(); + if (getLang().CPlusPlus) { + // "FOO : BAR" is not a potential typo for "FOO::BAR". + ColonProtectionRAIIObject X(*this); + + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true); + if (SS.isSet()) + if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) + Diag(Tok, diag::err_expected_ident); + } + + TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; + + // Parse the (optional) class name or simple-template-id. + IdentifierInfo *Name = 0; + SourceLocation NameLoc; + TemplateIdAnnotation *TemplateId = 0; + if (Tok.is(tok::identifier)) { + Name = Tok.getIdentifierInfo(); + NameLoc = ConsumeToken(); + + if (Tok.is(tok::less)) { + // The name was supposed to refer to a template, but didn't. + // Eat the template argument list and try to continue parsing this as + // a class (or template thereof). + TemplateArgList TemplateArgs; + SourceLocation LAngleLoc, RAngleLoc; + if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, &SS, + true, LAngleLoc, + TemplateArgs, RAngleLoc)) { + // We couldn't parse the template argument list at all, so don't + // try to give any location information for the list. + LAngleLoc = RAngleLoc = SourceLocation(); + } + + Diag(NameLoc, diag::err_explicit_spec_non_template) + << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) + << (TagType == DeclSpec::TST_class? 0 + : TagType == DeclSpec::TST_struct? 1 + : 2) + << Name + << SourceRange(LAngleLoc, RAngleLoc); + + // Strip off the last template parameter list if it was empty, since + // we've removed its template argument list. + if (TemplateParams && TemplateInfo.LastParameterListWasEmpty) { + if (TemplateParams && TemplateParams->size() > 1) { + TemplateParams->pop_back(); + } else { + TemplateParams = 0; + const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind + = ParsedTemplateInfo::NonTemplate; + } + } else if (TemplateInfo.Kind + == ParsedTemplateInfo::ExplicitInstantiation) { + // Pretend this is just a forward declaration. + TemplateParams = 0; + const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind + = ParsedTemplateInfo::NonTemplate; + const_cast<ParsedTemplateInfo&>(TemplateInfo).TemplateLoc + = SourceLocation(); + const_cast<ParsedTemplateInfo&>(TemplateInfo).ExternLoc + = SourceLocation(); + } + + + } + } else if (Tok.is(tok::annot_template_id)) { + TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + NameLoc = ConsumeToken(); + + 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 four options here. If we have 'struct foo;', then this + // is either a forward declaration or a friend declaration, which + // have to be treated differently. If we have 'struct foo {...' or + // 'struct foo :...' then this is a definition. Otherwise we have + // something like 'struct foo xyz', a reference. + // However, in some contexts, things look like declarations but are just + // references, e.g. + // new struct s; + // or + // &T::operator struct s; + // For these, SuppressDeclarations is true. + Action::TagUseKind TUK; + if (SuppressDeclarations) + TUK = Action::TUK_Reference; + else if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon))){ + if (DS.isFriendSpecified()) { + // C++ [class.friend]p2: + // A class shall not be defined in a friend declaration. + Diag(Tok.getLocation(), diag::err_friend_decl_defines_class) + << SourceRange(DS.getFriendSpecLoc()); + + // Skip everything up to the semicolon, so that this looks like a proper + // friend class (or template thereof) declaration. + SkipUntil(tok::semi, true, true); + TUK = Action::TUK_Friend; + } else { + // Okay, this is a class definition. + TUK = Action::TUK_Definition; + } + } else if (Tok.is(tok::semi)) + TUK = DS.isFriendSpecified() ? Action::TUK_Friend : Action::TUK_Declaration; + else + TUK = Action::TUK_Reference; + + if (!Name && !TemplateId && TUK != Action::TUK_Definition) { + // We have a declaration or reference to an anonymous class. + Diag(StartLoc, diag::err_anon_type_definition) + << DeclSpec::getSpecifierName(TagType); + + SkipUntil(tok::comma, true); + + if (TemplateId) + TemplateId->Destroy(); + return; + } + + // Create the tag portion of the class or class template. + Action::DeclResult TagOrTempResult = true; // invalid + Action::TypeResult TypeResult = true; // invalid + + bool Owned = false; + if (TemplateId) { + // Explicit specialization, class template partial specialization, + // or explicit instantiation. + ASTTemplateArgsPtr TemplateArgsPtr(Actions, + TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && + TUK == Action::TUK_Declaration) { + // This is an explicit instantiation of a class template. + TagOrTempResult + = Actions.ActOnExplicitInstantiation(CurScope, + TemplateInfo.ExternLoc, + TemplateInfo.TemplateLoc, + TagType, + StartLoc, + SS, + TemplateTy::make(TemplateId->Template), + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc, + AttrList); + + // Friend template-ids are treated as references unless + // they have template headers, in which case they're ill-formed + // (FIXME: "template <class T> friend class A<T>::B<int>;"). + // We diagnose this error in ActOnClassTemplateSpecialization. + } else if (TUK == Action::TUK_Reference || + (TUK == Action::TUK_Friend && + TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) { + TypeResult + = Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc); + + TypeResult = Actions.ActOnTagTemplateIdType(TypeResult, TUK, + TagType, StartLoc); + } 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(TUK == Action::TUK_Definition && "Expected a definition here"); + + SourceLocation LAngleLoc + = PP.getLocForEndOfToken(TemplateInfo.TemplateLoc); + Diag(TemplateId->TemplateNameLoc, + diag::err_explicit_instantiation_with_definition) + << SourceRange(TemplateInfo.TemplateLoc) + << FixItHint::CreateInsertion(LAngleLoc, "<>"); + + // Create a fake template parameter list that contains only + // "template<>", so that we treat this construct as a class + // template specialization. + FakedParamLists.push_back( + Actions.ActOnTemplateParameterList(0, SourceLocation(), + TemplateInfo.TemplateLoc, + LAngleLoc, + 0, 0, + LAngleLoc)); + TemplateParams = &FakedParamLists; + } + + // Build the class template specialization. + TagOrTempResult + = Actions.ActOnClassTemplateSpecialization(CurScope, TagType, TUK, + StartLoc, SS, + TemplateTy::make(TemplateId->Template), + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc, + AttrList, + Action::MultiTemplateParamsArg(Actions, + TemplateParams? &(*TemplateParams)[0] : 0, + TemplateParams? TemplateParams->size() : 0)); + } + TemplateId->Destroy(); + } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && + TUK == Action::TUK_Declaration) { + // Explicit instantiation of a member of a class template + // specialization, e.g., + // + // template struct Outer<int>::Inner; + // + TagOrTempResult + = Actions.ActOnExplicitInstantiation(CurScope, + TemplateInfo.ExternLoc, + TemplateInfo.TemplateLoc, + TagType, StartLoc, SS, Name, + NameLoc, AttrList); + } else { + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && + TUK == Action::TUK_Definition) { + // FIXME: Diagnose this particular error. + } + + bool IsDependent = false; + + // Declaration or definition of a class type + TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TUK, StartLoc, SS, + Name, NameLoc, AttrList, AS, + Action::MultiTemplateParamsArg(Actions, + TemplateParams? &(*TemplateParams)[0] : 0, + TemplateParams? TemplateParams->size() : 0), + Owned, IsDependent); + + // If ActOnTag said the type was dependent, try again with the + // less common call. + if (IsDependent) + TypeResult = Actions.ActOnDependentTag(CurScope, TagType, TUK, + SS, Name, StartLoc, NameLoc); + } + + // If there is a body, parse it and inform the actions module. + if (TUK == Action::TUK_Definition) { + assert(Tok.is(tok::l_brace) || + (getLang().CPlusPlus && Tok.is(tok::colon))); + if (getLang().CPlusPlus) + ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get()); + else + ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get()); + } + + void *Result; + if (!TypeResult.isInvalid()) { + TagType = DeclSpec::TST_typename; + Result = TypeResult.get(); + Owned = false; + } else if (!TagOrTempResult.isInvalid()) { + Result = TagOrTempResult.get().getAs<void>(); + } else { + DS.SetTypeSpecError(); + return; + } + + const char *PrevSpec = 0; + unsigned DiagID; + + // FIXME: The DeclSpec should keep the locations of both the keyword and the + // name (if there is one). + SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc; + + if (DS.SetTypeSpecType(TagType, TSTLoc, PrevSpec, DiagID, + Result, Owned)) + Diag(StartLoc, DiagID) << PrevSpec; + + // At this point, we've successfully parsed a class-specifier in 'definition' + // form (e.g. "struct foo { int x; }". While we could just return here, we're + // going to look at what comes after it to improve error recovery. If an + // impossible token occurs next, we assume that the programmer forgot a ; at + // the end of the declaration and recover that way. + // + // This switch enumerates the valid "follow" set for definition. + if (TUK == Action::TUK_Definition) { + bool ExpectedSemi = true; + switch (Tok.getKind()) { + default: break; + case tok::semi: // struct foo {...} ; + case tok::star: // struct foo {...} * P; + case tok::amp: // struct foo {...} & R = ... + case tok::identifier: // struct foo {...} V ; + case tok::r_paren: //(struct foo {...} ) {4} + case tok::annot_cxxscope: // struct foo {...} a:: b; + case tok::annot_typename: // struct foo {...} a ::b; + case tok::annot_template_id: // struct foo {...} a<int> ::b; + case tok::l_paren: // struct foo {...} ( x); + case tok::comma: // __builtin_offsetof(struct foo{...} , + ExpectedSemi = false; + break; + // Type qualifiers + case tok::kw_const: // struct foo {...} const x; + case tok::kw_volatile: // struct foo {...} volatile x; + case tok::kw_restrict: // struct foo {...} restrict x; + case tok::kw_inline: // struct foo {...} inline foo() {}; + // Storage-class specifiers + case tok::kw_static: // struct foo {...} static x; + case tok::kw_extern: // struct foo {...} extern x; + case tok::kw_typedef: // struct foo {...} typedef x; + case tok::kw_register: // struct foo {...} register x; + case tok::kw_auto: // struct foo {...} auto x; + case tok::kw_mutable: // struct foo {...} mutable x; + // As shown above, type qualifiers and storage class specifiers absolutely + // can occur after class specifiers according to the grammar. However, + // almost noone actually writes code like this. If we see one of these, + // it is much more likely that someone missed a semi colon and the + // type/storage class specifier we're seeing is part of the *next* + // intended declaration, as in: + // + // struct foo { ... } + // typedef int X; + // + // We'd really like to emit a missing semicolon error instead of emitting + // an error on the 'int' saying that you can't have two type specifiers in + // the same declaration of X. Because of this, we look ahead past this + // token to see if it's a type specifier. If so, we know the code is + // otherwise invalid, so we can produce the expected semi error. + if (!isKnownToBeTypeSpecifier(NextToken())) + ExpectedSemi = false; + break; + + case tok::r_brace: // struct bar { struct foo {...} } + // Missing ';' at end of struct is accepted as an extension in C mode. + if (!getLang().CPlusPlus) + ExpectedSemi = false; + break; + } + + if (ExpectedSemi) { + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, + TagType == DeclSpec::TST_class ? "class" + : TagType == DeclSpec::TST_struct? "struct" : "union"); + // Push this token back into the preprocessor and change our current token + // to ';' so that the rest of the code recovers as though there were an + // ';' after the definition. + PP.EnterToken(Tok); + Tok.setKind(tok::semi); + } + } +} + +/// 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 != AS_none) + 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) + << FixItHint::CreateRemoval(VirtualLoc); + } + + IsVirtual = true; + } + + // Parse optional '::' and optional nested-name-specifier. + CXXScopeSpec SS; + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, + /*EnteringContext=*/false); + + // 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; + } +} + +void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, + DeclPtrTy ThisDecl) { + // We just declared a member function. If this member function + // has any default arguments, we'll need to parse them later. + LateParsedMethodDeclaration *LateMethod = 0; + 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(); + LateMethod->TemplateScope = CurScope->isTemplateParamScope(); + + // 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[I].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)); + } + } +} + +/// 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, + const ParsedTemplateInfo &TemplateInfo) { + // Access declarations. + if (!TemplateInfo.Kind && + (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) && + !TryAnnotateCXXScopeToken() && + Tok.is(tok::annot_cxxscope)) { + bool isAccessDecl = false; + if (NextToken().is(tok::identifier)) + isAccessDecl = GetLookAheadToken(2).is(tok::semi); + else + isAccessDecl = NextToken().is(tok::kw_operator); + + if (isAccessDecl) { + // Collect the scope specifier token we annotated earlier. + CXXScopeSpec SS; + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType*/ 0, false); + + // Try to parse an unqualified-id. + UnqualifiedId Name; + if (ParseUnqualifiedId(SS, false, true, true, /*ObjectType*/ 0, Name)) { + SkipUntil(tok::semi); + return; + } + + // TODO: recover from mistakenly-qualified operator declarations. + if (ExpectAndConsume(tok::semi, + diag::err_expected_semi_after, + "access declaration", + tok::semi)) + return; + + Actions.ActOnUsingDeclaration(CurScope, AS, + false, SourceLocation(), + SS, Name, + /* AttrList */ 0, + /* IsTypeName */ false, + SourceLocation()); + return; + } + } + + // static_assert-declaration + if (Tok.is(tok::kw_static_assert)) { + // FIXME: Check for templates + SourceLocation DeclEnd; + ParseStaticAssertDeclaration(DeclEnd); + return; + } + + if (Tok.is(tok::kw_template)) { + assert(!TemplateInfo.TemplateParams && + "Nested template improperly parsed?"); + 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, TemplateInfo); + } + + // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it + // is a bitfield. + ColonProtectionRAIIObject X(*this); + + CXX0XAttributeList AttrList; + // Optional C++0x attribute-specifier + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + AttrList = ParseCXX0XAttributes(); + + if (Tok.is(tok::kw_using)) { + // FIXME: Check for template aliases + + if (AttrList.HasAttr) + Diag(AttrList.Range.getBegin(), diag::err_attributes_not_allowed) + << AttrList.Range; + + // Eat 'using'. + SourceLocation UsingLoc = ConsumeToken(); + + if (Tok.is(tok::kw_namespace)) { + Diag(UsingLoc, diag::err_using_namespace_in_class); + SkipUntil(tok::semi, true, true); + } else { + SourceLocation DeclEnd; + // Otherwise, it must be using-declaration. + ParseUsingDeclaration(Declarator::MemberContext, UsingLoc, DeclEnd, AS); + } + return; + } + + SourceLocation DSStart = Tok.getLocation(); + // decl-specifier-seq: + // Parse the common declaration-specifiers piece. + ParsingDeclSpec DS(*this); + DS.AddAttributes(AttrList.AttrList); + ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class); + + Action::MultiTemplateParamsArg TemplateParams(Actions, + TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0, + TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0); + + if (Tok.is(tok::semi)) { + ConsumeToken(); + Actions.ParsedFreeStandingDeclSpec(CurScope, AS, DS); + return; + } + + ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext); + + if (Tok.isNot(tok::colon)) { + // Don't parse FOO:BAR as if it were a typo for FOO::BAR. + ColonProtectionRAIIObject X(*this); + + // 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; + } + + // If attributes exist after the declarator, but before an '{', parse them. + if (Tok.is(tok::kw___attribute)) { + SourceLocation Loc; + AttributeList *AttrList = ParseGNUAttributes(&Loc); + DeclaratorInfo.AddAttributes(AttrList, Loc); + } + + // 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, TemplateInfo); + 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 = ParseGNUAttributes(&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; + if (DS.isFriendSpecified()) { + // TODO: handle initializers, bitfields, 'delete' + ThisDecl = Actions.ActOnFriendFunctionDecl(CurScope, DeclaratorInfo, + /*IsDefinition*/ false, + move(TemplateParams)); + } else { + ThisDecl = Actions.ActOnCXXMemberDeclarator(CurScope, AS, + DeclaratorInfo, + move(TemplateParams), + BitfieldSize.release(), + Init.release(), + /*IsDefinition*/Deleted, + Deleted); + } + if (ThisDecl) + DeclsInGroup.push_back(ThisDecl); + + if (DeclaratorInfo.isFunctionDeclarator() && + DeclaratorInfo.getDeclSpec().getStorageClassSpec() + != DeclSpec::SCS_typedef) { + HandleMemberFunctionDefaultArgs(DeclaratorInfo, ThisDecl); + } + + DeclaratorInfo.complete(ThisDecl); + + // If we don't have a comma, it is either the end of the list (a ';') + // or an error, bail out. + if (Tok.isNot(tok::comma)) + 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 = ParseGNUAttributes(&Loc); + DeclaratorInfo.AddAttributes(AttrList, Loc); + } + + if (Tok.isNot(tok::colon)) + ParseDeclarator(DeclaratorInfo); + } + + if (ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list)) { + // Skip to end of block or statement. + SkipUntil(tok::r_brace, true, true); + // If we stopped at a ';', eat it. + if (Tok.is(tok::semi)) ConsumeToken(); + return; + } + + Actions.FinalizeDeclaratorGroup(CurScope, DS, DeclsInGroup.data(), + DeclsInGroup.size()); +} + +/// 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"); + + // Determine whether this is a non-nested class. Note that local + // classes are *not* considered to be nested classes. + bool NonNestedClass = true; + if (!ClassStack.empty()) { + for (const Scope *S = CurScope; S; S = S->getParent()) { + if (S->isClassScope()) { + // We're inside a class scope, so this is a nested class. + NonNestedClass = false; + break; + } + + if ((S->getFlags() & Scope::FnScope)) { + // If we're in a function or function template declared in the + // body of a class, then this is a local class rather than a + // nested class. + const Scope *Parent = S->getParent(); + if (Parent->isTemplateParamScope()) + Parent = Parent->getParent(); + if (Parent->isClassScope()) + break; + } + } + } + + // 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, NonNestedClass); + + if (TagDecl) + Actions.ActOnTagStartDefinition(CurScope, TagDecl); + + if (Tok.is(tok::colon)) { + ParseBaseClause(TagDecl); + + if (!Tok.is(tok::l_brace)) { + Diag(Tok, diag::err_expected_lbrace_after_base_specifiers); + + if (TagDecl) + Actions.ActOnTagDefinitionError(CurScope, TagDecl); + return; + } + } + + assert(Tok.is(tok::l_brace)); + + SourceLocation LBraceLoc = ConsumeBrace(); + + if (!TagDecl) { + SkipUntil(tok::r_brace, false, false); + return; + } + + Actions.ActOnStartCXXMemberDeclarations(CurScope, TagDecl, LBraceLoc); + + // 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) + << FixItHint::CreateRemoval(Tok.getLocation()); + 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; + } + + // FIXME: Make sure we don't have a template here. + + // Parse all the comma separated declarators. + ParseCXXClassMemberDeclaration(CurAS); + } + + SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); + + // If attributes exist after class contents, parse them. + llvm::OwningPtr<AttributeList> AttrList; + if (Tok.is(tok::kw___attribute)) + AttrList.reset(ParseGNUAttributes()); + + Actions.ActOnFinishCXXMemberSpecification(CurScope, RecordLoc, TagDecl, + LBraceLoc, RBraceLoc, + AttrList.get()); + + // 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 (NonNestedClass) { + // 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()); + } + + Actions.ActOnTagFinishDefinition(CurScope, TagDecl, RBraceLoc); + + // Leave the class scope. + ParsingDef.Pop(); + ClassScope.Exit(); +} + +/// 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; + bool AnyErrors = false; + + do { + MemInitResult MemInit = ParseMemInitializer(ConstructorDecl); + if (!MemInit.isInvalid()) + MemInitializers.push_back(MemInit.get()); + else + AnyErrors = true; + + 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(), + AnyErrors); +} + +/// 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) { + // parse '::'[opt] nested-name-specifier[opt] + CXXScopeSpec SS; + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); + TypeTy *TemplateTypeTy = 0; + if (Tok.is(tok::annot_template_id)) { + TemplateIdAnnotation *TemplateId + = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + if (TemplateId->Kind == TNK_Type_template || + TemplateId->Kind == TNK_Dependent_template_name) { + AnnotateTemplateIdTokenAsType(&SS); + assert(Tok.is(tok::annot_typename) && "template-id -> type failed"); + TemplateTypeTy = Tok.getAnnotationValue(); + } + } + if (!TemplateTypeTy && 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.is(tok::identifier) ? Tok.getIdentifierInfo() : 0; + 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, SS, II, + TemplateTypeTy, 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 NonNestedClass) { + assert((NonNestedClass || !ClassStack.empty()) && + "Nested class without outer class"); + ClassStack.push(new ParsingClass(ClassDecl, NonNestedClass)); +} + +/// \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(); +} + +/// ParseCXX0XAttributes - Parse a C++0x attribute-specifier. Currently only +/// parses standard attributes. +/// +/// [C++0x] attribute-specifier: +/// '[' '[' attribute-list ']' ']' +/// +/// [C++0x] attribute-list: +/// attribute[opt] +/// attribute-list ',' attribute[opt] +/// +/// [C++0x] attribute: +/// attribute-token attribute-argument-clause[opt] +/// +/// [C++0x] attribute-token: +/// identifier +/// attribute-scoped-token +/// +/// [C++0x] attribute-scoped-token: +/// attribute-namespace '::' identifier +/// +/// [C++0x] attribute-namespace: +/// identifier +/// +/// [C++0x] attribute-argument-clause: +/// '(' balanced-token-seq ')' +/// +/// [C++0x] balanced-token-seq: +/// balanced-token +/// balanced-token-seq balanced-token +/// +/// [C++0x] balanced-token: +/// '(' balanced-token-seq ')' +/// '[' balanced-token-seq ']' +/// '{' balanced-token-seq '}' +/// any token but '(', ')', '[', ']', '{', or '}' +CXX0XAttributeList Parser::ParseCXX0XAttributes(SourceLocation *EndLoc) { + assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square) + && "Not a C++0x attribute list"); + + SourceLocation StartLoc = Tok.getLocation(), Loc; + AttributeList *CurrAttr = 0; + + ConsumeBracket(); + ConsumeBracket(); + + if (Tok.is(tok::comma)) { + Diag(Tok.getLocation(), diag::err_expected_ident); + ConsumeToken(); + } + + while (Tok.is(tok::identifier) || Tok.is(tok::comma)) { + // attribute not present + if (Tok.is(tok::comma)) { + ConsumeToken(); + continue; + } + + IdentifierInfo *ScopeName = 0, *AttrName = Tok.getIdentifierInfo(); + SourceLocation ScopeLoc, AttrLoc = ConsumeToken(); + + // scoped attribute + if (Tok.is(tok::coloncolon)) { + ConsumeToken(); + + if (!Tok.is(tok::identifier)) { + Diag(Tok.getLocation(), diag::err_expected_ident); + SkipUntil(tok::r_square, tok::comma, true, true); + continue; + } + + ScopeName = AttrName; + ScopeLoc = AttrLoc; + + AttrName = Tok.getIdentifierInfo(); + AttrLoc = ConsumeToken(); + } + + bool AttrParsed = false; + // No scoped names are supported; ideally we could put all non-standard + // attributes into namespaces. + if (!ScopeName) { + switch(AttributeList::getKind(AttrName)) + { + // No arguments + case AttributeList::AT_base_check: + case AttributeList::AT_carries_dependency: + case AttributeList::AT_final: + case AttributeList::AT_hiding: + case AttributeList::AT_noreturn: + case AttributeList::AT_override: { + if (Tok.is(tok::l_paren)) { + Diag(Tok.getLocation(), diag::err_cxx0x_attribute_forbids_arguments) + << AttrName->getName(); + break; + } + + CurrAttr = new AttributeList(AttrName, AttrLoc, 0, AttrLoc, 0, + SourceLocation(), 0, 0, CurrAttr, false, + true); + AttrParsed = true; + break; + } + + // One argument; must be a type-id or assignment-expression + case AttributeList::AT_aligned: { + if (Tok.isNot(tok::l_paren)) { + Diag(Tok.getLocation(), diag::err_cxx0x_attribute_requires_arguments) + << AttrName->getName(); + break; + } + SourceLocation ParamLoc = ConsumeParen(); + + OwningExprResult ArgExpr = ParseCXX0XAlignArgument(ParamLoc); + + MatchRHSPunctuation(tok::r_paren, ParamLoc); + + ExprVector ArgExprs(Actions); + ArgExprs.push_back(ArgExpr.release()); + CurrAttr = new AttributeList(AttrName, AttrLoc, 0, AttrLoc, + 0, ParamLoc, ArgExprs.take(), 1, CurrAttr, + false, true); + + AttrParsed = true; + break; + } + + // Silence warnings + default: break; + } + } + + // Skip the entire parameter clause, if any + if (!AttrParsed && Tok.is(tok::l_paren)) { + ConsumeParen(); + // SkipUntil maintains the balancedness of tokens. + SkipUntil(tok::r_paren, false); + } + } + + if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) + SkipUntil(tok::r_square, false); + Loc = Tok.getLocation(); + if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) + SkipUntil(tok::r_square, false); + + CXX0XAttributeList Attr (CurrAttr, SourceRange(StartLoc, Loc), true); + return Attr; +} + +/// ParseCXX0XAlignArgument - Parse the argument to C++0x's [[align]] +/// attribute. +/// +/// FIXME: Simply returns an alignof() expression if the argument is a +/// type. Ideally, the type should be propagated directly into Sema. +/// +/// [C++0x] 'align' '(' type-id ')' +/// [C++0x] 'align' '(' assignment-expression ')' +Parser::OwningExprResult Parser::ParseCXX0XAlignArgument(SourceLocation Start) { + if (isTypeIdInParens()) { + EnterExpressionEvaluationContext Unevaluated(Actions, + Action::Unevaluated); + SourceLocation TypeLoc = Tok.getLocation(); + TypeTy *Ty = ParseTypeName().get(); + SourceRange TypeRange(Start, Tok.getLocation()); + return Actions.ActOnSizeOfAlignOfExpr(TypeLoc, false, true, Ty, + TypeRange); + } else + return ParseConstantExpression(); +} diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp new file mode 100644 index 0000000..b036e56 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp @@ -0,0 +1,1707 @@ +//===--- 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/Parse/Template.h" +#include "clang/Basic/PrettyStackTrace.h" +#include "RAIIObjectsForParser.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/SmallString.h" +using namespace clang; + +/// 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::code_completion)) { + Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Expression); + ConsumeCodeCompletionToken(); + } + + 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 SuperLoc, + TypeTy *ReceiverType, + ExprArg ReceiverExpr) { + OwningExprResult R(ParseObjCMessageExpressionBody(LBracLoc, SuperLoc, + ReceiverType, + 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() { + // C++ [basic.def.odr]p2: + // An expression is potentially evaluated unless it appears where an + // integral constant expression is required (see 5.19) [...]. + EnterExpressionEvaluationContext Unevaluated(Actions, + Action::Unevaluated); + + 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, prec::Level MinPrec) { + prec::Level 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)) { + // Don't parse FOO:BAR as if it were a typo for FOO::BAR. + ColonProtectionRAIIObject X(*this); + + // 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.is(tok::colon)) { + // Eat the colon. + ColonLoc = ConsumeToken(); + } else { + // Otherwise, we're missing a ':'. Assume that this was a typo that the + // user forgot. If we're not in a macro instantion, we can suggest a + // fixit hint. If there were two spaces before the current token, + // suggest inserting the colon in between them, otherwise insert ": ". + SourceLocation FILoc = Tok.getLocation(); + const char *FIText = ": "; + if (FILoc.isFileID()) { + const SourceManager &SM = PP.getSourceManager(); + bool IsInvalid = false; + const char *SourcePtr = + SM.getCharacterData(FILoc.getFileLocWithOffset(-1), &IsInvalid); + if (!IsInvalid && *SourcePtr == ' ') { + SourcePtr = + SM.getCharacterData(FILoc.getFileLocWithOffset(-2), &IsInvalid); + if (!IsInvalid && *SourcePtr == ' ') { + FILoc = FILoc.getFileLocWithOffset(-1); + FIText = ":"; + } + } + } + + Diag(Tok, diag::err_expected_colon) + << FixItHint::CreateInsertion(FILoc, FIText); + Diag(OpToken, diag::note_matching) << "?"; + ColonLoc = Tok.getLocation(); + } + } + + // 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. + prec::Level 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), + static_cast<prec::Level>(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, + TypeTy *TypeOfCast) { + bool NotCastExpr; + OwningExprResult Res = ParseCastExpression(isUnaryExpression, + isAddressOfOperand, + NotCastExpr, + TypeOfCast); + 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] ')' [C++ 5.2.3] +/// [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 +/// +/// unqualified-id: [C++ 5.1] +/// identifier +/// operator-function-id +/// conversion-function-id +/// '~' class-name +/// template-id +/// +/// 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, + TypeTy *TypeOfCast) { + 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; + + { + // The inside of the parens don't need to be a colon protected scope. + ColonProtectionRAIIObject X(*this, false); + + Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/, + TypeOfCast, 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) { + // Avoid the unnecessary parse-time lookup in the common case + // where the syntax forbids a type. + const Token &Next = NextToken(); + if (Next.is(tok::coloncolon) || + (!ColonIsSacred && Next.is(tok::colon)) || + Next.is(tok::less) || + Next.is(tok::l_paren)) { + // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse. + if (TryAnnotateTypeOrScopeToken()) + return ExprError(); + if (!Tok.is(tok::identifier)) + return ParseCastExpression(isUnaryExpression, isAddressOfOperand); + } + } + + // Consume the identifier so that we can see if it is followed by a '(' or + // '.'. + IdentifierInfo &II = *Tok.getIdentifierInfo(); + SourceLocation ILoc = ConsumeToken(); + + // Support 'Class.property' and 'super.property' notation. + if (getLang().ObjC1 && Tok.is(tok::period) && + (Actions.getTypeName(II, ILoc, CurScope) || + // Allow the base to be 'super' if in an objc-method. + (&II == Ident_super && CurScope->isInObjcMethodScope()))) { + SourceLocation DotLoc = ConsumeToken(); + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_property_name); + return ExprError(); + } + IdentifierInfo &PropertyName = *Tok.getIdentifierInfo(); + SourceLocation PropertyLoc = ConsumeToken(); + + Res = Actions.ActOnClassPropertyRefExpr(II, PropertyName, + ILoc, PropertyLoc); + // These can be followed by postfix-expr pieces. + return ParsePostfixExpressionSuffix(move(Res)); + } + + // 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. + UnqualifiedId Name; + CXXScopeSpec ScopeSpec; + Name.setIdentifier(&II, ILoc); + Res = Actions.ActOnIdExpression(CurScope, ScopeSpec, Name, + Tok.is(tok::l_paren), false); + // These can be followed by postfix-expr pieces. + return ParsePostfixExpressionSuffix(move(Res)); + } + 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_char16_t: + case tok::kw_char32_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::kw___vector: + case tok::annot_typename: { + if (!getLang().CPlusPlus) { + Diag(Tok, diag::err_expected_expression); + return ExprError(); + } + + if (SavedKind == tok::kw_typename) { + // postfix-expression: typename-specifier '(' expression-list[opt] ')' + if (TryAnnotateTypeOrScopeToken()) + 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 + // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse. + // (We can end up in this situation after tentative parsing.) + if (TryAnnotateTypeOrScopeToken()) + return ExprError(); + if (!Tok.is(tok::annot_cxxscope)) + return ParseCastExpression(isUnaryExpression, isAddressOfOperand, + NotCastExpr, TypeOfCast); + + Token Next = NextToken(); + if (Next.is(tok::annot_template_id)) { + TemplateIdAnnotation *TemplateId + = static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue()); + if (TemplateId->Kind == TNK_Type_template) { + // We have a qualified template-id that we know refers to a + // type, translate it into a type and continue parsing as a + // cast expression. + CXXScopeSpec SS; + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); + AnnotateTemplateIdTokenAsType(&SS); + return ParseCastExpression(isUnaryExpression, isAddressOfOperand, + NotCastExpr, TypeOfCast); + } + } + + // Parse as an id-expression. + Res = ParseCXXIdExpression(isAddressOfOperand); + return ParsePostfixExpressionSuffix(move(Res)); + } + + case tok::annot_template_id: { // [C++] template-id + TemplateIdAnnotation *TemplateId + = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + if (TemplateId->Kind == TNK_Type_template) { + // We have a template-id that we know refers to a type, + // translate it into a type and continue parsing as a cast + // expression. + AnnotateTemplateIdTokenAsType(); + return ParseCastExpression(isUnaryExpression, isAddressOfOperand, + NotCastExpr, TypeOfCast); + } + + // Fall through to treat the template-id as an id-expression. + } + + case tok::kw_operator: // [C++] id-expression: operator/conversion-function-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 ExprError(); + if (!Tok.is(tok::coloncolon)) + 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_empty: + case tok::kw___is_polymorphic: + case tok::kw___is_abstract: + case tok::kw___is_literal: + case tok::kw___has_trivial_constructor: + case tok::kw___has_trivial_copy: + case tok::kw___has_trivial_assign: + 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::code_completion: + Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Expression); + ConsumeCodeCompletionToken(); + return ParseCastExpression(isUnaryExpression, isAddressOfOperand, + NotCastExpr, TypeOfCast); + 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.is(tok::code_completion)) { + Actions.CodeCompleteCall(CurScope, LHS.get(), 0, 0); + ConsumeCodeCompletionToken(); + } + + if (Tok.isNot(tok::r_paren)) { + if (ParseExpressionList(ArgExprs, CommaLocs, &Action::CodeCompleteCall, + LHS.get())) { + 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: + case tok::period: { + // postfix-expression: p-e '->' template[opt] id-expression + // postfix-expression: p-e '.' template[opt] id-expression + tok::TokenKind OpKind = Tok.getKind(); + SourceLocation OpLoc = ConsumeToken(); // Eat the "." or "->" token. + + CXXScopeSpec SS; + Action::TypeTy *ObjectType = 0; + bool MayBePseudoDestructor = false; + if (getLang().CPlusPlus && !LHS.isInvalid()) { + LHS = Actions.ActOnStartCXXMemberReference(CurScope, move(LHS), + OpLoc, OpKind, ObjectType, + MayBePseudoDestructor); + if (LHS.isInvalid()) + break; + + ParseOptionalCXXScopeSpecifier(SS, ObjectType, false, + &MayBePseudoDestructor); + } + + if (Tok.is(tok::code_completion)) { + // Code completion for a member access expression. + Actions.CodeCompleteMemberReferenceExpr(CurScope, LHS.get(), + OpLoc, OpKind == tok::arrow); + + ConsumeCodeCompletionToken(); + } + + if (MayBePseudoDestructor) { + LHS = ParseCXXPseudoDestructor(move(LHS), OpLoc, OpKind, SS, + ObjectType); + break; + } + + // Either the action has told is that this cannot be a + // pseudo-destructor expression (based on the type of base + // expression), or we didn't see a '~' in the right place. We + // can still parse a destructor name here, but in that case it + // names a real destructor. + UnqualifiedId Name; + if (ParseUnqualifiedId(SS, + /*EnteringContext=*/false, + /*AllowDestructorName=*/true, + /*AllowConstructorName=*/false, + ObjectType, + Name)) + return ExprError(); + + if (!LHS.isInvalid()) + LHS = Actions.ActOnMemberAccessExpr(CurScope, move(LHS), OpLoc, + OpKind, SS, Name, ObjCImpDecl, + Tok.is(tok::l_paren)); + break; + } + case tok::plusplus: // postfix-expression: postfix-expression '++' + 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(); + } + + // C++0x [expr.sizeof]p1: + // [...] The operand is either an expression, which is an unevaluated + // operand (Clause 5) [...] + // + // The GNU typeof and alignof extensions also behave as unevaluated + // operands. + EnterExpressionEvaluationContext Unevaluated(Actions, + Action::Unevaluated); + 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; + + // C++0x [expr.sizeof]p1: + // [...] The operand is either an expression, which is an unevaluated + // operand (Clause 5) [...] + // + // The GNU typeof and alignof extensions also behave as unevaluated + // operands. + EnterExpressionEvaluationContext Unevaluated(Actions, + Action::Unevaluated); + Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/, + 0/*TypeOfCast*/, + 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.isNot(tok::r_paren)) { + MatchRHSPunctuation(tok::r_paren, LParenLoc); + Res = ExprError(); + } else if (Ty.isInvalid()) { + Res = ExprError(); + } else { + Res = Actions.ActOnBuiltinOffsetOf(CurScope, StartLoc, TypeLoc, + Ty.get(), &Comps[0], + Comps.size(), ConsumeParen()); + } + break; + } + } + 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 *TypeOfCast, 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(0, 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(); + + // Note that this doesn't parse the subsequent cast-expression, it just + // returns the parsed type to the callee. + if (stopIfCastExpr) + return OwningExprResult(Actions); + + // Reject the cast of super idiom in ObjC. + if (Tok.is(tok::identifier) && getLang().ObjC1 && + Tok.getIdentifierInfo() == Ident_super && + CurScope->isInObjcMethodScope() && + GetLookAheadToken(1).isNot(tok::period)) { + Diag(Tok.getLocation(), diag::err_illegal_super_cast) + << SourceRange(OpenLoc, RParenLoc); + return ExprError(); + } + + // Parse the cast-expression that follows it next. + // TODO: For cast expression with CastTy. + Result = ParseCastExpression(false, false, CastTy); + if (!Result.isInvalid()) + Result = Actions.ActOnCastExpr(CurScope, OpenLoc, CastTy, RParenLoc, + move(Result)); + return move(Result); + } + + Diag(Tok, diag::err_expected_lbrace_in_compound_literal); + return ExprError(); + } else if (TypeOfCast) { + // Parse the expression-list. + ExprVector ArgExprs(Actions); + CommaLocsTy CommaLocs; + + if (!ParseExpressionList(ArgExprs, CommaLocs)) { + ExprType = SimpleExpr; + Result = Actions.ActOnParenOrParenListExpr(OpenLoc, Tok.getLocation(), + move_arg(ArgExprs), TypeOfCast); + } + } 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, + void (Action::*Completer)(Scope *S, + void *Data, + ExprTy **Args, + unsigned NumArgs), + void *Data) { + while (1) { + if (Tok.is(tok::code_completion)) { + if (Completer) + (Actions.*Completer)(CurScope, Data, Exprs.data(), Exprs.size()); + ConsumeCodeCompletionToken(); + } + + 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 = ParseGNUAttributes(&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 = ParseGNUAttributes(&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, CaretLoc, + ParamInfo), + CaretLoc); + + if (Tok.is(tok::kw___attribute)) { + SourceLocation Loc; + AttributeList *AttrList = ParseGNUAttributes(&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/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp new file mode 100644 index 0000000..46f1d94 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp @@ -0,0 +1,1921 @@ +//===--- 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" +#include "clang/Parse/Template.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace clang; + +/// \brief Parse global scope or nested-name-specifier if present. +/// +/// Parses a C++ global scope specifier ('::') or nested-name-specifier (which +/// may be preceded by '::'). 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 '::' +/// +/// +/// \param SS the scope specifier that will be set to the parsed +/// nested-name-specifier (or empty) +/// +/// \param ObjectType if this nested-name-specifier is being parsed following +/// the "." or "->" of a member access expression, this parameter provides the +/// type of the object whose members are being accessed. +/// +/// \param EnteringContext whether we will be entering into the context of +/// the nested-name-specifier after parsing it. +/// +/// \param MayBePseudoDestructor When non-NULL, points to a flag that +/// indicates whether this nested-name-specifier may be part of a +/// pseudo-destructor name. In this case, the flag will be set false +/// if we don't actually end up parsing a destructor name. Moreorover, +/// if we do end up determining that we are parsing a destructor name, +/// the last component of the nested-name-specifier is not parsed as +/// part of the scope specifier. + +/// member access expression, e.g., the \p T:: in \p p->T::m. +/// +/// \returns true if there was an error parsing a scope specifier +bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, + Action::TypeTy *ObjectType, + bool EnteringContext, + bool *MayBePseudoDestructor) { + 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 false; + } + + 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; + } + + bool CheckForDestructor = false; + if (MayBePseudoDestructor && *MayBePseudoDestructor) { + CheckForDestructor = true; + *MayBePseudoDestructor = false; + } + + while (true) { + if (HasScopeSpecifier) { + // C++ [basic.lookup.classref]p5: + // If the qualified-id has the form + // + // ::class-name-or-namespace-name::... + // + // the class-name-or-namespace-name is looked up in global scope as a + // class-name or namespace-name. + // + // To implement this, we clear out the object type as soon as we've + // seen a leading '::' or part of a nested-name-specifier. + ObjectType = 0; + + if (Tok.is(tok::code_completion)) { + // Code completion for a nested-name-specifier, where the code + // code completion token follows the '::'. + Actions.CodeCompleteQualifiedId(CurScope, SS, EnteringContext); + ConsumeCodeCompletionToken(); + } + } + + // nested-name-specifier: + // nested-name-specifier 'template'[opt] simple-template-id '::' + + // Parse the optional 'template' keyword, then make sure we have + // 'identifier <' after it. + if (Tok.is(tok::kw_template)) { + // If we don't have a scope specifier or an object type, this isn't a + // nested-name-specifier, since they aren't allowed to start with + // 'template'. + if (!HasScopeSpecifier && !ObjectType) + break; + + TentativeParsingAction TPA(*this); + SourceLocation TemplateKWLoc = ConsumeToken(); + + UnqualifiedId TemplateName; + if (Tok.is(tok::identifier)) { + // Consume the identifier. + TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeToken(); + } else if (Tok.is(tok::kw_operator)) { + if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, + TemplateName)) { + TPA.Commit(); + break; + } + + if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId && + TemplateName.getKind() != UnqualifiedId::IK_LiteralOperatorId) { + Diag(TemplateName.getSourceRange().getBegin(), + diag::err_id_after_template_in_nested_name_spec) + << TemplateName.getSourceRange(); + TPA.Commit(); + break; + } + } else { + TPA.Revert(); + break; + } + + // If the next token is not '<', we have a qualified-id that refers + // to a template name, such as T::template apply, but is not a + // template-id. + if (Tok.isNot(tok::less)) { + TPA.Revert(); + break; + } + + // Commit to parsing the template-id. + TPA.Commit(); + TemplateTy Template + = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, TemplateName, + ObjectType, EnteringContext); + if (!Template) + return true; + if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name, + &SS, TemplateName, TemplateKWLoc, false)) + return true; + + 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 (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) { + *MayBePseudoDestructor = true; + return false; + } + + if (TemplateId->Kind == TNK_Type_template || + TemplateId->Kind == TNK_Dependent_template_name) { + AnnotateTemplateIdTokenAsType(&SS); + + 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; + } + + assert(false && "FIXME: Only type template names supported here"); + } + + + // The rest of the nested-name-specifier possibilities start with + // tok::identifier. + if (Tok.isNot(tok::identifier)) + break; + + IdentifierInfo &II = *Tok.getIdentifierInfo(); + + // nested-name-specifier: + // type-name '::' + // namespace-name '::' + // nested-name-specifier identifier '::' + Token Next = NextToken(); + + // If we get foo:bar, this is almost certainly a typo for foo::bar. Recover + // and emit a fixit hint for it. + if (Next.is(tok::colon) && !ColonIsSacred) { + if (Actions.IsInvalidUnlessNestedName(CurScope, SS, II, ObjectType, + EnteringContext) && + // If the token after the colon isn't an identifier, it's still an + // error, but they probably meant something else strange so don't + // recover like this. + PP.LookAhead(1).is(tok::identifier)) { + Diag(Next, diag::err_unexected_colon_in_nested_name_spec) + << FixItHint::CreateReplacement(Next.getLocation(), "::"); + + // Recover as if the user wrote '::'. + Next.setKind(tok::coloncolon); + } + } + + if (Next.is(tok::coloncolon)) { + if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde) && + !Actions.isNonTypeNestedNameSpecifier(CurScope, SS, Tok.getLocation(), + II, ObjectType)) { + *MayBePseudoDestructor = true; + return false; + } + + // We have an identifier followed by a '::'. Lookup this name + // as the name in a nested-name-specifier. + SourceLocation IdLoc = ConsumeToken(); + assert((Tok.is(tok::coloncolon) || Tok.is(tok::colon)) && + "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, + ObjectType, EnteringContext)); + SS.setEndLoc(CCLoc); + continue; + } + + // nested-name-specifier: + // type-name '<' + if (Next.is(tok::less)) { + TemplateTy Template; + UnqualifiedId TemplateName; + TemplateName.setIdentifier(&II, Tok.getLocation()); + bool MemberOfUnknownSpecialization; + if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS, + TemplateName, + ObjectType, + EnteringContext, + Template, + MemberOfUnknownSpecialization)) { + // 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. + ConsumeToken(); + if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName, + SourceLocation(), false)) + return true; + continue; + } + + if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) && + IsTemplateArgumentList(1)) { + // We have something like t::getAs<T>, where getAs is a + // member of an unknown specialization. However, this will only + // parse correctly as a template, so suggest the keyword 'template' + // before 'getAs' and treat this as a dependent template name. + Diag(Tok.getLocation(), diag::err_missing_dependent_template_keyword) + << II.getName() + << FixItHint::CreateInsertion(Tok.getLocation(), "template "); + + Template = Actions.ActOnDependentTemplateName(Tok.getLocation(), SS, + TemplateName, ObjectType, + EnteringContext); + if (!Template.get()) + return true; + + // Consume the identifier. + ConsumeToken(); + if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name, &SS, + TemplateName, SourceLocation(), false)) + return true; + + continue; + } + } + + // We don't have any tokens that form the beginning of a + // nested-name-specifier, so we're done. + break; + } + + // Even if we didn't see any pieces of a nested-name-specifier, we + // still check whether there is a tilde in this position, which + // indicates a potential pseudo-destructor. + if (CheckForDestructor && Tok.is(tok::tilde)) + *MayBePseudoDestructor = true; + + return false; +} + +/// ParseCXXIdExpression - Handle id-expression. +/// +/// id-expression: +/// unqualified-id +/// qualified-id +/// +/// qualified-id: +/// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id +/// '::' identifier +/// '::' operator-function-id +/// '::' template-id +/// +/// 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, /*ObjectType=*/0, false); + + UnqualifiedId Name; + if (ParseUnqualifiedId(SS, + /*EnteringContext=*/false, + /*AllowDestructorName=*/false, + /*AllowConstructorName=*/false, + /*ObjectType=*/0, + Name)) + return ExprError(); + + // This is only the direct operand of an & operator if it is not + // followed by a postfix-expression suffix. + if (isAddressOfOperand) { + switch (Tok.getKind()) { + case tok::l_square: + case tok::l_paren: + case tok::arrow: + case tok::period: + case tok::plusplus: + case tok::minusminus: + isAddressOfOperand = false; + break; + + default: + break; + } + } + + return Actions.ActOnIdExpression(CurScope, SS, Name, Tok.is(tok::l_paren), + isAddressOfOperand); + +} + +/// 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 ')'. + RParenLoc = 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 { + // C++0x [expr.typeid]p3: + // When typeid is applied to an expression other than an lvalue of a + // polymorphic class type [...] The expression is an unevaluated + // operand (Clause 5). + // + // Note that we can't tell whether the expression is an lvalue of a + // polymorphic class type until after we've parsed the expression, so + // we the expression is potentially potentially evaluated. + EnterExpressionEvaluationContext Unevaluated(Actions, + Action::PotentiallyPotentiallyEvaluated); + 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); +} + +/// \brief Parse a C++ pseudo-destructor expression after the base, +/// . or -> operator, and nested-name-specifier have already been +/// parsed. +/// +/// postfix-expression: [C++ 5.2] +/// postfix-expression . pseudo-destructor-name +/// postfix-expression -> pseudo-destructor-name +/// +/// pseudo-destructor-name: +/// ::[opt] nested-name-specifier[opt] type-name :: ~type-name +/// ::[opt] nested-name-specifier template simple-template-id :: +/// ~type-name +/// ::[opt] nested-name-specifier[opt] ~type-name +/// +Parser::OwningExprResult +Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc, + tok::TokenKind OpKind, + CXXScopeSpec &SS, + Action::TypeTy *ObjectType) { + // We're parsing either a pseudo-destructor-name or a dependent + // member access that has the same form as a + // pseudo-destructor-name. We parse both in the same way and let + // the action model sort them out. + // + // Note that the ::[opt] nested-name-specifier[opt] has already + // been parsed, and if there was a simple-template-id, it has + // been coalesced into a template-id annotation token. + UnqualifiedId FirstTypeName; + SourceLocation CCLoc; + if (Tok.is(tok::identifier)) { + FirstTypeName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeToken(); + assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail"); + CCLoc = ConsumeToken(); + } else if (Tok.is(tok::annot_template_id)) { + FirstTypeName.setTemplateId( + (TemplateIdAnnotation *)Tok.getAnnotationValue()); + ConsumeToken(); + assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail"); + CCLoc = ConsumeToken(); + } else { + FirstTypeName.setIdentifier(0, SourceLocation()); + } + + // Parse the tilde. + assert(Tok.is(tok::tilde) && "ParseOptionalCXXScopeSpecifier fail"); + SourceLocation TildeLoc = ConsumeToken(); + if (!Tok.is(tok::identifier)) { + Diag(Tok, diag::err_destructor_tilde_identifier); + return ExprError(); + } + + // Parse the second type. + UnqualifiedId SecondTypeName; + IdentifierInfo *Name = Tok.getIdentifierInfo(); + SourceLocation NameLoc = ConsumeToken(); + SecondTypeName.setIdentifier(Name, NameLoc); + + // If there is a '<', the second type name is a template-id. Parse + // it as such. + if (Tok.is(tok::less) && + ParseUnqualifiedIdTemplateId(SS, Name, NameLoc, false, ObjectType, + SecondTypeName, /*AssumeTemplateName=*/true, + /*TemplateKWLoc*/SourceLocation())) + return ExprError(); + + return Actions.ActOnPseudoDestructorExpr(CurScope, move(Base), OpLoc, OpKind, + SS, FirstTypeName, CCLoc, + TildeLoc, SecondTypeName, + Tok.is(tok::l_paren)); +} + +/// 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); + + // TypeRep could be null, if it references an invalid typedef. + if (!TypeRep) + return ExprError(); + + 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 condition expression. +/// +/// condition: +/// expression +/// type-specifier-seq declarator '=' assignment-expression +/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] +/// '=' assignment-expression +/// +/// \param ExprResult if the condition was parsed as an expression, the +/// parsed expression. +/// +/// \param DeclResult if the condition was parsed as a declaration, the +/// parsed declaration. +/// +/// \param Loc The location of the start of the statement that requires this +/// condition, e.g., the "for" in a for loop. +/// +/// \param ConvertToBoolean Whether the condition expression should be +/// converted to a boolean value. +/// +/// \returns true if there was a parsing, false otherwise. +bool Parser::ParseCXXCondition(OwningExprResult &ExprResult, + DeclPtrTy &DeclResult, + SourceLocation Loc, + bool ConvertToBoolean) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Condition); + ConsumeCodeCompletionToken(); + } + + if (!isCXXConditionDeclaration()) { + // Parse the expression. + ExprResult = ParseExpression(); // expression + DeclResult = DeclPtrTy(); + if (ExprResult.isInvalid()) + return true; + + // If required, convert to a boolean value. + if (ConvertToBoolean) + ExprResult + = Actions.ActOnBooleanCondition(CurScope, Loc, move(ExprResult)); + return ExprResult.isInvalid(); + } + + // 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 true; + } + DeclaratorInfo.setAsmLabel(AsmLabel.release()); + DeclaratorInfo.SetRangeEnd(Loc); + } + + // If attributes are present, parse them. + if (Tok.is(tok::kw___attribute)) { + SourceLocation Loc; + AttributeList *AttrList = ParseGNUAttributes(&Loc); + DeclaratorInfo.AddAttributes(AttrList, Loc); + } + + // Type-check the declaration itself. + Action::DeclResult Dcl = Actions.ActOnCXXConditionDeclaration(CurScope, + DeclaratorInfo); + DeclResult = Dcl.get(); + ExprResult = ExprError(); + + // '=' assignment-expression + if (Tok.is(tok::equal)) { + SourceLocation EqualLoc = ConsumeToken(); + OwningExprResult AssignExpr(ParseAssignmentExpression()); + if (!AssignExpr.isInvalid()) + Actions.AddInitializerToDecl(DeclResult, move(AssignExpr)); + } else { + // FIXME: C++0x allows a braced-init-list + Diag(Tok, diag::err_expected_equal_after_declarator); + } + + // FIXME: Build a reference to this declaration? Convert it to bool? + // (This is currently handled by Sema). + + return false; +} + +/// \brief Determine whether the current token starts a C++ +/// simple-type-specifier. +bool Parser::isCXXSimpleTypeSpecifier() const { + switch (Tok.getKind()) { + case tok::annot_typename: + case tok::kw_short: + case tok::kw_long: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw_void: + case tok::kw_char: + case tok::kw_int: + case tok::kw_float: + case tok::kw_double: + case tok::kw_wchar_t: + case tok::kw_char16_t: + case tok::kw_char32_t: + case tok::kw_bool: + // FIXME: C++0x decltype support. + // GNU typeof support. + case tok::kw_typeof: + return true; + + default: + break; + } + + return false; +} + +/// 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; + unsigned DiagID; + 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, DiagID, + Tok.getAnnotationValue()); + break; + } + + // builtin types + case tok::kw_short: + DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, DiagID); + break; + case tok::kw_long: + DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec, DiagID); + break; + case tok::kw_signed: + DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID); + break; + case tok::kw_unsigned: + DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec, DiagID); + break; + case tok::kw_void: + DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID); + break; + case tok::kw_char: + DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID); + break; + case tok::kw_int: + DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID); + break; + case tok::kw_float: + DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID); + break; + case tok::kw_double: + DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID); + break; + case tok::kw_wchar_t: + DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID); + break; + case tok::kw_char16_t: + DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec, DiagID); + break; + case tok::kw_char32_t: + DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec, DiagID); + break; + case tok::kw_bool: + DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID); + break; + + // FIXME: C++0x decltype support. + // 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; + unsigned DiagID; + bool isInvalid = 0; + + // Parse one or more of the type specifiers. + if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, + ParsedTemplateInfo(), /*SuppressDeclarations*/true)) { + Diag(Tok, diag::err_operator_missing_type_specifier); + return true; + } + + while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, + ParsedTemplateInfo(), /*SuppressDeclarations*/true)) + {} + + DS.Finish(Diags, PP); + return false; +} + +/// \brief Finish parsing a C++ unqualified-id that is a template-id of +/// some form. +/// +/// This routine is invoked when a '<' is encountered after an identifier or +/// operator-function-id is parsed by \c ParseUnqualifiedId() to determine +/// whether the unqualified-id is actually a template-id. This routine will +/// then parse the template arguments and form the appropriate template-id to +/// return to the caller. +/// +/// \param SS the nested-name-specifier that precedes this template-id, if +/// we're actually parsing a qualified-id. +/// +/// \param Name for constructor and destructor names, this is the actual +/// identifier that may be a template-name. +/// +/// \param NameLoc the location of the class-name in a constructor or +/// destructor. +/// +/// \param EnteringContext whether we're entering the scope of the +/// nested-name-specifier. +/// +/// \param ObjectType if this unqualified-id occurs within a member access +/// expression, the type of the base object whose member is being accessed. +/// +/// \param Id as input, describes the template-name or operator-function-id +/// that precedes the '<'. If template arguments were parsed successfully, +/// will be updated with the template-id. +/// +/// \param AssumeTemplateId When true, this routine will assume that the name +/// refers to a template without performing name lookup to verify. +/// +/// \returns true if a parse error occurred, false otherwise. +bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool EnteringContext, + TypeTy *ObjectType, + UnqualifiedId &Id, + bool AssumeTemplateId, + SourceLocation TemplateKWLoc) { + assert((AssumeTemplateId || Tok.is(tok::less)) && + "Expected '<' to finish parsing a template-id"); + + TemplateTy Template; + TemplateNameKind TNK = TNK_Non_template; + switch (Id.getKind()) { + case UnqualifiedId::IK_Identifier: + case UnqualifiedId::IK_OperatorFunctionId: + case UnqualifiedId::IK_LiteralOperatorId: + if (AssumeTemplateId) { + Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, + Id, ObjectType, + EnteringContext); + TNK = TNK_Dependent_template_name; + if (!Template.get()) + return true; + } else { + bool MemberOfUnknownSpecialization; + TNK = Actions.isTemplateName(CurScope, SS, Id, ObjectType, + EnteringContext, Template, + MemberOfUnknownSpecialization); + + if (TNK == TNK_Non_template && MemberOfUnknownSpecialization && + ObjectType && IsTemplateArgumentList()) { + // We have something like t->getAs<T>(), where getAs is a + // member of an unknown specialization. However, this will only + // parse correctly as a template, so suggest the keyword 'template' + // before 'getAs' and treat this as a dependent template name. + std::string Name; + if (Id.getKind() == UnqualifiedId::IK_Identifier) + Name = Id.Identifier->getName(); + else { + Name = "operator "; + if (Id.getKind() == UnqualifiedId::IK_OperatorFunctionId) + Name += getOperatorSpelling(Id.OperatorFunctionId.Operator); + else + Name += Id.Identifier->getName(); + } + Diag(Id.StartLocation, diag::err_missing_dependent_template_keyword) + << Name + << FixItHint::CreateInsertion(Id.StartLocation, "template "); + Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, + Id, ObjectType, + EnteringContext); + TNK = TNK_Dependent_template_name; + if (!Template.get()) + return true; + } + } + break; + + case UnqualifiedId::IK_ConstructorName: { + UnqualifiedId TemplateName; + bool MemberOfUnknownSpecialization; + TemplateName.setIdentifier(Name, NameLoc); + TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType, + EnteringContext, Template, + MemberOfUnknownSpecialization); + break; + } + + case UnqualifiedId::IK_DestructorName: { + UnqualifiedId TemplateName; + bool MemberOfUnknownSpecialization; + TemplateName.setIdentifier(Name, NameLoc); + if (ObjectType) { + Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, + TemplateName, ObjectType, + EnteringContext); + TNK = TNK_Dependent_template_name; + if (!Template.get()) + return true; + } else { + TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType, + EnteringContext, Template, + MemberOfUnknownSpecialization); + + if (TNK == TNK_Non_template && Id.DestructorName == 0) { + Diag(NameLoc, diag::err_destructor_template_id) + << Name << SS.getRange(); + return true; + } + } + break; + } + + default: + return false; + } + + if (TNK == TNK_Non_template) + return false; + + // Parse the enclosed template argument list. + SourceLocation LAngleLoc, RAngleLoc; + TemplateArgList TemplateArgs; + if (Tok.is(tok::less) && + ParseTemplateIdAfterTemplateName(Template, Id.StartLocation, + &SS, true, LAngleLoc, + TemplateArgs, + RAngleLoc)) + return true; + + if (Id.getKind() == UnqualifiedId::IK_Identifier || + Id.getKind() == UnqualifiedId::IK_OperatorFunctionId || + Id.getKind() == UnqualifiedId::IK_LiteralOperatorId) { + // Form a parsed representation of the template-id to be stored in the + // UnqualifiedId. + TemplateIdAnnotation *TemplateId + = TemplateIdAnnotation::Allocate(TemplateArgs.size()); + + if (Id.getKind() == UnqualifiedId::IK_Identifier) { + TemplateId->Name = Id.Identifier; + TemplateId->Operator = OO_None; + TemplateId->TemplateNameLoc = Id.StartLocation; + } else { + TemplateId->Name = 0; + TemplateId->Operator = Id.OperatorFunctionId.Operator; + TemplateId->TemplateNameLoc = Id.StartLocation; + } + + TemplateId->Template = Template.getAs<void*>(); + TemplateId->Kind = TNK; + TemplateId->LAngleLoc = LAngleLoc; + TemplateId->RAngleLoc = RAngleLoc; + ParsedTemplateArgument *Args = TemplateId->getTemplateArgs(); + for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); + Arg != ArgEnd; ++Arg) + Args[Arg] = TemplateArgs[Arg]; + + Id.setTemplateId(TemplateId); + return false; + } + + // Bundle the template arguments together. + ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(), + TemplateArgs.size()); + + // Constructor and destructor names. + Action::TypeResult Type + = Actions.ActOnTemplateIdType(Template, NameLoc, + LAngleLoc, TemplateArgsPtr, + RAngleLoc); + if (Type.isInvalid()) + return true; + + if (Id.getKind() == UnqualifiedId::IK_ConstructorName) + Id.setConstructorName(Type.get(), NameLoc, RAngleLoc); + else + Id.setDestructorName(Id.StartLocation, Type.get(), RAngleLoc); + + return false; +} + +/// \brief Parse an operator-function-id or conversion-function-id as part +/// of a C++ unqualified-id. +/// +/// This routine is responsible only for parsing the operator-function-id or +/// conversion-function-id; it does not handle template arguments in any way. +/// +/// \code +/// operator-function-id: [C++ 13.5] +/// 'operator' operator +/// +/// operator: one of +/// new delete new[] delete[] +/// + - * / % ^ & | ~ +/// ! = < > += -= *= /= %= +/// ^= &= |= << >> >>= <<= == != +/// <= >= && || ++ -- , ->* -> +/// () [] +/// +/// conversion-function-id: [C++ 12.3.2] +/// operator conversion-type-id +/// +/// conversion-type-id: +/// type-specifier-seq conversion-declarator[opt] +/// +/// conversion-declarator: +/// ptr-operator conversion-declarator[opt] +/// \endcode +/// +/// \param The nested-name-specifier that preceded this unqualified-id. If +/// non-empty, then we are parsing the unqualified-id of a qualified-id. +/// +/// \param EnteringContext whether we are entering the scope of the +/// nested-name-specifier. +/// +/// \param ObjectType if this unqualified-id occurs within a member access +/// expression, the type of the base object whose member is being accessed. +/// +/// \param Result on a successful parse, contains the parsed unqualified-id. +/// +/// \returns true if parsing fails, false otherwise. +bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, + TypeTy *ObjectType, + UnqualifiedId &Result) { + assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword"); + + // Consume the 'operator' keyword. + SourceLocation KeywordLoc = ConsumeToken(); + + // Determine what kind of operator name we have. + unsigned SymbolIdx = 0; + SourceLocation SymbolLocations[3]; + OverloadedOperatorKind Op = OO_None; + switch (Tok.getKind()) { + case tok::kw_new: + case tok::kw_delete: { + bool isNew = Tok.getKind() == tok::kw_new; + // Consume the 'new' or 'delete'. + SymbolLocations[SymbolIdx++] = ConsumeToken(); + if (Tok.is(tok::l_square)) { + // Consume the '['. + SourceLocation LBracketLoc = ConsumeBracket(); + // Consume the ']'. + SourceLocation RBracketLoc = MatchRHSPunctuation(tok::r_square, + LBracketLoc); + if (RBracketLoc.isInvalid()) + return true; + + SymbolLocations[SymbolIdx++] = LBracketLoc; + SymbolLocations[SymbolIdx++] = RBracketLoc; + Op = isNew? OO_Array_New : OO_Array_Delete; + } else { + Op = isNew? OO_New : OO_Delete; + } + break; + } + +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + case tok::Token: \ + SymbolLocations[SymbolIdx++] = ConsumeToken(); \ + Op = OO_##Name; \ + break; +#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly) +#include "clang/Basic/OperatorKinds.def" + + case tok::l_paren: { + // Consume the '('. + SourceLocation LParenLoc = ConsumeParen(); + // Consume the ')'. + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, + LParenLoc); + if (RParenLoc.isInvalid()) + return true; + + SymbolLocations[SymbolIdx++] = LParenLoc; + SymbolLocations[SymbolIdx++] = RParenLoc; + Op = OO_Call; + break; + } + + case tok::l_square: { + // Consume the '['. + SourceLocation LBracketLoc = ConsumeBracket(); + // Consume the ']'. + SourceLocation RBracketLoc = MatchRHSPunctuation(tok::r_square, + LBracketLoc); + if (RBracketLoc.isInvalid()) + return true; + + SymbolLocations[SymbolIdx++] = LBracketLoc; + SymbolLocations[SymbolIdx++] = RBracketLoc; + Op = OO_Subscript; + break; + } + + case tok::code_completion: { + // Code completion for the operator name. + Actions.CodeCompleteOperatorName(CurScope); + + // Consume the operator token. + ConsumeCodeCompletionToken(); + + // Don't try to parse any further. + return true; + } + + default: + break; + } + + if (Op != OO_None) { + // We have parsed an operator-function-id. + Result.setOperatorFunctionId(KeywordLoc, Op, SymbolLocations); + return false; + } + + // Parse a literal-operator-id. + // + // literal-operator-id: [C++0x 13.5.8] + // operator "" identifier + + if (getLang().CPlusPlus0x && Tok.is(tok::string_literal)) { + if (Tok.getLength() != 2) + Diag(Tok.getLocation(), diag::err_operator_string_not_empty); + ConsumeStringToken(); + + if (Tok.isNot(tok::identifier)) { + Diag(Tok.getLocation(), diag::err_expected_ident); + return true; + } + + IdentifierInfo *II = Tok.getIdentifierInfo(); + Result.setLiteralOperatorId(II, KeywordLoc, ConsumeToken()); + return false; + } + + // Parse a conversion-function-id. + // + // conversion-function-id: [C++ 12.3.2] + // operator conversion-type-id + // + // conversion-type-id: + // type-specifier-seq conversion-declarator[opt] + // + // conversion-declarator: + // ptr-operator conversion-declarator[opt] + + // Parse the type-specifier-seq. + DeclSpec DS; + if (ParseCXXTypeSpecifierSeq(DS)) // FIXME: ObjectType? + return true; + + // Parse the conversion-declarator, which is merely a sequence of + // ptr-operators. + Declarator D(DS, Declarator::TypeNameContext); + ParseDeclaratorInternal(D, /*DirectDeclParser=*/0); + + // Finish up the type. + Action::TypeResult Ty = Actions.ActOnTypeName(CurScope, D); + if (Ty.isInvalid()) + return true; + + // Note that this is a conversion-function-id. + Result.setConversionFunctionId(KeywordLoc, Ty.get(), + D.getSourceRange().getEnd()); + return false; +} + +/// \brief Parse a C++ unqualified-id (or a C identifier), which describes the +/// name of an entity. +/// +/// \code +/// unqualified-id: [C++ expr.prim.general] +/// identifier +/// operator-function-id +/// conversion-function-id +/// [C++0x] literal-operator-id [TODO] +/// ~ class-name +/// template-id +/// +/// \endcode +/// +/// \param The nested-name-specifier that preceded this unqualified-id. If +/// non-empty, then we are parsing the unqualified-id of a qualified-id. +/// +/// \param EnteringContext whether we are entering the scope of the +/// nested-name-specifier. +/// +/// \param AllowDestructorName whether we allow parsing of a destructor name. +/// +/// \param AllowConstructorName whether we allow parsing a constructor name. +/// +/// \param ObjectType if this unqualified-id occurs within a member access +/// expression, the type of the base object whose member is being accessed. +/// +/// \param Result on a successful parse, contains the parsed unqualified-id. +/// +/// \returns true if parsing fails, false otherwise. +bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, + bool AllowDestructorName, + bool AllowConstructorName, + TypeTy *ObjectType, + UnqualifiedId &Result) { + + // Handle 'A::template B'. This is for template-ids which have not + // already been annotated by ParseOptionalCXXScopeSpecifier(). + bool TemplateSpecified = false; + SourceLocation TemplateKWLoc; + if (getLang().CPlusPlus && Tok.is(tok::kw_template) && + (ObjectType || SS.isSet())) { + TemplateSpecified = true; + TemplateKWLoc = ConsumeToken(); + } + + // unqualified-id: + // identifier + // template-id (when it hasn't already been annotated) + if (Tok.is(tok::identifier)) { + // Consume the identifier. + IdentifierInfo *Id = Tok.getIdentifierInfo(); + SourceLocation IdLoc = ConsumeToken(); + + if (!getLang().CPlusPlus) { + // If we're not in C++, only identifiers matter. Record the + // identifier and return. + Result.setIdentifier(Id, IdLoc); + return false; + } + + if (AllowConstructorName && + Actions.isCurrentClassName(*Id, CurScope, &SS)) { + // We have parsed a constructor name. + Result.setConstructorName(Actions.getTypeName(*Id, IdLoc, CurScope, + &SS, false), + IdLoc, IdLoc); + } else { + // We have parsed an identifier. + Result.setIdentifier(Id, IdLoc); + } + + // If the next token is a '<', we may have a template. + if (TemplateSpecified || Tok.is(tok::less)) + return ParseUnqualifiedIdTemplateId(SS, Id, IdLoc, EnteringContext, + ObjectType, Result, + TemplateSpecified, TemplateKWLoc); + + return false; + } + + // unqualified-id: + // template-id (already parsed and annotated) + if (Tok.is(tok::annot_template_id)) { + TemplateIdAnnotation *TemplateId + = static_cast<TemplateIdAnnotation*>(Tok.getAnnotationValue()); + + // If the template-name names the current class, then this is a constructor + if (AllowConstructorName && TemplateId->Name && + Actions.isCurrentClassName(*TemplateId->Name, CurScope, &SS)) { + if (SS.isSet()) { + // C++ [class.qual]p2 specifies that a qualified template-name + // is taken as the constructor name where a constructor can be + // declared. Thus, the template arguments are extraneous, so + // complain about them and remove them entirely. + Diag(TemplateId->TemplateNameLoc, + diag::err_out_of_line_constructor_template_id) + << TemplateId->Name + << FixItHint::CreateRemoval( + SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)); + Result.setConstructorName(Actions.getTypeName(*TemplateId->Name, + TemplateId->TemplateNameLoc, + CurScope, + &SS, false), + TemplateId->TemplateNameLoc, + TemplateId->RAngleLoc); + TemplateId->Destroy(); + ConsumeToken(); + return false; + } + + Result.setConstructorTemplateId(TemplateId); + ConsumeToken(); + return false; + } + + // We have already parsed a template-id; consume the annotation token as + // our unqualified-id. + Result.setTemplateId(TemplateId); + ConsumeToken(); + return false; + } + + // unqualified-id: + // operator-function-id + // conversion-function-id + if (Tok.is(tok::kw_operator)) { + if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, Result)) + return true; + + // If we have an operator-function-id or a literal-operator-id and the next + // token is a '<', we may have a + // + // template-id: + // operator-function-id < template-argument-list[opt] > + if ((Result.getKind() == UnqualifiedId::IK_OperatorFunctionId || + Result.getKind() == UnqualifiedId::IK_LiteralOperatorId) && + (TemplateSpecified || Tok.is(tok::less))) + return ParseUnqualifiedIdTemplateId(SS, 0, SourceLocation(), + EnteringContext, ObjectType, + Result, + TemplateSpecified, TemplateKWLoc); + + return false; + } + + if (getLang().CPlusPlus && + (AllowDestructorName || SS.isSet()) && Tok.is(tok::tilde)) { + // C++ [expr.unary.op]p10: + // There is an ambiguity in the unary-expression ~X(), where X is a + // class-name. The ambiguity is resolved in favor of treating ~ as a + // unary complement rather than treating ~X as referring to a destructor. + + // Parse the '~'. + SourceLocation TildeLoc = ConsumeToken(); + + // Parse the class-name. + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_destructor_tilde_identifier); + return true; + } + + // Parse the class-name (or template-name in a simple-template-id). + IdentifierInfo *ClassName = Tok.getIdentifierInfo(); + SourceLocation ClassNameLoc = ConsumeToken(); + + if (TemplateSpecified || Tok.is(tok::less)) { + Result.setDestructorName(TildeLoc, 0, ClassNameLoc); + return ParseUnqualifiedIdTemplateId(SS, ClassName, ClassNameLoc, + EnteringContext, ObjectType, Result, + TemplateSpecified, TemplateKWLoc); + } + + // Note that this is a destructor name. + Action::TypeTy *Ty = Actions.getDestructorName(TildeLoc, *ClassName, + ClassNameLoc, CurScope, + SS, ObjectType, + EnteringContext); + if (!Ty) + return true; + + Result.setDestructorName(TildeLoc, Ty, ClassNameLoc); + return false; + } + + Diag(Tok, diag::err_expected_unqualified_id) + << getLang().CPlusPlus; + return true; +} + +/// 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), + 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; + case tok::kw___is_literal: return UTT_IsLiteral; + } +} + +/// 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, Toks)) { + // 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, false); + } + + // 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(CurScope, 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/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp new file mode 100644 index 0000000..a382a9a --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp @@ -0,0 +1,376 @@ +//===--- 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 "clang/Parse/Scope.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.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); + } +} + +static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc, + Designation &Desig) { + // 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())) + P.Diag(Loc, diag::ext_gnu_missing_equal_designator); + else if (Desig.getNumDesignators() > 0) + P.Diag(Loc, diag::err_expected_equal_designator); +} + +/// 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(); + + llvm::SmallString<256> NewSyntax; + llvm::raw_svector_ostream(NewSyntax) << '.' << FieldName->getName() + << " = "; + + 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) + << FixItHint::CreateReplacement(SourceRange(NameLoc, ColonLoc), + NewSyntax.str()); + + 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(); + OwningExprResult Idx(Actions); + + // If Objective-C is enabled and this is a typename (class message + // send) or send to 'super', parse this as a message send + // expression. We handle C++ and C separately, since C++ requires + // much more complicated parsing. + if (getLang().ObjC1 && getLang().CPlusPlus) { + // Send to 'super'. + if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super && + NextToken().isNot(tok::period) && CurScope->isInObjcMethodScope()) { + CheckArrayDesignatorSyntax(*this, StartLoc, Desig); + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + ConsumeToken(), 0, + ExprArg(Actions)); + } + + // Parse the receiver, which is either a type or an expression. + bool IsExpr; + void *TypeOrExpr; + if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) { + SkipUntil(tok::r_square); + return ExprError(); + } + + // If the receiver was a type, we have a class message; parse + // the rest of it. + if (!IsExpr) { + CheckArrayDesignatorSyntax(*this, StartLoc, Desig); + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + SourceLocation(), + TypeOrExpr, + ExprArg(Actions)); + } + + // If the receiver was an expression, we still don't know + // whether we have a message send or an array designator; just + // adopt the expression for further analysis below. + // FIXME: potentially-potentially evaluated expression above? + Idx = OwningExprResult(Actions, TypeOrExpr); + } else if (getLang().ObjC1 && Tok.is(tok::identifier)) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + SourceLocation IILoc = Tok.getLocation(); + TypeTy *ReceiverType; + // Three cases. This is a message send to a type: [type foo] + // This is a message send to super: [super foo] + // This is a message sent to an expr: [super.bar foo] + switch (Action::ObjCMessageKind Kind + = Actions.getObjCMessageKind(CurScope, II, IILoc, + II == Ident_super, + NextToken().is(tok::period), + ReceiverType)) { + case Action::ObjCSuperMessage: + case Action::ObjCClassMessage: + CheckArrayDesignatorSyntax(*this, StartLoc, Desig); + if (Kind == Action::ObjCSuperMessage) + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + ConsumeToken(), + 0, + ExprArg(Actions)); + ConsumeToken(); // the identifier + if (!ReceiverType) { + SkipUntil(tok::r_square); + return ExprError(); + } + + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + SourceLocation(), + ReceiverType, + ExprArg(Actions)); + + case Action::ObjCInstanceMessage: + // Fall through; we'll just parse the expression and + // (possibly) treat this like an Objective-C message send + // later. + break; + } + } + + // Parse the index expression, if we haven't already gotten one + // above (which can only happen in Objective-C++). + // 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. + // FIXME: We also need to tell Sema that we're in a + // potentially-potentially evaluated context. + if (!Idx.get()) { + 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)) { + CheckArrayDesignatorSyntax(*this, Tok.getLocation(), Desig); + 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) + << FixItHint::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/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp new file mode 100644 index 0000000..9cfe734 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp @@ -0,0 +1,2171 @@ +//===--- 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 "@" + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, false); + ConsumeCodeCompletionToken(); + } + + 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; + llvm::SmallVector<SourceLocation, 8> ClassLocs; + + + while (1) { + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + SkipUntil(tok::semi); + return DeclPtrTy(); + } + ClassNames.push_back(Tok.getIdentifierInfo()); + ClassLocs.push_back(Tok.getLocation()); + 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.data(), + ClassLocs.data(), + 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 + + // Code completion after '@interface'. + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCInterfaceDecl(CurScope); + ConsumeCodeCompletionToken(); + } + + 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) && + !isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category. + SourceLocation lparenLoc = ConsumeParen(); + SourceLocation categoryLoc, rparenLoc; + IdentifierInfo *categoryId = 0; + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCInterfaceCategory(CurScope, nameId, nameLoc); + ConsumeCodeCompletionToken(); + } + + // 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 LAngleLoc, EndProtoLoc; + llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs; + llvm::SmallVector<SourceLocation, 8> ProtocolLocs; + if (Tok.is(tok::less) && + ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, + LAngleLoc, 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(), + ProtocolLocs.data(), + EndProtoLoc); + if (Tok.is(tok::l_brace)) + ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, + atLoc); + + 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(); + + // Code completion of superclass names. + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCSuperclass(CurScope, nameId, nameLoc); + ConsumeCodeCompletionToken(); + } + + 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; + llvm::SmallVector<SourceLocation, 8> ProtocolLocs; + SourceLocation LAngleLoc, EndProtoLoc; + if (Tok.is(tok::less) && + ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, + LAngleLoc, EndProtoLoc)) + return DeclPtrTy(); + + DeclPtrTy ClsType = + Actions.ActOnStartClassInterface(atLoc, nameId, nameLoc, + superClassId, superClassLoc, + ProtocolRefs.data(), ProtocolRefs.size(), + ProtocolLocs.data(), + EndProtoLoc, attrList); + + if (Tok.is(tok::l_brace)) + ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, atLoc); + + ParseObjCInterfaceDeclList(ClsType, tok::objc_interface); + return ClsType; +} + +/// The Objective-C property callback. This should be defined where +/// it's used, but instead it's been lifted to here to support VS2005. +struct Parser::ObjCPropertyCallback : FieldCallback { + Parser &P; + DeclPtrTy IDecl; + llvm::SmallVectorImpl<DeclPtrTy> &Props; + ObjCDeclSpec &OCDS; + SourceLocation AtLoc; + tok::ObjCKeywordKind MethodImplKind; + + ObjCPropertyCallback(Parser &P, DeclPtrTy IDecl, + llvm::SmallVectorImpl<DeclPtrTy> &Props, + ObjCDeclSpec &OCDS, SourceLocation AtLoc, + tok::ObjCKeywordKind MethodImplKind) : + P(P), IDecl(IDecl), Props(Props), OCDS(OCDS), AtLoc(AtLoc), + MethodImplKind(MethodImplKind) { + } + + DeclPtrTy invoke(FieldDeclarator &FD) { + if (FD.D.getIdentifier() == 0) { + P.Diag(AtLoc, diag::err_objc_property_requires_field_name) + << FD.D.getSourceRange(); + return DeclPtrTy(); + } + if (FD.BitfieldSize) { + P.Diag(AtLoc, diag::err_objc_property_bitfield) + << FD.D.getSourceRange(); + return DeclPtrTy(); + } + + // Install the property declarator into interfaceDecl. + IdentifierInfo *SelName = + OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier(); + + Selector GetterSel = + P.PP.getSelectorTable().getNullarySelector(SelName); + IdentifierInfo *SetterName = OCDS.getSetterName(); + Selector SetterSel; + if (SetterName) + SetterSel = P.PP.getSelectorTable().getSelector(1, &SetterName); + else + SetterSel = SelectorTable::constructSetterName(P.PP.getIdentifierTable(), + P.PP.getSelectorTable(), + FD.D.getIdentifier()); + bool isOverridingProperty = false; + DeclPtrTy Property = + P.Actions.ActOnProperty(P.CurScope, AtLoc, FD, OCDS, + GetterSel, SetterSel, IDecl, + &isOverridingProperty, + MethodImplKind); + if (!isOverridingProperty) + Props.push_back(Property); + + return Property; + } +}; + +/// 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; + + SourceRange AtEnd; + + 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; + } + if (Tok.is(tok::l_paren)) { + Diag(Tok, diag::err_expected_minus_or_plus); + DeclPtrTy methodPrototype = ParseObjCMethodDecl(Tok.getLocation(), + tok::minus, + interfaceDecl, + MethodImplKind); + 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; + + // Code completion within an Objective-C interface. + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(CurScope, + ObjCImpDecl? Action::CCC_ObjCImplementation + : Action::CCC_ObjCInterface); + ConsumeCodeCompletionToken(); + } + + // 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(0)); + continue; + } + + // Otherwise, we have an @ directive, eat the @. + SourceLocation AtLoc = ConsumeToken(); // the "@" + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, true); + ConsumeCodeCompletionToken(); + break; + } + + tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID(); + + if (DirectiveKind == tok::objc_end) { // @end -> terminate list + AtEnd.setBegin(AtLoc); + AtEnd.setEnd(Tok.getLocation()); + break; + } else if (DirectiveKind == tok::objc_not_keyword) { + Diag(Tok, diag::err_objc_unknown_at); + SkipUntil(tok::semi); + continue; + } + + // 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, interfaceDecl, + allMethods.data(), allMethods.size()); + + ObjCPropertyCallback Callback(*this, interfaceDecl, allProperties, + OCDS, AtLoc, MethodImplKind); + + // Parse all the comma separated declarators. + DeclSpec DS; + ParseStructDeclaration(DS, Callback); + + ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list, "", + tok::at); + 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.is(tok::code_completion)) { + Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, true); + ConsumeCodeCompletionToken(); + } else 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(CurScope, AtEnd, 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, DeclPtrTy ClassDecl, + DeclPtrTy *Methods, + unsigned NumMethods) { + assert(Tok.getKind() == tok::l_paren); + SourceLocation LHSLoc = ConsumeParen(); // consume '(' + + while (1) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCPropertyFlags(CurScope, DS); + ConsumeCodeCompletionToken(); + } + 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.is(tok::code_completion)) { + if (II->getNameStart()[0] == 's') + Actions.CodeCompleteObjCPropertySetter(CurScope, ClassDecl, + Methods, NumMethods); + else + Actions.CodeCompleteObjCPropertyGetter(CurScope, ClassDecl, + Methods, NumMethods); + ConsumeCodeCompletionToken(); + } + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + SkipUntil(tok::r_paren); + return; + } + + if (II->getNameStart()[0] == 's') { + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter); + DS.setSetterName(Tok.getIdentifierInfo()); + ConsumeToken(); // consume method name + + if (ExpectAndConsume(tok::colon, + diag::err_expected_colon_after_setter_name, "", + 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) { + ParsingDeclRAIIObject PD(*this); + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCMethodDecl(CurScope, mType == tok::minus, + /*ReturnType=*/0, IDecl); + ConsumeCodeCompletionToken(); + } + + // Parse the return type if present. + TypeTy *ReturnType = 0; + ObjCDeclSpec DSRet; + if (Tok.is(tok::l_paren)) + ReturnType = ParseObjCTypeName(DSRet); + + // If attributes exist before the method, parse them. + llvm::OwningPtr<AttributeList> MethodAttrs; + if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) + MethodAttrs.reset(ParseGNUAttributes()); + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCMethodDecl(CurScope, mType == tok::minus, + ReturnType, IDecl); + ConsumeCodeCompletionToken(); + } + + // Now parse the selector. + 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<DeclaratorChunk::ParamInfo, 8> CParamInfo; + if (Tok.isNot(tok::colon)) { + // If attributes exist after the method, parse them. + if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) + MethodAttrs.reset(addAttributeLists(MethodAttrs.take(), + ParseGNUAttributes())); + + Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); + DeclPtrTy Result + = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), + mType, IDecl, DSRet, ReturnType, Sel, + 0, + CParamInfo.data(), CParamInfo.size(), + MethodAttrs.get(), + MethodImplKind); + PD.complete(Result); + return Result; + } + + 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 = ParseGNUAttributes(); + + 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); + IdentifierInfo *ParmII = ParmDecl.getIdentifier(); + DeclPtrTy Param = Actions.ActOnParamDeclarator(CurScope, ParmDecl); + CParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, + ParmDecl.getIdentifierLoc(), + Param, + 0)); + + } + + // FIXME: Add support for optional parmameter list... + // If attributes exist after the method, parse them. + if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) + MethodAttrs.reset(addAttributeLists(MethodAttrs.take(), + ParseGNUAttributes())); + + if (KeyIdents.size() == 0) + return DeclPtrTy(); + Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(), + &KeyIdents[0]); + DeclPtrTy Result + = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), + mType, IDecl, DSRet, ReturnType, Sel, + &ArgInfos[0], + CParamInfo.data(), CParamInfo.size(), + MethodAttrs.get(), + MethodImplKind, isVariadic); + PD.complete(Result); + + // Delete referenced AttributeList objects. + for (llvm::SmallVectorImpl<Action::ObjCArgInfo>::iterator + I = ArgInfos.begin(), E = ArgInfos.end(); I != E; ++I) + delete I->ArgAttrs; + + return Result; +} + +/// objc-protocol-refs: +/// '<' identifier-list '>' +/// +bool Parser:: +ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &Protocols, + llvm::SmallVectorImpl<SourceLocation> &ProtocolLocs, + bool WarnOnDeclarations, + SourceLocation &LAngleLoc, SourceLocation &EndLoc) { + assert(Tok.is(tok::less) && "expected <"); + + LAngleLoc = ConsumeToken(); // the "<" + + llvm::SmallVector<IdentifierLocPair, 8> ProtocolIdents; + + while (1) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents.data(), + ProtocolIdents.size()); + ConsumeCodeCompletionToken(); + } + + 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())); + ProtocolLocs.push_back(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, + tok::ObjCKeywordKind visibility, + SourceLocation atLoc) { + assert(Tok.is(tok::l_brace) && "expected {"); + llvm::SmallVector<DeclPtrTy, 32> AllIvarDecls; + + ParseScope ClassScope(this, Scope::DeclScope|Scope::ClassScope); + + SourceLocation LBraceLoc = ConsumeBrace(); // the "{" + + // 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) + << FixItHint::CreateRemoval(Tok.getLocation()); + ConsumeToken(); + continue; + } + + // Set the default visibility to private. + if (Tok.is(tok::at)) { // parse objc-visibility-spec + ConsumeToken(); // eat the @ sign + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCAtVisibility(CurScope); + ConsumeCodeCompletionToken(); + } + + 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; + } + } + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(CurScope, + Action::CCC_ObjCInstanceVariableList); + ConsumeCodeCompletionToken(); + } + + struct ObjCIvarCallback : FieldCallback { + Parser &P; + DeclPtrTy IDecl; + tok::ObjCKeywordKind visibility; + llvm::SmallVectorImpl<DeclPtrTy> &AllIvarDecls; + + ObjCIvarCallback(Parser &P, DeclPtrTy IDecl, tok::ObjCKeywordKind V, + llvm::SmallVectorImpl<DeclPtrTy> &AllIvarDecls) : + P(P), IDecl(IDecl), visibility(V), AllIvarDecls(AllIvarDecls) { + } + + DeclPtrTy invoke(FieldDeclarator &FD) { + // Install the declarator into the interface decl. + DeclPtrTy Field + = P.Actions.ActOnIvar(P.CurScope, + FD.D.getDeclSpec().getSourceRange().getBegin(), + IDecl, FD.D, FD.BitfieldSize, visibility); + if (Field) + AllIvarDecls.push_back(Field); + return Field; + } + } Callback(*this, interfaceDecl, visibility, AllIvarDecls); + + // Parse all the comma separated declarators. + DeclSpec DS; + ParseStructDeclaration(DS, Callback); + + 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.is(tok::code_completion)) { + Actions.CodeCompleteObjCProtocolDecl(CurScope); + ConsumeCodeCompletionToken(); + } + + 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 LAngleLoc, EndProtoLoc; + + llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs; + llvm::SmallVector<SourceLocation, 8> ProtocolLocs; + if (Tok.is(tok::less) && + ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, + LAngleLoc, EndProtoLoc)) + return DeclPtrTy(); + + DeclPtrTy ProtoType = + Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc, + ProtocolRefs.data(), + ProtocolRefs.size(), + ProtocolLocs.data(), + 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 + + // Code completion after '@implementation'. + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCImplementationDecl(CurScope); + ConsumeCodeCompletionToken(); + } + + 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::code_completion)) { + Actions.CodeCompleteObjCImplementationCategory(CurScope, nameId, nameLoc); + ConsumeCodeCompletionToken(); + } + + 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; + PendingObjCImpDecl.push_back(ObjCImpDecl); + 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*/, + tok::objc_private, atLoc); + ObjCImpDecl = ImplClsType; + PendingObjCImpDecl.push_back(ObjCImpDecl); + + return DeclPtrTy(); +} + +Parser::DeclPtrTy Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) { + assert(Tok.isObjCAtKeyword(tok::objc_end) && + "ParseObjCAtEndDeclaration(): Expected @end"); + DeclPtrTy Result = ObjCImpDecl; + ConsumeToken(); // the "end" identifier + if (ObjCImpDecl) { + Actions.ActOnAtEnd(CurScope, atEnd, ObjCImpDecl); + ObjCImpDecl = DeclPtrTy(); + PendingObjCImpDecl.pop_back(); + } + else { + // missing @implementation + Diag(atEnd.getBegin(), diag::warn_expected_implementation); + } + return Result; +} + +Parser::DeclGroupPtrTy Parser::RetrievePendingObjCImpDecl() { + if (PendingObjCImpDecl.empty()) + return Actions.ConvertDeclToDeclGroup(DeclPtrTy()); + DeclPtrTy ImpDecl = PendingObjCImpDecl.pop_back_val(); + Actions.ActOnAtEnd(CurScope, SourceRange(), ImpDecl); + return Actions.ConvertDeclToDeclGroup(ImpDecl); +} + +/// 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 + + while (true) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCPropertyDefinition(CurScope, ObjCImpDecl); + ConsumeCodeCompletionToken(); + } + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_synthesized_property_name); + SkipUntil(tok::semi); + return DeclPtrTy(); + } + + 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.is(tok::code_completion)) { + Actions.CodeCompleteObjCPropertySynthesizeIvar(CurScope, propertyId, + ObjCImpDecl); + ConsumeCodeCompletionToken(); + } + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + break; + } + propertyIvar = Tok.getIdentifierInfo(); + ConsumeToken(); // consume ivar-name + } + Actions.ActOnPropertyImplDecl(CurScope, 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"; + SkipUntil(tok::semi); + } + else + ConsumeToken(); // consume ';' + 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 + while (true) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCPropertyDefinition(CurScope, ObjCImpDecl); + ConsumeCodeCompletionToken(); + } + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + SkipUntil(tok::semi); + return DeclPtrTy(); + } + + IdentifierInfo *propertyId = Tok.getIdentifierInfo(); + SourceLocation propertyLoc = ConsumeToken(); // consume property name + Actions.ActOnPropertyImplDecl(CurScope, 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"; + SkipUntil(tok::semi); + } + else + ConsumeToken(); // consume ';' + 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(); + } + } + // consume ';' + ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@throw"); + 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(); + } + StmtVector 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 declarator, so it + // gets added to the current scope. + FirstPart = Actions.ActOnObjCExceptionDecl(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()); + + OwningStmtResult Catch = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc, + RParenLoc, + FirstPart, + move(CatchBody)); + if (!Catch.isInvalid()) + CatchStmts.push_back(Catch.release()); + + } 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_arg(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)) { + if (ObjCImpDecl) { + Diag(Tok, diag::warn_semicolon_before_method_body) + << FixItHint::CreateRemoval(Tok.getLocation()); + } + 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::ObjCMethodScope|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.is(tok::code_completion)) { + Actions.CodeCompleteObjCAtStatement(CurScope); + ConsumeCodeCompletionToken(); + return StmtError(); + } + + if (Tok.isObjCAtKeyword(tok::objc_try)) + return ParseObjCTryStmt(AtLoc); + + if (Tok.isObjCAtKeyword(tok::objc_throw)) + return ParseObjCThrowStmt(AtLoc); + + 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.MakeFullExpr(Res)); +} + +Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { + switch (Tok.getKind()) { + case tok::code_completion: + Actions.CodeCompleteObjCAtExpression(CurScope); + ConsumeCodeCompletionToken(); + return ExprError(); + + 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)); + } + } +} + +/// \brirg Parse the receiver of an Objective-C++ message send. +/// +/// This routine parses the receiver of a message send in +/// Objective-C++ either as a type or as an expression. Note that this +/// routine must not be called to parse a send to 'super', since it +/// has no way to return such a result. +/// +/// \param IsExpr Whether the receiver was parsed as an expression. +/// +/// \param TypeOrExpr If the receiver was parsed as an expression (\c +/// IsExpr is true), the parsed expression. If the receiver was parsed +/// as a type (\c IsExpr is false), the parsed type. +/// +/// \returns True if an error occurred during parsing or semantic +/// analysis, in which case the arguments do not have valid +/// values. Otherwise, returns false for a successful parse. +/// +/// objc-receiver: [C++] +/// 'super' [not parsed here] +/// expression +/// simple-type-specifier +/// typename-specifier + +bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) { + if (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || + Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope)) + TryAnnotateTypeOrScopeToken(); + + if (!isCXXSimpleTypeSpecifier()) { + // objc-receiver: + // expression + OwningExprResult Receiver = ParseExpression(); + if (Receiver.isInvalid()) + return true; + + IsExpr = true; + TypeOrExpr = Receiver.take(); + return false; + } + + // objc-receiver: + // typename-specifier + // simple-type-specifier + // expression (that starts with one of the above) + DeclSpec DS; + ParseCXXSimpleTypeSpecifier(DS); + + if (Tok.is(tok::l_paren)) { + // If we see an opening parentheses at this point, we are + // actually parsing an expression that starts with a + // function-style cast, e.g., + // + // postfix-expression: + // simple-type-specifier ( expression-list [opt] ) + // typename-specifier ( expression-list [opt] ) + // + // Parse the remainder of this case, then the (optional) + // postfix-expression suffix, followed by the (optional) + // right-hand side of the binary expression. We have an + // instance method. + OwningExprResult Receiver = ParseCXXTypeConstructExpression(DS); + if (!Receiver.isInvalid()) + Receiver = ParsePostfixExpressionSuffix(move(Receiver)); + if (!Receiver.isInvalid()) + Receiver = ParseRHSOfBinaryExpression(move(Receiver), prec::Comma); + if (Receiver.isInvalid()) + return true; + + IsExpr = true; + TypeOrExpr = Receiver.take(); + return false; + } + + // We have a class message. Turn the simple-type-specifier or + // typename-specifier we parsed into a type and parse the + // remainder of the class message. + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + TypeResult Type = Actions.ActOnTypeName(CurScope, DeclaratorInfo); + if (Type.isInvalid()) + return true; + + IsExpr = false; + TypeOrExpr = Type.get(); + return false; +} + +/// objc-message-expr: +/// '[' objc-receiver objc-message-args ']' +/// +/// objc-receiver: [C] +/// 'super' +/// expression +/// class-name +/// type-name +/// +Parser::OwningExprResult Parser::ParseObjCMessageExpression() { + assert(Tok.is(tok::l_square) && "'[' expected"); + SourceLocation LBracLoc = ConsumeBracket(); // consume '[' + + if (getLang().CPlusPlus) { + // We completely separate the C and C++ cases because C++ requires + // more complicated (read: slower) parsing. + + // Handle send to super. + // FIXME: This doesn't benefit from the same typo-correction we + // get in Objective-C. + if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super && + NextToken().isNot(tok::period) && CurScope->isInObjcMethodScope()) + return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), 0, + ExprArg(Actions)); + + // Parse the receiver, which is either a type or an expression. + bool IsExpr; + void *TypeOrExpr; + if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) { + SkipUntil(tok::r_square); + return ExprError(); + } + + if (IsExpr) + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), 0, + OwningExprResult(Actions, TypeOrExpr)); + + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), + TypeOrExpr, ExprArg(Actions)); + } else if (Tok.is(tok::identifier)) { + IdentifierInfo *Name = Tok.getIdentifierInfo(); + SourceLocation NameLoc = Tok.getLocation(); + TypeTy *ReceiverType; + switch (Actions.getObjCMessageKind(CurScope, Name, NameLoc, + Name == Ident_super, + NextToken().is(tok::period), + ReceiverType)) { + case Action::ObjCSuperMessage: + return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), 0, + ExprArg(Actions)); + + case Action::ObjCClassMessage: + if (!ReceiverType) { + SkipUntil(tok::r_square); + return ExprError(); + } + + ConsumeToken(); // the type name + + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), + ReceiverType, + ExprArg(Actions)); + + case Action::ObjCInstanceMessage: + // Fall through to parse an expression. + break; + } + } + + // Otherwise, an arbitrary expression can be the receiver of a send. + OwningExprResult Res(ParseExpression()); + if (Res.isInvalid()) { + SkipUntil(tok::r_square); + return move(Res); + } + + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), 0, + move(Res)); +} + +/// \brief Parse the remainder of an Objective-C message following the +/// '[' objc-receiver. +/// +/// This routine handles sends to super, class messages (sent to a +/// class name), and instance messages (sent to an object), and the +/// target is represented by \p SuperLoc, \p ReceiverType, or \p +/// ReceiverExpr, respectively. Only one of these parameters may have +/// a valid value. +/// +/// \param LBracLoc The location of the opening '['. +/// +/// \param SuperLoc If this is a send to 'super', the location of the +/// 'super' keyword that indicates a send to the superclass. +/// +/// \param ReceiverType If this is a class message, the type of the +/// class we are sending a message to. +/// +/// \param ReceiverExpr If this is an instance message, the expression +/// used to compute the receiver object. +/// +/// 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 SuperLoc, + TypeTy *ReceiverType, + ExprArg ReceiverExpr) { + if (Tok.is(tok::code_completion)) { + if (SuperLoc.isValid()) + Actions.CodeCompleteObjCSuperMessage(CurScope, SuperLoc, 0, 0); + else if (ReceiverType) + Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverType, 0, 0); + else + Actions.CodeCompleteObjCInstanceMessage(CurScope, ReceiverExpr.get(), + 0, 0); + ConsumeCodeCompletionToken(); + } + + // 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()); + + // Code completion after each argument. + if (Tok.is(tok::code_completion)) { + if (SuperLoc.isValid()) + Actions.CodeCompleteObjCSuperMessage(CurScope, SuperLoc, + KeyIdents.data(), + KeyIdents.size()); + else if (ReceiverType) + Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverType, + KeyIdents.data(), + KeyIdents.size()); + else + Actions.CodeCompleteObjCInstanceMessage(CurScope, ReceiverExpr.get(), + KeyIdents.data(), + KeyIdents.size()); + ConsumeCodeCompletionToken(); + } + + // 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)) { + if (Tok.is(tok::identifier)) + Diag(Tok, diag::err_expected_colon); + else + 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]); + + if (SuperLoc.isValid()) + return Actions.ActOnSuperMessage(CurScope, SuperLoc, Sel, + LBracLoc, SelectorLoc, RBracLoc, + Action::MultiExprArg(Actions, + KeyExprs.take(), + KeyExprs.size())); + else if (ReceiverType) + return Actions.ActOnClassMessage(CurScope, ReceiverType, Sel, + LBracLoc, SelectorLoc, RBracLoc, + Action::MultiExprArg(Actions, + KeyExprs.take(), + KeyExprs.size())); + return Actions.ActOnInstanceMessage(CurScope, move(ReceiverExpr), Sel, + LBracLoc, SelectorLoc, RBracLoc, + Action::MultiExprArg(Actions, + 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/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp new file mode 100644 index 0000000..c4e4a52 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp @@ -0,0 +1,269 @@ +//===--- 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) { + 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(); + PP.Lex(Tok); + if (Tok.isNot(tok::eom)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "pack"; + return; + } + + Actions.ActOnPragmaPack(Kind, Name, Alignment.release(), PackLoc, + LParenLoc, RParenLoc); +} + +// #pragma 'options' 'align' '=' {'natural', 'mac68k', 'power', 'reset'} +void PragmaOptionsHandler::HandlePragma(Preprocessor &PP, Token &OptionsTok) { + SourceLocation OptionsLoc = OptionsTok.getLocation(); + + Token Tok; + PP.Lex(Tok); + if (Tok.isNot(tok::identifier) || !Tok.getIdentifierInfo()->isStr("align")) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_align); + return; + } + + PP.Lex(Tok); + if (Tok.isNot(tok::equal)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_equal); + return; + } + + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) + << "options"; + return; + } + + Action::PragmaOptionsAlignKind Kind = Action::POAK_Natural; + const IdentifierInfo *II = Tok.getIdentifierInfo(); + if (II->isStr("natural")) + Kind = Action::POAK_Natural; + else if (II->isStr("power")) + Kind = Action::POAK_Power; + else if (II->isStr("mac68k")) + Kind = Action::POAK_Mac68k; + else if (II->isStr("reset")) + Kind = Action::POAK_Reset; + else { + PP.Diag(Tok.getLocation(), diag::warn_pragma_options_invalid_option); + return; + } + + SourceLocation KindLoc = Tok.getLocation(); + PP.Lex(Tok); + if (Tok.isNot(tok::eom)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) + << "options"; + return; + } + + Actions.ActOnPragmaOptionsAlign(Kind, OptionsLoc, KindLoc); +} + +// #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<Token, 5> Identifiers; + SourceLocation RParenLoc; + bool LexID = true; + + while (true) { + PP.Lex(Tok); + + if (LexID) { + if (Tok.is(tok::identifier)) { + Identifiers.push_back(Tok); + LexID = false; + continue; + } + + // Illegal token! + 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! + PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_punc); + return; + } + + PP.Lex(Tok); + if (Tok.isNot(tok::eom)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << + "unused"; + return; + } + + // Verify that we have a location for the right parenthesis. + assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'"); + assert(!Identifiers.empty() && "Valid '#pragma unused' must have arguments"); + + // Perform the action to handle the pragma. + Actions.ActOnPragmaUnused(Identifiers.data(), Identifiers.size(), + parser.CurScope, UnusedLoc, LParenLoc, RParenLoc); +} + +// #pragma weak identifier +// #pragma weak identifier '=' identifier +void PragmaWeakHandler::HandlePragma(Preprocessor &PP, Token &WeakTok) { + // FIXME: Should we be expanding macros here? My guess is no. + SourceLocation WeakLoc = WeakTok.getLocation(); + + Token Tok; + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << "weak"; + return; + } + + IdentifierInfo *WeakName = Tok.getIdentifierInfo(), *AliasName = 0; + SourceLocation WeakNameLoc = Tok.getLocation(), AliasNameLoc; + + PP.Lex(Tok); + if (Tok.is(tok::equal)) { + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) + << "weak"; + return; + } + AliasName = Tok.getIdentifierInfo(); + AliasNameLoc = Tok.getLocation(); + PP.Lex(Tok); + } + + if (Tok.isNot(tok::eom)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "weak"; + return; + } + + if (AliasName) { + Actions.ActOnPragmaWeakAlias(WeakName, AliasName, WeakLoc, WeakNameLoc, + AliasNameLoc); + } else { + Actions.ActOnPragmaWeakID(WeakName, WeakLoc, WeakNameLoc); + } +} diff --git a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.h b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.h new file mode 100644 index 0000000..d9d06a1 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.h @@ -0,0 +1,62 @@ +//===---- 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 PragmaOptionsHandler : public PragmaHandler { + Action &Actions; +public: + PragmaOptionsHandler(const IdentifierInfo *N, Action &A) : PragmaHandler(N), + Actions(A) {} + + virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); +}; + +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); +}; + +class PragmaWeakHandler : public PragmaHandler { + Action &Actions; +public: + PragmaWeakHandler(const IdentifierInfo *N, Action &A) + : PragmaHandler(N), Actions(A) {} + + virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); +}; + +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp new file mode 100644 index 0000000..98c0058 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp @@ -0,0 +1,1607 @@ +//===--- 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 "RAIIObjectsForParser.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); + + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + Attr = ParseCXX0XAttributes(); + llvm::OwningPtr<AttributeList> AttrList(Attr.AttrList); + + // 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::code_completion: + Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Statement); + ConsumeToken(); + return ParseStatementOrDeclaration(OnlyStatement); + + case tok::identifier: + if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement + // identifier ':' statement + return ParseLabeledStatement(AttrList.take()); + } + // PASS THROUGH. + + default: { + if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) { + SourceLocation DeclStart = Tok.getLocation(), DeclEnd; + AttrList.take(); //Passing 'Attr' to ParseDeclaration transfers ownership. + DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext, DeclEnd, + Attr); + return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd); + } + + if (Tok.is(tok::r_brace)) { + Diag(Tok, diag::err_expected_statement); + return StmtError(); + } + + // FIXME: Use the attributes + // expression[opt] ';' + OwningExprResult Expr(ParseExpression()); + if (Expr.isInvalid()) { + // If the expression is invalid, skip ahead to the next semicolon or '}'. + // Not doing this opens us up to the possibility of infinite loops if + // ParseExpression does not consume any tokens. + SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true); + if (Tok.is(tok::semi)) + ConsumeToken(); + return StmtError(); + } + // Otherwise, eat the semicolon. + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); + return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr)); + } + + case tok::kw_case: // C99 6.8.1: labeled-statement + return ParseCaseStatement(AttrList.take()); + case tok::kw_default: // C99 6.8.1: labeled-statement + return ParseDefaultStatement(AttrList.take()); + + case tok::l_brace: // C99 6.8.2: compound-statement + return ParseCompoundStatement(AttrList.take()); + 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(AttrList.take()); + case tok::kw_switch: // C99 6.8.4.2: switch-statement + return ParseSwitchStatement(AttrList.take()); + + case tok::kw_while: // C99 6.8.5.1: while-statement + return ParseWhileStatement(AttrList.take()); + case tok::kw_do: // C99 6.8.5.2: do-statement + Res = ParseDoStatement(AttrList.take()); + SemiError = "do/while"; + break; + case tok::kw_for: // C99 6.8.5.3: for-statement + return ParseForStatement(AttrList.take()); + + case tok::kw_goto: // C99 6.8.6.1: goto-statement + Res = ParseGotoStatement(AttrList.take()); + SemiError = "goto"; + break; + case tok::kw_continue: // C99 6.8.6.2: continue-statement + Res = ParseContinueStatement(AttrList.take()); + SemiError = "continue"; + break; + case tok::kw_break: // C99 6.8.6.3: break-statement + Res = ParseBreakStatement(AttrList.take()); + SemiError = "break"; + break; + case tok::kw_return: // C99 6.8.6.4: return-statement + Res = ParseReturnStatement(AttrList.take()); + SemiError = "return"; + break; + + case tok::kw_asm: { + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; + bool msAsm = false; + Res = ParseAsmStatement(msAsm); + if (msAsm) return move(Res); + SemiError = "asm"; + break; + } + + case tok::kw_try: // C++ 15: try-block + return ParseCXXTryBlock(AttrList.take()); + } + + // If we reached this code, the statement must end in a semicolon. + if (Tok.is(tok::semi)) { + ConsumeToken(); + } else if (!Res.isInvalid()) { + // If the result was valid, then we do want to diagnose this. Use + // ExpectAndConsume to emit the diagnostic, even though we know it won't + // succeed. + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_stmt, 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(AttributeList *Attr) { + assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() && + "Not an identifier!"); + + llvm::OwningPtr<AttributeList> AttrList(Attr); + 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. + if (Tok.is(tok::kw___attribute)) + AttrList.reset(addAttributeLists(AttrList.take(), ParseGNUAttributes())); + + OwningStmtResult SubStmt(ParseStatement()); + + // Broken substmt shouldn't prevent the label from being added to the AST. + if (SubStmt.isInvalid()) + SubStmt = Actions.ActOnNullStmt(ColonLoc); + + // FIXME: use attributes? + 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(AttributeList *Attr) { + assert(Tok.is(tok::kw_case) && "Not a case stmt!"); + // FIXME: Use attributes? + delete Attr; + + // 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'. + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteCase(CurScope); + ConsumeCodeCompletionToken(); + } + + /// We don't want to treat 'case x : y' as a potential typo for 'case x::y'. + /// Disable this form of error recovery while we're parsing the case + /// expression. + ColonProtectionRAIIObject ColonProtection(*this); + + 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(); + } + } + + ColonProtection.restore(); + + 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(AttributeList *Attr) { + //FIXME: Use attributes? + delete Attr; + + 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(AttributeList *Attr, + bool isStmtExpr) { + //FIXME: Use attributes? + delete Attr; + + 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(); + + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + Attr = ParseCXX0XAttributes(); + + // 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, + Attr); + 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; + } + + // FIXME: Use attributes? + // 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.MakeFullExpr(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 &ExprResult, + DeclPtrTy &DeclResult, + SourceLocation Loc, + bool ConvertToBoolean) { + bool ParseError = false; + + SourceLocation LParenLoc = ConsumeParen(); + if (getLang().CPlusPlus) + ParseError = ParseCXXCondition(ExprResult, DeclResult, Loc, + ConvertToBoolean); + else { + ExprResult = ParseExpression(); + DeclResult = DeclPtrTy(); + + // If required, convert to a boolean value. + if (!ExprResult.isInvalid() && ConvertToBoolean) + ExprResult + = Actions.ActOnBooleanCondition(CurScope, Loc, move(ExprResult)); + } + + // 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 (ExprResult.isInvalid() && !DeclResult.get() && 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(AttributeList *Attr) { + // FIXME: Use attributes? + delete Attr; + + 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); + DeclPtrTy CondVar; + if (ParseParenExprOrCondition(CondExp, CondVar, IfLoc, true)) + return StmtError(); + + FullExprArg FullCondExp(Actions.MakeFullExpr(CondExp)); + + // 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(); + ElseStmtLoc = Tok.getLocation(); + + // 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)); + + // Regardless of whether or not InnerScope actually pushed a scope, set the + // ElseScope flag for the innermost scope so we can diagnose use of the if + // condition variable in C++. + unsigned OldFlags = CurScope->getFlags(); + CurScope->setFlags(OldFlags | Scope::ElseScope); + ElseStmt = ParseStatement(); + CurScope->setFlags(OldFlags); + + // 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() && !CondVar.get()) + 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, FullCondExp, CondVar, move(ThenStmt), + ElseLoc, move(ElseStmt)); +} + +/// ParseSwitchStatement +/// switch-statement: +/// 'switch' '(' expression ')' statement +/// [C++] 'switch' '(' condition ')' statement +Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) { + // FIXME: Use attributes? + delete Attr; + + 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); + DeclPtrTy CondVar; + if (ParseParenExprOrCondition(Cond, CondVar, SwitchLoc, false)) + return StmtError(); + + OwningStmtResult Switch + = Actions.ActOnStartOfSwitchStmt(SwitchLoc, move(Cond), CondVar); + + if (Switch.isInvalid()) { + // Skip the switch body. + // FIXME: This is not optimal recovery, but parsing the body is more + // dangerous due to the presence of case and default statements, which + // will have no place to connect back with the switch. + if (Tok.is(tok::l_brace)) { + ConsumeBrace(); + SkipUntil(tok::r_brace, false, false); + } else + SkipUntil(tok::semi); + return move(Switch); + } + + // 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 scopes. + InnerScope.Exit(); + SwitchScope.Exit(); + + if (Body.isInvalid()) + // FIXME: Remove the case statement list from the Switch statement. + Body = Actions.ActOnNullStmt(Tok.getLocation()); + + 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(AttributeList *Attr) { + // FIXME: Use attributes? + delete Attr; + + 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); + DeclPtrTy CondVar; + if (ParseParenExprOrCondition(Cond, CondVar, WhileLoc, true)) + return StmtError(); + + FullExprArg FullCond(Actions.MakeFullExpr(Cond)); + + // 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() && !CondVar.get()) || Body.isInvalid()) + return StmtError(); + + return Actions.ActOnWhileStmt(WhileLoc, FullCond, CondVar, 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(AttributeList *Attr) { + // FIXME: Use attributes? + delete Attr; + + 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. + SourceLocation LPLoc = ConsumeParen(); + OwningExprResult Cond = ParseExpression(); + SourceLocation RPLoc = MatchRHSPunctuation(tok::r_paren, LPLoc); + DoScope.Exit(); + + if (Cond.isInvalid() || Body.isInvalid()) + return StmtError(); + + return Actions.ActOnDoStmt(DoLoc, move(Body), WhileLoc, LPLoc, + move(Cond), RPLoc); +} + +/// 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(AttributeList *Attr) { + // FIXME: Use attributes? + delete Attr; + + 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); + bool SecondPartIsInvalid = false; + FullExprArg SecondPart(Actions); + OwningExprResult Collection(Actions); + FullExprArg ThirdPart(Actions); + DeclPtrTy SecondVar; + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(CurScope, + C99orCXXorObjC? Action::CCC_ForInit + : Action::CCC_Expression); + ConsumeCodeCompletionToken(); + } + + // 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); + + AttributeList *AttrList = 0; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + AttrList = ParseCXX0XAttributes().AttrList; + + SourceLocation DeclStart = Tok.getLocation(), DeclEnd; + DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd, + AttrList, false); + FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); + + if (Tok.is(tok::semi)) { // for (int x = 4; + ConsumeToken(); + } else if ((ForEach = isTokIdentifier_in())) { + Actions.ActOnForEachDeclStmt(DG); + // ObjC: for (id x in expr) + ConsumeToken(); // consume 'in' + Collection = 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.MakeFullExpr(Value)); + + if (Tok.is(tok::semi)) { + ConsumeToken(); + } else if ((ForEach = isTokIdentifier_in())) { + ConsumeToken(); // consume 'in' + Collection = 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 { + OwningExprResult Second(Actions); + if (getLang().CPlusPlus) + ParseCXXCondition(Second, SecondVar, ForLoc, true); + else { + Second = ParseExpression(); + if (!Second.isInvalid()) + Second = Actions.ActOnBooleanCondition(CurScope, ForLoc, + move(Second)); + } + SecondPartIsInvalid = Second.isInvalid(); + SecondPart = Actions.MakeFullExpr(Second); + } + + if (Tok.is(tok::semi)) { + ConsumeToken(); + } else { + if (!SecondPartIsInvalid || SecondVar.get()) + 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 (...;...;) + OwningExprResult Third = ParseExpression(); + ThirdPart = Actions.MakeFullExpr(Third); + } + } + // 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), SecondPart, + SecondVar, ThirdPart, RParenLoc, move(Body)); + + // FIXME: It isn't clear how to communicate the late destruction of + // C++ temporaries used to create the collection. + return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, move(FirstPart), + move(Collection), RParenLoc, + move(Body)); +} + +/// ParseGotoStatement +/// jump-statement: +/// 'goto' identifier ';' +/// [GNU] 'goto' '*' expression ';' +/// +/// Note: this lets the caller parse the end ';'. +/// +Parser::OwningStmtResult Parser::ParseGotoStatement(AttributeList *Attr) { + // FIXME: Use attributes? + delete Attr; + + 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(AttributeList *Attr) { + // FIXME: Use attributes? + delete Attr; + + 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(AttributeList *Attr) { + // FIXME: Use attributes? + delete Attr; + + SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'. + return Actions.ActOnBreakStmt(BreakLoc, CurScope); +} + +/// ParseReturnStatement +/// jump-statement: +/// 'return' expression[opt] ';' +Parser::OwningStmtResult Parser::ParseReturnStatement(AttributeList *Attr) { + // FIXME: Use attributes? + delete Attr; + + 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, move(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)); + } + Token t; + t.setKind(tok::string_literal); + t.setLiteralData("\"FIXME: not done\""); + t.clearFlag(Token::NeedsCleaning); + t.setLength(17); + OwningExprResult AsmString(Actions.ActOnStringLiteral(&t, 1)); + ExprVector Constraints(Actions); + ExprVector Exprs(Actions); + ExprVector Clobbers(Actions); + return Actions.ActOnAsmStmt(Tok.getLocation(), true, true, 0, 0, 0, + move_arg(Constraints), move_arg(Exprs), + move(AsmString), move_arg(Clobbers), + Tok.getLocation(), true); +} + +/// 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, true, false); + + // 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; + 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<IdentifierInfo *, 4> Names; + ExprVector Constraints(Actions); + ExprVector Exprs(Actions); + ExprVector Clobbers(Actions); + + if (Tok.is(tok::r_paren)) { + // We have a simple asm expression like 'asm("foo")'. + SourceLocation RParenLoc = ConsumeParen(); + return Actions.ActOnAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile, + /*NumOutputs*/ 0, /*NumInputs*/ 0, 0, + move_arg(Constraints), move_arg(Exprs), + move(AsmString), move_arg(Clobbers), + RParenLoc); + } + + // Parse Outputs, if present. + bool AteExtraColon = false; + if (Tok.is(tok::colon) || Tok.is(tok::coloncolon)) { + // In C++ mode, parse "::" like ": :". + AteExtraColon = Tok.is(tok::coloncolon); + ConsumeToken(); + + if (!AteExtraColon && + ParseAsmOperandsOpt(Names, Constraints, Exprs)) + return StmtError(); + } + + unsigned NumOutputs = Names.size(); + + // Parse Inputs, if present. + if (AteExtraColon || + Tok.is(tok::colon) || Tok.is(tok::coloncolon)) { + // In C++ mode, parse "::" like ": :". + if (AteExtraColon) + AteExtraColon = false; + else { + AteExtraColon = Tok.is(tok::coloncolon); + ConsumeToken(); + } + + if (!AteExtraColon && + ParseAsmOperandsOpt(Names, Constraints, Exprs)) + return StmtError(); + } + + assert(Names.size() == Constraints.size() && + Constraints.size() == Exprs.size() && + "Input operand size mismatch!"); + + unsigned NumInputs = Names.size() - NumOutputs; + + // Parse the clobbers, if present. + if (AteExtraColon || Tok.is(tok::colon)) { + if (!AteExtraColon) + 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(); + } + } + + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, Loc); + return Actions.ActOnAsmStmt(AsmLoc, false, 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, assuming the leading ':' token was eaten. +/// +/// [GNU] asm-operands: +/// asm-operand +/// asm-operands ',' asm-operand +/// +/// [GNU] asm-operand: +/// asm-string-literal '(' expression ')' +/// '[' identifier ']' asm-string-literal '(' expression ')' +/// +// +// FIXME: Avoid unnecessary std::string trashing. +bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names, + llvm::SmallVectorImpl<ExprTy *> &Constraints, + llvm::SmallVectorImpl<ExprTy *> &Exprs) { + // '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(II); + MatchRHSPunctuation(tok::r_square, Loc); + } else + Names.push_back(0); + + 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(AttributeList* Attr) { + // FIXME: Add attributes? + delete Attr; + + 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)); + // FIXME: Possible draft standard bug: attribute-specifier should be allowed? + OwningStmtResult TryBlock(ParseCompoundStatement(0)); + if (TryBlock.isInvalid()) + return move(TryBlock); + + StmtVector Handlers(Actions); + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { + CXX0XAttributeList Attr = ParseCXX0XAttributes(); + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; + } + 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)); + + // FIXME: Possible draft standard bug: attribute-specifier should be allowed? + OwningStmtResult Block(ParseCompoundStatement(0)); + if (Block.isInvalid()) + return move(Block); + + return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, move(Block)); +} diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp new file mode 100644 index 0000000..c87ddad --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp @@ -0,0 +1,1046 @@ +//===--- 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" +#include "clang/Parse/Template.h" +#include "RAIIObjectsForParser.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(SourceLocation(), ConsumeToken(), + DeclEnd); + + return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS); +} + +/// \brief RAII class that manages the template parameter depth. +namespace { + class TemplateParameterDepthCounter { + unsigned &Depth; + unsigned AddedLevels; + + public: + explicit TemplateParameterDepthCounter(unsigned &Depth) + : Depth(Depth), AddedLevels(0) { } + + ~TemplateParameterDepthCounter() { + Depth -= AddedLevels; + } + + void operator++() { + ++Depth; + ++AddedLevels; + } + + operator unsigned() const { return Depth; } + }; +} + +/// \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 isSpecialization = true; + bool LastParamListWasEmpty = false; + TemplateParameterLists ParamLists; + TemplateParameterDepthCounter Depth(TemplateParameterDepth); + 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; + if (ParseTemplateParameters(Depth, TemplateParams, LAngleLoc, + RAngleLoc)) { + // Skip until the semi-colon or a }. + SkipUntil(tok::r_brace, true, true); + if (Tok.is(tok::semi)) + ConsumeToken(); + return DeclPtrTy(); + } + + ParamLists.push_back( + Actions.ActOnTemplateParameterList(Depth, ExportLoc, + TemplateLoc, LAngleLoc, + TemplateParams.data(), + TemplateParams.size(), RAngleLoc)); + + if (!TemplateParams.empty()) { + isSpecialization = false; + ++Depth; + } else { + LastParamListWasEmpty = true; + } + } while (Tok.is(tok::kw_export) || Tok.is(tok::kw_template)); + + // Parse the actual template declaration. + return ParseSingleDeclarationAfterTemplate(Context, + ParsedTemplateInfo(&ParamLists, + isSpecialization, + LastParamListWasEmpty), + 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"); + + if (Context == Declarator::MemberContext) { + // We are parsing a member template. + ParseCXXClassMemberDeclaration(AS, TemplateInfo); + return DeclPtrTy::make((void*)0); + } + + // Parse the declaration specifiers. + ParsingDeclSpec DS(*this); + + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + DS.AddAttributes(ParseCXX0XAttributes().AttrList); + + ParseDeclarationSpecifiers(DS, TemplateInfo, AS, + getDeclSpecContextFromDeclaratorContext(Context)); + + if (Tok.is(tok::semi)) { + DeclEnd = ConsumeToken(); + DeclPtrTy Decl = Actions.ParsedFreeStandingDeclSpec(CurScope, AS, DS); + DS.complete(Decl); + return Decl; + } + + // Parse the declarator. + ParsingDeclarator DeclaratorInfo(*this, 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, + TemplateInfo); + + 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_declaration); + DS.complete(ThisDecl); + 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, TemplateInfo); + } + + 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. +/// +/// \returns true if an error occurred, false otherwise. +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 true; + } + 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 true; + } + RAngleLoc = ConsumeToken(); + } + return false; +} + +/// 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; +} + +/// \brief Determine whether the parser is at the start of a template +/// type parameter. +bool Parser::isStartOfTemplateTypeParameter() { + if (Tok.is(tok::kw_class)) + return true; + + if (Tok.isNot(tok::kw_typename)) + return false; + + // C++ [temp.param]p2: + // There is no semantic difference between class and typename in a + // template-parameter. typename followed by an unqualified-id + // names a template type parameter. typename followed by a + // qualified-id denotes the type in a non-type + // parameter-declaration. + Token Next = NextToken(); + + // If we have an identifier, skip over it. + if (Next.getKind() == tok::identifier) + Next = GetLookAheadToken(2); + + switch (Next.getKind()) { + case tok::equal: + case tok::comma: + case tok::greater: + case tok::greatergreater: + case tok::ellipsis: + return true; + + default: + return false; + } +} + +/// ParseTemplateParameter - Parse a template-parameter (C++ [temp.param]). +/// +/// template-parameter: [C++ temp.param] +/// type-parameter +/// parameter-declaration +/// +/// type-parameter: (see below) +/// 'class' ...[opt][C++0x] identifier[opt] +/// 'class' identifier[opt] '=' type-id +/// 'typename' ...[opt][C++0x] identifier[opt] +/// 'typename' identifier[opt] '=' type-id +/// 'template' ...[opt][C++0x] '<' template-parameter-list '>' 'class' identifier[opt] +/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression +Parser::DeclPtrTy +Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { + if (isStartOfTemplateTypeParameter()) + 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' ...[opt][C++0x] identifier[opt] +/// 'class' identifier[opt] '=' type-id +/// 'typename' ...[opt][C++0x] 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 ellipsis (if given). + bool Ellipsis = false; + SourceLocation EllipsisLoc; + if (Tok.is(tok::ellipsis)) { + Ellipsis = true; + EllipsisLoc = ConsumeToken(); + + if (!getLang().CPlusPlus0x) + Diag(EllipsisLoc, diag::err_variadic_templates); + } + + // 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, + Ellipsis, EllipsisLoc, + 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(); + ParsedTemplateArgument Default = ParseTemplateTemplateArgument(); + if (Default.isInvalid()) { + Diag(Tok.getLocation(), + diag::err_default_template_template_parameter_not_template); + static const tok::TokenKind EndToks[] = { + tok::comma, tok::greater, tok::greatergreater + }; + SkipUntil(EndToks, 3, true, true); + return Param; + } else if (Param) + Actions.ActOnTemplateTemplateParameterDefault(Param, EqualLoc, Default); + } + + 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, + 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); + + if (Invalid) { + // Try to find the closing '>'. + SkipUntil(tok::greater, true, !ConsumeLastToken); + + return true; + } + } + + if (Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater)) { + Diag(Tok.getLocation(), diag::err_expected_greater); + 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) + << FixItHint::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. +/// +/// If an unrecoverable parse error occurs and no annotation token can be +/// formed, this function returns true. +/// +bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, + const CXXScopeSpec *SS, + UnqualifiedId &TemplateName, + SourceLocation TemplateKWLoc, + bool AllowTypeAnnotation) { + assert(getLang().CPlusPlus && "Can only annotate template-ids in C++"); + assert(Template && Tok.is(tok::less) && + "Parser isn't at the beginning of a template-id"); + + // Consume the template-name. + SourceLocation TemplateNameLoc = TemplateName.getSourceRange().getBegin(); + + // Parse the enclosed template argument list. + SourceLocation LAngleLoc, RAngleLoc; + TemplateArgList TemplateArgs; + bool Invalid = ParseTemplateIdAfterTemplateName(Template, + TemplateNameLoc, + SS, false, LAngleLoc, + TemplateArgs, + RAngleLoc); + + if (Invalid) { + // If we failed to parse the template ID but skipped ahead to a >, we're not + // going to be able to form a token annotation. Eat the '>' if present. + if (Tok.is(tok::greater)) + ConsumeToken(); + return true; + } + + ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(), + TemplateArgs.size()); + + // Build the annotation token. + if (TNK == TNK_Type_template && AllowTypeAnnotation) { + Action::TypeResult Type + = Actions.ActOnTemplateIdType(Template, TemplateNameLoc, + LAngleLoc, TemplateArgsPtr, + RAngleLoc); + if (Type.isInvalid()) { + // If we failed to parse the template ID but skipped ahead to a >, we're not + // going to be able to form a token annotation. Eat the '>' if present. + if (Tok.is(tok::greater)) + ConsumeToken(); + return true; + } + + 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; + if (TemplateName.getKind() == UnqualifiedId::IK_Identifier) { + TemplateId->Name = TemplateName.Identifier; + TemplateId->Operator = OO_None; + } else { + TemplateId->Name = 0; + TemplateId->Operator = TemplateName.OperatorFunctionId.Operator; + } + TemplateId->Template = Template.getAs<void*>(); + TemplateId->Kind = TNK; + TemplateId->LAngleLoc = LAngleLoc; + TemplateId->RAngleLoc = RAngleLoc; + ParsedTemplateArgument *Args = TemplateId->getTemplateArgs(); + for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg) + Args[Arg] = TemplateArgs[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); + return false; +} + +/// \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->NumArgs); + + Action::TypeResult Type + = Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + 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()); + // End location stays the same + + // Replace the template-id annotation token, and possible the scope-specifier + // that precedes it, with the typename annotation token. + PP.AnnotateCachedTokens(Tok); + TemplateId->Destroy(); +} + +/// \brief Determine whether the given token can end a template argument. +static bool isEndOfTemplateArgument(Token Tok) { + return Tok.is(tok::comma) || Tok.is(tok::greater) || + Tok.is(tok::greatergreater); +} + +/// \brief Parse a C++ template template argument. +ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { + if (!Tok.is(tok::identifier) && !Tok.is(tok::coloncolon) && + !Tok.is(tok::annot_cxxscope)) + return ParsedTemplateArgument(); + + // C++0x [temp.arg.template]p1: + // A template-argument for a template template-parameter shall be the name + // of a class template or a template alias, expressed as id-expression. + // + // We parse an id-expression that refers to a class template or template + // alias. The grammar we parse is: + // + // nested-name-specifier[opt] template[opt] identifier + // + // followed by a token that terminates a template argument, such as ',', + // '>', or (in some cases) '>>'. + CXXScopeSpec SS; // nested-name-specifier, if present + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, + /*EnteringContext=*/false); + + if (SS.isSet() && Tok.is(tok::kw_template)) { + // Parse the optional 'template' keyword following the + // nested-name-specifier. + SourceLocation TemplateLoc = ConsumeToken(); + + if (Tok.is(tok::identifier)) { + // We appear to have a dependent template name. + UnqualifiedId Name; + Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeToken(); // the identifier + + // If the next token signals the end of a template argument, + // then we have a dependent template name that could be a template + // template argument. + if (isEndOfTemplateArgument(Tok)) { + TemplateTy Template + = Actions.ActOnDependentTemplateName(TemplateLoc, SS, Name, + /*ObjectType=*/0, + /*EnteringContext=*/false); + if (Template.get()) + return ParsedTemplateArgument(SS, Template, Name.StartLocation); + } + } + } else if (Tok.is(tok::identifier)) { + // We may have a (non-dependent) template name. + TemplateTy Template; + UnqualifiedId Name; + Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeToken(); // the identifier + + if (isEndOfTemplateArgument(Tok)) { + bool MemberOfUnknownSpecialization; + TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS, Name, + /*ObjectType=*/0, + /*EnteringContext=*/false, + Template, + MemberOfUnknownSpecialization); + if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) { + // We have an id-expression that refers to a class template or + // (C++0x) template alias. + return ParsedTemplateArgument(SS, Template, Name.StartLocation); + } + } + } + + // We don't have a template template argument. + return ParsedTemplateArgument(); +} + +/// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]). +/// +/// template-argument: [C++ 14.2] +/// constant-expression +/// type-id +/// id-expression +ParsedTemplateArgument Parser::ParseTemplateArgument() { + // 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)) { + SourceLocation Loc = Tok.getLocation(); + TypeResult TypeArg = ParseTypeName(); + if (TypeArg.isInvalid()) + return ParsedTemplateArgument(); + + return ParsedTemplateArgument(ParsedTemplateArgument::Type, TypeArg.get(), + Loc); + } + + // Try to parse a template template argument. + { + TentativeParsingAction TPA(*this); + + ParsedTemplateArgument TemplateTemplateArgument + = ParseTemplateTemplateArgument(); + if (!TemplateTemplateArgument.isInvalid()) { + TPA.Commit(); + return TemplateTemplateArgument; + } + + // Revert this tentative parse to parse a non-type template argument. + TPA.Revert(); + } + + // Parse a non-type template argument. + SourceLocation Loc = Tok.getLocation(); + OwningExprResult ExprArg = ParseConstantExpression(); + if (ExprArg.isInvalid() || !ExprArg.get()) + return ParsedTemplateArgument(); + + return ParsedTemplateArgument(ParsedTemplateArgument::NonType, + ExprArg.release(), Loc); +} + +/// \brief Determine whether the current tokens can only be parsed as a +/// template argument list (starting with the '<') and never as a '<' +/// expression. +bool Parser::IsTemplateArgumentList(unsigned Skip) { + struct AlwaysRevertAction : TentativeParsingAction { + AlwaysRevertAction(Parser &P) : TentativeParsingAction(P) { } + ~AlwaysRevertAction() { Revert(); } + } Tentative(*this); + + while (Skip) { + ConsumeToken(); + --Skip; + } + + // '<' + if (!Tok.is(tok::less)) + return false; + ConsumeToken(); + + // An empty template argument list. + if (Tok.is(tok::greater)) + return true; + + // See whether we have declaration specifiers, which indicate a type. + while (isCXXDeclarationSpecifier() == TPResult::True()) + ConsumeToken(); + + // If we have a '>' or a ',' then this is a template argument list. + return Tok.is(tok::greater) || Tok.is(tok::comma); +} + +/// 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) { + while (true) { + ParsedTemplateArgument Arg = ParseTemplateArgument(); + if (Arg.isInvalid()) { + SkipUntil(tok::comma, tok::greater, true, true); + return true; + } + + // Save this template argument. + TemplateArgs.push_back(Arg); + + // If the next token is a comma, consume it and keep reading + // arguments. + if (Tok.isNot(tok::comma)) break; + + // Consume the comma. + ConsumeToken(); + } + + return false; +} + +/// \brief Parse a C++ explicit template instantiation +/// (C++ [temp.explicit]). +/// +/// explicit-instantiation: +/// 'extern' [opt] 'template' declaration +/// +/// Note that the 'extern' is a GNU extension and C++0x feature. +Parser::DeclPtrTy +Parser::ParseExplicitInstantiation(SourceLocation ExternLoc, + SourceLocation TemplateLoc, + SourceLocation &DeclEnd) { + return ParseSingleDeclarationAfterTemplate(Declarator::FileContext, + ParsedTemplateInfo(ExternLoc, + TemplateLoc), + DeclEnd, AS_none); +} diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp new file mode 100644 index 0000000..5e64e61 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp @@ -0,0 +1,1052 @@ +//===--- 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" +#include "clang/Parse/Template.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: + // static_assert-declaration + case tok::kw_static_assert: + return true; + // simple-declaration + default: + 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(); +} + +/// isCXX0XAttributeSpecifier - returns true if this is a C++0x +/// attribute-specifier. By default, unless in Obj-C++, only a cursory check is +/// performed that will simply return true if a [[ is seen. Currently C++ has no +/// syntactical ambiguities from this check, but it may inhibit error recovery. +/// If CheckClosing is true, a check is made for closing ]] brackets. +/// +/// If given, After is set to the token after the attribute-specifier so that +/// appropriate parsing decisions can be made; it is left untouched if false is +/// returned. +/// +/// FIXME: If an error is in the closing ]] brackets, the program assumes +/// the absence of an attribute-specifier, which can cause very yucky errors +/// to occur. +/// +/// [C++0x] attribute-specifier: +/// '[' '[' attribute-list ']' ']' +/// +/// [C++0x] attribute-list: +/// attribute[opt] +/// attribute-list ',' attribute[opt] +/// +/// [C++0x] attribute: +/// attribute-token attribute-argument-clause[opt] +/// +/// [C++0x] attribute-token: +/// identifier +/// attribute-scoped-token +/// +/// [C++0x] attribute-scoped-token: +/// attribute-namespace '::' identifier +/// +/// [C++0x] attribute-namespace: +/// identifier +/// +/// [C++0x] attribute-argument-clause: +/// '(' balanced-token-seq ')' +/// +/// [C++0x] balanced-token-seq: +/// balanced-token +/// balanced-token-seq balanced-token +/// +/// [C++0x] balanced-token: +/// '(' balanced-token-seq ')' +/// '[' balanced-token-seq ']' +/// '{' balanced-token-seq '}' +/// any token but '(', ')', '[', ']', '{', or '}' +bool Parser::isCXX0XAttributeSpecifier (bool CheckClosing, + tok::TokenKind *After) { + if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) + return false; + + // No tentative parsing if we don't need to look for ]] + if (!CheckClosing && !getLang().ObjC1) + return true; + + struct TentativeReverter { + TentativeParsingAction PA; + + TentativeReverter (Parser& P) + : PA(P) + {} + ~TentativeReverter () { + PA.Revert(); + } + } R(*this); + + // Opening brackets were checked for above. + ConsumeBracket(); + ConsumeBracket(); + + // SkipUntil will handle balanced tokens, which are guaranteed in attributes. + SkipUntil(tok::r_square, false); + + if (Tok.isNot(tok::r_square)) + return false; + ConsumeBracket(); + + if (After) + *After = Tok.getKind(); + + return 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)) + if (TryAnnotateCXXScopeToken(true)) + return TPResult::Error(); + + 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) || + (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) && + mayHaveIdentifier) { + // declarator-id + if (Tok.is(tok::annot_cxxscope)) + ConsumeToken(); + 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' +/// [C++0x] 'constexpr' +/// [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] +/// [C++0x] 'decltype' ( expression ) +/// +/// 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 + // Check for need to substitute AltiVec __vector keyword + // for "vector" identifier. + if (TryAltiVecVectorToken()) + return TPResult::True(); + // 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 TPResult::Error(); + if (Tok.is(tok::identifier)) + return TPResult::False(); + return isCXXDeclarationSpecifier(); + + case tok::coloncolon: { // ::foo::bar + const Token &Next = NextToken(); + if (Next.is(tok::kw_new) || // ::new + Next.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 TPResult::Error(); + return isCXXDeclarationSpecifier(); + } + + // decl-specifier: + // storage-class-specifier + // type-specifier + // function-specifier + // 'friend' + // 'typedef' + // 'constexpr' + case tok::kw_friend: + case tok::kw_typedef: + case tok::kw_constexpr: + // 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: + case tok::kw___thiscall: + case tok::kw___w64: + case tok::kw___ptr64: + case tok::kw___forceinline: + return TPResult::True(); + + // AltiVec + case tok::kw___vector: + return TPResult::True(); + + case tok::annot_template_id: { + TemplateIdAnnotation *TemplateId + = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + if (TemplateId->Kind != TNK_Type_template) + return TPResult::False(); + CXXScopeSpec SS; + AnnotateTemplateIdTokenAsType(&SS); + assert(Tok.is(tok::annot_typename)); + goto case_typename; + } + + case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed + // We've already annotated a scope; try to annotate a type. + if (TryAnnotateTypeOrScopeToken()) + return TPResult::Error(); + if (!Tok.is(tok::annot_typename)) + return TPResult::False(); + // If that succeeded, fallthrough into the generic simple-type-id case. + + // 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_char16_t: + case tok::kw_char32_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: + case_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(); + } + + // C++0x decltype support. + case tok::kw_decltype: + 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/contrib/llvm/tools/clang/lib/Parse/Parser.cpp b/contrib/llvm/tools/clang/lib/Parse/Parser.cpp new file mode 100644 index 0000000..2968970 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Parse/Parser.cpp @@ -0,0 +1,1107 @@ +//===--- 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 "clang/Parse/Template.h" +#include "llvm/Support/raw_ostream.h" +#include "RAIIObjectsForParser.h" +#include "ParsePragma.h" +using namespace clang; + +Parser::Parser(Preprocessor &pp, Action &actions) + : CrashInfo(*this), PP(pp), Actions(actions), Diags(PP.getDiagnostics()), + GreaterThanIsOperator(true), ColonIsSacred(false), + TemplateParameterDepth(0) { + 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. + OptionsHandler.reset(new + PragmaOptionsHandler(&PP.getIdentifierTable().get("options"), + actions)); + PP.AddPragmaHandler(0, OptionsHandler.get()); + + 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()); + + WeakHandler.reset(new + PragmaWeakHandler(&PP.getIdentifierTable().get("weak"), actions)); + PP.AddPragmaHandler(0, WeakHandler.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()); + if (Tok.isAnnotation()) + OS << ": at annotation token \n"; + else + 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) + << FixItHint::CreateInsertion(ParenRange.getBegin(), "(") + << FixItHint::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) || Tok.is(tok::code_completion)) { + 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 + << FixItHint::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::code_completion: + ConsumeToken(); + 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); + } + CurScope->setNumErrorsAtStart(Diags.getNumErrors()); +} + +/// 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, OptionsHandler.get()); + OptionsHandler.reset(); + PP.RemovePragmaHandler(0, PackHandler.get()); + PackHandler.reset(); + PP.RemovePragmaHandler(0, UnusedHandler.get()); + UnusedHandler.reset(); + PP.RemovePragmaHandler(0, WeakHandler.get()); + WeakHandler.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"); + + if (getLang().AltiVec) { + Ident_vector = &PP.getIdentifierTable().get("vector"); + Ident_pixel = &PP.getIdentifierTable().get("pixel"); + } +} + +/// 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; + } + + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + Attr = ParseCXX0XAttributes(); + Result = ParseExternalDeclaration(Attr); + 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 +/// [C++0x] empty-declaration +/// [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 ';' +/// +/// [C++0x] empty-declaration: +/// ';' +/// +/// [C++0x/GNU] 'extern' 'template' declaration +Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr) { + DeclPtrTy SingleDecl; + switch (Tok.getKind()) { + case tok::semi: + if (!getLang().CPlusPlus0x) + Diag(Tok, diag::ext_top_level_semi) + << FixItHint::CreateRemoval(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(Attr); + } + case tok::kw_asm: { + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; + + 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::code_completion: + Actions.CodeCompleteOrdinaryName(CurScope, + ObjCImpDecl? Action::CCC_ObjCImplementation + : Action::CCC_Namespace); + ConsumeCodeCompletionToken(); + return ParseExternalDeclaration(Attr); + 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, Attr); + } + case tok::kw_extern: + if (getLang().CPlusPlus && NextToken().is(tok::kw_template)) { + // Extern templates + SourceLocation ExternLoc = ConsumeToken(); + SourceLocation TemplateLoc = ConsumeToken(); + SourceLocation DeclEnd; + return Actions.ConvertDeclToDeclGroup( + ParseExplicitInstantiation(ExternLoc, TemplateLoc, DeclEnd)); + } + + // FIXME: Detect C++ linkage specifications here? + + // Fall through to handle other declarations or function definitions. + + default: + // We can't tell whether this is a function-definition or declaration yet. + return ParseDeclarationOrFunctionDefinition(Attr.AttrList); + } + + // 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() { + if (Tok.is(tok::l_brace)) // int X() {} + return true; + + if (!getLang().CPlusPlus) + return isDeclarationSpecifier(); // int X(f) int f; {} + return 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(ParsingDeclSpec &DS, + AttributeList *Attr, + AccessSpecifier AS) { + // Parse the common declaration-specifiers piece. + if (Attr) + DS.AddAttributes(Attr); + + ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC_top_level); + + // 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, AS, DS); + DS.complete(TheDecl); + 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(); + } + + DS.abort(); + + const char *PrevSpec = 0; + unsigned DiagID; + if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec, DiagID)) + Diag(AtLoc, DiagID) << 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(DS, Declarator::FileContext); + return Actions.ConvertDeclToDeclGroup(TheDecl); + } + + return ParseDeclGroup(DS, Declarator::FileContext, true); +} + +Parser::DeclGroupPtrTy +Parser::ParseDeclarationOrFunctionDefinition(AttributeList *Attr, + AccessSpecifier AS) { + ParsingDeclSpec DS(*this); + return ParseDeclarationOrFunctionDefinition(DS, Attr, AS); +} + +/// 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(ParsingDeclarator &D, + const ParsedTemplateInfo &TemplateInfo) { + 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; + unsigned DiagID; + D.getMutableDeclSpec().SetTypeSpecType(DeclSpec::TST_int, + D.getIdentifierLoc(), + PrevSpec, DiagID); + 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 = TemplateInfo.TemplateParams? + Actions.ActOnStartOfFunctionTemplateDef(CurScope, + Action::MultiTemplateParamsArg(Actions, + TemplateInfo.TemplateParams->data(), + TemplateInfo.TemplateParams->size()), + D) + : Actions.ActOnStartOfFunctionDef(CurScope, D); + + // Break out of the ParsingDeclarator context before we parse the body. + D.complete(Res); + + // Break out of the ParsingDeclSpec context, too. This const_cast is + // safe because we're always the sole owner. + D.getMutableDeclSpec().abort(); + + if (Tok.is(tok::kw_try)) + return ParseFunctionTryBlock(Res); + + // If we have a colon, then we're probably parsing a C++ + // ctor-initializer. + if (Tok.is(tok::colon)) { + ParseConstructorInitializer(Res); + + // Recover from error. + if (!Tok.is(tok::l_brace)) { + Actions.ActOnFinishFunctionBody(Res, Action::StmtArg(Actions)); + return Res; + } + } else + Actions.ActOnDefaultCtorInitializers(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) { + // If attributes are present, parse them. + if (Tok.is(tok::kw___attribute)) { + SourceLocation Loc; + AttributeList *AttrList = ParseGNUAttributes(&Loc); + ParmDeclarator.AddAttributes(AttrList, Loc); + } + + // 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.is(tok::kw_volatile)) { + // Remove from the end of 'asm' to the end of 'volatile'. + SourceRange RemovalRange(PP.getLocForEndOfToken(Loc), + PP.getLocForEndOfToken(Tok.getLocation())); + + Diag(Tok, diag::warn_file_asm_volatile) + << FixItHint::CreateRemoval(RemovalRange); + 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 an error occurred. +/// +/// 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(bool EnteringContext) { + assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) + || Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope)) && + "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; + if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false)) + return true; + if (!SS.isSet()) { + Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename); + return true; + } + + 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 true; + } + + 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 true; + } + + SourceLocation EndLoc = Tok.getLastLoc(); + Tok.setKind(tok::annot_typename); + Tok.setAnnotationValue(Ty.isInvalid()? 0 : Ty.get()); + Tok.setAnnotationEndLoc(EndLoc); + Tok.setLocation(TypenameLoc); + PP.AnnotateCachedTokens(Tok); + return false; + } + + // Remembers whether the token was originally a scope annotation. + bool wasScopeAnnotation = Tok.is(tok::annot_cxxscope); + + CXXScopeSpec SS; + if (getLang().CPlusPlus) + if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext)) + return true; + + 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 false; + } + + 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; + UnqualifiedId TemplateName; + TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + bool MemberOfUnknownSpecialization; + if (TemplateNameKind TNK + = Actions.isTemplateName(CurScope, SS, TemplateName, + /*ObjectType=*/0, EnteringContext, + Template, MemberOfUnknownSpecialization)) { + // Consume the identifier. + ConsumeToken(); + if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName)) { + // If an unrecoverable error occurred, we need to return true here, + // because the token stream is in a damaged state. We may not return + // a valid identifier. + return true; + } + } + } + + // 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 false; + } + } + + 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. We don't need to do this if we've + // just reverted back to the state we were in before being called. + if (!wasScopeAnnotation) + PP.AnnotateCachedTokens(Tok); + return false; +} + +/// TryAnnotateScopeToken - Like TryAnnotateTypeOrScopeToken but only +/// annotates C++ scope specifiers and template-ids. This returns +/// true if the token was annotated or there was an error that could not be +/// recovered from. +/// +/// 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(bool EnteringContext) { + 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, /*ObjectType=*/0, EnteringContext)) + return true; + if (SS.isEmpty()) + return false; + + // 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 false; +} + +void Parser::CodeCompletionRecovery() { + for (Scope *S = CurScope; S; S = S->getParent()) { + if (S->getFlags() & Scope::FnScope) { + Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_RecoveryInFunction); + return; + } + + if (S->getFlags() & Scope::ClassScope) { + Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Class); + return; + } + } + + Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Namespace); +} + +// Anchor the Parser::FieldCallback vtable to this translation unit. +// We use a spurious method instead of the destructor because +// destroying FieldCallbacks can actually be slightly +// performance-sensitive. +void Parser::FieldCallback::_anchor() { +} diff --git a/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h b/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h new file mode 100644 index 0000000..06bbbc2 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h @@ -0,0 +1,85 @@ +//===--- RAIIObjectsForParser.h - RAII helpers for the parser ---*- 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 some simple RAII objects that are used +// by the parser to manage bits in recursion. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_H +#define LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_H + +#include "clang/Parse/ParseDiagnostic.h" + +namespace clang { + // TODO: move ParsingDeclRAIIObject here. + // TODO: move ParsingClassDefinition here. + // TODO: move TentativeParsingAction here. + + + /// 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(); + } + }; + + /// ColonProtectionRAIIObject - This sets the Parser::ColonIsSacred bool and + /// restores it when destroyed. This says that "foo:" should not be + /// considered a possible typo for "foo::" for error recovery purposes. + class ColonProtectionRAIIObject { + Parser &P; + bool OldVal; + public: + ColonProtectionRAIIObject(Parser &p, bool Value = true) + : P(p), OldVal(P.ColonIsSacred) { + P.ColonIsSacred = Value; + } + + /// restore - This can be used to restore the state early, before the dtor + /// is run. + void restore() { + P.ColonIsSacred = OldVal; + } + + ~ColonProtectionRAIIObject() { + restore(); + } + }; + + /// \brief RAII object that makes '>' behave either as an operator + /// or as the closing angle bracket for a template argument list. + class GreaterThanIsOperatorScope { + bool &GreaterThanIsOperator; + bool OldGreaterThanIsOperator; + public: + GreaterThanIsOperatorScope(bool >IO, bool Val) + : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) { + GreaterThanIsOperator = Val; + } + + ~GreaterThanIsOperatorScope() { + GreaterThanIsOperator = OldGreaterThanIsOperator; + } + }; + +} // end namespace clang + +#endif |