diff options
author | Roman Divacky <rdivacky@FreeBSD.org> | 2009-10-14 18:03:49 +0000 |
---|---|---|
committer | Roman Divacky <rdivacky@FreeBSD.org> | 2009-10-14 18:03:49 +0000 |
commit | 4c8b24812ddcd1dedaca343a6d4e76f91f398981 (patch) | |
tree | 137ebebcae16fb0ce7ab4af456992bbd8d22fced /lib/Parse | |
parent | 5362a71c02e7d448a8ce98cf00c47e353fba5d04 (diff) | |
download | src-4c8b24812ddcd1dedaca343a6d4e76f91f398981.tar.gz src-4c8b24812ddcd1dedaca343a6d4e76f91f398981.zip |
Update clang to r84119.vendor/clang/clang-r84119
Notes
Notes:
svn path=/vendor/clang/dist/; revision=198092
svn path=/vendor/clang/clang-84119/; revision=198093; tag=vendor/clang/clang-r84119
Diffstat (limited to 'lib/Parse')
-rw-r--r-- | lib/Parse/AttributeList.cpp | 20 | ||||
-rw-r--r-- | lib/Parse/CMakeLists.txt | 4 | ||||
-rw-r--r-- | lib/Parse/DeclSpec.cpp | 186 | ||||
-rw-r--r-- | lib/Parse/ExtensionRAIIObject.h | 2 | ||||
-rw-r--r-- | lib/Parse/MinimalAction.cpp | 70 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 44 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 858 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 533 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 255 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 220 | ||||
-rw-r--r-- | lib/Parse/ParseInit.cpp | 40 | ||||
-rw-r--r-- | lib/Parse/ParseObjc.cpp | 301 | ||||
-rw-r--r-- | lib/Parse/ParsePragma.cpp | 65 | ||||
-rw-r--r-- | lib/Parse/ParsePragma.h | 18 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 109 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 221 | ||||
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 24 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 137 |
18 files changed, 1883 insertions, 1224 deletions
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp index 5ee668a31723..2ee41bc3eb8d 100644 --- a/lib/Parse/AttributeList.cpp +++ b/lib/Parse/AttributeList.cpp @@ -21,7 +21,7 @@ AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc, AttributeList *n, bool declspec) : AttrName(aName), AttrLoc(aLoc), ParmName(pName), ParmLoc(pLoc), NumArgs(numArgs), Next(n), DeclspecAttribute(declspec) { - + if (numArgs == 0) Args = 0; else { @@ -32,12 +32,12 @@ AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc, AttributeList::~AttributeList() { if (Args) { - // FIXME: before we delete the vector, we need to make sure the Expr's + // 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 + // 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; } @@ -54,7 +54,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { Str += 2; Len -= 4; } - + // FIXME: Hand generating this is neither smart nor efficient. switch (Len) { case 4: @@ -69,7 +69,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { break; case 6: if (!memcmp(Str, "packed", 6)) return AT_packed; - if (!memcmp(Str, "malloc", 6)) return IgnoredAttribute; // FIXME: noalias. + if (!memcmp(Str, "malloc", 6)) return AT_malloc; if (!memcmp(Str, "format", 6)) return AT_format; if (!memcmp(Str, "unused", 6)) return AT_unused; if (!memcmp(Str, "blocks", 6)) return AT_blocks; @@ -103,7 +103,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { if (!memcmp(Str, "deprecated", 10)) return AT_deprecated; if (!memcmp(Str, "visibility", 10)) return AT_visibility; if (!memcmp(Str, "destructor", 10)) return AT_destructor; - if (!memcmp(Str, "format_arg", 10)) return AT_format_arg; + if (!memcmp(Str, "format_arg", 10)) return AT_format_arg; if (!memcmp(Str, "gnu_inline", 10)) return AT_gnu_inline; break; case 11: @@ -136,13 +136,13 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { case 19: if (!memcmp(Str, "ns_returns_retained", 19)) return AT_ns_returns_retained; if (!memcmp(Str, "cf_returns_retained", 19)) return AT_cf_returns_retained; - break; + break; case 20: if (!memcmp(Str, "reqd_work_group_size", 20)) return AT_reqd_wg_size; case 22: if (!memcmp(Str, "no_instrument_function", 22)) return AT_no_instrument_function; break; - } + } return UnknownAttribute; } diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt index 8fb7cd23b89a..bec1c6e10e8b 100644 --- a/lib/Parse/CMakeLists.txt +++ b/lib/Parse/CMakeLists.txt @@ -12,10 +12,10 @@ add_clang_library(clangParse ParseInit.cpp ParseObjc.cpp ParsePragma.cpp - Parser.cpp ParseStmt.cpp - ParseTentative.cpp ParseTemplate.cpp + ParseTentative.cpp + Parser.cpp ) add_dependencies(clangParse ClangDiagnosticParse) diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index 8b3b2851c1e0..b8422aad5a84 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -16,6 +16,7 @@ #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; @@ -38,11 +39,13 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, ActionBase::TypeTy **Exceptions, SourceRange *ExceptionRanges, unsigned NumExceptions, - SourceLocation Loc, + SourceLocation LPLoc, + SourceLocation RPLoc, Declarator &TheDeclarator) { DeclaratorChunk I; I.Kind = Function; - I.Loc = Loc; + I.Loc = LPLoc; + I.EndLoc = RPLoc; I.Fun.hasPrototype = hasProto; I.Fun.isVariadic = isVariadic; I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding(); @@ -62,7 +65,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, // 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 && + if (!TheDeclarator.InlineParamsUsed && NumArgs <= llvm::array_lengthof(TheDeclarator.InlineParams)) { I.Fun.ArgInfo = TheDeclarator.InlineParams; I.Fun.DeleteArgInfo = false; @@ -95,18 +98,26 @@ unsigned DeclSpec::getParsedSpecifiers() const { 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) { - default: assert(0 && "Unknown typespec!"); case DeclSpec::SCS_unspecified: return "unspecified"; case DeclSpec::SCS_typedef: return "typedef"; case DeclSpec::SCS_extern: return "extern"; @@ -116,49 +127,46 @@ const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) { case DeclSpec::SCS_private_extern: return "__private_extern__"; case DeclSpec::SCS_mutable: return "mutable"; } + llvm::llvm_unreachable("Unknown typespec!"); } -bool DeclSpec::BadSpecifier(SCS S, const char *&PrevSpec) { - PrevSpec = getSpecifierName(S); - return true; -} - -bool DeclSpec::BadSpecifier(TSW W, const char *&PrevSpec) { +const char *DeclSpec::getSpecifierName(TSW W) { switch (W) { - case TSW_unspecified: PrevSpec = "unspecified"; break; - case TSW_short: PrevSpec = "short"; break; - case TSW_long: PrevSpec = "long"; break; - case TSW_longlong: PrevSpec = "long long"; break; + case TSW_unspecified: return "unspecified"; + case TSW_short: return "short"; + case TSW_long: return "long"; + case TSW_longlong: return "long long"; } - return true; + llvm::llvm_unreachable("Unknown typespec!"); } -bool DeclSpec::BadSpecifier(TSC C, const char *&PrevSpec) { +const char *DeclSpec::getSpecifierName(TSC C) { switch (C) { - case TSC_unspecified: PrevSpec = "unspecified"; break; - case TSC_imaginary: PrevSpec = "imaginary"; break; - case TSC_complex: PrevSpec = "complex"; break; + case TSC_unspecified: return "unspecified"; + case TSC_imaginary: return "imaginary"; + case TSC_complex: return "complex"; } - return true; + llvm::llvm_unreachable("Unknown typespec!"); } -bool DeclSpec::BadSpecifier(TSS S, const char *&PrevSpec) { +const char *DeclSpec::getSpecifierName(TSS S) { switch (S) { - case TSS_unspecified: PrevSpec = "unspecified"; break; - case TSS_signed: PrevSpec = "signed"; break; - case TSS_unsigned: PrevSpec = "unsigned"; break; + case TSS_unspecified: return "unspecified"; + case TSS_signed: return "signed"; + case TSS_unsigned: return "unsigned"; } - return true; + llvm::llvm_unreachable("Unknown typespec!"); } const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { switch (T) { - default: assert(0 && "Unknown typespec!"); case DeclSpec::TST_unspecified: return "unspecified"; case DeclSpec::TST_void: return "void"; case DeclSpec::TST_char: return "char"; case DeclSpec::TST_wchar: return "wchar_t"; + case DeclSpec::TST_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"; @@ -173,39 +181,40 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { 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_auto: return "auto"; + case DeclSpec::TST_decltype: return "(decltype)"; + case DeclSpec::TST_error: return "(error)"; } + llvm::llvm_unreachable("Unknown typespec!"); } -bool DeclSpec::BadSpecifier(TST T, const char *&PrevSpec) { - PrevSpec = getSpecifierName(T); - return true; -} - -bool DeclSpec::BadSpecifier(TQ T, const char *&PrevSpec) { +const char *DeclSpec::getSpecifierName(TQ T) { switch (T) { - case DeclSpec::TQ_unspecified: PrevSpec = "unspecified"; break; - case DeclSpec::TQ_const: PrevSpec = "const"; break; - case DeclSpec::TQ_restrict: PrevSpec = "restrict"; break; - case DeclSpec::TQ_volatile: PrevSpec = "volatile"; break; + case DeclSpec::TQ_unspecified: return "unspecified"; + case DeclSpec::TQ_const: return "const"; + case DeclSpec::TQ_restrict: return "restrict"; + case DeclSpec::TQ_volatile: return "volatile"; } - return true; + llvm::llvm_unreachable("Unknown typespec!"); } bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc, - const char *&PrevSpec) { + const char *&PrevSpec, + unsigned &DiagID) { if (StorageClassSpec != SCS_unspecified) - return BadSpecifier((SCS)StorageClassSpec, PrevSpec); + 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) { +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; @@ -218,39 +227,46 @@ bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc, /// and ignore the request if invalid (e.g. "extern" then "auto" is /// specified). bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc, - const char *&PrevSpec) { + const char *&PrevSpec, + unsigned &DiagID) { if (TypeSpecWidth != TSW_unspecified && // Allow turning long -> long long. (W != TSW_longlong || TypeSpecWidth != TSW_long)) - return BadSpecifier((TSW)TypeSpecWidth, PrevSpec); + return BadSpecifier(W, (TSW)TypeSpecWidth, PrevSpec, DiagID); TypeSpecWidth = W; TSWLoc = Loc; return false; } -bool DeclSpec::SetTypeSpecComplex(TSC C, SourceLocation Loc, - const char *&PrevSpec) { +bool DeclSpec::SetTypeSpecComplex(TSC C, SourceLocation Loc, + const char *&PrevSpec, + unsigned &DiagID) { if (TypeSpecComplex != TSC_unspecified) - return BadSpecifier((TSC)TypeSpecComplex, PrevSpec); + return BadSpecifier(C, (TSC)TypeSpecComplex, PrevSpec, DiagID); TypeSpecComplex = C; TSCLoc = Loc; return false; } -bool DeclSpec::SetTypeSpecSign(TSS S, SourceLocation Loc, - const char *&PrevSpec) { +bool DeclSpec::SetTypeSpecSign(TSS S, SourceLocation Loc, + const char *&PrevSpec, + unsigned &DiagID) { if (TypeSpecSign != TSS_unspecified) - return BadSpecifier((TSS)TypeSpecSign, PrevSpec); + return BadSpecifier(S, (TSS)TypeSpecSign, PrevSpec, DiagID); TypeSpecSign = S; TSSLoc = Loc; return false; } bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, - const char *&PrevSpec, void *Rep, - bool Owned) { - if (TypeSpecType != TST_unspecified) - return BadSpecifier((TST)TypeSpecType, PrevSpec); + 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; @@ -266,12 +282,12 @@ bool DeclSpec::SetTypeSpecError() { } bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, - const LangOptions &Lang) { + unsigned &DiagID, const LangOptions &Lang) { // Duplicates turn into warnings pre-C99. if ((TypeQualifiers & T) && !Lang.C99) - return BadSpecifier(T, PrevSpec); + return BadSpecifier(T, T, PrevSpec, DiagID); TypeQualifiers |= T; - + switch (T) { default: assert(0 && "Unknown type qualifier!"); case TQ_const: TQ_constLoc = Loc; break; @@ -281,38 +297,56 @@ bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, return false; } -bool DeclSpec::SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec){ +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){ +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){ +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) { +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; } +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; +} + /// 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, @@ -359,7 +393,7 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { } break; } - + // TODO: if the implementation does not implement _Complex or _Imaginary, // disallow their use. Need information about the backend. if (TypeSpecComplex != TSC_unspecified) { @@ -379,10 +413,28 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { } } + // 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 + << CodeModificationHint::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'? } diff --git a/lib/Parse/ExtensionRAIIObject.h b/lib/Parse/ExtensionRAIIObject.h index 2b2bd3b21648..cc7c8e21705c 100644 --- a/lib/Parse/ExtensionRAIIObject.h +++ b/lib/Parse/ExtensionRAIIObject.h @@ -30,7 +30,7 @@ namespace clang { ExtensionRAIIObject(Diagnostic &diags) : Diags(diags) { Diags.IncrementAllExtensionsSilenced(); } - + ~ExtensionRAIIObject() { Diags.DecrementAllExtensionsSilenced(); } diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index 648e2da54bfe..71b22cad6f62 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -34,7 +34,7 @@ Action::DeclPtrTy Action::ActOnUsingDirective(Scope *CurScope, 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? @@ -44,14 +44,15 @@ Action::DeclPtrTy Action::ActOnUsingDirective(Scope *CurScope, // Defined out-of-line here because of dependecy on AttributeList Action::DeclPtrTy Action::ActOnUsingDeclaration(Scope *CurScope, - SourceLocation UsingLoc, - const CXXScopeSpec &SS, - SourceLocation IdentLoc, - IdentifierInfo *TargetName, - OverloadedOperatorKind Op, - AttributeList *AttrList, - bool IsTypeName) { - + AccessSpecifier AS, + SourceLocation UsingLoc, + const CXXScopeSpec &SS, + SourceLocation IdentLoc, + IdentifierInfo *TargetName, + OverloadedOperatorKind Op, + AttributeList *AttrList, + bool IsTypeName) { + // 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? @@ -66,11 +67,11 @@ void PrettyStackTraceActionsDecl::print(llvm::raw_ostream &OS) const { OS << ": "; } OS << Message; - + std::string Name = Actions.getDeclName(TheDecl); if (!Name.empty()) OS << " '" << Name << '\''; - + OS << '\n'; } @@ -80,7 +81,7 @@ namespace { struct TypeNameInfo { TypeNameInfo *Prev; bool isTypeName; - + TypeNameInfo(bool istypename, TypeNameInfo *prev) { isTypeName = istypename; Prev = prev; @@ -89,13 +90,13 @@ namespace { 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); @@ -107,7 +108,7 @@ static TypeNameInfoTable *getTable(void *TP) { return static_cast<TypeNameInfoTable*>(TP); } -MinimalAction::MinimalAction(Preprocessor &pp) +MinimalAction::MinimalAction(Preprocessor &pp) : Idents(pp.getIdentifierTable()), PP(pp) { TypeNameInfoTablePtr = new TypeNameInfoTable(); } @@ -126,9 +127,9 @@ void MinimalAction::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { 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. + // 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")); @@ -143,7 +144,8 @@ void MinimalAction::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { /// FIXME: Use the passed CXXScopeSpec for accurate C++ type checking. Action::TypeTy * MinimalAction::getTypeName(IdentifierInfo &II, SourceLocation Loc, - Scope *S, const CXXScopeSpec *SS) { + Scope *S, const CXXScopeSpec *SS, + bool isClassName) { if (TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>()) if (TI->isTypeName) return TI; @@ -157,10 +159,14 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *, return false; } -TemplateNameKind -MinimalAction::isTemplateName(const IdentifierInfo &II, Scope *S, - TemplateTy &TemplateDecl, - const CXXScopeSpec *SS) { +TemplateNameKind +MinimalAction::isTemplateName(Scope *S, + const IdentifierInfo &II, + SourceLocation IdLoc, + const CXXScopeSpec *SS, + TypeTy *ObjectType, + bool EnteringScope, + TemplateTy &TemplateDecl) { return TNK_Non_template; } @@ -170,10 +176,10 @@ MinimalAction::isTemplateName(const IdentifierInfo &II, Scope *S, 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; @@ -184,10 +190,10 @@ MinimalAction::ActOnDeclarator(Scope *S, Declarator &D) { 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(); } @@ -206,15 +212,15 @@ MinimalAction::ActOnStartClassInterface(SourceLocation AtInterfaceLoc, return DeclPtrTy(); } -/// ActOnForwardClassDeclaration - -/// Scope will always be top level file scope. +/// ActOnForwardClassDeclaration - +/// Scope will always be top level file scope. Action::DeclPtrTy MinimalAction::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, IdentifierInfo **IdentList, unsigned NumElts) { for (unsigned i = 0; i != NumElts; ++i) { // Allocate and add the 'TypeNameInfo' "decl". getTable(TypeNameInfoTablePtr)->AddEntry(true, IdentList[i]); - + // Remember that this needs to be removed when the scope is popped. TUScope->AddDecl(DeclPtrTy::make(IdentList[i])); } @@ -225,17 +231,17 @@ MinimalAction::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, /// out-of-scope, they are removed from the IdentifierInfo::FETokenInfo field. void MinimalAction::ActOnPopScope(SourceLocation Loc, Scope *S) { TypeNameInfoTable &Table = *getTable(TypeNameInfoTablePtr); - + for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end(); I != E; ++I) { IdentifierInfo &II = *(*I).getAs<IdentifierInfo>(); TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>(); assert(TI && "This decl didn't get pushed??"); - + if (TI) { TypeNameInfo *Next = TI->Prev; Table.DeleteEntry(TI); - + II.setFETokenInfo(Next); } } diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index af6fab7cb188..c34653ee425c 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -21,17 +21,31 @@ using namespace clang; /// 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) { +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'!"); - DeclPtrTy FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, 0, 0); + 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); + + 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(); @@ -40,7 +54,7 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) { // Consume everything up to (and including) the left brace. if (!ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks, tok::semi)) { // We didn't find the left-brace we expected after the - // constructor initializer. + // constructor initializer. if (Tok.is(tok::semi)) { // We found a semicolon; complain, consume the semicolon, and // don't try to parse this method later. @@ -52,7 +66,7 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) { } } else { - // Begin by storing the '{' token. + // Begin by storing the '{' token. Toks.push_back(Tok); ConsumeBrace(); } @@ -86,16 +100,18 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { for (; !Class.MethodDecls.empty(); Class.MethodDecls.pop_front()) { LateParsedMethodDeclaration &LM = Class.MethodDecls.front(); - - // FIXME: For member function templates, we'll need to introduce a - // scope for the template parameters. + + // 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, + ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope); for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) { // Introduce the parameter into scope. @@ -149,11 +165,16 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) { 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); + assert(!LM.Toks.empty() && "Empty body!"); // Append the current token at the end of the new token stream so that it // doesn't get lost. LM.Toks.push_back(Tok); - PP.EnterTokenStream(&LM.Toks.front(), LM.Toks.size(), true, false); + PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false); // Consume the previously pushed token. ConsumeAnyToken(); @@ -171,6 +192,9 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) { } if (Tok.is(tok::colon)) ParseConstructorInitializer(LM.D); + else + Actions.ActOnDefaultCtorInitializers(LM.D); + // FIXME: What if ParseConstructorInitializer doesn't leave us with a '{'?? ParseFunctionStatementBody(LM.D); } @@ -181,7 +205,7 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) { /// ConsumeAndStoreUntil - Consume and store the token at the passed token /// container until the token 'T' is reached (which gets -/// consumed/stored too, if ConsumeFinalToken). +/// consumed/stored too, if ConsumeFinalToken). /// If EarlyAbortIf is specified, then we will stop early if we find that /// token at the top level. /// Returns true if token 'T1' or 'T2' was found. diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 4a3532c4103b..b56c33170cbf 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -69,10 +69,10 @@ Action::TypeResult Parser::ParseTypeName(SourceRange *Range) { /// 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 +/// 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 @@ -82,9 +82,9 @@ Action::TypeResult Parser::ParseTypeName(SourceRange *Range) { AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { assert(Tok.is(tok::kw___attribute) && "Not an attribute list!"); - + AttributeList *CurrAttr = 0; - + while (Tok.is(tok::kw___attribute)) { ConsumeToken(); if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, @@ -99,8 +99,8 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { // 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)) { + + if (Tok.is(tok::comma)) { // allows for empty/non-empty attributes. ((__vector_size__(16),,,,)) ConsumeToken(); continue; @@ -108,26 +108,26 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { // we have an identifier or declaration specifier (const, int, etc.) IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - + // check if we have a "paramterized" attribute if (Tok.is(tok::l_paren)) { ConsumeParen(); // ignore the left paren loc for now - + if (Tok.is(tok::identifier)) { IdentifierInfo *ParmName = Tok.getIdentifierInfo(); SourceLocation ParmLoc = ConsumeToken(); - - if (Tok.is(tok::r_paren)) { + + if (Tok.is(tok::r_paren)) { // __attribute__(( mode(byte) )) ConsumeParen(); // ignore the right paren loc for now - CurrAttr = new AttributeList(AttrName, AttrNameLoc, + CurrAttr = new AttributeList(AttrName, AttrNameLoc, ParmName, ParmLoc, 0, 0, CurrAttr); } else if (Tok.is(tok::comma)) { ConsumeToken(); // __attribute__(( format(printf, 1, 2) )) ExprVector ArgExprs(Actions); bool ArgExprsOk = true; - + // now parse the non-empty comma separated list of expressions while (1) { OwningExprResult ArgExpr(ParseAssignmentExpression()); @@ -144,7 +144,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { } if (ArgExprsOk && Tok.is(tok::r_paren)) { ConsumeParen(); // ignore the right paren loc for now - CurrAttr = new AttributeList(AttrName, AttrNameLoc, ParmName, + CurrAttr = new AttributeList(AttrName, AttrNameLoc, ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size(), CurrAttr); } } @@ -154,11 +154,13 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { // parse a possibly empty comma separated list of expressions // __attribute__(( nonnull() )) ConsumeParen(); // ignore the right paren loc for now - CurrAttr = new AttributeList(AttrName, AttrNameLoc, + CurrAttr = new AttributeList(AttrName, 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: @@ -172,7 +174,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { // If it's a builtin type name, eat it and expect a rparen // __attribute__(( vec_type_hint(char) )) ConsumeToken(); - CurrAttr = new AttributeList(AttrName, AttrNameLoc, + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, SourceLocation(), 0, 0, CurrAttr); if (Tok.is(tok::r_paren)) ConsumeParen(); @@ -181,7 +183,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { // __attribute__(( aligned(16) )) ExprVector ArgExprs(Actions); bool ArgExprsOk = true; - + // now parse the list of expressions while (1) { OwningExprResult ArgExpr(ParseAssignmentExpression()); @@ -207,7 +209,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { } } } else { - CurrAttr = new AttributeList(AttrName, AttrNameLoc, + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, SourceLocation(), 0, 0, CurrAttr); } } @@ -320,7 +322,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context, default: return ParseSimpleDeclaration(Context, DeclEnd); } - + // This routine returns a DeclGroup, if the thing we parsed only contains a // single decl, convert it now. return Actions.ConvertDeclToDeclGroup(SingleDecl); @@ -339,7 +341,7 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context, // Parse the common declaration-specifiers piece. DeclSpec DS; ParseDeclarationSpecifiers(DS); - + // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" // declaration-specifiers init-declarator-list[opt] ';' if (Tok.is(tok::semi)) { @@ -347,25 +349,25 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context, DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS); return Actions.ConvertDeclToDeclGroup(TheDecl); } - + Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context); ParseDeclarator(DeclaratorInfo); - + DeclGroupPtrTy DG = ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo); DeclEnd = Tok.getLocation(); - + // If the client wants to check what comes after the declaration, just return // immediately without checking anything! if (!RequireSemi) return DG; - + if (Tok.is(tok::semi)) { ConsumeToken(); return DG; } - - Diag(Tok, diag::err_expected_semi_declation); + + Diag(Tok, diag::err_expected_semi_declaration); // Skip to end of block or statement SkipUntil(tok::r_brace, true, true); if (Tok.is(tok::semi)) @@ -404,27 +406,50 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D, SkipUntil(tok::semi, true, true); return DeclPtrTy(); } - + D.setAsmLabel(AsmLabel.release()); D.SetRangeEnd(Loc); } - + // If attributes are present, parse them. if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; AttributeList *AttrList = ParseAttributes(&Loc); D.AddAttributes(AttrList, Loc); } - + // Inform the current actions module that we just parsed this declarator. - DeclPtrTy ThisDecl = TemplateInfo.TemplateParams? - Actions.ActOnTemplateDeclarator(CurScope, + 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) - : Actions.ActOnDeclarator(CurScope, D); - + 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(); @@ -444,7 +469,7 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D, SkipUntil(tok::semi, true, true); return DeclPtrTy(); } - Actions.AddInitializerToDecl(ThisDecl, Actions.FullExpr(Init)); + Actions.AddInitializerToDecl(ThisDecl, move(Init)); } } else if (Tok.is(tok::l_paren)) { // Parse C++ direct initializer: '(' expression-list ')' @@ -465,7 +490,9 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D, CommaLocs.data(), RParenLoc); } } else { - Actions.ActOnUninitializedDecl(ThisDecl); + bool TypeContainsUndeducedAuto = + D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; + Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsUndeducedAuto); } return ThisDecl; @@ -488,25 +515,25 @@ ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) { // Declarators may be grouped together ("int X, *Y, Z();"). Remember the decls // that we parse together here. llvm::SmallVector<DeclPtrTy, 8> DeclsInGroup; - + // At this point, we know that it is not a function definition. Parse the // rest of the init-declarator-list. while (1) { DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(D); if (ThisDecl.get()) DeclsInGroup.push_back(ThisDecl); - + // If we don't have a comma, it is either the end of the list (a ';') or an // error, bail out. if (Tok.isNot(tok::comma)) break; - + // Consume the comma. ConsumeToken(); - + // Parse the next declarator. D.clear(); - + // Accept attributes in an init-declarator. In the first declarator in a // declaration, these would be part of the declspec. In subsequent // declarators, they become part of the declarator itself, so that they @@ -519,10 +546,10 @@ ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) { AttributeList *AttrList = ParseAttributes(&Loc); D.AddAttributes(AttrList, Loc); } - + ParseDeclarator(D); } - + return Actions.FinalizeDeclaratorGroup(CurScope, D.getDeclSpec(), DeclsInGroup.data(), DeclsInGroup.size()); @@ -538,13 +565,13 @@ 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()) @@ -553,7 +580,7 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS) { 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()) @@ -604,7 +631,7 @@ 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 @@ -619,7 +646,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, // 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())) { @@ -628,7 +655,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, // 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. @@ -638,7 +665,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *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; @@ -646,12 +673,12 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, case DeclSpec::TST_struct:TagName="struct";TagKind=tok::kw_struct;break; case DeclSpec::TST_class: TagName="class" ;TagKind=tok::kw_class ;break; } - + if (TagName) { Diag(Loc, diag::err_use_of_tag_name_without_tag) << Tok.getIdentifierInfo() << TagName << CodeModificationHint::CreateInsertion(Tok.getLocation(),TagName); - + // Parse this as a tag as if the missing tag were present. if (TagKind == tok::kw_enum) ParseEnumSpecifier(Loc, DS, AS); @@ -660,19 +687,43 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, return true; } } - - // Since this is almost certainly an invalid type name, emit a - // diagnostic that says it, eat the token, and mark the declspec as - // invalid. - SourceRange R; - if (SS) R = SS->getRange(); - - Diag(Loc, diag::err_unknown_typename) << Tok.getIdentifierInfo() << R; + + // 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; - DS.SetTypeSpecType(DeclSpec::TST_error, Loc, 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. @@ -703,24 +754,32 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, /// void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, - AccessSpecifier AS) { + AccessSpecifier AS, + DeclSpecContext DSContext) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(CurScope); + ConsumeToken(); + } + DS.SetRangeStart(Tok.getLocation()); while (1) { - int isInvalid = false; + bool isInvalid = false; const char *PrevSpec = 0; + unsigned DiagID = 0; + SourceLocation Loc = Tok.getLocation(); switch (Tok.getKind()) { - default: + default: DoneWithDeclSpec: // If this is not a declaration specifier token, we're done reading decl // specifiers. First verify that DeclSpec's are consistent. DS.Finish(Diags, PP); return; - + case tok::coloncolon: // ::foo::bar // Annotate C++ scope specifiers. If we get one, loop. - if (TryAnnotateCXXScopeToken()) + if (TryAnnotateCXXScopeToken(true)) continue; goto DoneWithDeclSpec; @@ -730,18 +789,31 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // We are looking for a qualified typename. Token Next = NextToken(); - if (Next.is(tok::annot_template_id) && + if (Next.is(tok::annot_template_id) && static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue()) ->Kind == TNK_Type_template) { // We have a qualified template-id, e.g., N::A<int> CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS); - assert(Tok.is(tok::annot_template_id) && + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true); + assert(Tok.is(tok::annot_template_id) && "ParseOptionalCXXScopeSpecifier not working"); AnnotateTemplateIdTokenAsType(&SS); continue; } + if (Next.is(tok::annot_typename)) { + // FIXME: is this scope-specifier getting dropped? + ConsumeToken(); // the scope-specifier + 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; @@ -763,66 +835,69 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // 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. + // typename. if (TypeRep == 0) { ConsumeToken(); // Eat the scope spec so the identifier is current. if (ParseImplicitInt(DS, &SS, TemplateInfo, AS)) continue; goto DoneWithDeclSpec; } - + ConsumeToken(); // The C++ scope. isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, - TypeRep); + 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, - Tok.getAnnotationValue()); + 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) continue; - - SourceLocation EndProtoLoc; + + SourceLocation LAngleLoc, EndProtoLoc; llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl; - ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc); - DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size()); - + 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 && TryAnnotateCXXScopeToken()) + if (getLang().CPlusPlus && TryAnnotateCXXScopeToken(true)) continue; - + // This identifier can only be a typedef name if we haven't already seen // a type-specifier. Without this check we misparse: // typedef int X; struct Y { short X; }; as 'short int'. if (DS.hasTypeSpecifier()) goto DoneWithDeclSpec; - + // It has to be available as a typedef too! - TypeTy *TypeRep = Actions.getTypeName(*Tok.getIdentifierInfo(), + 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, @@ -836,16 +911,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // being defined and the next token is a '(', then this is a // constructor declaration. We're done with the decl-specifiers // and will treat this token as an identifier. - if (getLang().CPlusPlus && CurScope->isClassScope() && - Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope) && + if (getLang().CPlusPlus && + (CurScope->isClassScope() || + (CurScope->isTemplateParamScope() && + CurScope->getParent()->isClassScope())) && + Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope) && NextToken().getKind() == tok::l_paren) goto DoneWithDeclSpec; isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, - TypeRep); + DiagID, TypeRep); if (isInvalid) break; - + DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); // The identifier @@ -855,12 +933,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // just a normal reference to a typedef name. if (!Tok.is(tok::less) || !getLang().ObjC1) continue; - - SourceLocation EndProtoLoc; + + SourceLocation LAngleLoc, EndProtoLoc; llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl; - ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc); - DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size()); - + 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"). @@ -870,7 +951,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // type-name case tok::annot_template_id: { - TemplateIdAnnotation *TemplateId + 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 @@ -893,7 +974,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___declspec: DS.AddAttributes(ParseMicrosoftDeclSpec()); continue; - + // Microsoft single token adornments. case tok::kw___forceinline: // FIXME: Add handling here! @@ -909,106 +990,144 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // storage-class-specifier case tok::kw_typedef: - isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Loc, PrevSpec); + 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); + isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_extern, Loc, PrevSpec, + DiagID); break; case tok::kw___private_extern__: isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_private_extern, Loc, - PrevSpec); + 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); + 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); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, + DiagID); else - isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec); + isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec, + DiagID); break; case tok::kw_register: - isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, Loc, PrevSpec); + isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, Loc, PrevSpec, + DiagID); break; case tok::kw_mutable: - isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_mutable, Loc, PrevSpec); + isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_mutable, Loc, PrevSpec, + DiagID); break; case tok::kw___thread: - isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec)*2; + isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec, DiagID); break; - + // function-specifier case tok::kw_inline: - isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec); + isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec, DiagID); break; case tok::kw_virtual: - isInvalid = DS.SetFunctionSpecVirtual(Loc, PrevSpec); + isInvalid = DS.SetFunctionSpecVirtual(Loc, PrevSpec, DiagID); break; case tok::kw_explicit: - isInvalid = DS.SetFunctionSpecExplicit(Loc, PrevSpec); + isInvalid = DS.SetFunctionSpecExplicit(Loc, PrevSpec, DiagID); break; // friend case tok::kw_friend: - isInvalid = DS.SetFriendSpec(Loc, PrevSpec); + 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; - + // type-specifier case tok::kw_short: - isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec); + 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); + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec, + DiagID); else - isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, + DiagID); break; case tok::kw_signed: - isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, + DiagID); break; case tok::kw_unsigned: - isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec, + DiagID); break; case tok::kw__Complex: - isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec, + DiagID); break; case tok::kw__Imaginary: - isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec, + DiagID); break; case tok::kw_void: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, + DiagID); break; case tok::kw_char: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, + DiagID); break; case tok::kw_int: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, + DiagID); break; case tok::kw_float: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, + DiagID); break; case tok::kw_double: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, + DiagID); break; case tok::kw_wchar_t: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec); + 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); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, + DiagID); break; case tok::kw__Decimal32: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec, + DiagID); break; case tok::kw__Decimal64: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec, + DiagID); break; case tok::kw__Decimal128: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec, + DiagID); break; // class-specifier: @@ -1029,15 +1148,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // cv-qualifier: case tok::kw_const: - isInvalid = DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec,getLang())*2; + isInvalid = DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec, DiagID, + getLang()); break; case tok::kw_volatile: - isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, - getLang())*2; + isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID, + getLang()); break; case tok::kw_restrict: - isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, - getLang())*2; + isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID, + getLang()); break; // C++ typename-specifier: @@ -1061,12 +1181,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // but we support it. if (DS.hasTypeSpecifier() || !getLang().ObjC1) goto DoneWithDeclSpec; - + { - SourceLocation EndProtoLoc; + SourceLocation LAngleLoc, EndProtoLoc; llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl; - ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc); - DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size()); + 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) @@ -1077,12 +1200,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, continue; } } - // If the specifier combination wasn't legal, issue a diagnostic. + // If the specifier wasn't legal, issue a diagnostic. if (isInvalid) { assert(PrevSpec && "Method did not return previous specifier!"); - // Pick between error or extwarn. - unsigned DiagID = isInvalid == 1 ? diag::err_invalid_decl_spec_combination - : diag::ext_duplicate_declspec; + assert(DiagID); Diag(Tok, DiagID) << PrevSpec; } DS.SetRangeEnd(Tok.getLocation()); @@ -1133,8 +1254,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, /// [OBJC] class-name objc-protocol-refs[opt] [TODO] /// [OBJC] typedef-name objc-protocol-refs[opt] [TODO] /// [C++0x] 'decltype' ( expression ) -bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid, +bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, const char *&PrevSpec, + unsigned &DiagID, const ParsedTemplateInfo &TemplateInfo) { SourceLocation Loc = Tok.getLocation(); @@ -1144,98 +1266,117 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid, // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) - return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, TemplateInfo); + return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, + TemplateInfo); // Otherwise, not a type specifier. return false; case tok::coloncolon: // ::foo::bar if (NextToken().is(tok::kw_new) || // ::new NextToken().is(tok::kw_delete)) // ::delete return false; - + // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) - return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, TemplateInfo); + return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, + TemplateInfo); // Otherwise, not a type specifier. return false; - + // simple-type-specifier: case tok::annot_typename: { if (Tok.getAnnotationValue()) isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, - Tok.getAnnotationValue()); + 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 EndProtoLoc; + + SourceLocation LAngleLoc, EndProtoLoc; llvm::SmallVector<DeclPtrTy, 8> ProtocolDecl; - ParseObjCProtocolReferences(ProtocolDecl, false, EndProtoLoc); - DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size()); - + 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); + 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); + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec, + DiagID); else - isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, + DiagID); break; case tok::kw_signed: - isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID); break; case tok::kw_unsigned: - isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec, + DiagID); break; case tok::kw__Complex: - isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec, + DiagID); break; case tok::kw__Imaginary: - isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec, + DiagID); break; case tok::kw_void: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID); break; case tok::kw_char: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID); break; case tok::kw_int: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID); break; case tok::kw_float: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID); break; case tok::kw_double: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID); break; case tok::kw_wchar_t: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec); + 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); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID); break; case tok::kw__Decimal32: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec, + DiagID); break; case tok::kw__Decimal64: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec, + DiagID); break; case tok::kw__Decimal128: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec, + DiagID); break; // class-specifier: @@ -1257,15 +1398,15 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid, // cv-qualifier: case tok::kw_const: isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, - getLang())*2; + DiagID, getLang()); break; case tok::kw_volatile: isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, - getLang())*2; + DiagID, getLang()); break; case tok::kw_restrict: isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, - getLang())*2; + DiagID, getLang()); break; // GNU typeof support. @@ -1277,13 +1418,13 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid, 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); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID); break; case tok::kw___ptr64: case tok::kw___w64: @@ -1302,8 +1443,6 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid, if (isInvalid) { assert(PrevSpec && "Method did not return previous specifier!"); // Pick between error or extwarn. - unsigned DiagID = isInvalid == 1 ? diag::err_invalid_decl_spec_combination - : diag::ext_duplicate_declspec; Diag(Tok, DiagID) << PrevSpec; } DS.SetRangeEnd(Tok.getLocation()); @@ -1337,11 +1476,11 @@ ParseStructDeclaration(DeclSpec &DS, 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)) { @@ -1353,12 +1492,12 @@ ParseStructDeclaration(DeclSpec &DS, Fields.push_back(FieldDeclarator(DS)); while (1) { FieldDeclarator &DeclaratorInfo = Fields.back(); - + /// struct-declarator: declarator /// struct-declarator: declarator[opt] ':' constant-expression if (Tok.isNot(tok::colon)) ParseDeclarator(DeclaratorInfo.D); - + if (Tok.is(tok::colon)) { ConsumeToken(); OwningExprResult Res(ParseConstantExpression()); @@ -1410,9 +1549,9 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, 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); @@ -1428,7 +1567,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, // 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) @@ -1442,14 +1581,23 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, FieldDeclarators.clear(); if (!Tok.is(tok::at)) { ParseStructDeclaration(DS, FieldDeclarators); - + // Convert them all to fields. for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) { FieldDeclarator &FD = FieldDeclarators[i]; + DeclPtrTy Field; // Install the declarator into the current TagDecl. - DeclPtrTy Field = Actions.ActOnField(CurScope, TagDecl, - DS.getSourceRange().getBegin(), - FD.D, FD.BitfieldSize); + if (FD.D.getExtension()) { + // Silences extension warnings + ExtensionRAIIObject O(Diags); + Field = Actions.ActOnField(CurScope, TagDecl, + DS.getSourceRange().getBegin(), + FD.D, FD.BitfieldSize); + } else { + Field = Actions.ActOnField(CurScope, TagDecl, + DS.getSourceRange().getBegin(), + FD.D, FD.BitfieldSize); + } FieldDecls.push_back(Field); } } else { // Handle @defs @@ -1467,12 +1615,12 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, continue; } llvm::SmallVector<DeclPtrTy, 16> Fields; - Actions.ActOnDefs(CurScope, TagDecl, Tok.getLocation(), + 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(); @@ -1485,9 +1633,9 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, SkipUntil(tok::r_brace, true, true); } } - + SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); - + AttributeList *AttrList = 0; // If attributes exist after struct contents, parse them. if (Tok.is(tok::kw___attribute)) @@ -1498,7 +1646,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, LBraceLoc, RBraceLoc, AttrList); StructScope.Exit(); - Actions.ActOnTagFinishDefinition(CurScope, TagDecl); + Actions.ActOnTagFinishDefinition(CurScope, TagDecl, RBraceLoc); } @@ -1517,14 +1665,19 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, 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); + ConsumeToken(); + } + AttributeList *Attr = 0; // If attributes exist after tag, parse them. if (Tok.is(tok::kw___attribute)) Attr = ParseAttributes(); CXXScopeSpec SS; - if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS)) { + if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, 0, false)) { if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); if (Tok.isNot(tok::l_brace)) { @@ -1535,16 +1688,16 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, } } } - + // 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; @@ -1552,7 +1705,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, 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. @@ -1561,26 +1714,30 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // enum foo {..}; void bar() { enum foo; } <- new foo in bar. // enum foo {..}; void bar() { enum foo x; } <- use of old foo. // - Action::TagKind TK; + Action::TagUseKind TUK; if (Tok.is(tok::l_brace)) - TK = Action::TK_Definition; + TUK = Action::TUK_Definition; else if (Tok.is(tok::semi)) - TK = Action::TK_Declaration; + TUK = Action::TUK_Declaration; else - TK = Action::TK_Reference; + TUK = Action::TUK_Reference; bool Owned = false; - DeclPtrTy TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TK, + bool IsDependent = false; + DeclPtrTy TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TUK, StartLoc, SS, Name, NameLoc, Attr, AS, - Owned); - + Action::MultiTemplateParamsArg(Actions), + Owned, IsDependent); + assert(!IsDependent && "didn't expect dependent enum"); + if (Tok.is(tok::l_brace)) ParseEnumBody(StartLoc, TagDecl); - + // TODO: semantic analysis on the declspec for enums. const char *PrevSpec = 0; - if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, PrevSpec, + unsigned DiagID; + if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, PrevSpec, DiagID, TagDecl.getAs<void>(), Owned)) - Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec; + Diag(StartLoc, DiagID) << PrevSpec; } /// ParseEnumBody - Parse a {} enclosed enumerator-list. @@ -1599,20 +1756,20 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) { 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)) { @@ -1621,7 +1778,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) { if (AssignedVal.isInvalid()) SkipUntil(tok::comma, tok::r_brace, true, true); } - + // Install the enumerator constant into EnumDecl. DeclPtrTy EnumConstDecl = Actions.ActOnEnumConstant(CurScope, EnumDecl, LastEnumConstDecl, @@ -1630,31 +1787,32 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) { AssignedVal.release()); EnumConstantDecls.push_back(EnumConstDecl); LastEnumConstDecl = EnumConstDecl; - + if (Tok.isNot(tok::comma)) break; SourceLocation CommaLoc = ConsumeToken(); - - if (Tok.isNot(tok::identifier) && + + if (Tok.isNot(tok::identifier) && !(getLang().C99 || getLang().CPlusPlus0x)) Diag(CommaLoc, diag::ext_enumerator_list_comma) << getLang().CPlusPlus << CodeModificationHint::CreateRemoval((SourceRange(CommaLoc))); } - + // Eat the }. SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); - Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl, - EnumConstantDecls.data(), EnumConstantDecls.size()); - - Action::AttrTy *AttrList = 0; + AttributeList *Attr = 0; // If attributes exist after the identifier list, parse them. if (Tok.is(tok::kw___attribute)) - AttrList = ParseAttributes(); // FIXME: where do they do? + Attr = ParseAttributes(); + + Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl, + EnumConstantDecls.data(), EnumConstantDecls.size(), + CurScope, Attr); EnumScope.Exit(); - Actions.ActOnTagFinishDefinition(CurScope, EnumDecl); + Actions.ActOnTagFinishDefinition(CurScope, EnumDecl, RBraceLoc); } /// isTypeSpecifierQualifier - Return true if the current token could be the @@ -1675,7 +1833,7 @@ bool Parser::isTypeQualifier() const { bool Parser::isTypeSpecifierQualifier() { switch (Tok.getKind()) { default: return false; - + case tok::identifier: // foo::bar case tok::kw_typename: // typename T::type // Annotate typenames and C++ scope specifiers. If we get one, just @@ -1696,12 +1854,12 @@ bool Parser::isTypeSpecifierQualifier() { return isTypeSpecifierQualifier(); // Otherwise, not a type specifier. return false; - + // GNU attributes support. case tok::kw___attribute: // GNU typeof support. case tok::kw_typeof: - + // type-specifiers case tok::kw_short: case tok::kw_long: @@ -1712,6 +1870,8 @@ bool Parser::isTypeSpecifierQualifier() { 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: @@ -1720,14 +1880,14 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw__Decimal32: case tok::kw__Decimal64: case tok::kw__Decimal128: - + // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: case tok::kw_struct: case tok::kw_union: // enum-specifier case tok::kw_enum: - + // type-qualifier case tok::kw_const: case tok::kw_volatile: @@ -1736,11 +1896,11 @@ bool Parser::isTypeSpecifierQualifier() { // 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: @@ -1755,7 +1915,7 @@ bool Parser::isTypeSpecifierQualifier() { 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)) @@ -1773,14 +1933,14 @@ bool Parser::isDeclarationSpecifier() { if (NextToken().is(tok::kw_new) || // ::new NextToken().is(tok::kw_delete)) // ::delete return false; - + // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return isDeclarationSpecifier(); // Otherwise, not a declaration specifier. return false; - + // storage-class-specifier case tok::kw_typedef: case tok::kw_extern: @@ -1789,7 +1949,7 @@ bool Parser::isDeclarationSpecifier() { case tok::kw_auto: case tok::kw_register: case tok::kw___thread: - + // type-specifiers case tok::kw_short: case tok::kw_long: @@ -1800,6 +1960,9 @@ bool Parser::isDeclarationSpecifier() { 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: @@ -1808,14 +1971,14 @@ bool Parser::isDeclarationSpecifier() { case tok::kw__Decimal32: case tok::kw__Decimal64: case tok::kw__Decimal128: - + // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: case tok::kw_struct: case tok::kw_union: // enum-specifier case tok::kw_enum: - + // type-qualifier case tok::kw_const: case tok::kw_volatile: @@ -1831,15 +1994,15 @@ bool Parser::isDeclarationSpecifier() { // 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: @@ -1861,22 +2024,23 @@ bool Parser::isDeclarationSpecifier() { /// void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed) { while (1) { - int isInvalid = false; + 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, - getLang())*2; + isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, DiagID, + getLang()); break; case tok::kw_volatile: - isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, - getLang())*2; + isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID, + getLang()); break; case tok::kw_restrict: - isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, - getLang())*2; + isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID, + getLang()); break; case tok::kw___w64: case tok::kw___ptr64: @@ -1905,9 +2069,6 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed) { // If the specifier combination wasn't legal, issue a diagnostic. if (isInvalid) { assert(PrevSpec && "Method did not return previous specifier!"); - // Pick between error or extwarn. - unsigned DiagID = isInvalid == 1 ? diag::err_invalid_decl_spec_combination - : diag::ext_duplicate_declspec; Diag(Tok, DiagID) << PrevSpec; } ConsumeToken(); @@ -1947,6 +2108,8 @@ void Parser::ParseDeclarator(Declarator &D) { 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. @@ -1954,8 +2117,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D, (Tok.is(tok::coloncolon) || Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope))) { CXXScopeSpec SS; - if (ParseOptionalCXXScopeSpecifier(SS)) { - if(Tok.isNot(tok::star)) { + if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true)) { + if (Tok.isNot(tok::star)) { // The scope spec really belongs to the direct-declarator. D.getCXXScopeSpec() = SS; if (DirectDeclParser) @@ -2013,7 +2176,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, SourceLocation()); else // Remember that we parsed a Block type, and remember the type-quals. - D.AddTypeInfo(DeclaratorChunk::getBlockPointer(DS.getTypeQualifiers(), + D.AddTypeInfo(DeclaratorChunk::getBlockPointer(DS.getTypeQualifiers(), Loc, DS.TakeAttributes()), SourceLocation()); } else { @@ -2095,13 +2258,13 @@ void Parser::ParseDeclaratorInternal(Declarator &D, /// /// id-expression: [C++ 5.1] /// unqualified-id -/// qualified-id [TODO] +/// qualified-id /// /// unqualified-id: [C++ 5.1] -/// identifier +/// identifier /// operator-function-id -/// conversion-function-id [TODO] -/// '~' class-name +/// conversion-function-id +/// '~' class-name /// template-id /// void Parser::ParseDirectDeclarator(Declarator &D) { @@ -2111,7 +2274,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) { if (D.mayHaveIdentifier()) { // ParseDeclaratorInternal might already have parsed the scope. bool afterCXXScope = D.getCXXScopeSpec().isSet() || - ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec()); + ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0, + true); if (afterCXXScope) { // Change the declaration context for name lookup, until this function // is exited (and the declarator has been parsed). @@ -2122,11 +2286,12 @@ void Parser::ParseDirectDeclarator(Declarator &D) { assert(Tok.getIdentifierInfo() && "Not an identifier?"); // If this identifier is the name of the current class, it's a - // constructor name. + // constructor name. if (!D.getDeclSpec().hasTypeSpecifier() && Actions.isCurrentClassName(*Tok.getIdentifierInfo(),CurScope)) { + CXXScopeSpec *SS = afterCXXScope? &D.getCXXScopeSpec() : 0; D.setConstructor(Actions.getTypeName(*Tok.getIdentifierInfo(), - Tok.getLocation(), CurScope), + Tok.getLocation(), CurScope, SS), Tok.getLocation()); // This is a normal identifier. } else @@ -2134,18 +2299,10 @@ void Parser::ParseDirectDeclarator(Declarator &D) { ConsumeToken(); goto PastIdentifier; } else if (Tok.is(tok::annot_template_id)) { - TemplateIdAnnotation *TemplateId + TemplateIdAnnotation *TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); - // FIXME: Could this template-id name a constructor? - - // FIXME: This is an egregious hack, where we silently ignore - // the specialization (which should be a function template - // specialization name) and use the name instead. This hack - // will go away when we have support for function - // specializations. - D.SetIdentifier(TemplateId->Name, Tok.getLocation()); - TemplateId->Destroy(); + D.setTemplateId(TemplateId); ConsumeToken(); goto PastIdentifier; } else if (Tok.is(tok::kw_operator)) { @@ -2167,17 +2324,18 @@ void Parser::ParseDirectDeclarator(Declarator &D) { } else if (Tok.is(tok::tilde)) { // This should be a C++ destructor. SourceLocation TildeLoc = ConsumeToken(); - if (Tok.is(tok::identifier)) { + if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) { // FIXME: Inaccurate. SourceLocation NameLoc = Tok.getLocation(); SourceLocation EndLoc; - TypeResult Type = ParseClassName(EndLoc); + CXXScopeSpec *SS = afterCXXScope? &D.getCXXScopeSpec() : 0; + TypeResult Type = ParseClassName(EndLoc, SS, true); if (Type.isInvalid()) D.SetIdentifier(0, TildeLoc); else D.setDestructor(Type.get(), TildeLoc, NameLoc); } else { - Diag(Tok, diag::err_expected_class_name); + Diag(Tok, diag::err_destructor_class_name); D.SetIdentifier(0, TildeLoc); } goto PastIdentifier; @@ -2222,11 +2380,11 @@ void Parser::ParseDirectDeclarator(Declarator &D) { D.SetIdentifier(0, Tok.getLocation()); D.setInvalidType(true); } - + PastIdentifier: assert(D.isPastIdentifier() && "Haven't past the location of the identifier yet?"); - + while (1) { if (Tok.is(tok::l_paren)) { // The paren may be part of a C++ direct initializer, eg. "int x(1);". @@ -2250,7 +2408,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { /// 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 +/// parens for precedence. If we find that these are actually function /// parameter parens in an abstract-declarator, we call ParseFunctionDeclarator. /// /// direct-declarator: @@ -2264,7 +2422,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { 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: @@ -2279,7 +2437,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { bool RequiresArg = false; if (Tok.is(tok::kw___attribute)) { AttrList = ParseAttributes(); - + // We require that the argument list (if this is a non-grouping paren) be // present even if the attribute list was empty. RequiresArg = true; @@ -2290,13 +2448,13 @@ void Parser::ParseParenDeclarator(Declarator &D) { Tok.is(tok::kw___ptr64)) { AttrList = ParseMicrosoftTypeAttributes(AttrList); } - + // 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. @@ -2311,7 +2469,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { // 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 ')' @@ -2329,7 +2487,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { 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 @@ -2353,6 +2511,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { /// parameter-type-list: [C99 6.7.5] /// parameter-list /// parameter-list ',' '...' +/// [C++] parameter-list '...' /// /// parameter-list: [C99 6.7.5] /// parameter-declaration @@ -2375,7 +2534,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, 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) { @@ -2383,7 +2542,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, delete AttrList; } - SourceLocation Loc = ConsumeParen(); // Eat the closing ')'. + SourceLocation RParenLoc = ConsumeParen(); // Eat the closing ')'. + SourceLocation EndLoc = RParenLoc; // cv-qualifier-seq[opt]. DeclSpec DS; @@ -2395,13 +2555,13 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, if (getLang().CPlusPlus) { ParseTypeQualifierListOpt(DS, false /*no attributes*/); if (!DS.getSourceRange().getEnd().isInvalid()) - Loc = DS.getSourceRange().getEnd(); + EndLoc = DS.getSourceRange().getEnd(); // Parse exception-specification[opt]. if (Tok.is(tok::kw_throw)) { hasExceptionSpec = true; ThrowLoc = Tok.getLocation(); - ParseExceptionSpecification(Loc, Exceptions, ExceptionRanges, + ParseExceptionSpecification(EndLoc, Exceptions, ExceptionRanges, hasAnyExceptionSpec); assert(Exceptions.size() == ExceptionRanges.size() && "Produced different number of exception types and ranges."); @@ -2420,8 +2580,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, Exceptions.data(), ExceptionRanges.data(), Exceptions.size(), - LParenLoc, D), - Loc); + LParenLoc, RParenLoc, D), + EndLoc); return; } @@ -2440,9 +2600,9 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, return ParseFunctionDeclaratorIdentifierList(LParenLoc, D); } } - + // Finally, a normal, non-empty parameter type list. - + // Build up an array of information about the parsed arguments. llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo; @@ -2450,7 +2610,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // function prototype scope, including parameter declarators. ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope); - + bool IsVariadic = false; SourceLocation EllipsisLoc; while (1) { @@ -2459,9 +2619,9 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, EllipsisLoc = ConsumeToken(); // Consume the ellipsis. break; } - + SourceLocation DSStart = Tok.getLocation(); - + // Parse the declaration-specifiers. DeclSpec DS; @@ -2471,7 +2631,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, 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); @@ -2483,10 +2643,10 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, AttributeList *AttrList = ParseAttributes(&Loc); ParmDecl.AddAttributes(AttrList, Loc); } - + // Remember this parsed parameter in ParamInfo. IdentifierInfo *ParmII = ParmDecl.getIdentifier(); - + // DefArgToks is used when the parsing of default arguments needs // to be delayed. CachedTokens *DefArgToks = 0; @@ -2500,7 +2660,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, } 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); @@ -2521,18 +2681,18 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // FIXME: Can we use a smart pointer for Toks? DefArgToks = new CachedTokens; - if (!ConsumeAndStoreUntil(tok::comma, tok::r_paren, *DefArgToks, + if (!ConsumeAndStoreUntil(tok::comma, tok::r_paren, *DefArgToks, tok::semi, false)) { delete DefArgToks; DefArgToks = 0; Actions.ActOnParamDefaultArgumentError(Param); } else - Actions.ActOnParamUnparsedDefaultArgument(Param, EqualLoc, + Actions.ActOnParamUnparsedDefaultArgument(Param, EqualLoc, (*DefArgToks)[1].getLocation()); } else { // Consume the '='. ConsumeToken(); - + OwningExprResult DefArgResult(ParseAssignmentExpression()); if (DefArgResult.isInvalid()) { Actions.ActOnParamDefaultArgumentError(Param); @@ -2544,24 +2704,39 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, } } } - - ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, - ParmDecl.getIdentifierLoc(), Param, + + ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, + ParmDecl.getIdentifierLoc(), Param, DefArgToks)); } // If the next token is a comma, consume it and keep reading arguments. - if (Tok.isNot(tok::comma)) break; - + 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) + << CodeModificationHint::CreateInsertion(EllipsisLoc, ", "); + } + } + + break; + } + // Consume the comma. ConsumeToken(); } - + // Leave prototype scope. PrototypeScope.Exit(); - + // If we have the closing ')', eat it. - SourceLocation Loc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + SourceLocation EndLoc = RParenLoc; DeclSpec DS; bool hasExceptionSpec = false; @@ -2573,13 +2748,13 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // Parse cv-qualifier-seq[opt]. ParseTypeQualifierListOpt(DS, false /*no attributes*/); if (!DS.getSourceRange().getEnd().isInvalid()) - Loc = DS.getSourceRange().getEnd(); + EndLoc = DS.getSourceRange().getEnd(); // Parse exception-specification[opt]. if (Tok.is(tok::kw_throw)) { hasExceptionSpec = true; ThrowLoc = Tok.getLocation(); - ParseExceptionSpecification(Loc, Exceptions, ExceptionRanges, + ParseExceptionSpecification(EndLoc, Exceptions, ExceptionRanges, hasAnyExceptionSpec); assert(Exceptions.size() == ExceptionRanges.size() && "Produced different number of exception types and ranges."); @@ -2595,8 +2770,9 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, hasAnyExceptionSpec, Exceptions.data(), ExceptionRanges.data(), - Exceptions.size(), LParenLoc, D), - Loc); + Exceptions.size(), + LParenLoc, RParenLoc, D), + EndLoc); } /// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator @@ -2612,7 +2788,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc, // 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: @@ -2626,13 +2802,13 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc, ParamInfo.push_back(DeclaratorChunk::ParamInfo(Tok.getIdentifierInfo(), Tok.getLocation(), DeclPtrTy())); - + ConsumeToken(); // eat the first identifier. - + while (Tok.is(tok::comma)) { // Eat the comma. ConsumeToken(); - + // If this isn't an identifier, report the error and skip until ')'. if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); @@ -2645,7 +2821,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc, // 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; @@ -2655,7 +2831,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc, Tok.getLocation(), DeclPtrTy())); } - + // Eat the identifier. ConsumeToken(); } @@ -2672,7 +2848,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc, /*TypeQuals*/0, /*exception*/false, SourceLocation(), false, 0, 0, 0, - LParenLoc, D), + LParenLoc, RLoc, D), RLoc); } @@ -2683,14 +2859,15 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc, /// [C99] direct-declarator '[' type-qual-list[opt] '*' ']' void Parser::ParseBracketDeclarator(Declarator &D) { SourceLocation StartLoc = ConsumeBracket(); - + // C array syntax has many features, but by-far the most common is [] and [4]. // This code does a fast path to handle some of the most obvious cases. if (Tok.getKind() == tok::r_square) { SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc); // Remember that we parsed the empty array type. OwningExprResult NumElements(Actions); - D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0, StartLoc), + D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0, + StartLoc, EndLoc), EndLoc); return; } else if (Tok.getKind() == tok::numeric_constant && @@ -2704,33 +2881,33 @@ void Parser::ParseBracketDeclarator(Declarator &D) { // 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), + 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 @@ -2748,7 +2925,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { // 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) @@ -2756,7 +2933,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { else NumElements = ParseAssignmentExpression(); } - + // If there was an error parsing the assignment-expression, recover. if (NumElements.isInvalid()) { D.setInvalidType(true); @@ -2770,7 +2947,8 @@ void Parser::ParseBracketDeclarator(Declarator &D) { // Remember that we parsed a array type, and remember its features. D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(), StaticLoc.isValid(), isStar, - NumElements.release(), StartLoc), + NumElements.release(), + StartLoc, EndLoc), EndLoc); } @@ -2797,7 +2975,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { DS.SetRangeEnd(Tok.getLocation()); else DS.SetRangeEnd(CastRange.getEnd()); - + if (isCastExpr) { if (!CastTy) { DS.SetTypeSpecError(); @@ -2805,10 +2983,11 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { } const char *PrevSpec = 0; + unsigned DiagID; // Check for duplicate type specifiers (e.g. "int typeof(int)"). if (DS.SetTypeSpecType(DeclSpec::TST_typeofType, StartLoc, PrevSpec, - CastTy)) - Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec; + DiagID, CastTy)) + Diag(StartLoc, DiagID) << PrevSpec; return; } @@ -2819,8 +2998,9 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { } const char *PrevSpec = 0; + unsigned DiagID; // Check for duplicate type specifiers (e.g. "int typeof(int)"). if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec, - Operand.release())) - Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec; + DiagID, Operand.release())) + Diag(StartLoc, DiagID) << PrevSpec; } diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 373d22fd9f4f..d381e3e97472 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -38,7 +38,7 @@ using namespace clang; /// /// extension-namespace-definition: /// 'namespace' original-namespace-name '{' namespace-body '}' -/// +/// /// namespace-alias-definition: [C++ 7.3.2: namespace.alias] /// 'namespace' identifier '=' qualified-namespace-specifier ';' /// @@ -46,17 +46,22 @@ 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); + ConsumeToken(); + } 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. Action::AttrTy *AttrList = 0; if (Tok.is(tok::kw___attribute)) { @@ -65,20 +70,20 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context, // FIXME: save these somewhere. AttrList = ParseAttributes(); } - + 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(Tok, Ident ? diag::err_expected_lbrace : diag::err_expected_ident_lbrace); return DeclPtrTy(); } - + SourceLocation LBrace = ConsumeBrace(); // Enter a scope for the namespace. @@ -90,10 +95,10 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context, PrettyStackTraceActionsDecl CrashInfo(NamespcDecl, NamespaceLoc, Actions, PP.getSourceManager(), "parsing namespace"); - + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) ParseExternalDeclaration(); - + // Leave the namespace scope. NamespaceScope.Exit(); @@ -108,16 +113,21 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context, /// alias definition. /// Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, - SourceLocation AliasLoc, + 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); + ConsumeToken(); + } CXXScopeSpec SS; // Parse (optional) nested-name-specifier. - ParseOptionalCXXScopeSpecifier(SS); + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); if (SS.isInvalid() || Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_namespace_name); @@ -129,13 +139,13 @@ Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, // 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, + + return Actions.ActOnNamespaceAliasDef(CurScope, NamespaceLoc, AliasLoc, Alias, SS, IdentLoc, Ident); } @@ -157,18 +167,18 @@ Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) { SourceLocation Loc = ConsumeStringToken(); ParseScope LinkageScope(this, Scope::DeclScope); - DeclPtrTy LinkageSpec - = Actions.ActOnStartLinkageSpecification(CurScope, + DeclPtrTy LinkageSpec + = Actions.ActOnStartLinkageSpecification(CurScope, /*FIXME: */SourceLocation(), Loc, LangBufPtr, StrSize, - Tok.is(tok::l_brace)? Tok.getLocation() + Tok.is(tok::l_brace)? Tok.getLocation() : SourceLocation()); if (Tok.isNot(tok::l_brace)) { ParseDeclarationOrFunctionDefinition(); - return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec, + return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec, SourceLocation()); - } + } SourceLocation LBrace = ConsumeBrace(); while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { @@ -188,6 +198,11 @@ Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, // Eat 'using'. SourceLocation UsingLoc = ConsumeToken(); + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteUsing(CurScope); + ConsumeToken(); + } + if (Tok.is(tok::kw_namespace)) // Next token after 'using' is 'namespace' so it must be using-directive return ParseUsingDirective(Context, UsingLoc, DeclEnd); @@ -214,9 +229,14 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context, // Eat 'namespace'. SourceLocation NamespcLoc = ConsumeToken(); + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteUsingDirective(CurScope); + ConsumeToken(); + } + CXXScopeSpec SS; // Parse (optional) nested-name-specifier. - ParseOptionalCXXScopeSpecifier(SS); + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); AttributeList *AttrList = 0; IdentifierInfo *NamespcName = 0; @@ -230,15 +250,15 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context, // FIXME: Are there cases, when we would like to call ActOnUsingDirective? return DeclPtrTy(); } - + // Parse identifier. NamespcName = Tok.getIdentifierInfo(); IdentLoc = ConsumeToken(); - + // Parse (optional) attributes (most likely GNU strong-using extension). if (Tok.is(tok::kw___attribute)) AttrList = ParseAttributes(); - + // Eat ';'. DeclEnd = Tok.getLocation(); ExpectAndConsume(tok::semi, @@ -259,7 +279,8 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context, /// Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, SourceLocation UsingLoc, - SourceLocation &DeclEnd) { + SourceLocation &DeclEnd, + AccessSpecifier AS) { CXXScopeSpec SS; bool IsTypeName; @@ -272,7 +293,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, IsTypeName = false; // Parse nested-name-specifier. - ParseOptionalCXXScopeSpecifier(SS); + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); AttributeList *AttrList = 0; @@ -282,15 +303,17 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, return DeclPtrTy(); } if (Tok.is(tok::annot_template_id)) { - Diag(Tok, diag::err_unexpected_template_spec_in_using); + // C++0x N2914 [namespace.udecl]p5: + // A using-declaration shall not name a template-id. + Diag(Tok, diag::err_using_decl_can_not_refer_to_template_spec); SkipUntil(tok::semi); return DeclPtrTy(); } - + IdentifierInfo *TargetName = 0; OverloadedOperatorKind Op = OO_None; SourceLocation IdentLoc; - + if (Tok.is(tok::kw_operator)) { IdentLoc = Tok.getLocation(); @@ -312,17 +335,17 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, SkipUntil(tok::semi); return DeclPtrTy(); } - + // Parse (optional) attributes (most likely GNU strong-using extension). if (Tok.is(tok::kw___attribute)) AttrList = ParseAttributes(); - + // Eat ';'. DeclEnd = Tok.getLocation(); ExpectAndConsume(tok::semi, diag::err_expected_semi_after, AttrList ? "attributes list" : "namespace name", tok::semi); - return Actions.ActOnUsingDeclaration(CurScope, UsingLoc, SS, + return Actions.ActOnUsingDeclaration(CurScope, AS, UsingLoc, SS, IdentLoc, TargetName, Op, AttrList, IsTypeName); } @@ -335,12 +358,12 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, 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()); @@ -348,7 +371,7 @@ Parser::DeclPtrTy Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ SkipUntil(tok::semi); return DeclPtrTy(); } - + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::semi)) return DeclPtrTy(); @@ -357,17 +380,17 @@ Parser::DeclPtrTy Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ SkipUntil(tok::semi); return DeclPtrTy(); } - + OwningExprResult AssertMessage(ParseStringLiteralExpression()); - if (AssertMessage.isInvalid()) + 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), + return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc, move(AssertExpr), move(AssertMessage)); } @@ -380,15 +403,15 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) { SourceLocation StartLoc = ConsumeToken(); SourceLocation LParenLoc = Tok.getLocation(); - - if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, + + 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, @@ -398,22 +421,23 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) { 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, - Result.release())) - Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec; + 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 @@ -425,12 +449,13 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) { /// class-name: [C++ 9.1] /// identifier /// simple-template-id -/// +/// Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, - const CXXScopeSpec *SS) { + const CXXScopeSpec *SS, + bool DestrExpected) { // Check whether we have a template-id that names a type. if (Tok.is(tok::annot_template_id)) { - TemplateIdAnnotation *TemplateId + TemplateIdAnnotation *TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); if (TemplateId->Kind == TNK_Type_template) { AnnotateTemplateIdTokenAsType(SS); @@ -454,10 +479,12 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, } // We have an identifier; check whether it is actually a type. - TypeTy *Type = Actions.getTypeName(*Tok.getIdentifierInfo(), - Tok.getLocation(), CurScope, SS); + TypeTy *Type = Actions.getTypeName(*Tok.getIdentifierInfo(), + Tok.getLocation(), CurScope, SS, + true); if (!Type) { - Diag(Tok, diag::err_expected_class_name); + Diag(Tok, DestrExpected ? diag::err_destructor_class_name + : diag::err_expected_class_name); return true; } @@ -480,9 +507,9 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, /// 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 +/// [GNU] class-key attributes[opt] nested-name-specifier /// identifier base-clause[opt] -/// [GNU] class-key attributes[opt] nested-name-specifier[opt] +/// [GNU] class-key attributes[opt] nested-name-specifier[opt] /// simple-template-id base-clause[opt] /// class-key: /// 'class' @@ -490,9 +517,9 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, /// '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 +/// 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: @@ -520,6 +547,12 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TagType = DeclSpec::TST_union; } + if (Tok.is(tok::code_completion)) { + // Code completion for a struct, class, or union name. + Actions.CodeCompleteTag(CurScope, TagType); + ConsumeToken(); + } + AttributeList *Attr = 0; // If attributes exist after tag, parse them. if (Tok.is(tok::kw___attribute)) @@ -528,10 +561,31 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // If declspecs exist after tag, parse them. if (Tok.is(tok::kw___declspec)) Attr = ParseMicrosoftDeclSpec(Attr); - + + 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; - if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS)) + if (getLang().CPlusPlus && + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true)) if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) Diag(Tok, diag::err_expected_ident); @@ -556,7 +610,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, 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(); @@ -564,19 +618,33 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } } - // There are three options here. If we have 'struct foo;', then - // this is a forward declaration. If we have 'struct foo {...' or + // 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. - Action::TagKind TK; - if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon))) - TK = Action::TK_Definition; - else if (Tok.is(tok::semi) && !DS.isFriendSpecified()) - TK = Action::TK_Declaration; + Action::TagUseKind TUK; + 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 - TK = Action::TK_Reference; + TUK = Action::TUK_Reference; - if (!Name && !TemplateId && TK != Action::TK_Definition) { + 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); @@ -590,36 +658,49 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } // Create the tag portion of the class or class template. - Action::DeclResult TagOrTempResult; + Action::DeclResult TagOrTempResult = true; // invalid + Action::TypeResult TypeResult = true; // invalid TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; - // FIXME: When TK == TK_Reference and we have a template-id, we need + // FIXME: When TUK == TUK_Reference and we have a template-id, we need // to turn that template-id into a type. bool Owned = false; - if (TemplateId && TK != Action::TK_Reference) { + if (TemplateId) { // Explicit specialization, class template partial specialization, // or explicit instantiation. - ASTTemplateArgsPtr TemplateArgsPtr(Actions, + ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateId->getTemplateArgs(), TemplateId->getTemplateArgIsType(), TemplateId->NumArgs); if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && - TK == Action::TK_Declaration) { + TUK == Action::TUK_Declaration) { // This is an explicit instantiation of a class template. TagOrTempResult - = Actions.ActOnExplicitInstantiation(CurScope, - TemplateInfo.TemplateLoc, + = Actions.ActOnExplicitInstantiation(CurScope, + TemplateInfo.ExternLoc, + TemplateInfo.TemplateLoc, TagType, - StartLoc, + StartLoc, SS, - TemplateTy::make(TemplateId->Template), - TemplateId->TemplateNameLoc, - TemplateId->LAngleLoc, + TemplateTy::make(TemplateId->Template), + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->getTemplateArgLocations(), - TemplateId->RAngleLoc, + TemplateId->RAngleLoc, Attr); + } else if (TUK == Action::TUK_Reference) { + TypeResult + = Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->getTemplateArgLocations(), + TemplateId->RAngleLoc); + + TypeResult = Actions.ActOnTagTemplateIdType(TypeResult, TUK, + TagType, StartLoc); } else { // This is an explicit specialization or a class template // partial specialization. @@ -634,11 +715,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // but it actually has a definition. Most likely, this was // meant to be an explicit specialization, but the user forgot // the '<>' after 'template'. - assert(TK == Action::TK_Definition && "Expected a definition here"); + assert(TUK == Action::TUK_Definition && "Expected a definition here"); - SourceLocation LAngleLoc + SourceLocation LAngleLoc = PP.getLocForEndOfToken(TemplateInfo.TemplateLoc); - Diag(TemplateId->TemplateNameLoc, + Diag(TemplateId->TemplateNameLoc, diag::err_explicit_instantiation_with_definition) << SourceRange(TemplateInfo.TemplateLoc) << CodeModificationHint::CreateInsertion(LAngleLoc, "<>"); @@ -647,60 +728,64 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // "template<>", so that we treat this construct as a class // template specialization. FakedParamLists.push_back( - Actions.ActOnTemplateParameterList(0, SourceLocation(), + Actions.ActOnTemplateParameterList(0, SourceLocation(), TemplateInfo.TemplateLoc, - LAngleLoc, - 0, 0, + LAngleLoc, + 0, 0, LAngleLoc)); TemplateParams = &FakedParamLists; } // Build the class template specialization. TagOrTempResult - = Actions.ActOnClassTemplateSpecialization(CurScope, TagType, TK, + = Actions.ActOnClassTemplateSpecialization(CurScope, TagType, TUK, StartLoc, SS, - TemplateTy::make(TemplateId->Template), - TemplateId->TemplateNameLoc, - TemplateId->LAngleLoc, + TemplateTy::make(TemplateId->Template), + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->getTemplateArgLocations(), - TemplateId->RAngleLoc, + TemplateId->RAngleLoc, Attr, - Action::MultiTemplateParamsArg(Actions, + Action::MultiTemplateParamsArg(Actions, TemplateParams? &(*TemplateParams)[0] : 0, TemplateParams? TemplateParams->size() : 0)); } TemplateId->Destroy(); - } else if (TemplateParams && TK != Action::TK_Reference) { - // Class template declaration or definition. - TagOrTempResult = Actions.ActOnClassTemplate(CurScope, TagType, TK, - StartLoc, SS, Name, NameLoc, - Attr, - Action::MultiTemplateParamsArg(Actions, - &(*TemplateParams)[0], - TemplateParams->size()), - AS); } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && - TK == Action::TK_Declaration) { + 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.TemplateLoc, - TagType, StartLoc, SS, Name, + = Actions.ActOnExplicitInstantiation(CurScope, + TemplateInfo.ExternLoc, + TemplateInfo.TemplateLoc, + TagType, StartLoc, SS, Name, NameLoc, Attr); } else { if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && - TK == Action::TK_Definition) { + TUK == Action::TUK_Definition) { // FIXME: Diagnose this particular error. } + bool IsDependent = false; + // Declaration or definition of a class type - TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, SS, - Name, NameLoc, Attr, AS, Owned); + TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TUK, StartLoc, SS, + Name, NameLoc, Attr, 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); } // Parse the optional base clause (C++ only). @@ -713,28 +798,33 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get()); else ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get()); - else if (TK == Action::TK_Definition) { + else if (TUK == Action::TUK_Definition) { // FIXME: Complain that we have a base-specifier list but no // definition. Diag(Tok, diag::err_expected_lbrace); } - const char *PrevSpec = 0; - if (TagOrTempResult.isInvalid()) { + 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; } - - if (DS.SetTypeSpecType(TagType, StartLoc, PrevSpec, - TagOrTempResult.get().getAs<void>(), Owned)) - Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec; - - if (DS.isFriendSpecified()) - Actions.ActOnFriendDecl(CurScope, DS.getFriendSpecLoc(), - TagOrTempResult.get()); + + const char *PrevSpec = 0; + unsigned DiagID; + + if (DS.SetTypeSpecType(TagType, StartLoc, PrevSpec, DiagID, + Result, Owned)) + Diag(StartLoc, DiagID) << PrevSpec; } -/// ParseBaseClause - Parse the base-clause of a C++ class [C++ class.derived]. +/// ParseBaseClause - Parse the base-clause of a C++ class [C++ class.derived]. /// /// base-clause : [C++ class.derived] /// ':' base-specifier-list @@ -763,7 +853,7 @@ void Parser::ParseBaseClause(DeclPtrTy ClassDecl) { // If the next token is a comma, consume it and keep reading // base-specifiers. if (Tok.isNot(tok::comma)) break; - + // Consume the comma. ConsumeToken(); } @@ -797,7 +887,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) { AccessSpecifier Access = getAccessSpecifierIfPresent(); if (Access) ConsumeToken(); - + // Parse the 'virtual' keyword (again!), in case it came after the // access specifier. if (Tok.is(tok::kw_virtual)) { @@ -813,7 +903,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) { // Parse optional '::' and optional nested-name-specifier. CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS); + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true); // The location of the base class itself. SourceLocation BaseLoc = Tok.getLocation(); @@ -823,10 +913,10 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) { TypeResult BaseType = ParseClassName(EndLocation, &SS); if (BaseType.isInvalid()) return true; - - // Find the complete source range for the base-specifier. + + // 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, @@ -840,8 +930,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) { /// 'private' /// 'protected' /// 'public' -AccessSpecifier Parser::getAccessSpecifierIfPresent() const -{ +AccessSpecifier Parser::getAccessSpecifierIfPresent() const { switch (Tok.getKind()) { default: return AS_none; case tok::kw_private: return AS_private; @@ -850,6 +939,40 @@ AccessSpecifier Parser::getAccessSpecifierIfPresent() const } } +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[ParamIdx].Param)); + } + + // Add this parameter to the list of parameters (it or may + // not have a default argument). + LateMethod->DefaultArgs.push_back( + LateParsedDefaultArgument(FTI.ArgInfo[ParamIdx].Param, + FTI.ArgInfo[ParamIdx].DefaultArgTokens)); + } + } +} + /// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration. /// /// member-declaration: @@ -876,17 +999,21 @@ AccessSpecifier Parser::getAccessSpecifierIfPresent() const /// constant-initializer: /// '=' constant-expression /// -void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) { +void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, + const ParsedTemplateInfo &TemplateInfo) { // 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, + ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd, AS); return; } @@ -896,10 +1023,12 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) { // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. ConsumeToken(); - return ParseCXXClassMemberDeclaration(AS); + return ParseCXXClassMemberDeclaration(AS, TemplateInfo); } if (Tok.is(tok::kw_using)) { + // FIXME: Check for template aliases + // Eat 'using'. SourceLocation UsingLoc = ConsumeToken(); @@ -910,7 +1039,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) { else { SourceLocation DeclEnd; // Otherwise, it must be using-declaration. - ParseUsingDeclaration(Declarator::MemberContext, UsingLoc, DeclEnd); + ParseUsingDeclaration(Declarator::MemberContext, UsingLoc, DeclEnd, AS); } return; } @@ -919,24 +1048,16 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) { // decl-specifier-seq: // Parse the common declaration-specifiers piece. DeclSpec DS; - ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS); + 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(); - // C++ 9.2p7: The member-declarator-list can be omitted only after a - // class-specifier or an enum-specifier or in a friend declaration. - // FIXME: Friend declarations. - switch (DS.getTypeSpecType()) { - case DeclSpec::TST_struct: - case DeclSpec::TST_union: - case DeclSpec::TST_class: - case DeclSpec::TST_enum: - Actions.ParsedFreeStandingDeclSpec(CurScope, DS); - return; - default: - Diag(DSStart, diag::err_no_declarators); - return; - } + Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + return; } Declarator DeclaratorInfo(DS, Declarator::MemberContext); @@ -974,7 +1095,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) { return; } - ParseCXXInlineMethodDef(AS, DeclaratorInfo); + ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo); return; } } @@ -1001,7 +1122,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) { if (BitfieldSize.isInvalid()) SkipUntil(tok::comma, true, true); } - + // pure-specifier: // '= 0' // @@ -1034,62 +1155,44 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) { // NOTE: If Sema is the Action module and declarator is an instance field, // this call will *not* return the created decl; It will return null. // See Sema::ActOnCXXMemberDeclarator for details. - DeclPtrTy ThisDecl = Actions.ActOnCXXMemberDeclarator(CurScope, AS, - DeclaratorInfo, - BitfieldSize.release(), - Init.release(), - Deleted); + + 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(), + Deleted); + } if (ThisDecl) DeclsInGroup.push_back(ThisDecl); if (DeclaratorInfo.isFunctionDeclarator() && - DeclaratorInfo.getDeclSpec().getStorageClassSpec() + DeclaratorInfo.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef) { - // We just declared a member function. If this member function - // has any default arguments, we'll need to parse them later. - LateParsedMethodDeclaration *LateMethod = 0; - DeclaratorChunk::FunctionTypeInfo &FTI - = DeclaratorInfo.getTypeObject(0).Fun; - for (unsigned ParamIdx = 0; ParamIdx < FTI.NumArgs; ++ParamIdx) { - if (LateMethod || FTI.ArgInfo[ParamIdx].DefaultArgTokens) { - if (!LateMethod) { - // Push this method onto the stack of late-parsed method - // declarations. - getCurrentClass().MethodDecls.push_back( - LateParsedMethodDeclaration(ThisDecl)); - LateMethod = &getCurrentClass().MethodDecls.back(); - - // Add all of the parameters prior to this one (they don't - // have default arguments). - LateMethod->DefaultArgs.reserve(FTI.NumArgs); - for (unsigned I = 0; I < ParamIdx; ++I) - LateMethod->DefaultArgs.push_back( - LateParsedDefaultArgument(FTI.ArgInfo[ParamIdx].Param)); - } - - // Add this parameter to the list of parameters (it or may - // not have a default argument). - LateMethod->DefaultArgs.push_back( - LateParsedDefaultArgument(FTI.ArgInfo[ParamIdx].Param, - FTI.ArgInfo[ParamIdx].DefaultArgTokens)); - } - } + HandleMemberFunctionDefaultArgs(DeclaratorInfo, 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; @@ -1131,11 +1234,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, PrettyStackTraceActionsDecl CrashInfo(TagDecl, RecordLoc, Actions, PP.getSourceManager(), "parsing struct/union/class body"); - + SourceLocation LBraceLoc = ConsumeBrace(); // Determine whether this is a top-level (non-nested) class. - bool TopLevelClass = ClassStack.empty() || + bool TopLevelClass = ClassStack.empty() || CurScope->isInCXXInlineMethodScope(); // Enter a scope for the class. @@ -1163,7 +1266,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // 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); @@ -1180,12 +1283,14 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, 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); - + AttributeList *AttrList = 0; // If attributes exist after class contents, parse them. if (Tok.is(tok::kw___attribute)) @@ -1213,7 +1318,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, ParsingDef.Pop(); ClassScope.Exit(); - Actions.ActOnTagFinishDefinition(CurScope, TagDecl); + Actions.ActOnTagFinishDefinition(CurScope, TagDecl, RBraceLoc); } /// ParseConstructorInitializer - Parse a C++ constructor initializer, @@ -1231,19 +1336,19 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, /// }; /// @endcode /// -/// [C++] ctor-initializer: -/// ':' mem-initializer-list +/// [C++] ctor-initializer: +/// ':' mem-initializer-list /// -/// [C++] mem-initializer-list: -/// mem-initializer -/// mem-initializer , mem-initializer-list +/// [C++] mem-initializer-list: +/// mem-initializer +/// mem-initializer , mem-initializer-list void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) { assert(Tok.is(tok::colon) && "Constructor initializer always starts with ':'"); SourceLocation ColonLoc = ConsumeToken(); - + llvm::SmallVector<MemInitTy*, 4> MemInitializers; - + do { MemInitResult MemInit = ParseMemInitializer(ConstructorDecl); if (!MemInit.isInvalid()) @@ -1261,7 +1366,7 @@ void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) { } } while (true); - Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc, + Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc, MemInitializers.data(), MemInitializers.size()); } @@ -1272,14 +1377,14 @@ void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) { /// /// [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); + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); TypeTy *TemplateTypeTy = 0; if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId @@ -1295,7 +1400,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(DeclPtrTy ConstructorDecl) { 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; @@ -1331,7 +1436,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(DeclPtrTy ConstructorDecl) { /// exception-specification: /// 'throw' '(' type-id-list [opt] ')' /// [MS] 'throw' '(' '...' ')' -/// +/// /// type-id-list: /// type-id /// type-id-list ',' type-id @@ -1343,9 +1448,9 @@ bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc, &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"; } @@ -1384,7 +1489,7 @@ bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc, /// so push that class onto our stack of classes that is currently /// being parsed. void Parser::PushParsingClass(DeclPtrTy ClassDecl, bool TopLevelClass) { - assert((TopLevelClass || !ClassStack.empty()) && + assert((TopLevelClass || !ClassStack.empty()) && "Nested class without outer class"); ClassStack.push(new ParsingClass(ClassDecl, TopLevelClass)); } @@ -1408,7 +1513,7 @@ void Parser::DeallocateParsedClasses(Parser::ParsingClass *Class) { /// false otherwise. void Parser::PopParsingClass() { assert(!ClassStack.empty() && "Mismatched push/pop for class parsing"); - + ParsingClass *Victim = ClassStack.top(); ClassStack.pop(); if (Victim->TopLevelClass) { @@ -1416,7 +1521,7 @@ void Parser::PopParsingClass() { // 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() && diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index cd7618f66536..72e30e3b6079 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -55,7 +55,7 @@ namespace prec { /// getBinOpPrecedence - Return the precedence of the specified binary operator /// token. This returns: /// -static prec::Level getBinOpPrecedence(tok::TokenKind Kind, +static prec::Level getBinOpPrecedence(tok::TokenKind Kind, bool GreaterThanIsOperator, bool CPlusPlus0x) { switch (Kind) { @@ -67,7 +67,7 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind, if (GreaterThanIsOperator) return prec::Relational; return prec::Unknown; - + case tok::greatergreater: // C++0x [temp.names]p3: // @@ -200,13 +200,18 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind, /// expression ',' assignment-expression /// Parser::OwningExprResult Parser::ParseExpression() { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(CurScope); + ConsumeToken(); + } + 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. +/// 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. @@ -277,11 +282,11 @@ Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc, Parser::OwningExprResult Parser::ParseConstantExpression() { // C++ [basic.def.odr]p2: - // An expression is potentially evaluated unless it appears where an + // 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); @@ -292,7 +297,7 @@ Parser::OwningExprResult Parser::ParseConstantExpression() { /// LHS and has a precedence of at least MinPrec. Parser::OwningExprResult Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { - unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind(), + unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, getLang().CPlusPlus0x); SourceLocation ColonLoc; @@ -407,11 +412,13 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { /// due to member pointers. /// Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, - bool isAddressOfOperand) { + bool isAddressOfOperand, + bool parseParenAsExprList){ bool NotCastExpr; OwningExprResult Res = ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr); + NotCastExpr, + parseParenAsExprList); if (NotCastExpr) Diag(Tok, diag::err_expected_expression); return move(Res); @@ -463,10 +470,10 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// assign-expr ')' /// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' /// [GNU] '__null' -/// [OBJC] '[' objc-message-expr ']' +/// [OBJC] '[' objc-message-expr ']' /// [OBJC] '@selector' '(' objc-selector-arg ')' -/// [OBJC] '@protocol' '(' identifier ')' -/// [OBJC] '@encode' '(' type-name ')' +/// [OBJC] '@protocol' '(' identifier ')' +/// [OBJC] '@encode' '(' type-name ')' /// [OBJC] objc-string-literal /// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3] /// [C++] typename-specifier '(' expression-list[opt] ')' [TODO] @@ -530,11 +537,12 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, - bool &NotCastExpr) { + bool &NotCastExpr, + bool parseParenAsExprList){ 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 @@ -555,9 +563,9 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, SourceLocation LParenLoc = Tok.getLocation(); SourceLocation RParenLoc; Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/, - CastTy, RParenLoc); + parseParenAsExprList, CastTy, RParenLoc); if (Res.isInvalid()) return move(Res); - + switch (ParenExprType) { case SimpleExpr: break; // Nothing else to do. case CompoundStmt: break; // Nothing else to do. @@ -605,23 +613,23 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, } // Support 'Class.property' notation. - // We don't use isTokObjCMessageIdentifierReceiver(), since it allows + // We don't use isTokObjCMessageIdentifierReceiver(), since it allows // 'super' (which is inappropriate here). - if (getLang().ObjC1 && - Actions.getTypeName(*Tok.getIdentifierInfo(), + if (getLang().ObjC1 && + Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(), CurScope) && NextToken().is(tok::period)) { IdentifierInfo &ReceiverName = *Tok.getIdentifierInfo(); SourceLocation IdentLoc = ConsumeToken(); SourceLocation DotLoc = ConsumeToken(); - + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); return ExprError(); } IdentifierInfo &PropertyName = *Tok.getIdentifierInfo(); SourceLocation PropertyLoc = ConsumeToken(); - + Res = Actions.ActOnClassPropertyRefExpr(ReceiverName, PropertyName, IdentLoc, PropertyLoc); // These can be followed by postfix-expr pieces. @@ -739,6 +747,8 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, 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: @@ -794,7 +804,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, 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(); @@ -810,9 +820,12 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, 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___has_trivial_constructor: + case tok::kw___has_trivial_copy: + case tok::kw___has_trivial_assign: case tok::kw___has_trivial_destructor: return ParseUnaryTypeTrait(); @@ -826,7 +839,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, // These can be followed by postfix-expr pieces. if (getLang().ObjC1) return ParsePostfixExpressionSuffix(ParseObjCMessageExpression()); - // FALL THROUGH. + // FALL THROUGH. default: NotCastExpr = true; return ExprError(); @@ -886,8 +899,14 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { Loc = ConsumeParen(); + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteCall(CurScope, LHS.get(), 0, 0); + ConsumeToken(); + } + if (Tok.isNot(tok::r_paren)) { - if (ParseExpressionList(ArgExprs, CommaLocs)) { + if (ParseExpressionList(ArgExprs, CommaLocs, &Action::CodeCompleteCall, + LHS.get())) { SkipUntil(tok::r_paren); return ExprError(); } @@ -898,7 +917,7 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { MatchRHSPunctuation(tok::r_paren, Loc); return ExprError(); } - + if (!LHS.isInvalid()) { assert((ArgExprs.size() == 0 || ArgExprs.size()-1 == CommaLocs.size())&& "Unexpected number of commas!"); @@ -906,33 +925,117 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { move_arg(ArgExprs), CommaLocs.data(), Tok.getLocation()); } - + ConsumeParen(); break; } - case tok::arrow: // postfix-expression: p-e '->' identifier - case tok::period: { // postfix-expression: p-e '.' identifier + 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. - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); - return ExprError(); + CXXScopeSpec SS; + Action::TypeTy *ObjectType = 0; + if (getLang().CPlusPlus && !LHS.isInvalid()) { + LHS = Actions.ActOnStartCXXMemberReference(CurScope, move(LHS), + OpLoc, OpKind, ObjectType); + if (LHS.isInvalid()) + break; + ParseOptionalCXXScopeSpecifier(SS, ObjectType, false); } - if (!LHS.isInvalid()) { - LHS = Actions.ActOnMemberReferenceExpr(CurScope, move(LHS), OpLoc, - OpKind, Tok.getLocation(), - *Tok.getIdentifierInfo(), - ObjCImpDecl); + if (Tok.is(tok::code_completion)) { + // Code completion for a member access expression. + Actions.CodeCompleteMemberReferenceExpr(CurScope, LHS.get(), + OpLoc, OpKind == tok::arrow); + + ConsumeToken(); + } + + if (Tok.is(tok::identifier)) { + if (!LHS.isInvalid()) + LHS = Actions.ActOnMemberReferenceExpr(CurScope, move(LHS), OpLoc, + OpKind, Tok.getLocation(), + *Tok.getIdentifierInfo(), + ObjCImpDecl, &SS); + ConsumeToken(); + } else if (getLang().CPlusPlus && Tok.is(tok::tilde)) { + // We have a C++ pseudo-destructor or a destructor call, e.g., t.~T() + + // Consume the tilde. + ConsumeToken(); + + if (!Tok.is(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + return ExprError(); + } + + if (!LHS.isInvalid()) + LHS = Actions.ActOnDestructorReferenceExpr(CurScope, move(LHS), + OpLoc, OpKind, + Tok.getLocation(), + Tok.getIdentifierInfo(), + SS, + NextToken().is(tok::l_paren)); + ConsumeToken(); + } else if (getLang().CPlusPlus && Tok.is(tok::kw_operator)) { + // We have a reference to a member operator, e.g., t.operator int or + // t.operator+. + SourceLocation OperatorLoc = Tok.getLocation(); + + if (OverloadedOperatorKind Op = TryParseOperatorFunctionId()) { + if (!LHS.isInvalid()) + LHS = Actions.ActOnOverloadedOperatorReferenceExpr(CurScope, + move(LHS), OpLoc, + OpKind, + OperatorLoc, + Op, &SS); + // TryParseOperatorFunctionId already consumed our token, so + // don't bother + } else if (TypeTy *ConvType = ParseConversionFunctionId()) { + if (!LHS.isInvalid()) + LHS = Actions.ActOnConversionOperatorReferenceExpr(CurScope, + move(LHS), OpLoc, + OpKind, + OperatorLoc, + ConvType, &SS); + } else { + // Don't emit a diagnostic; ParseConversionFunctionId does it for us + return ExprError(); + } + } else if (getLang().CPlusPlus && Tok.is(tok::annot_template_id)) { + // We have a reference to a member template along with explicitly- + // specified template arguments, e.g., t.f<int>. + TemplateIdAnnotation *TemplateId + = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + if (!LHS.isInvalid()) { + ASTTemplateArgsPtr TemplateArgsPtr(Actions, + TemplateId->getTemplateArgs(), + TemplateId->getTemplateArgIsType(), + TemplateId->NumArgs); + + LHS = Actions.ActOnMemberTemplateIdReferenceExpr(CurScope, move(LHS), + OpLoc, OpKind, SS, + TemplateTy::make(TemplateId->Template), + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->getTemplateArgLocations(), + TemplateId->RAngleLoc); + } + ConsumeToken(); + } else { + Diag(Tok, diag::err_expected_ident); + return ExprError(); } - ConsumeToken(); break; } case tok::plusplus: // postfix-expression: postfix-expression '++' case tok::minusminus: // postfix-expression: postfix-expression '--' if (!LHS.isInvalid()) { - LHS = Actions.ActOnPostfixUnaryOp(CurScope, Tok.getLocation(), + LHS = Actions.ActOnPostfixUnaryOp(CurScope, Tok.getLocation(), Tok.getKind(), move(LHS)); } ConsumeToken(); @@ -963,13 +1066,13 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, bool &isCastExpr, TypeTy *&CastTy, SourceRange &CastRange) { - - assert((OpTok.is(tok::kw_typeof) || OpTok.is(tok::kw_sizeof) || + + 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; @@ -977,9 +1080,9 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, 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 + // [...] The operand is either an expression, which is an unevaluated // operand (Clause 5) [...] // // The GNU typeof and alignof extensions also behave as unevaluated @@ -994,16 +1097,16 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, // expression. ParenParseOption ExprType = CastExpr; SourceLocation LParenLoc = Tok.getLocation(), RParenLoc; - + // C++0x [expr.sizeof]p1: - // [...] The operand is either an expression, which is an unevaluated + // [...] 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*/, + Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/, false, CastTy, RParenLoc); CastRange = SourceRange(LParenLoc, RParenLoc); @@ -1014,7 +1117,7 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, return ExprEmpty(); } - // If this is a parenthesized expression, it is the start of a + // 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)); @@ -1039,7 +1142,7 @@ Parser::OwningExprResult Parser::ParseSizeofAlignofExpression() { "Not a sizeof/alignof expression!"); Token OpTok = Tok; ConsumeToken(); - + bool isCastExpr; TypeTy *CastTy; SourceRange CastRange; @@ -1071,7 +1174,7 @@ Parser::OwningExprResult Parser::ParseSizeofAlignofExpression() { /// [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 @@ -1123,7 +1226,7 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() { SkipUntil(tok::r_paren); return ExprError(); } - + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) return ExprError(); @@ -1179,8 +1282,8 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() { } else if (Ty.isInvalid()) { Res = ExprError(); } else { - Res = Actions.ActOnBuiltinOffsetOf(CurScope, StartLoc, TypeLoc, - Ty.get(), &Comps[0], + Res = Actions.ActOnBuiltinOffsetOf(CurScope, StartLoc, TypeLoc, + Ty.get(), &Comps[0], Comps.size(), ConsumeParen()); } break; @@ -1260,7 +1363,8 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() { /// Parser::OwningExprResult Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, - TypeTy *&CastTy, SourceLocation &RParenLoc) { + bool parseAsExprList, TypeTy *&CastTy, + SourceLocation &RParenLoc) { assert(Tok.is(tok::l_paren) && "Not a paren expr!"); GreaterThanIsOperatorScope G(GreaterThanIsOperator, true); SourceLocation OpenLoc = ConsumeParen(); @@ -1279,9 +1383,9 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, } 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. @@ -1290,7 +1394,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, if (isAmbiguousTypeId && !stopIfCastExpr) return ParseCXXAmbiguousParenExpression(ExprType, CastTy, OpenLoc, RParenLoc); - + TypeResult Ty = ParseTypeName(); // Match the ')'. @@ -1320,14 +1424,25 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, // Parse the cast-expression that follows it next. // TODO: For cast expression with CastTy. - Result = ParseCastExpression(false); + Result = ParseCastExpression(false, false, true); if (!Result.isInvalid()) - Result = Actions.ActOnCastExpr(OpenLoc, CastTy, RParenLoc,move(Result)); + 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 (parseAsExprList) { + // Parse the expression-list. + ExprVector ArgExprs(Actions); + CommaLocsTy CommaLocs; + + if (!ParseExpressionList(ArgExprs, CommaLocs)) { + ExprType = SimpleExpr; + Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(), + move_arg(ArgExprs)); + } } else { Result = ParseExpression(); ExprType = SimpleExpr; @@ -1340,7 +1455,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, SkipUntil(tok::r_paren); return ExprError(); } - + if (Tok.is(tok::r_paren)) RParenLoc = ConsumeParen(); else @@ -1401,8 +1516,19 @@ Parser::OwningExprResult Parser::ParseStringLiteralExpression() { /// [C++] assignment-expression /// [C++] expression-list , assignment-expression /// -bool Parser::ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs) { +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()); + ConsumeToken(); + } + OwningExprResult Expr(ParseAssignmentExpression()); if (Expr.isInvalid()) return true; @@ -1460,7 +1586,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() { PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), CaretLoc, "block literal parsing"); - // Enter a scope to hold everything within the block. This includes the + // 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. @@ -1470,7 +1596,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() { // 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); @@ -1508,12 +1634,13 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() { ParseBlockId(); } else { // Otherwise, pretend we saw (void). - ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, + ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, SourceLocation(), 0, 0, 0, false, SourceLocation(), false, 0, 0, 0, - CaretLoc, ParamInfo), + CaretLoc, CaretLoc, + ParamInfo), CaretLoc); if (Tok.is(tok::kw___attribute)) { @@ -1534,7 +1661,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() { Actions.ActOnBlockError(CaretLoc, CurScope); return ExprError(); } - + OwningStmtResult Stmt(ParseCompoundStatementBody()); if (!Stmt.isInvalid()) Result = Actions.ActOnBlockStmtExpr(CaretLoc, move(Stmt), CurScope); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 1220b2d27b4f..325f085a49d8 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -16,10 +16,11 @@ #include "clang/Parse/DeclSpec.h" using namespace clang; -/// ParseOptionalCXXScopeSpecifier - Parse global scope or -/// nested-name-specifier if present. Returns true if a nested-name-specifier -/// was parsed from the token stream. Note that this routine will not parse -/// ::new or ::delete, it will just leave them in the token stream. +/// \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 /// '::' @@ -28,9 +29,23 @@ using namespace clang; /// type-name '::' /// namespace-name '::' /// nested-name-specifier identifier '::' -/// nested-name-specifier 'template'[opt] simple-template-id '::' [TODO] +/// 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. /// -bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { +/// \param EnteringContext whether we will be entering into the context of +/// the nested-name-specifier after parsing it. +/// +/// \returns true if a scope specifier was parsed. +bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, + Action::TypeTy *ObjectType, + bool EnteringContext) { assert(getLang().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); @@ -48,7 +63,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { 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); @@ -58,21 +73,48 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { } 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); + ConsumeToken(); + } + } + // 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; + SourceLocation TemplateKWLoc = ConsumeToken(); - + if (Tok.isNot(tok::identifier)) { - Diag(Tok.getLocation(), + Diag(Tok.getLocation(), diag::err_id_after_template_in_nested_name_spec) << SourceRange(TemplateKWLoc); break; } - + if (NextToken().isNot(tok::less)) { Diag(NextToken().getLocation(), diag::err_less_after_template_name_in_nested_name_spec) @@ -80,49 +122,51 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { << SourceRange(TemplateKWLoc, Tok.getLocation()); break; } - - TemplateTy Template + + TemplateTy Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, *Tok.getIdentifierInfo(), - Tok.getLocation(), SS); + Tok.getLocation(), SS, + ObjectType); + if (!Template) + break; if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name, &SS, TemplateKWLoc, false)) break; - + continue; } - + if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) { - // We have + // 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 + TemplateIdAnnotation *TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); - if (TemplateId->Kind == TNK_Type_template || + if (TemplateId->Kind == TNK_Type_template || TemplateId->Kind == TNK_Dependent_template_name) { AnnotateTemplateIdTokenAsType(&SS); - SS.setScopeRep(0); - assert(Tok.is(tok::annot_typename) && + 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, + Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, TypeToken.getAnnotationValue(), TypeToken.getAnnotationRange(), CCLoc)); @@ -131,7 +175,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { SS.setEndLoc(CCLoc); continue; } - + assert(false && "FIXME: Only type template names supported here"); } @@ -154,27 +198,32 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { SourceLocation IdLoc = ConsumeToken(); assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); SourceLocation CCLoc = ConsumeToken(); - + if (!HasScopeSpecifier) { SS.setBeginLoc(IdLoc); HasScopeSpecifier = true; } - + if (SS.isInvalid()) continue; - + SS.setScopeRep( - Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, II)); + 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; - if (TemplateNameKind TNK = Actions.isTemplateName(II, CurScope, - Template, &SS)) { + if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, II, + Tok.getLocation(), + &SS, + ObjectType, + EnteringContext, + Template)) { // 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, @@ -192,7 +241,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { // nested-name-specifier, so we're done. break; } - + return HasScopeSpecifier; } @@ -257,7 +306,7 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { // '::' unqualified-id // CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS); + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); // unqualified-id: // identifier @@ -295,17 +344,17 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { } case tok::annot_template_id: { - TemplateIdAnnotation *TemplateId + TemplateIdAnnotation *TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); assert((TemplateId->Kind == TNK_Function_template || TemplateId->Kind == TNK_Dependent_template_name) && "A template type name is not an ID expression"); - ASTTemplateArgsPtr TemplateArgsPtr(Actions, + ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateId->getTemplateArgs(), TemplateId->getTemplateArgIsType(), TemplateId->NumArgs); - + OwningExprResult Result = Actions.ActOnTemplateIdExpr(TemplateTy::make(TemplateId->Template), TemplateId->TemplateNameLoc, @@ -361,11 +410,11 @@ Parser::OwningExprResult Parser::ParseCXXCasts() { return ExprError(); OwningExprResult Result = ParseExpression(); - + // Match the ')'. if (Result.isInvalid()) SkipUntil(tok::r_paren); - + if (Tok.is(tok::r_paren)) RParenLoc = ConsumeParen(); else @@ -413,11 +462,11 @@ Parser::OwningExprResult Parser::ParseCXXTypeid() { 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 + // 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 + // 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, @@ -516,6 +565,10 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { // 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, @@ -606,58 +659,65 @@ Parser::OwningExprResult Parser::ParseCXXCondition() { 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: + default: assert(0 && "Not a simple-type-specifier token!"); abort(); // type-name case tok::annot_typename: { - DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, + DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, Tok.getAnnotationValue()); break; } - + // builtin types case tok::kw_short: - DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec); + DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, DiagID); break; case tok::kw_long: - DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec); + DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec, DiagID); break; case tok::kw_signed: - DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec); + DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID); break; case tok::kw_unsigned: - DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec); + DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec, DiagID); break; case tok::kw_void: - DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec); + DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID); break; case tok::kw_char: - DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec); + DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID); break; case tok::kw_int: - DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec); + DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID); break; case tok::kw_float: - DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec); + DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID); break; case tok::kw_double: - DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec); + DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID); break; case tok::kw_wchar_t: - DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec); + 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); + DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID); break; - + // GNU typeof support. case tok::kw_typeof: ParseTypeofSpecifier(DS); @@ -686,15 +746,16 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) { DS.SetRangeStart(Tok.getLocation()); const char *PrevSpec = 0; - int isInvalid = 0; + unsigned DiagID; + bool isInvalid = 0; // Parse one or more of the type specifiers. - if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec)) { + if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID)) { Diag(Tok, diag::err_operator_missing_type_specifier); return true; } - - while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec)) ; + + while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID)) ; return false; } @@ -774,6 +835,18 @@ Parser::TryParseOperatorFunctionId(SourceLocation *EndLoc) { *EndLoc = Loc; return OO_Subscript; + case tok::code_completion: { + // Code completion for the operator name. + Actions.CodeCompleteOperatorName(CurScope); + + // Consume the 'operator' token, then replace the code-completion token + // with an 'operator' token and try again. + SourceLocation OperatorLoc = ConsumeToken(); + Tok.setLocation(OperatorLoc); + Tok.setKind(tok::kw_operator); + return TryParseOperatorFunctionId(EndLoc); + } + default: return OO_None; } @@ -824,7 +897,7 @@ Parser::TypeTy *Parser::ParseConversionFunctionId(SourceLocation *EndLoc) { /// 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. @@ -966,7 +1039,7 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) { SourceLocation RLoc = MatchRHSPunctuation(tok::r_square, LLoc); D.AddTypeInfo(DeclaratorChunk::getArray(0, /*static=*/false, /*star=*/false, - Size.release(), LLoc), + Size.release(), LLoc, RLoc), RLoc); if (RLoc.isInvalid()) @@ -1033,8 +1106,7 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) { return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, move(Operand)); } -static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) -{ +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; @@ -1062,8 +1134,7 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) /// primary-expression: /// [GNU] unary-type-trait '(' type-id ')' /// -Parser::OwningExprResult Parser::ParseUnaryTypeTrait() -{ +Parser::OwningExprResult Parser::ParseUnaryTypeTrait() { UnaryTypeTrait UTT = UnaryTypeTraitFromTokKind(Tok.getKind()); SourceLocation Loc = ConsumeToken(); @@ -1118,7 +1189,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, // parsing a cast-expression), and then we re-introduce the cached tokens // into the token stream and parse them appropriately. - ParenParseOption ParseAs; + ParenParseOption ParseAs; CachedTokens Toks; // Store the tokens of the parentheses. We will parse them after we determine @@ -1142,7 +1213,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, // will be consumed. Result = ParseCastExpression(false/*isUnaryExpression*/, false/*isAddressofOperand*/, - NotCastExpr); + NotCastExpr, false); } // If we parsed a cast-expression, it's really a type-id, otherwise it's @@ -1150,7 +1221,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, ParseAs = NotCastExpr ? SimpleExpr : CastExpr; } - // The current token should go after the cached tokens. + // 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. @@ -1173,7 +1244,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, ExprType = CompoundLiteral; return ParseCompoundLiteralExpression(Ty.get(), LParenLoc, RParenLoc); } - + // We parsed '(' type-id ')' and the thing after it wasn't a '{'. assert(ParseAs == CastExpr); @@ -1184,10 +1255,11 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, // Result is what ParseCastExpression returned earlier. if (!Result.isInvalid()) - Result = Actions.ActOnCastExpr(LParenLoc, CastTy, RParenLoc,move(Result)); + 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); @@ -1201,7 +1273,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, SkipUntil(tok::r_paren); return ExprError(); } - + if (Tok.is(tok::r_paren)) RParenLoc = ConsumeParen(); else diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index bbc2124e5986..6ab23fd42ddc 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -20,7 +20,7 @@ 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. +/// false. static bool MayBeDesignationStart(tok::TokenKind K, Preprocessor &PP) { switch (K) { default: return false; @@ -70,46 +70,46 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { NewSyntax += " = "; SourceLocation NameLoc = ConsumeToken(); // Eat the identifier. - + assert(Tok.is(tok::colon) && "MayBeDesignationStart not working properly!"); SourceLocation ColonLoc = ConsumeToken(); Diag(Tok, diag::ext_gnu_old_style_field_designator) - << CodeModificationHint::CreateReplacement(SourceRange(NameLoc, + << CodeModificationHint::CreateReplacement(SourceRange(NameLoc, ColonLoc), NewSyntax); Designation D; D.AddDesignator(Designator::getField(FieldName, SourceLocation(), NameLoc)); - return Actions.ActOnDesignatedInitializer(D, ColonLoc, true, + 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 ']' @@ -123,14 +123,14 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { // [4][foo bar] -> obsolete GNU designation with objc message send. // SourceLocation StartLoc = ConsumeBracket(); - + // If Objective-C is enabled and this is a typename or other identifier // receiver, parse this as a message send expression. if (getLang().ObjC1 && isTokObjCMessageIdentifierReceiver()) { // If we have exactly one array designator, this used the GNU // 'designation: array-designator' extension, otherwise there should be no // designators at all! - if (Desig.getNumDesignators() == 1 && + if (Desig.getNumDesignators() == 1 && (Desig.getDesignator(0).isArrayDesignator() || Desig.getDesignator(0).isArrayRangeDesignator())) Diag(StartLoc, diag::ext_gnu_missing_equal_designator); @@ -151,18 +151,18 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { 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 + // message send, handle it now. An objc-message send is the start of // an assignment-expression production. - if (getLang().ObjC1 && Tok.isNot(tok::ellipsis) && + if (getLang().ObjC1 && Tok.isNot(tok::ellipsis) && Tok.isNot(tok::r_square)) { - + // If we have exactly one array designator, this used the GNU // 'designation: array-designator' extension, otherwise there should be no // designators at all! - if (Desig.getNumDesignators() == 1 && + if (Desig.getNumDesignators() == 1 && (Desig.getDesignator(0).isArrayDesignator() || Desig.getDesignator(0).isArrayRangeDesignator())) Diag(StartLoc, diag::ext_gnu_missing_equal_designator); @@ -213,7 +213,7 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { // 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 && + if (Desig.getNumDesignators() == 1 && (Desig.getDesignator(0).isArrayDesignator() || Desig.getDesignator(0).isArrayRangeDesignator())) { Diag(Tok, diag::ext_gnu_missing_equal_designator) @@ -267,13 +267,13 @@ Parser::OwningExprResult Parser::ParseBraceInitializer() { 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 diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 013e26b891e1..1d29f319c584 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -29,7 +29,7 @@ using namespace clang; /// [OBJC] '@' 'end' Parser::DeclPtrTy Parser::ParseObjCAtDirectives() { SourceLocation AtLoc = ConsumeToken(); // the "@" - + switch (Tok.getObjCKeywordID()) { case tok::objc_class: return ParseObjCAtClassDeclaration(AtLoc); @@ -55,13 +55,13 @@ Parser::DeclPtrTy Parser::ParseObjCAtDirectives() { } /// -/// objc-class-declaration: +/// objc-class-declaration: /// '@' 'class' identifier-list ';' -/// +/// Parser::DeclPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { ConsumeToken(); // the identifier "class" llvm::SmallVector<IdentifierInfo *, 8> ClassNames; - + while (1) { if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); @@ -70,17 +70,17 @@ Parser::DeclPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { } ClassNames.push_back(Tok.getIdentifierInfo()); ConsumeToken(); - + if (Tok.isNot(tok::comma)) break; - + ConsumeToken(); } - + // Consume the ';'. if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class")) return DeclPtrTy(); - + return Actions.ActOnForwardClassDeclaration(atLoc, &ClassNames[0], ClassNames.size()); } @@ -91,14 +91,14 @@ Parser::DeclPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { /// objc-category-interface /// /// objc-class-interface: -/// '@' 'interface' identifier objc-superclass[opt] +/// '@' 'interface' identifier objc-superclass[opt] /// objc-protocol-refs[opt] -/// objc-class-instance-variables[opt] +/// objc-class-instance-variables[opt] /// objc-interface-decl-list /// @end /// /// objc-category-interface: -/// '@' 'interface' identifier '(' identifier[opt] ')' +/// '@' 'interface' identifier '(' identifier[opt] ')' /// objc-protocol-refs[opt] /// objc-interface-decl-list /// @end @@ -118,7 +118,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( assert(Tok.isObjCAtKeyword(tok::objc_interface) && "ParseObjCAtInterfaceDeclaration(): Expected @interface"); ConsumeToken(); // the "interface" identifier - + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing class or category name. return DeclPtrTy(); @@ -126,12 +126,12 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( // We have a class or category name - consume it. IdentifierInfo *nameId = Tok.getIdentifierInfo(); SourceLocation nameLoc = ConsumeToken(); - + if (Tok.is(tok::l_paren)) { // we have a category. SourceLocation lparenLoc = ConsumeParen(); SourceLocation categoryLoc, rparenLoc; IdentifierInfo *categoryId = 0; - + // For ObjC2, the category name is optional (not an error). if (Tok.is(tok::identifier)) { categoryId = Tok.getIdentifierInfo(); @@ -146,25 +146,27 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( return DeclPtrTy(); } rparenLoc = ConsumeParen(); - + // Next, we need to check for any protocol references. - SourceLocation EndProtoLoc; + SourceLocation LAngleLoc, EndProtoLoc; llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs; + llvm::SmallVector<SourceLocation, 8> ProtocolLocs; if (Tok.is(tok::less) && - ParseObjCProtocolReferences(ProtocolRefs, true, EndProtoLoc)) + 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, + Actions.ActOnStartCategoryInterface(atLoc, nameId, nameLoc, categoryId, categoryLoc, ProtocolRefs.data(), ProtocolRefs.size(), EndProtoLoc); - + ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword); return CategoryType; } @@ -183,17 +185,19 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( } // Next, we need to check for any protocol references. llvm::SmallVector<Action::DeclPtrTy, 8> ProtocolRefs; - SourceLocation EndProtoLoc; + llvm::SmallVector<SourceLocation, 8> ProtocolLocs; + SourceLocation LAngleLoc, EndProtoLoc; if (Tok.is(tok::less) && - ParseObjCProtocolReferences(ProtocolRefs, true, EndProtoLoc)) + ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, + LAngleLoc, EndProtoLoc)) return DeclPtrTy(); - - DeclPtrTy ClsType = - Actions.ActOnStartClassInterface(atLoc, nameId, nameLoc, + + DeclPtrTy ClsType = + Actions.ActOnStartClassInterface(atLoc, nameId, nameLoc, superClassId, superClassLoc, ProtocolRefs.data(), ProtocolRefs.size(), EndProtoLoc, attrList); - + if (Tok.is(tok::l_brace)) ParseObjCClassInstanceVariables(ClsType, atLoc); @@ -219,13 +223,13 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, llvm::SmallVector<DeclPtrTy, 16> allProperties; llvm::SmallVector<DeclGroupPtrTy, 8> allTUVariables; tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword; - + SourceLocation AtEndLoc; while (1) { // If this is a method prototype, parse it. if (Tok.is(tok::minus) || Tok.is(tok::plus)) { - DeclPtrTy methodPrototype = + DeclPtrTy methodPrototype = ParseObjCMethodPrototype(interfaceDecl, MethodImplKind); allMethods.push_back(methodPrototype); // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for @@ -234,17 +238,17 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, "", tok::semi); continue; } - + // Ignore excess semicolons. if (Tok.is(tok::semi)) { ConsumeToken(); continue; } - + // If we got to the end of the file, exit the loop. if (Tok.is(tok::eof)) break; - + // If we don't have an @ directive, parse it as a function definition. if (Tok.isNot(tok::at)) { // The code below does not consume '}'s because it is afraid of eating the @@ -252,22 +256,22 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, // erroneous r_brace would cause an infinite loop if not handled here. if (Tok.is(tok::r_brace)) break; - + // FIXME: as the name implies, this rule allows function definitions. // We could pass a flag or check for functions during semantic analysis. allTUVariables.push_back(ParseDeclarationOrFunctionDefinition()); continue; } - + // Otherwise, we have an @ directive, eat the @. SourceLocation AtLoc = ConsumeToken(); // the "@" tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID(); - + if (DirectiveKind == tok::objc_end) { // @end -> terminate list AtEndLoc = AtLoc; break; } - + // Eat the identifier. ConsumeToken(); @@ -281,7 +285,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, // 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. @@ -291,24 +295,24 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, 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. + // Parse property attribute list, if any. if (Tok.is(tok::l_paren)) ParseObjCPropertyAttribute(OCDS); - + // Parse all the comma separated declarators. DeclSpec DS; llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators; ParseStructDeclaration(DS, FieldDeclarators); - + ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list, "", tok::at); - + // Convert them all to property declarations. for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) { FieldDeclarator &FD = FieldDeclarators[i]; @@ -322,12 +326,12 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, << FD.D.getSourceRange(); continue; } - + // Install the property declarator into interfaceDecl. IdentifierInfo *SelName = OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier(); - - Selector GetterSel = + + Selector GetterSel = PP.getSelectorTable().getNullarySelector(SelName); IdentifierInfo *SetterName = OCDS.getSetterName(); Selector SetterSel; @@ -340,7 +344,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, bool isOverridingProperty = false; DeclPtrTy Property = Actions.ActOnProperty(CurScope, AtLoc, FD, OCDS, GetterSel, SetterSel, - interfaceDecl, + interfaceDecl, &isOverridingProperty, MethodImplKind); if (!isOverridingProperty) @@ -356,11 +360,11 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, ConsumeToken(); // the "end" identifier else Diag(Tok, diag::err_objc_missing_end); - + // Insert collected methods declarations into the @interface object. // This passes in an invalid SourceLocation for AtEndLoc when EOF is hit. Actions.ActOnAtEnd(AtEndLoc, interfaceDecl, - allMethods.data(), allMethods.size(), + allMethods.data(), allMethods.size(), allProperties.data(), allProperties.size(), allTUVariables.data(), allTUVariables.size()); } @@ -384,18 +388,22 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { assert(Tok.getKind() == tok::l_paren); SourceLocation LHSLoc = ConsumeParen(); // consume '(' - + while (1) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCProperty(CurScope, DS); + ConsumeToken(); + } 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")) @@ -413,18 +421,18 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { if (ExpectAndConsume(tok::equal, diag::err_objc_expected_equal, "", tok::r_paren)) return; - + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); SkipUntil(tok::r_paren); return; } - + if (II->getName()[0] == 's') { DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter); DS.setSetterName(Tok.getIdentifierInfo()); ConsumeToken(); // consume method name - + if (ExpectAndConsume(tok::colon, diag::err_expected_colon, "", tok::r_paren)) return; @@ -438,18 +446,18 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { 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-instance-method objc-method-decl objc-method-attributes[opt] /// objc-class-method objc-method-decl objc-method-attributes[opt] /// /// objc-instance-method: '-' @@ -458,13 +466,13 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { /// objc-method-attributes: [OBJC2] /// __attribute__((deprecated)) /// -Parser::DeclPtrTy Parser::ParseObjCMethodPrototype(DeclPtrTy IDecl, +Parser::DeclPtrTy Parser::ParseObjCMethodPrototype(DeclPtrTy IDecl, tok::ObjCKeywordKind MethodImplKind) { assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-"); - tok::TokenKind methodType = Tok.getKind(); + 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 ';'. @@ -564,7 +572,7 @@ 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) && + return (getLang().ObjC2 && Tok.is(tok::identifier) && Tok.getIdentifierInfo() == ObjCTypeQuals[objc_in]); } @@ -580,12 +588,12 @@ 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"); @@ -601,7 +609,7 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS) { II = 0; break; } - + // If this wasn't a recognized qualifier, bail out. if (II) return; } @@ -613,10 +621,10 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS) { /// 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); @@ -626,7 +634,7 @@ Parser::TypeTy *Parser::ParseObjCTypeName(ObjCDeclSpec &DS) { if (!TypeSpec.isInvalid()) Ty = TypeSpec.get(); } - + if (Tok.is(tok::r_paren)) ConsumeParen(); else if (Tok.getLocation() == TypeStartLoc) { @@ -648,7 +656,7 @@ Parser::TypeTy *Parser::ParseObjCTypeName(ObjCDeclSpec &DS) { /// objc-type-name objc-keyword-selector objc-parmlist[opt] /// /// objc-keyword-selector: -/// objc-keyword-decl +/// objc-keyword-decl /// objc-keyword-selector objc-keyword-decl /// /// objc-keyword-decl: @@ -678,7 +686,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, ObjCDeclSpec DSRet; if (Tok.is(tok::l_paren)) ReturnType = ParseObjCTypeName(DSRet); - + SourceLocation selLoc; IdentifierInfo *SelIdent = ParseObjCSelectorPiece(selLoc); @@ -690,14 +698,14 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, SkipUntil(tok::r_brace); return DeclPtrTy(); } - + llvm::SmallVector<Declarator, 8> CargNames; if (Tok.isNot(tok::colon)) { // If attributes exist after the method, parse them. AttributeList *MethodAttrs = 0; - if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) + if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) MethodAttrs = ParseAttributes(); - + Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), mType, IDecl, DSRet, ReturnType, Sel, @@ -707,17 +715,17 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, 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); @@ -731,11 +739,11 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, 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); @@ -746,9 +754,9 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, break; // We have a selector or a colon, continue parsing. } - + bool isVariadic = false; - + // Parse the (optional) parameter list. while (Tok.is(tok::comma)) { ConsumeToken(); @@ -759,18 +767,18 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, } DeclSpec DS; ParseDeclarationSpecifiers(DS); - // Parse the declarator. + // Parse the declarator. Declarator ParmDecl(DS, Declarator::PrototypeContext); ParseDeclarator(ParmDecl); CargNames.push_back(ParmDecl); } - + // FIXME: Add support for optional parmameter list... // If attributes exist after the method, parse them. AttributeList *MethodAttrs = 0; - if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) + if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) MethodAttrs = ParseAttributes(); - + if (KeyIdents.size() == 0) return DeclPtrTy(); Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(), @@ -786,13 +794,15 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, /// bool Parser:: ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &Protocols, - bool WarnOnDeclarations, SourceLocation &EndLoc) { + llvm::SmallVectorImpl<SourceLocation> &ProtocolLocs, + bool WarnOnDeclarations, + SourceLocation &LAngleLoc, SourceLocation &EndLoc) { assert(Tok.is(tok::less) && "expected <"); - - ConsumeToken(); // the "<" - + + LAngleLoc = ConsumeToken(); // the "<" + llvm::SmallVector<IdentifierLocPair, 8> ProtocolIdents; - + while (1) { if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); @@ -801,21 +811,22 @@ ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &Protocols, } 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(), @@ -841,7 +852,7 @@ ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &Protocols, /// @package [OBJC2] /// /// objc-instance-variable-decl: -/// struct-declaration +/// struct-declaration /// void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, SourceLocation atLoc) { @@ -852,19 +863,19 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, ParseScope ClassScope(this, Scope::DeclScope|Scope::ClassScope); SourceLocation LBraceLoc = ConsumeBrace(); // the "{" - + tok::ObjCKeywordKind visibility = tok::objc_protected; // While we still have something to read, read the instance variables. while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { // Each iteration of this loop reads one objc-instance-variable-decl. - + // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { Diag(Tok, diag::ext_extra_struct_semi); ConsumeToken(); continue; } - + // Set the default visibility to private. if (Tok.is(tok::at)) { // parse objc-visibility-spec ConsumeToken(); // eat the @ sign @@ -875,18 +886,18 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, case tok::objc_package: visibility = Tok.getObjCKeywordID(); ConsumeToken(); - continue; + continue; default: Diag(Tok, diag::err_objc_illegal_visibility_spec); continue; } } - + // Parse all the comma separated declarators. DeclSpec DS; FieldDeclarators.clear(); ParseStructDeclaration(DS, FieldDeclarators); - + // Convert them all to fields. for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) { FieldDeclarator &FD = FieldDeclarators[i]; @@ -897,7 +908,7 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, FD.D, FD.BitfieldSize, visibility); AllIvarDecls.push_back(Field); } - + if (Tok.is(tok::semi)) { ConsumeToken(); } else { @@ -920,9 +931,9 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, /// objc-protocol-forward-reference /// /// objc-protocol-definition: -/// @protocol identifier -/// objc-protocol-refs[opt] -/// objc-interface-decl-list +/// @protocol identifier +/// objc-protocol-refs[opt] +/// objc-interface-decl-list /// @end /// /// objc-protocol-forward-reference: @@ -936,7 +947,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, assert(Tok.isObjCAtKeyword(tok::objc_protocol) && "ParseObjCAtProtocolDeclaration(): Expected @protocol"); ConsumeToken(); // the "protocol" identifier - + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing protocol name. return DeclPtrTy(); @@ -944,14 +955,14 @@ Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, // 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, + 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)); @@ -967,28 +978,30 @@ Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, 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[0], ProtocolRefs.size(), attrList); } - + // Last, and definitely not least, parse a protocol declaration. - SourceLocation EndProtoLoc; + SourceLocation LAngleLoc, EndProtoLoc; llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs; + llvm::SmallVector<SourceLocation, 8> ProtocolLocs; if (Tok.is(tok::less) && - ParseObjCProtocolReferences(ProtocolRefs, false, EndProtoLoc)) + ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, + LAngleLoc, EndProtoLoc)) return DeclPtrTy(); - + DeclPtrTy ProtoType = Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc, ProtocolRefs.data(), @@ -1013,7 +1026,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( assert(Tok.isObjCAtKeyword(tok::objc_implementation) && "ParseObjCAtImplementationDeclaration(): Expected @implementation"); ConsumeToken(); // the "implementation" identifier - + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing class or category name. return DeclPtrTy(); @@ -1021,20 +1034,20 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( // 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)) { + + if (Tok.is(tok::l_paren)) { // we have a category implementation. SourceLocation lparenLoc = ConsumeParen(); SourceLocation categoryLoc, rparenLoc; IdentifierInfo *categoryId = 0; - + if (Tok.is(tok::identifier)) { categoryId = Tok.getIdentifierInfo(); categoryLoc = ConsumeToken(); } else { Diag(Tok, diag::err_expected_ident); // missing category name. return DeclPtrTy(); - } + } if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected_rparen); SkipUntil(tok::r_paren, false); // don't stop at ';' @@ -1042,7 +1055,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( } rparenLoc = ConsumeParen(); DeclPtrTy ImplCatType = Actions.ActOnStartCategoryImplementation( - atLoc, nameId, nameLoc, categoryId, + atLoc, nameId, nameLoc, categoryId, categoryLoc); ObjCImpDecl = ImplCatType; return DeclPtrTy(); @@ -1063,11 +1076,11 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( DeclPtrTy ImplClsType = Actions.ActOnStartClassImplementation( atLoc, nameId, nameLoc, superClassId, superClassLoc); - + if (Tok.is(tok::l_brace)) // we have ivars ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/, atLoc); ObjCImpDecl = ImplClsType; - + return DeclPtrTy(); } @@ -1131,7 +1144,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { Diag(Tok, diag::err_expected_ident); return DeclPtrTy(); } - + while (Tok.is(tok::identifier)) { IdentifierInfo *propertyIvar = 0; IdentifierInfo *propertyId = Tok.getIdentifierInfo(); @@ -1186,7 +1199,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { Diag(Tok, diag::err_expected_semi_after) << "@dynamic"; return DeclPtrTy(); } - + /// objc-throw-statement: /// throw expression[opt]; /// @@ -1288,7 +1301,7 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { 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 + // 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); @@ -1298,9 +1311,9 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { FirstPart = Actions.ActOnParamDeclarator(CurScope, ParmDecl); } else ConsumeToken(); // consume '...' - + SourceLocation RParenLoc; - + if (Tok.is(tok::r_paren)) RParenLoc = ConsumeParen(); else // Skip over garbage, until we get to ')'. Eat the ')'. @@ -1352,11 +1365,11 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { /// Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() { DeclPtrTy MDecl = ParseObjCMethodPrototype(ObjCImpDecl); - + PrettyStackTraceActionsDecl CrashInfo(MDecl, Tok.getLocation(), Actions, PP.getSourceManager(), "parsing Objective-C method"); - + // parse optional ';' if (Tok.is(tok::semi)) ConsumeToken(); @@ -1364,19 +1377,19 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() { // We should have an opening brace now. if (Tok.isNot(tok::l_brace)) { Diag(Tok, diag::err_expected_method_body); - + // Skip over garbage, until we get to '{'. Don't eat the '{'. SkipUntil(tok::l_brace, true, true); - + // If we didn't find the '{', bail out. if (Tok.isNot(tok::l_brace)) return DeclPtrTy(); } SourceLocation BraceLoc = Tok.getLocation(); - + // Enter a scope for the method body. ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); - + // Tell the actions module that we have entered a method definition with the // specified Declarator for the method. Actions.ActOnStartOfObjCMethodDef(CurScope, MDecl); @@ -1390,7 +1403,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() { // TODO: Pass argument information. Actions.ActOnFinishFunctionBody(MDecl, move(FnBody)); - + // Leave the function body scope. BodyScope.Exit(); @@ -1439,7 +1452,7 @@ Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { } } -/// objc-message-expr: +/// objc-message-expr: /// '[' objc-receiver objc-message-args ']' /// /// objc-receiver: @@ -1472,7 +1485,7 @@ Parser::OwningExprResult Parser::ParseObjCMessageExpression() { /// ParseObjCMessageExpressionBody - Having parsed "'[' objc-receiver", parse /// the rest of a message expression. -/// +/// /// objc-message-args: /// objc-selector /// objc-keywordarg-list @@ -1481,7 +1494,7 @@ Parser::OwningExprResult Parser::ParseObjCMessageExpression() { /// objc-keywordarg /// objc-keywordarg-list objc-keywordarg /// -/// objc-keywordarg: +/// objc-keywordarg: /// selector-name[opt] ':' objc-keywordexpr /// /// objc-keywordexpr: @@ -1501,7 +1514,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc); SourceLocation SelectorLoc = Loc; - + llvm::SmallVector<IdentifierInfo *, 12> KeyIdents; ExprVector KeyExprs(Actions); @@ -1520,7 +1533,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, } ConsumeToken(); // Eat the ':'. - /// Parse the expression after ':' + /// Parse the expression after ':' OwningExprResult Res(ParseAssignmentExpression()); if (Res.isInvalid()) { // We must manually skip to a ']', otherwise the expression skipper will @@ -1542,7 +1555,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, // Parse the, optional, argument list, comma separated. while (Tok.is(tok::comma)) { ConsumeToken(); // Eat the ','. - /// Parse the expression after ',' + /// Parse the expression after ',' OwningExprResult Res(ParseAssignmentExpression()); if (Res.isInvalid()) { // We must manually skip to a ']', otherwise the expression skipper will @@ -1584,7 +1597,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, // We've just parsed a keyword message. if (ReceiverName) return Owned(Actions.ActOnClassMessage(CurScope, ReceiverName, Sel, - LBracLoc, NameLoc, SelectorLoc, + LBracLoc, NameLoc, SelectorLoc, RBracLoc, KeyExprs.take(), KeyExprs.size())); return Owned(Actions.ActOnInstanceMessage(ReceiverExpr.release(), Sel, @@ -1642,7 +1655,7 @@ Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) { if (Ty.isInvalid()) return ExprError(); - return Owned(Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, LParenLoc, + return Owned(Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, LParenLoc, Ty.get(), RParenLoc)); } diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index 58c729aef29e..812d8e2af901 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -37,7 +37,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) { IdentifierInfo *Name = 0; Action::OwningExprResult Alignment(Actions); SourceLocation LParenLoc = Tok.getLocation(); - PP.Lex(Tok); + PP.Lex(Tok); if (Tok.is(tok::numeric_constant)) { Alignment = Actions.ActOnNumericConstant(Tok); if (Alignment.isInvalid()) @@ -57,12 +57,12 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) { } 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()) @@ -72,15 +72,15 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) { } 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; @@ -115,7 +115,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) { 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); @@ -124,57 +124,39 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, Token &UnusedTok) { return; } SourceLocation LParenLoc = Tok.getLocation(); - + // Lex the declaration reference(s). - llvm::SmallVector<Action::ExprTy*, 5> Ex; + llvm::SmallVector<Token, 5> Identifiers; SourceLocation RParenLoc; bool LexID = true; - + while (true) { PP.Lex(Tok); - + if (LexID) { - if (Tok.is(tok::identifier)) { - Action::OwningExprResult Name = - Actions.ActOnIdentifierExpr(parser.CurScope, Tok.getLocation(), - *Tok.getIdentifierInfo(), false); - - if (Name.isInvalid()) { - if (!Ex.empty()) - Action::MultiExprArg Release(Actions, &Ex[0], Ex.size()); - return; - } - - Ex.push_back(Name.release()); + if (Tok.is(tok::identifier)) { + Identifiers.push_back(Tok); LexID = false; continue; } - // Illegal token! Release the parsed expressions (if any) and emit - // a warning. - if (!Ex.empty()) - Action::MultiExprArg Release(Actions, &Ex[0], Ex.size()); - + // 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! Release the parsed expressions (if any) and emit - // a warning. - if (!Ex.empty()) - Action::MultiExprArg Release(Actions, &Ex[0], Ex.size()); - + + // Illegal token! PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_punc); return; } @@ -188,10 +170,11 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, Token &UnusedTok) { // Verify that we have a location for the right parenthesis. assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'"); - assert(!Ex.empty() && "Valid '#pragma unused' must have arguments"); + assert(!Identifiers.empty() && "Valid '#pragma unused' must have arguments"); - // Perform the action to handle the pragma. - Actions.ActOnPragmaUnused(&Ex[0], Ex.size(), UnusedLoc, LParenLoc, RParenLoc); + // Perform the action to handle the pragma. + Actions.ActOnPragmaUnused(Identifiers.data(), Identifiers.size(), + parser.CurScope, UnusedLoc, LParenLoc, RParenLoc); } // #pragma weak identifier @@ -214,7 +197,7 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP, Token &WeakTok) { if (Tok.is(tok::equal)) { PP.Lex(Tok); if (Tok.isNot(tok::identifier)) { - PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << "weak"; return; } diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h index 39c86eea43b0..db385c6371e3 100644 --- a/lib/Parse/ParsePragma.h +++ b/lib/Parse/ParsePragma.h @@ -23,29 +23,29 @@ namespace clang { class PragmaPackHandler : public PragmaHandler { Action &Actions; public: - PragmaPackHandler(const IdentifierInfo *N, Action &A) : PragmaHandler(N), + PragmaPackHandler(const IdentifierInfo *N, Action &A) : PragmaHandler(N), Actions(A) {} - - virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); + + 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); -}; + + 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); + + virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); }; } // end namespace clang diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 955f00d7a0b5..907ca802b4ae 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -71,8 +71,8 @@ using namespace clang; /// /// [OBC] objc-throw-statement: /// [OBC] '@' 'throw' expression ';' -/// [OBC] '@' 'throw' ';' -/// +/// [OBC] '@' 'throw' ';' +/// Parser::OwningStmtResult Parser::ParseStatementOrDeclaration(bool OnlyStatement) { const char *SemiError = 0; @@ -90,6 +90,11 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { return ParseObjCAtStatement(AtLoc); } + case tok::code_completion: + Actions.CodeCompleteOrdinaryName(CurScope); + ConsumeToken(); + return ParseStatementOrDeclaration(OnlyStatement); + case tok::identifier: if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement // identifier ':' statement @@ -108,7 +113,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { Diag(Tok, diag::err_expected_statement); return StmtError(); } - + // expression[opt] ';' OwningExprResult Expr(ParseExpression()); if (Expr.isInvalid()) { @@ -187,7 +192,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { // Skip until we see a } or ;, but don't eat it. SkipUntil(tok::r_brace, true, true); } - + return move(Res); } @@ -233,7 +238,7 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement() { /// Parser::OwningStmtResult Parser::ParseCaseStatement() { assert(Tok.is(tok::kw_case) && "Not a case stmt!"); - + // It is very very common for code to contain many case statements recursively // nested, as in (but usually without indentation): // case 1: @@ -247,19 +252,24 @@ Parser::OwningStmtResult Parser::ParseCaseStatement() { // 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); + ConsumeToken(); + } OwningExprResult LHS(ParseConstantExpression()); if (LHS.isInvalid()) { @@ -288,11 +298,11 @@ Parser::OwningStmtResult Parser::ParseCaseStatement() { } 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()) { @@ -309,15 +319,15 @@ Parser::OwningStmtResult Parser::ParseCaseStatement() { 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 { @@ -327,11 +337,11 @@ Parser::OwningStmtResult Parser::ParseCaseStatement() { 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)); @@ -415,10 +425,10 @@ Parser::OwningStmtResult Parser::ParseCompoundStatement(bool isStmtExpr) { /// 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(), + 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 @@ -496,12 +506,12 @@ bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp, SourceLocation *RParenLocPtr) { SourceLocation LParenLoc = ConsumeParen(); if (LParenLocPtr) *LParenLocPtr = LParenLoc; - + if (getLang().CPlusPlus) CondExp = ParseCXXCondition(); else CondExp = ParseExpression(); - + // If the parser was confused by the condition and we don't have a ')', try to // recover by skipping ahead to a semi and bailing out. If condexp is // semantically invalid but we have well formed code, keep going. @@ -512,7 +522,7 @@ bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp, if (Tok.isNot(tok::r_paren)) return true; } - + // Otherwise the condition is valid or the rparen is present. SourceLocation RPLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); if (RParenLocPtr) *RParenLocPtr = RPLoc; @@ -559,7 +569,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement() { return StmtError(); FullExprArg FullCondExp(Actions.FullExpr(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. @@ -578,7 +588,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement() { // 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, + ParseScope InnerScope(this, Scope::DeclScope, C99orCXX && Tok.isNot(tok::l_brace)); // Read the 'then' stmt. @@ -619,14 +629,14 @@ Parser::OwningStmtResult Parser::ParseIfStatement() { } IfScope.Exit(); - + // If the condition was invalid, discard the if statement. We could recover // better by replacing it with a valid expr, but don't do that yet. if (CondExp.isInvalid()) return StmtError(); // If the then or else stmt is invalid and the other is valid (and present), - // make turn the invalid one into a null stmt to avoid dropping the other + // 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) || @@ -641,7 +651,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement() { if (ElseStmt.isInvalid()) ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc); - return Actions.ActOnIfStmt(IfLoc, FullCondExp, move(ThenStmt), + return Actions.ActOnIfStmt(IfLoc, FullCondExp, move(ThenStmt), ElseLoc, move(ElseStmt)); } @@ -698,7 +708,7 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement() { // 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, + ParseScope InnerScope(this, Scope::DeclScope, C99orCXX && Tok.isNot(tok::l_brace)); // Read the body statement. @@ -763,7 +773,7 @@ Parser::OwningStmtResult Parser::ParseWhileStatement() { return StmtError(); FullExprArg FullCond(Actions.FullExpr(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. @@ -775,7 +785,7 @@ Parser::OwningStmtResult Parser::ParseWhileStatement() { // 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, + ParseScope InnerScope(this, Scope::DeclScope, C99orCXX && Tok.isNot(tok::l_brace)); // Read the body statement. @@ -818,7 +828,7 @@ Parser::OwningStmtResult Parser::ParseDoStatement() { // which is entered and exited each time through the loop. // ParseScope InnerScope(this, Scope::DeclScope, - (getLang().C99 || getLang().CPlusPlus) && + (getLang().C99 || getLang().CPlusPlus) && Tok.isNot(tok::l_brace)); // Read the body statement. @@ -847,7 +857,7 @@ Parser::OwningStmtResult Parser::ParseDoStatement() { OwningExprResult Cond(Actions); SourceLocation LPLoc, RPLoc; ParseParenExprOrCondition(Cond, true, &LPLoc, &RPLoc); - + DoScope.Exit(); if (Cond.isInvalid() || Body.isInvalid()) @@ -913,6 +923,11 @@ Parser::OwningStmtResult Parser::ParseForStatement() { OwningStmtResult FirstPart(Actions); OwningExprResult SecondPart(Actions), ThirdPart(Actions); + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(CurScope); + ConsumeToken(); + } + // Parse the first part of the for specifier. if (Tok.is(tok::semi)) { // for (; // no first part, eat the ';'. @@ -926,11 +941,11 @@ Parser::OwningStmtResult Parser::ParseForStatement() { DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd, false); FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); - + if (Tok.is(tok::semi)) { // for (int x = 4; ConsumeToken(); } else if ((ForEach = isTokIdentifier_in())) { - // ObjC: for (id x in expr) + // ObjC: for (id x in expr) ConsumeToken(); // consume 'in' SecondPart = ParseExpression(); } else { @@ -988,7 +1003,7 @@ Parser::OwningStmtResult Parser::ParseForStatement() { // 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, + ParseScope InnerScope(this, Scope::DeclScope, C99orCXXorObjC && Tok.isNot(tok::l_brace)); // Read the body statement. @@ -1007,7 +1022,7 @@ Parser::OwningStmtResult Parser::ParseForStatement() { return Actions.ActOnForStmt(ForLoc, LParenLoc, move(FirstPart), move(SecondPart), move(ThirdPart), RParenLoc, move(Body)); - + return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, move(FirstPart), move(SecondPart), @@ -1085,7 +1100,7 @@ Parser::OwningStmtResult Parser::ParseReturnStatement() { return StmtError(); } } - return Actions.ActOnReturnStmt(ReturnLoc, Actions.FullExpr(R)); + return Actions.ActOnReturnStmt(ReturnLoc, move(R)); } /// FuzzyParseMicrosoftAsmStatement. When -fms-extensions is enabled, this @@ -1096,7 +1111,7 @@ Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() { do { ConsumeAnyToken(); } while (BraceCount > savedBraceCount && Tok.isNot(tok::eof)); - } else { + } 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(); @@ -1105,8 +1120,8 @@ Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() { do { ConsumeAnyToken(); TokLoc = Tok.getLocation(); - } while ((SrcMgr.getInstantiationLineNumber(TokLoc) == LineNo) && - Tok.isNot(tok::r_brace) && Tok.isNot(tok::semi) && + } while ((SrcMgr.getInstantiationLineNumber(TokLoc) == LineNo) && + Tok.isNot(tok::r_brace) && Tok.isNot(tok::semi) && Tok.isNot(tok::eof)); } return Actions.ActOnNullStmt(Tok.getLocation()); @@ -1196,7 +1211,7 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) { return StmtError(); assert(Names.size() == Constraints.size() && - Constraints.size() == Exprs.size() + Constraints.size() == Exprs.size() && "Input operand size mismatch!"); NumInputs = Names.size() - NumOutputs; @@ -1247,22 +1262,22 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names, // Only do anything if this operand is present. if (Tok.isNot(tok::colon)) return false; ConsumeToken(); - + // 'asm-operands' isn't present? if (!isTokenStringLiteral() && Tok.isNot(tok::l_square)) return false; - - while (1) { + + 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(); @@ -1308,7 +1323,7 @@ Parser::DeclPtrTy Parser::ParseFunctionStatementBody(DeclPtrTy Decl) { 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. @@ -1316,7 +1331,7 @@ Parser::DeclPtrTy Parser::ParseFunctionStatementBody(DeclPtrTy Decl) { // If the function body could not be parsed, make a bogus compoundstmt. if (FnBody.isInvalid()) - FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, + FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, MultiStmtArg(Actions), false); return Actions.ActOnFinishFunctionBody(Decl, move(FnBody)); diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 57a09fbc737f..8e63fb89db31 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -15,6 +15,7 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" +#include "llvm/Support/Compiler.h" using namespace clang; /// \brief Parse a template declaration, explicit instantiation, or @@ -24,11 +25,35 @@ Parser::ParseDeclarationStartingWithTemplate(unsigned Context, SourceLocation &DeclEnd, AccessSpecifier AS) { if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) - return ParseExplicitInstantiation(ConsumeToken(), DeclEnd); + return ParseExplicitInstantiation(SourceLocation(), ConsumeToken(), + DeclEnd); return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS); } +/// \brief RAII class that manages the template parameter depth. +namespace { + class VISIBILITY_HIDDEN 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 @@ -48,9 +73,9 @@ 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."); - + 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); @@ -75,8 +100,9 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, // defining A<T>::B receives just the inner template parameter list // (and retrieves the outer template parameter list from its // context). - bool isSpecialiation = true; + bool isSpecialization = true; TemplateParameterLists ParamLists; + TemplateParameterDepthCounter Depth(TemplateParameterDepth); do { // Consume the 'export', if any. SourceLocation ExportLoc; @@ -92,27 +118,35 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, Diag(Tok.getLocation(), diag::err_expected_template); return DeclPtrTy(); } - + // Parse the '<' template-parameter-list '>' SourceLocation LAngleLoc, RAngleLoc; TemplateParameterList TemplateParams; - ParseTemplateParameters(ParamLists.size(), TemplateParams, LAngleLoc, - RAngleLoc); - - if (!TemplateParams.empty()) - isSpecialiation = false; + 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(ParamLists.size(), ExportLoc, - TemplateLoc, LAngleLoc, + Actions.ActOnTemplateParameterList(Depth, ExportLoc, + TemplateLoc, LAngleLoc, TemplateParams.data(), TemplateParams.size(), RAngleLoc)); + + if (!TemplateParams.empty()) { + isSpecialization = false; + ++Depth; + } } while (Tok.is(tok::kw_export) || Tok.is(tok::kw_template)); // Parse the actual template declaration. - return ParseSingleDeclarationAfterTemplate(Context, + return ParseSingleDeclarationAfterTemplate(Context, ParsedTemplateInfo(&ParamLists, - isSpecialiation), + isSpecialization), DeclEnd, AS); } @@ -136,7 +170,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, /// declaration. Will be AS_none for namespace-scope declarations. /// /// \returns the new declaration. -Parser::DeclPtrTy +Parser::DeclPtrTy Parser::ParseSingleDeclarationAfterTemplate( unsigned Context, const ParsedTemplateInfo &TemplateInfo, @@ -145,9 +179,14 @@ Parser::ParseSingleDeclarationAfterTemplate( 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. DeclSpec DS; - // FIXME: Pass TemplateLoc through for explicit template instantiations ParseDeclarationSpecifiers(DS, TemplateInfo, AS); if (Tok.is(tok::semi)) { @@ -166,7 +205,7 @@ Parser::ParseSingleDeclarationAfterTemplate( ConsumeToken(); return DeclPtrTy(); } - + // If we have a declaration or declarator list, handle it. if (isDeclarationAfterDeclarator()) { // Parse this declaration. @@ -181,7 +220,7 @@ Parser::ParseSingleDeclarationAfterTemplate( } // Eat the semi colon after the declaration. - ExpectAndConsume(tok::semi, diag::err_expected_semi_declation); + ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration); return ThisDecl; } @@ -217,44 +256,46 @@ Parser::ParseSingleDeclarationAfterTemplate( /// 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, +/// 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)) { + if (!Tok.is(tok::less)) { Diag(Tok.getLocation(), diag::err_expected_less_after) << "template"; - return false; + 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)) { + else if (ParseTemplateParameterList(Depth, TemplateParams)) { + if (!Tok.is(tok::greater)) { Diag(Tok.getLocation(), diag::err_expected_greater); - return false; + return true; } RAngleLoc = ConsumeToken(); } - return true; + 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. +/// a statement, etc.) and return false. /// /// template-parameter-list: [C++ temp] /// template-parameter /// template-parameter-list ',' template-parameter -bool +bool Parser::ParseTemplateParameterList(unsigned Depth, TemplateParameterList &TemplateParams) { - while(1) { + while (1) { if (DeclPtrTy TmpParam = ParseTemplateParameter(Depth, TemplateParams.size())) { TemplateParams.push_back(TmpParam); @@ -263,11 +304,11 @@ Parser::ParseTemplateParameterList(unsigned Depth, // 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)) { + if (Tok.is(tok::comma)) { ConsumeToken(); - } else if(Tok.is(tok::greater)) { + } else if (Tok.is(tok::greater)) { // Don't consume this... that's done by template parser. break; } else { @@ -297,16 +338,16 @@ Parser::ParseTemplateParameterList(unsigned Depth, /// '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::DeclPtrTy Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { - if(Tok.is(tok::kw_class) || - (Tok.is(tok::kw_typename) && - // FIXME: Next token has not been annotated! - NextToken().isNot(tok::annot_typename))) { + if (Tok.is(tok::kw_class) || + (Tok.is(tok::kw_typename) && + // FIXME: Next token has not been annotated! + NextToken().isNot(tok::annot_typename))) { return ParseTypeParameter(Depth, Position); } - - if(Tok.is(tok::kw_template)) + + if (Tok.is(tok::kw_template)) return ParseTemplateTemplateParameter(Depth, Position); // If it's none of the above, then it must be a parameter declaration. @@ -326,7 +367,7 @@ Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { /// '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'"); + "A type-parameter starts with 'class' or 'typename'"); // Consume the 'class' or 'typename' keyword. bool TypenameKeyword = Tok.is(tok::kw_typename); @@ -338,33 +379,33 @@ Parser::DeclPtrTy Parser::ParseTypeParameter(unsigned Depth, unsigned Position){ if (Tok.is(tok::ellipsis)) { Ellipsis = true; EllipsisLoc = ConsumeToken(); - - if (!getLang().CPlusPlus0x) + + 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)) { + if (Tok.is(tok::identifier)) { ParamName = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); - } else if(Tok.is(tok::equal) || Tok.is(tok::comma) || - Tok.is(tok::greater)) { + } 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)) { + if (Tok.is(tok::equal)) { SourceLocation EqualLoc = ConsumeToken(); SourceLocation DefaultLoc = Tok.getLocation(); TypeResult DefaultType = ParseTypeName(); @@ -372,12 +413,12 @@ Parser::DeclPtrTy Parser::ParseTypeParameter(unsigned Depth, unsigned Position){ Actions.ActOnTypeParameterDefault(TypeParam, EqualLoc, DefaultLoc, DefaultType.get()); } - + return TypeParam; } /// ParseTemplateTemplateParameter - Handle the parsing of template -/// template parameters. +/// template parameters. /// /// type-parameter: [C++ temp.param] /// 'template' '<' template-parameter-list '>' 'class' identifier[opt] @@ -388,20 +429,20 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { // Handle the template <...> part. SourceLocation TemplateLoc = ConsumeToken(); - TemplateParameterList TemplateParams; + TemplateParameterList TemplateParams; SourceLocation LAngleLoc, RAngleLoc; { ParseScope TemplateParmScope(this, Scope::TemplateParamScope); - if(!ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc, - RAngleLoc)) { + 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) + if (!Tok.is(tok::kw_class)) { + Diag(Tok.getLocation(), diag::err_expected_class_before) << PP.getSpelling(Tok); return DeclPtrTy(); } @@ -410,10 +451,10 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { // Get the identifier, if given. SourceLocation NameLoc; IdentifierInfo* ParamName = 0; - if(Tok.is(tok::identifier)) { + if (Tok.is(tok::identifier)) { ParamName = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); - } else if(Tok.is(tok::equal) || Tok.is(tok::comma) || Tok.is(tok::greater)) { + } 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 { @@ -421,10 +462,10 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { return DeclPtrTy(); } - TemplateParamsTy *ParamList = + TemplateParamsTy *ParamList = Actions.ActOnTemplateParameterList(Depth, SourceLocation(), TemplateLoc, LAngleLoc, - &TemplateParams[0], + &TemplateParams[0], TemplateParams.size(), RAngleLoc); @@ -448,7 +489,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { } /// ParseNonTypeTemplateParameter - Handle the parsing of non-type -/// template parameters (e.g., in "template<int Size> class array;"). +/// template parameters (e.g., in "template<int Size> class array;"). /// /// template-parameter: /// ... @@ -460,7 +501,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { /// parameters. /// FIXME: We need to make a ParseParameterDeclaration that works for /// non-type template parameters and normal function parameters. -Parser::DeclPtrTy +Parser::DeclPtrTy Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { SourceLocation StartLoc = Tok.getLocation(); @@ -483,7 +524,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { return DeclPtrTy(); } - // Create the parameter. + // Create the parameter. DeclPtrTy Param = Actions.ActOnNonTypeTemplateParameter(CurScope, ParamDecl, Depth, Position); @@ -496,16 +537,16 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { // 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); + GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); OwningExprResult DefaultArg = ParseAssignmentExpression(); if (DefaultArg.isInvalid()) SkipUntil(tok::comma, tok::greater, true, true); else if (Param) - Actions.ActOnNonTypeTemplateParameterDefault(Param, EqualLoc, + Actions.ActOnNonTypeTemplateParameterDefault(Param, EqualLoc, move(DefaultArg)); } - + return Param; } @@ -527,9 +568,9 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { /// 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 +bool Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, - SourceLocation TemplateNameLoc, + SourceLocation TemplateNameLoc, const CXXScopeSpec *SS, bool ConsumeLastToken, SourceLocation &LAngleLoc, @@ -587,7 +628,7 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, return false; } - + /// \brief Replace the tokens that form a simple-template-id with an /// annotation token containing the complete template-id. /// @@ -626,7 +667,7 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, /// formed, this function returns true. /// bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, - const CXXScopeSpec *SS, + const CXXScopeSpec *SS, SourceLocation TemplateKWLoc, bool AllowTypeAnnotation) { assert(getLang().CPlusPlus && "Can only annotate template-ids in C++"); @@ -643,12 +684,12 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, TemplateArgIsTypeList TemplateArgIsType; TemplateArgLocationList TemplateArgLocations; bool Invalid = ParseTemplateIdAfterTemplateName(Template, TemplateNameLoc, - SS, false, LAngleLoc, - TemplateArgs, + SS, false, LAngleLoc, + TemplateArgs, TemplateArgIsType, TemplateArgLocations, 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. @@ -663,7 +704,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, // Build the annotation token. if (TNK == TNK_Type_template && AllowTypeAnnotation) { - Action::TypeResult Type + Action::TypeResult Type = Actions.ActOnTemplateIdType(Template, TemplateNameLoc, LAngleLoc, TemplateArgsPtr, &TemplateArgLocations[0], @@ -682,13 +723,13 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, Tok.setLocation(SS->getBeginLoc()); else if (TemplateKWLoc.isValid()) Tok.setLocation(TemplateKWLoc); - else + 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 *TemplateId = TemplateIdAnnotation::Allocate(TemplateArgs.size()); TemplateId->TemplateNameLoc = TemplateNameLoc; TemplateId->Name = Name; @@ -731,21 +772,21 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) { assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens"); - TemplateIdAnnotation *TemplateId + 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, + + ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateId->getTemplateArgs(), TemplateId->getTemplateArgIsType(), TemplateId->NumArgs); - Action::TypeResult Type + Action::TypeResult Type = Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), TemplateId->TemplateNameLoc, - TemplateId->LAngleLoc, + TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->getTemplateArgLocations(), TemplateId->RAngleLoc); @@ -798,7 +839,7 @@ void *Parser::ParseTemplateArgument(bool &ArgIsType) { /// template-argument-list: [C++ 14.2] /// template-argument /// template-argument-list ',' template-argument -bool +bool Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs, TemplateArgIsTypeList &TemplateArgIsType, TemplateArgLocationList &TemplateArgLocations) { @@ -826,15 +867,19 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs, return Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater); } -/// \brief Parse a C++ explicit template instantiation +/// \brief Parse a C++ explicit template instantiation /// (C++ [temp.explicit]). /// /// explicit-instantiation: -/// 'template' declaration -Parser::DeclPtrTy -Parser::ParseExplicitInstantiation(SourceLocation TemplateLoc, +/// '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(TemplateLoc), + return ParseSingleDeclarationAfterTemplate(Declarator::FileContext, + ParsedTemplateInfo(ExternLoc, + TemplateLoc), DeclEnd, AS_none); } diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 02687a216c7d..eb6e93540566 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -270,7 +270,7 @@ bool Parser::isCXXConditionDeclaration() { return TPR == TPResult::True(); } - /// \brief Determine whether the next set of tokens contains a type-id. + /// \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 @@ -288,7 +288,7 @@ bool Parser::isCXXConditionDeclaration() { /// type-specifier-seq abstract-declarator[opt] /// bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { - + isAmbiguous = false; // C++ 8.2p2: @@ -409,7 +409,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, while (1) { if (Tok.is(tok::coloncolon) || Tok.is(tok::identifier)) - TryAnnotateCXXScopeToken(); + TryAnnotateCXXScopeToken(true); if (Tok.is(tok::star) || Tok.is(tok::amp) || Tok.is(tok::caret) || (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) { @@ -427,8 +427,12 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, // direct-declarator: // direct-abstract-declarator: - if (Tok.is(tok::identifier) && mayHaveIdentifier) { + 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(); @@ -597,14 +601,14 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { if (NextToken().is(tok::kw_new) || // ::new NextToken().is(tok::kw_delete)) // ::delete return TPResult::False(); - + // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return isCXXDeclarationSpecifier(); // Otherwise, not a typename. return TPResult::False(); - + // decl-specifier: // storage-class-specifier // type-specifier @@ -650,7 +654,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw__Complex: case tok::kw___attribute: return TPResult::True(); - + // Microsoft case tok::kw___declspec: case tok::kw___cdecl: @@ -681,6 +685,8 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { 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: @@ -752,7 +758,7 @@ Parser::TPResult Parser::TryParseDeclarationSpecifier() { TryParseTypeofSpecifier(); else ConsumeToken(); - + assert(Tok.is(tok::l_paren) && "Expected '('!"); return TPResult::Ambiguous(); } @@ -874,7 +880,7 @@ Parser::TPResult Parser::TryParseParameterDeclarationClause() { /// 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] /// diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 9771cf7b8474..2f500a484da3 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -24,18 +24,18 @@ using namespace clang; /// to the parser action. class ActionCommentHandler : public CommentHandler { Action &Actions; - + public: explicit ActionCommentHandler(Action &Actions) : Actions(Actions) { } - + virtual void HandleComment(Preprocessor &PP, SourceRange Comment) { Actions.ActOnComment(Comment); } }; Parser::Parser(Preprocessor &pp, Action &actions) - : CrashInfo(*this), PP(pp), Actions(actions), Diags(PP.getDiagnostics()), - GreaterThanIsOperator(true) { + : CrashInfo(*this), PP(pp), Actions(actions), Diags(PP.getDiagnostics()), + GreaterThanIsOperator(true), TemplateParameterDepth(0) { Tok.setKind(tok::eof); CurScope = 0; NumCachedScopes = 0; @@ -47,7 +47,7 @@ Parser::Parser(Preprocessor &pp, Action &actions) PackHandler.reset(new PragmaPackHandler(&PP.getIdentifierTable().get("pack"), actions)); PP.AddPragmaHandler(0, PackHandler.get()); - + UnusedHandler.reset(new PragmaUnusedHandler(&PP.getIdentifierTable().get("unused"), actions, *this)); @@ -56,9 +56,9 @@ Parser::Parser(Preprocessor &pp, Action &actions) WeakHandler.reset(new PragmaWeakHandler(&PP.getIdentifierTable().get("weak"), actions)); PP.AddPragmaHandler(0, WeakHandler.get()); - + CommentHandler.reset(new ActionCommentHandler(actions)); - PP.AddCommentHandler(CommentHandler.get()); + PP.AddCommentHandler(CommentHandler.get()); } /// If a crash happens while the parser is active, print out a line indicating @@ -69,12 +69,12 @@ void PrettyStackTraceParserEntry::print(llvm::raw_ostream &OS) const { OS << "<eof> parser at end of file\n"; return; } - + if (Tok.getLocation().isInvalid()) { OS << "<unknown> parser at unknown location\n"; return; } - + const Preprocessor &PP = P.getPreprocessor(); Tok.getLocation().print(OS, PP.getSourceManager()); OS << ": current parser token '" << PP.getSpelling(Tok) << "'\n"; @@ -104,8 +104,8 @@ void Parser::SuggestParentheses(SourceLocation Loc, unsigned DK, Diag(Loc, DK); return; } - - Diag(Loc, DK) + + Diag(Loc, DK) << CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(") << CodeModificationHint::CreateInsertion(EndLoc, ")"); } @@ -152,10 +152,10 @@ bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID, const char *Spelling = 0; SourceLocation EndLoc = PP.getLocForEndOfToken(PrevTokLocation); - if (EndLoc.isValid() && + if (EndLoc.isValid() && (Spelling = tok::getTokenSimpleSpelling(ExpectedTok))) { // Show what code to insert to fix this problem. - Diag(EndLoc, DiagID) + Diag(EndLoc, DiagID) << Msg << CodeModificationHint::CreateInsertion(EndLoc, Spelling); } else @@ -365,7 +365,7 @@ void Parser::ParseTranslationUnit() { DeclGroupPtrTy Res; while (!ParseTopLevelDecl(Res)) /*parse them all*/; - + ExitScope(); assert(CurScope == 0 && "Scope imbalance!"); } @@ -375,7 +375,7 @@ void Parser::ParseTranslationUnit() { /// external-declaration: [C99 6.9], declaration: [C++ dcl.dcl] /// function-definition /// declaration -/// [EXT] ';' +/// [C++0x] empty-declaration /// [GNU] asm-definition /// [GNU] __extension__ external-declaration /// [OBJC] objc-class-definition @@ -388,12 +388,18 @@ void Parser::ParseTranslationUnit() { /// [GNU] asm-definition: /// simple-asm-expr ';' /// +/// [C++0x] empty-declaration: +/// ';' +/// +/// [C++0x/GNU] 'extern' 'template' declaration Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() { DeclPtrTy SingleDecl; switch (Tok.getKind()) { case tok::semi: - Diag(Tok, diag::ext_top_level_semi) - << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation())); + if (!getLang().CPlusPlus0x) + Diag(Tok, diag::ext_top_level_semi) + << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation())); + ConsumeToken(); // TODO: Invoke action for top-level semicolon. return DeclGroupPtrTy(); @@ -436,6 +442,10 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() { } SingleDecl = ParseObjCMethodDefinition(); break; + case tok::code_completion: + Actions.CodeCompleteOrdinaryName(CurScope); + ConsumeToken(); + return ParseExternalDeclaration(); case tok::kw_using: case tok::kw_namespace: case tok::kw_typedef: @@ -447,11 +457,25 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() { SourceLocation DeclEnd; return ParseDeclaration(Declarator::FileContext, DeclEnd); } + 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(); } - + // This routine returns a DeclGroup, if the thing we parsed only contains a // single decl, convert it now. return Actions.ConvertDeclToDeclGroup(SingleDecl); @@ -473,7 +497,7 @@ bool Parser::isDeclarationAfterDeclarator() { /// declarator, indicates the start of a function definition. bool Parser::isStartOfFunctionDefinition() { return Tok.is(tok::l_brace) || // int X() {} - (!getLang().CPlusPlus && + (!getLang().CPlusPlus && isDeclarationSpecifier()) || // int X(f) int f; {} (getLang().CPlusPlus && (Tok.is(tok::colon) || // X() : Base() {} (used for ctors) @@ -484,7 +508,7 @@ bool Parser::isStartOfFunctionDefinition() { /// 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. +/// C++ template-declaration. /// /// function-definition: [C99 6.9.1] /// decl-specs declarator declaration-list[opt] compound-statement @@ -515,16 +539,17 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { // attributes here, no types, etc. if (getLang().ObjC2 && Tok.is(tok::at)) { SourceLocation AtLoc = ConsumeToken(); // the "@" - if (!Tok.isObjCAtKeyword(tok::objc_interface) && + if (!Tok.isObjCAtKeyword(tok::objc_interface) && !Tok.isObjCAtKeyword(tok::objc_protocol)) { Diag(Tok, diag::err_objc_unexpected_attr); SkipUntil(tok::semi); // FIXME: better skip? return DeclGroupPtrTy(); } const char *PrevSpec = 0; - if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec)) - Diag(AtLoc, diag::err_invalid_decl_spec_combination) << PrevSpec; - + 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()); @@ -561,10 +586,10 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { DeclGroupPtrTy DG = ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo); // Eat the semi colon after the declaration. - ExpectAndConsume(tok::semi, diag::err_expected_semi_declation); + ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration); return DG; } - + if (DeclaratorInfo.isFunctionDeclarator() && isStartOfFunctionDefinition()) { if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { @@ -584,7 +609,7 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { DeclPtrTy TheDecl = ParseFunctionDefinition(DeclaratorInfo); return Actions.ConvertDeclToDeclGroup(TheDecl); } - + if (DeclaratorInfo.isFunctionDeclarator()) Diag(Tok, diag::err_expected_fn_body); else @@ -619,9 +644,10 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D, // 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); + PrevSpec, DiagID); D.SetRangeBegin(D.getDeclSpec().getSourceRange().getBegin()); } @@ -650,7 +676,7 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D, // Tell the actions module that we have entered a function definition with the // specified Declarator for the function. - DeclPtrTy Res = TemplateInfo.TemplateParams? + DeclPtrTy Res = TemplateInfo.TemplateParams? Actions.ActOnStartOfFunctionTemplateDef(CurScope, Action::MultiTemplateParamsArg(Actions, TemplateInfo.TemplateParams->data(), @@ -665,6 +691,8 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D, // ctor-initializer. if (Tok.is(tok::colon)) ParseConstructorInitializer(Res); + else + Actions.ActOnDefaultCtorInitializers(Res); return ParseFunctionStatementBody(Res); } @@ -858,24 +886,25 @@ Parser::OwningExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) { /// /// This returns true if the token was annotated or an unrecoverable error /// occurs. -/// +/// /// Note that this routine emits an error if you call it with ::new or ::delete /// as the current tokens, so only call it in contexts where these are invalid. -bool Parser::TryAnnotateTypeOrScopeToken() { - assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) +bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { + assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || Tok.is(tok::kw_typename)) && "Cannot be a type or scope token!"); - + if (Tok.is(tok::kw_typename)) { // Parse a C++ typename-specifier, e.g., "typename T::type". // // typename-specifier: // 'typename' '::' [opt] nested-name-specifier identifier - // 'typename' '::' [opt] nested-name-specifier template [opt] + // 'typename' '::' [opt] nested-name-specifier template [opt] // simple-template-id SourceLocation TypenameLoc = ConsumeToken(); CXXScopeSpec SS; - bool HadNestedNameSpecifier = ParseOptionalCXXScopeSpecifier(SS); + bool HadNestedNameSpecifier + = ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); if (!HadNestedNameSpecifier) { Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename); return false; @@ -884,10 +913,10 @@ bool Parser::TryAnnotateTypeOrScopeToken() { TypeResult Ty; if (Tok.is(tok::identifier)) { // FIXME: check whether the next token is '<', first! - Ty = Actions.ActOnTypenameType(TypenameLoc, SS, *Tok.getIdentifierInfo(), + Ty = Actions.ActOnTypenameType(TypenameLoc, SS, *Tok.getIdentifierInfo(), Tok.getLocation()); } else if (Tok.is(tok::annot_template_id)) { - TemplateIdAnnotation *TemplateId + TemplateIdAnnotation *TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); if (TemplateId->Kind == TNK_Function_template) { Diag(Tok, diag::err_typename_refers_to_non_type_template) @@ -896,7 +925,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() { } AnnotateTemplateIdTokenAsType(0); - assert(Tok.is(tok::annot_typename) && + assert(Tok.is(tok::annot_typename) && "AnnotateTemplateIdTokenAsType isn't working properly"); if (Tok.getAnnotationValue()) Ty = Actions.ActOnTypenameType(TypenameLoc, SS, SourceLocation(), @@ -919,11 +948,11 @@ bool Parser::TryAnnotateTypeOrScopeToken() { CXXScopeSpec SS; if (getLang().CPlusPlus) - ParseOptionalCXXScopeSpecifier(SS); + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext); if (Tok.is(tok::identifier)) { // Determine whether the identifier is a type name. - if (TypeTy *Ty = Actions.getTypeName(*Tok.getIdentifierInfo(), + 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. @@ -932,26 +961,28 @@ bool Parser::TryAnnotateTypeOrScopeToken() { Tok.setAnnotationEndLoc(Tok.getLocation()); if (SS.isNotEmpty()) // it was a C++ qualified type name. Tok.setLocation(SS.getBeginLoc()); - + // In case the tokens were cached, have Preprocessor replace // them with the annotation token. PP.AnnotateCachedTokens(Tok); return true; - } + } if (!getLang().CPlusPlus) { // If we're in C, we can't have :: tokens at all (the lexer won't return // them). If the identifier is not a type, then it can't be scope either, - // just early exit. + // just early exit. return false; } - + // If this is a template-id, annotate with a template-id or type token. if (NextToken().is(tok::less)) { TemplateTy Template; - if (TemplateNameKind TNK - = Actions.isTemplateName(*Tok.getIdentifierInfo(), - CurScope, Template, &SS)) + if (TemplateNameKind TNK + = Actions.isTemplateName(CurScope, *Tok.getIdentifierInfo(), + Tok.getLocation(), &SS, + /*ObjectType=*/0, EnteringContext, + Template)) if (AnnotateTemplateIdToken(Template, TNK, &SS)) { // If an unrecoverable error occurred, we need to return true here, // because the token stream is in a damaged state. We may not return @@ -964,10 +995,10 @@ bool Parser::TryAnnotateTypeOrScopeToken() { // 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 + 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 @@ -981,7 +1012,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() { if (SS.isEmpty()) return Tok.isNot(tok::identifier) && Tok.isNot(tok::coloncolon); - + // 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. @@ -1003,17 +1034,17 @@ bool Parser::TryAnnotateTypeOrScopeToken() { /// 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 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)) + if (!ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext)) return Tok.is(tok::annot_template_id); // Push the current token back into the token stream (or revert it if it is |