diff options
25 files changed, 571 insertions, 233 deletions
diff --git a/docs/InternalsManual.html b/docs/InternalsManual.html index 7b6d201053..9250fd1dd7 100644 --- a/docs/InternalsManual.html +++ b/docs/InternalsManual.html @@ -628,12 +628,10 @@ by the Action::ActOnCXXGlobalScopeSpecifier and Action::ActOnCXXNestedNameSpecifier callbacks. In the case of Sema, this is a <tt>DeclContext*</tt>.</li> -<li><b>tok::annot_template_id</b>: This annotation token represents a C++ -template-id such as "foo<int, 4>", which may refer to a function or type -depending on whether foo is a function template or class template. The -AnnotationValue pointer is a pointer to a malloc'd TemplateIdAnnotation object. -FIXME: I don't think the parsing logic is right for this. Shouldn't type -templates be turned into annot_typename??</li> +<li><b>tok::annot_template_id</b>: This annotation token represents a +C++ template-id such as "foo<int, 4>", where "foo" is the name +of a template. The AnnotationValue pointer is a pointer to a malloc'd +TemplateIdAnnotation object. Depending on the context, a parsed template-id that names a type might become a typename annotation token (if all we care about is the named type, e.g., because it occurs in a type specifier) or might remain a template-id token (if we want to retain more source location information or produce a new type, e.g., in a declaration of a class template specialization). template-id annotation tokens that refer to a type can be "upgraded" to typename annotation tokens by the parser.</li> </ol> diff --git a/include/clang/Basic/DiagnosticParseKinds.def b/include/clang/Basic/DiagnosticParseKinds.def index 6d87c70a17..e8485c69bf 100644 --- a/include/clang/Basic/DiagnosticParseKinds.def +++ b/include/clang/Basic/DiagnosticParseKinds.def @@ -274,6 +274,10 @@ DIAG(err_expected_class_before, ERROR, "expected 'class' before '%0'") DIAG(err_template_spec_syntax_non_template, ERROR, "identifier followed by '<' indicates a class template specialization but %0 %select{does not refer to a template|refers to a function template|<unused>|refers to a template template parameter}1") +DIAG(err_id_after_template_in_nested_name_spec, ERROR, + "expected template name after 'template' keyword in nested name specifier") +DIAG(err_less_after_template_name_in_nested_name_spec, ERROR, + "expected '<' after 'template %0' in nested name specifier") // Language specific pragmas diff --git a/include/clang/Basic/TemplateKinds.h b/include/clang/Basic/TemplateKinds.h new file mode 100644 index 0000000000..dbaf5bdb60 --- /dev/null +++ b/include/clang/Basic/TemplateKinds.h @@ -0,0 +1,37 @@ +//===--- TemplateKinds.h - Enum values for C++ Template Kinds ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TemplateNameKind enum. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_TEMPLATEKINDS_H +#define LLVM_CLANG_TEMPLATEKINDS_H + +namespace clang { + +/// \brief Specifies the kind of template name that an identifier refers to. +enum TemplateNameKind { + /// The name does not refer to a template. + TNK_Non_template = 0, + /// The name refers to a function template or a set of overloaded + /// functions that includes at least one function template. + TNK_Function_template, + /// The name refers to a class template. + TNK_Class_template, + /// The name referes to a template template parameter. + TNK_Template_template_parm, + /// The name is dependent and is known to be a template name based + /// on syntax, e.g., "Alloc::template rebind<Other>". + TNK_Dependent_template_name +}; + +} +#endif + + diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index a0ed1767df..9d99142480 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -431,7 +431,21 @@ public: if (CachedLexPos != 0 && isBacktrackEnabled()) AnnotatePreviousCachedTokens(Tok); } - + + /// \brief Replace the last token with an annotation token. + /// + /// Like AnnotateCachedTokens(), this routine replaces an + /// already-parsed (and resolved) token with an annotation + /// token. However, this routine only replaces the last token with + /// the annotation token; it does not affect any other cached + /// tokens. This function has no effect if backtracking is not + /// enabled. + void ReplaceLastTokenWithAnnotation(const Token &Tok) { + assert(Tok.isAnnotation() && "Expected annotation token"); + if (CachedLexPos != 0 && isBacktrackEnabled()) + CachedTokens[CachedLexPos-1] = Tok; + } + /// Diag - Forwarding function for diagnostics. This emits a diagnostic at /// the specified Token's location, translating the token's start /// position in the current buffer into a SourcePosition object for rendering. diff --git a/include/clang/Lex/Token.h b/include/clang/Lex/Token.h index 73e087ecb6..5bbb63add9 100644 --- a/include/clang/Lex/Token.h +++ b/include/clang/Lex/Token.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_TOKEN_H #define LLVM_CLANG_TOKEN_H +#include "clang/Basic/TemplateKinds.h" #include "clang/Basic/TokenKinds.h" #include "clang/Basic/SourceLocation.h" @@ -247,24 +248,62 @@ struct PPConditionalInfo { /// TemplateIdAnnotation - Information about a template-id annotation /// token, which contains the template declaration, template -/// arguments, and the source locations for important tokens. +/// arguments, whether those template arguments were types or +/// expressions, and the source locations for important tokens. All of +/// the information about template arguments is allocated directly +/// after this structure. struct TemplateIdAnnotation { /// TemplateNameLoc - The location of the template name within the /// source. SourceLocation TemplateNameLoc; - /// Template - The declaration of the template corresponding to the + /// FIXME: Temporarily stores the name of a specialization + IdentifierInfo *Name; + + /// The declaration of the template corresponding to the /// template-name. This is an Action::DeclTy*. void *Template; - /// LAngleLoc - The location of the '<' before the template argument + /// The kind of template that Template refers to. + TemplateNameKind Kind; + + /// The location of the '<' before the template argument /// list. SourceLocation LAngleLoc; - /// NumArgs - The number of template arguments. The arguments - /// themselves are Action::TemplateArgTy pointers allocated directly - /// following the TemplateIdAnnotation structure. + /// The location of the '>' after the template argument + /// list. + SourceLocation RAngleLoc; + + /// NumArgs - The number of template arguments. unsigned NumArgs; + + /// \brief Retrieves a pointer to the template arguments + void **getTemplateArgs() { return (void **)(this + 1); } + + /// \brief Retrieves a pointer to the array of template argument + /// locations. + SourceLocation *getTemplateArgLocations() { + return (SourceLocation *)(getTemplateArgs() + NumArgs); + } + + /// \brief Retrieves a pointer to the array of flags that states + /// whether the template arguments are types. + bool *getTemplateArgIsType() { + return (bool *)(getTemplateArgLocations() + NumArgs); + } + + static TemplateIdAnnotation* Allocate(unsigned NumArgs) { + TemplateIdAnnotation *TemplateId + = (TemplateIdAnnotation *)malloc(sizeof(TemplateIdAnnotation) + + sizeof(void*) * NumArgs + + sizeof(SourceLocation) * NumArgs + + sizeof(bool) * NumArgs); + TemplateId->NumArgs = NumArgs; + return TemplateId; + } + + void Destroy() { free(this); } }; } // end namespace clang diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 5103c16ee3..ebcd79caae 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -16,6 +16,7 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Basic/TemplateKinds.h" #include "clang/Basic/TypeTraits.h" #include "clang/Parse/AccessSpecifier.h" #include "clang/Parse/Ownership.h" @@ -134,20 +135,6 @@ public: virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S, const CXXScopeSpec *SS = 0) = 0; - /// \brief Specifies the kind of template name. Returned from - /// isTemplateName. - enum TemplateNameKind { - /// The name does not refer to a template. - TNK_Non_template = 0, - /// The name refers to a function template or a set of overloaded - /// functions that includes at least one function template. - TNK_Function_template, - /// The name refers to a class template. - TNK_Class_template, - /// The name referes to a template template parameter. - TNK_Template_template_parm - }; - /// \brief Determines whether the identifier II is a template name /// in the current scope. If so, the kind of template name is /// returned, and \p TemplateDecl receives the declaration. An @@ -178,6 +165,22 @@ public: return 0; } + /// ActOnCXXNestedNameSpecifier - Called during parsing of a + /// nested-name-specifier that involves a template-id, e.g., + /// "foo::bar<int, float>::", and now we need to build a scope + /// specifier. \p SS is empty or the previously parsed nested-name + /// part ("foo::"), \p Type is the already-parsed class template + /// specialization (or other template-id that names a type), \p + /// TypeRange is the source range where the type is located, and \p + /// CCLoc is the location of the trailing '::'. + virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S, + const CXXScopeSpec &SS, + TypeTy *Type, + SourceRange TypeRange, + SourceLocation CCLoc) { + return 0; + } + /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global /// scope or nested-name-specifier) is parsed, part of a declarator-id. /// After this method is called, according to [C++ 3.4.3p3], names should be diff --git a/include/clang/Parse/Ownership.h b/include/clang/Parse/Ownership.h index 684203d6d1..9665576a05 100644 --- a/include/clang/Parse/Ownership.h +++ b/include/clang/Parse/Ownership.h @@ -538,7 +538,7 @@ namespace clang void **Args; bool *ArgIsType; mutable unsigned Count; - + #if !defined(DISABLE_SMART_POINTERS) void destroy() { if (!Count) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 2432f445d9..9ef23d4865 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -993,7 +993,6 @@ private: //===--------------------------------------------------------------------===// // C++ 14: Templates [temp] typedef llvm::SmallVector<DeclTy *, 4> TemplateParameterList; - typedef Action::TemplateNameKind TemplateNameKind; // C++ 14.1: Template Parameters [temp.param] DeclTy *ParseTemplateDeclarationOrSpecialization(unsigned Context); @@ -1023,7 +1022,10 @@ private: SourceLocation &RAngleLoc); void AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK, - const CXXScopeSpec *SS = 0); + const CXXScopeSpec *SS, + SourceLocation TemplateKWLoc = SourceLocation(), + bool AllowTypeAnnotation = true); + bool AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS = 0); bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs, TemplateArgIsTypeList &TemplateArgIsType, TemplateArgLocationList &TemplateArgLocations); diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index e10e270c7d..3ed4435bb3 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -162,7 +162,7 @@ ClassTemplateSpecializationDecl(DeclContext *DC, SourceLocation L, NumTemplateArgs(NumTemplateArgs), SpecializationKind(TSK_Undeclared) { TemplateArgument *Arg = reinterpret_cast<TemplateArgument *>(this + 1); for (unsigned ArgIdx = 0; ArgIdx < NumTemplateArgs; ++ArgIdx, ++Arg) - *Arg = TemplateArgs[ArgIdx]; + new (Arg) TemplateArgument(TemplateArgs[ArgIdx]); } ClassTemplateSpecializationDecl * diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index ce15cf9dda..9cd5b979ca 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -95,7 +95,7 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *, return false; } -Action::TemplateNameKind +TemplateNameKind MinimalAction::isTemplateName(IdentifierInfo &II, Scope *S, DeclTy *&TemplateDecl, const CXXScopeSpec *SS) { diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 6e68b20fa5..bdd352f341 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -558,21 +558,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, TypeTy *TypeRep = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(), CurScope); - if (TypeRep == 0 && getLang().CPlusPlus && NextToken().is(tok::less)) { - // If we have a template name, annotate the token and try again. - DeclTy *Template = 0; - if (TemplateNameKind TNK = - Actions.isTemplateName(*Tok.getIdentifierInfo(), CurScope, - Template)) { - AnnotateTemplateIdToken(Template, TNK, 0); - continue; - } - } - if (TypeRep == 0) goto DoneWithDeclSpec; - - // C++: If the identifier is actually the name of the class type // being defined and the next token is a '(', then this is a @@ -610,6 +597,25 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // If a type specifier follows, it will be diagnosed elsewhere. continue; } + + // type-name + case tok::annot_template_id: { + TemplateIdAnnotation *TemplateId + = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + if (TemplateId->Kind != TNK_Class_template) { + // This template-id does not refer to a type name, so we're + // done with the type-specifiers. + goto DoneWithDeclSpec; + } + + // Turn the template-id annotation token into a type annotation + // token, then try again to parse it as a type-specifier. + if (AnnotateTemplateIdTokenAsType()) + DS.SetTypeSpecError(); + + continue; + } + // GNU attributes support. case tok::kw___attribute: DS.AddAttributes(ParseAttributes()); @@ -1749,7 +1755,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, /// operator-function-id /// conversion-function-id [TODO] /// '~' class-name -/// template-id [TODO] +/// template-id /// void Parser::ParseDirectDeclarator(Declarator &D) { DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec()); @@ -1768,21 +1774,9 @@ void Parser::ParseDirectDeclarator(Declarator &D) { if (Tok.is(tok::identifier)) { assert(Tok.getIdentifierInfo() && "Not an identifier?"); - // If this identifier is followed by a '<', we may have a template-id. - DeclTy *Template; - Action::TemplateNameKind TNK; - if (getLang().CPlusPlus && NextToken().is(tok::less) && - (TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(), - CurScope, Template))) { - IdentifierInfo *II = Tok.getIdentifierInfo(); - AnnotateTemplateIdToken(Template, TNK, 0); - // FIXME: Set the declarator to a template-id. How? I don't - // know... for now, just use the identifier. - D.SetIdentifier(II, Tok.getLocation()); - } // If this identifier is the name of the current class, it's a // constructor name. - else if (Actions.isCurrentClassName(*Tok.getIdentifierInfo(),CurScope)){ + if (Actions.isCurrentClassName(*Tok.getIdentifierInfo(),CurScope)){ D.setConstructor(Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(), CurScope), Tok.getLocation()); @@ -1791,6 +1785,21 @@ void Parser::ParseDirectDeclarator(Declarator &D) { D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); ConsumeToken(); goto PastIdentifier; + } else if (Tok.is(tok::annot_template_id)) { + TemplateIdAnnotation *TemplateId + = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + + // FIXME: Could this template-id name a constructor? + + // FIXME: This is an egregious hack, where we silently ignore + // the specialization (which should be a function template + // specialization name) and use the name instead. This hack + // will go away when we have support for function + // specializations. + D.SetIdentifier(TemplateId->Name, Tok.getLocation()); + TemplateId->Destroy(); + ConsumeToken(); + goto PastIdentifier; } else if (Tok.is(tok::kw_operator)) { SourceLocation OperatorLoc = Tok.getLocation(); SourceLocation EndLoc; diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index e36bc40bac..3ef3f93fdf 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -309,75 +309,42 @@ void Parser::ParseClassSpecifier(DeclSpec &DS, // Parse the (optional) nested-name-specifier. CXXScopeSpec SS; - if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS)) { - // FIXME: can we get a class template specialization or - // template-id token here? - if (Tok.isNot(tok::identifier)) + if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS)) + if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) Diag(Tok, diag::err_expected_ident); - } - - - // These variables encode the simple-template-id that we might end - // up parsing below. We don't translate this into a type - // automatically because (1) we want to create a separate - // declaration for each specialization, and (2) we want to retain - // more information about source locations that types provide. - DeclTy *Template = 0; - SourceLocation LAngleLoc, RAngleLoc; - TemplateArgList TemplateArgs; - TemplateArgIsTypeList TemplateArgIsType; - TemplateArgLocationList TemplateArgLocations; - ASTTemplateArgsPtr TemplateArgsPtr(Actions, 0, 0, 0); - // Parse the (optional) class name or simple-template-id. IdentifierInfo *Name = 0; SourceLocation NameLoc; + TemplateIdAnnotation *TemplateId = 0; if (Tok.is(tok::identifier)) { Name = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); + } else if (Tok.is(tok::annot_template_id)) { + TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + NameLoc = ConsumeToken(); - if (Tok.is(tok::less)) { - // This is a simple-template-id. - Action::TemplateNameKind TNK - = Actions.isTemplateName(*Name, CurScope, Template, &SS); - - bool Invalid = false; - - // Parse the enclosed template argument list. - if (TNK != Action::TNK_Non_template) - Invalid = ParseTemplateIdAfterTemplateName(Template, NameLoc, - &SS, true, LAngleLoc, - TemplateArgs, - TemplateArgIsType, - TemplateArgLocations, - RAngleLoc); + if (TemplateId->Kind != TNK_Class_template) { + // The template-name in the simple-template-id refers to + // something other than a class template. Give an appropriate + // error message and skip to the ';'. + SourceRange Range(NameLoc); + if (SS.isNotEmpty()) + Range.setBegin(SS.getBeginLoc()); + + Diag(TemplateId->LAngleLoc, diag::err_template_spec_syntax_non_template) + << Name << static_cast<int>(TemplateId->Kind) << Range; - TemplateArgsPtr.reset(&TemplateArgs[0], &TemplateArgIsType[0], - TemplateArgs.size()); - - if (TNK != Action::TNK_Class_template) { - // The template-name in the simple-template-id refers to - // something other than a class template. Give an appropriate - // error message and skip to the ';'. - SourceRange Range(NameLoc); - if (SS.isNotEmpty()) - Range.setBegin(SS.getBeginLoc()); - else if (!Invalid) - - Diag(LAngleLoc, diag::err_template_spec_syntax_non_template) - << Name << static_cast<int>(TNK) << Range; - - DS.SetTypeSpecError(); - SkipUntil(tok::semi, false, true); - return; - } + DS.SetTypeSpecError(); + SkipUntil(tok::semi, false, true); + TemplateId->Destroy(); + return; } } // There are three options here. If we have 'struct foo;', then // this is a forward declaration. If we have 'struct foo {...' or - // 'struct fo :...' then this is a definition. Otherwise we have + // '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))) @@ -387,35 +354,43 @@ void Parser::ParseClassSpecifier(DeclSpec &DS, else TK = Action::TK_Reference; - if (!Name && TK != Action::TK_Definition) { + if (!Name && !TemplateId && TK != Action::TK_Definition) { // We have a declaration or reference to an anonymous class. Diag(StartLoc, diag::err_anon_type_definition) << DeclSpec::getSpecifierName(TagType); // Skip the rest of this declarator, up until the comma or semicolon. SkipUntil(tok::comma, true); + + if (TemplateId) + TemplateId->Destroy(); return; } // Create the tag portion of the class or class template. DeclTy *TagOrTempDecl; - if (Template && TK != Action::TK_Reference) + if (TemplateId && TK != Action::TK_Reference) { // Explicit specialization or class template partial // specialization. Let semantic analysis decide. - - // FIXME: we want a source range covering the simple-template-id. + ASTTemplateArgsPtr TemplateArgsPtr(Actions, + TemplateId->getTemplateArgs(), + TemplateId->getTemplateArgIsType(), + TemplateId->NumArgs); TagOrTempDecl = Actions.ActOnClassTemplateSpecialization(CurScope, TagType, TK, - StartLoc, SS, /*Range*/ - Template, NameLoc, - LAngleLoc, TemplateArgsPtr, - &TemplateArgLocations[0], - RAngleLoc, Attr, + StartLoc, SS, + TemplateId->Template, + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->getTemplateArgLocations(), + TemplateId->RAngleLoc, + Attr, Action::MultiTemplateParamsArg(Actions, TemplateParams? &(*TemplateParams)[0] : 0, TemplateParams? TemplateParams->size() : 0)); - - else if (TemplateParams && TK != Action::TK_Reference) + TemplateId->Destroy(); + } else if (TemplateParams && TK != Action::TK_Reference) TagOrTempDecl = Actions.ActOnClassTemplate(CurScope, TagType, TK, StartLoc, SS, Name, NameLoc, Attr, Action::MultiTemplateParamsArg(Actions, diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index fb60bde4f1..50e6657ad8 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -42,6 +42,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { return true; } + bool HasScopeSpecifier = false; + if (Tok.is(tok::coloncolon)) { // ::new and ::delete aren't nested-name-specifiers. tok::TokenKind NextKind = NextToken().getKind(); @@ -53,32 +55,132 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { SS.setBeginLoc(CCLoc); SS.setScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(CurScope, CCLoc)); SS.setEndLoc(CCLoc); - } else if (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) { - SS.setBeginLoc(Tok.getLocation()); - } else { - // Not a CXXScopeSpecifier. - return false; + HasScopeSpecifier = true; } - // nested-name-specifier: - // type-name '::' - // namespace-name '::' - // nested-name-specifier identifier '::' - // nested-name-specifier 'template'[opt] simple-template-id '::' [TODO] - while (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) { - IdentifierInfo *II = Tok.getIdentifierInfo(); - SourceLocation IdLoc = ConsumeToken(); - assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); - SourceLocation CCLoc = ConsumeToken(); - if (SS.isInvalid()) + while (true) { + // nested-name-specifier: + // type-name '::' + // namespace-name '::' + // nested-name-specifier identifier '::' + if (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) { + // We have an identifier followed by a '::'. Lookup this name + // as the name in a nested-name-specifier. + IdentifierInfo *II = Tok.getIdentifierInfo(); + SourceLocation IdLoc = ConsumeToken(); + assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); + SourceLocation CCLoc = ConsumeToken(); + + if (!HasScopeSpecifier) { + SS.setBeginLoc(IdLoc); + HasScopeSpecifier = true; + } + + if (SS.isInvalid()) + continue; + + SS.setScopeRep( + Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, *II)); + SS.setEndLoc(CCLoc); continue; + } - SS.setScopeRep( - Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, *II)); - SS.setEndLoc(CCLoc); - } + // nested-name-specifier: + // type-name '::' + // nested-name-specifier 'template'[opt] simple-template-id '::' + if ((Tok.is(tok::identifier) && NextToken().is(tok::less)) || + Tok.is(tok::kw_template)) { + // Parse the optional 'template' keyword, then make sure we have + // 'identifier <' after it. + SourceLocation TemplateKWLoc; + if (Tok.is(tok::kw_template)) { + TemplateKWLoc = ConsumeToken(); + + if (Tok.isNot(tok::identifier)) { + Diag(Tok.getLocation(), + diag::err_id_after_template_in_nested_name_spec) + << SourceRange(TemplateKWLoc); + break; + } + + if (NextToken().isNot(tok::less)) { + Diag(NextToken().getLocation(), + diag::err_less_after_template_name_in_nested_name_spec) + << Tok.getIdentifierInfo()->getName() + << SourceRange(TemplateKWLoc, Tok.getLocation()); + break; + } + } + else { + // FIXME: If the nested-name-specifier thus far is dependent, + // we need to break out of here, because this '<' is taken as + // an operator and not as part of a simple-template-id. + } + + DeclTy *Template = 0; + TemplateNameKind TNK = TNK_Non_template; + // FIXME: If the nested-name-specifier thus far is dependent, + // set TNK = TNK_Dependent_template_name and skip the + // "isTemplateName" check. + TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(), + CurScope, Template, &SS); + if (TNK) { + // We have found a template name, so annotate this this token + // with a template-id annotation. We do not permit the + // template-id to be translated into a type annotation, + // because some clients (e.g., the parsing of class template + // specializations) still want to see the original template-id + // token. + AnnotateTemplateIdToken(Template, TNK, &SS, TemplateKWLoc, false); + continue; + } + } + + if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) { + // We have + // + // simple-template-id '::' + // + // So we need to check whether the simple-template-id is of the + // right kind (it should name a type), and then convert it into + // a type within the nested-name-specifier. + TemplateIdAnnotation *TemplateId + = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + + if (TemplateId->Kind == TNK_Class_template) { + if (AnnotateTemplateIdTokenAsType(&SS)) + SS.setScopeRep(0); + + assert(Tok.is(tok::annot_typename) && + "AnnotateTemplateIdTokenAsType isn't working"); + + Token TypeToken = Tok; + ConsumeToken(); + assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); + SourceLocation CCLoc = ConsumeToken(); + + if (!HasScopeSpecifier) { + SS.setBeginLoc(TypeToken.getLocation()); + HasScopeSpecifier = true; + } - return true; + SS.setScopeRep( + Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, + TypeToken.getAnnotationValue(), + TypeToken.getAnnotationRange(), + CCLoc)); + SS.setEndLoc(CCLoc); + continue; + } else + assert(false && "FIXME: Only class template names supported here"); + } + + // We don't have any tokens that form the beginning of a + // nested-name-specifier, so we're done. + break; + } + + return HasScopeSpecifier; } /// ParseCXXIdExpression - Handle id-expression. diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 747a4de152..64fc8fdf47 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -444,16 +444,49 @@ Parser::ParseTemplateIdAfterTemplateName(DeclTy *Template, return false; } -/// AnnotateTemplateIdToken - The current token is an identifier that -/// refers to the template declaration Template, and is followed by a -/// '<'. Turn this template-id into a template-id annotation token. +/// \brief Replace the tokens that form a simple-template-id with an +/// annotation token containing the complete template-id. +/// +/// The first token in the stream must be the name of a template that +/// is followed by a '<'. This routine will parse the complete +/// simple-template-id and replace the tokens with a single annotation +/// token with one of two different kinds: if the template-id names a +/// type (and \p AllowTypeAnnotation is true), the annotation token is +/// a type annotation that includes the optional nested-name-specifier +/// (\p SS). Otherwise, the annotation token is a template-id +/// annotation that does not include the optional +/// nested-name-specifier. +/// +/// \param Template the declaration of the template named by the first +/// token (an identifier), as returned from \c Action::isTemplateName(). +/// +/// \param TemplateNameKind the kind of template that \p Template +/// refers to, as returned from \c Action::isTemplateName(). +/// +/// \param SS if non-NULL, the nested-name-specifier that precedes +/// this template name. +/// +/// \param TemplateKWLoc if valid, specifies that this template-id +/// annotation was preceded by the 'template' keyword and gives the +/// location of that keyword. If invalid (the default), then this +/// template-id was not preceded by a 'template' keyword. +/// +/// \param AllowTypeAnnotation if true (the default), then a +/// simple-template-id that refers to a class template, template +/// template parameter, or other template that produces a type will be +/// replaced with a type annotation token. Otherwise, the +/// simple-template-id is always replaced with a template-id +/// annotation token. void Parser::AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK, - const CXXScopeSpec *SS) { + const CXXScopeSpec *SS, + SourceLocation TemplateKWLoc, + bool AllowTypeAnnotation) { assert(getLang().CPlusPlus && "Can only annotate template-ids in C++"); assert(Template && Tok.is(tok::identifier) && NextToken().is(tok::less) && "Parser isn't at the beginning of a template-id"); // Consume the template-name. + IdentifierInfo *Name = Tok.getIdentifierInfo(); SourceLocation TemplateNameLoc = ConsumeToken(); // Parse the enclosed template argument list. @@ -476,7 +509,7 @@ void Parser::AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK, return; // Build the annotation token. - if (TNK == Action::TNK_Class_template) { + if (TNK == TNK_Class_template && AllowTypeAnnotation) { Action::TypeResult Type = Actions.ActOnClassTemplateId(Template, TemplateNameLoc, LAngleLoc, TemplateArgsPtr, @@ -487,34 +520,96 @@ void Parser::AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK, Tok.setKind(tok::annot_typename); Tok.setAnnotationValue(Type.get()); + if (SS && SS->isNotEmpty()) + Tok.setLocation(SS->getBeginLoc()); + else if (TemplateKWLoc.isValid()) + Tok.setLocation(TemplateKWLoc); + else + Tok.setLocation(TemplateNameLoc); } else { // This is a function template. We'll be building a template-id // annotation token. - Tok.setKind(tok::annot_template_id); + Tok.setKind(tok::annot_template_id); TemplateIdAnnotation *TemplateId - = (TemplateIdAnnotation *)malloc(sizeof(TemplateIdAnnotation) + - sizeof(void*) * TemplateArgs.size()); + = TemplateIdAnnotation::Allocate(TemplateArgs.size()); TemplateId->TemplateNameLoc = TemplateNameLoc; + TemplateId->Name = Name; TemplateId->Template = Template; + TemplateId->Kind = TNK; TemplateId->LAngleLoc = LAngleLoc; - TemplateId->NumArgs = TemplateArgs.size(); - void **Args = (void**)(TemplateId + 1); - for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg) + TemplateId->RAngleLoc = RAngleLoc; + void **Args = TemplateId->getTemplateArgs(); + bool *ArgIsType = TemplateId->getTemplateArgIsType(); + SourceLocation *ArgLocs = TemplateId->getTemplateArgLocations(); + for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg) { Args[Arg] = TemplateArgs[Arg]; + ArgIsType[Arg] = TemplateArgIsType[Arg]; + ArgLocs[Arg] = TemplateArgLocations[Arg]; + } Tok.setAnnotationValue(TemplateId); + if (TemplateKWLoc.isValid()) + Tok.setLocation(TemplateKWLoc); + else + Tok.setLocation(TemplateNameLoc); + + TemplateArgsPtr.release(); } // Common fields for the annotation token Tok.setAnnotationEndLoc(RAngleLoc); - Tok.setLocation(TemplateNameLoc); - if (SS && SS->isNotEmpty()) - Tok.setLocation(SS->getBeginLoc()); // In case the tokens were cached, have Preprocessor replace them with the // annotation token. PP.AnnotateCachedTokens(Tok); } +/// \brief Replaces a template-id annotation token with a type +/// annotation token. +/// +/// \returns true if there was an error, false otherwise. +bool Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) { + assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens"); + + TemplateIdAnnotation *TemplateId + = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + assert(TemplateId->Kind == TNK_Class_template && + "Only works for class templates"); + + ASTTemplateArgsPtr TemplateArgsPtr(Actions, + TemplateId->getTemplateArgs(), + TemplateId->getTemplateArgIsType(), + TemplateId->NumArgs); + + Action::TypeResult Type + = Actions.ActOnClassTemplateId(TemplateId->Template, + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->getTemplateArgLocations(), + TemplateId->RAngleLoc, SS); + if (Type.isInvalid()) { + // FIXME: better recovery? + ConsumeToken(); + TemplateId->Destroy(); + return true; + } + + // Create the new "type" annotation token. + Tok.setKind(tok::annot_typename); + Tok.setAnnotationValue(Type.get()); + if (SS && SS->isNotEmpty()) // it was a C++ qualified type name. + Tok.setLocation(SS->getBeginLoc()); + + // We might be backtracking, in which case we need to replace the + // template-id annotation token with the type annotation within the + // set of cached tokens. That way, we won't try to form the same + // class template specialization again. + PP.ReplaceLastTokenWithAnnotation(Tok); + TemplateId->Destroy(); + + return false; +} + /// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]). /// /// template-argument: [C++ 14.2] diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 7b09d2105c..a3ed027846 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -778,31 +778,41 @@ bool Parser::TryAnnotateTypeOrScopeToken() { // them with the annotation token. PP.AnnotateCachedTokens(Tok); return true; - } else if (!getLang().CPlusPlus) { + } + + if (!getLang().CPlusPlus) { // If we're in C, we can't have :: tokens at all (the lexer won't return // them). If the identifier is not a type, then it can't be scope either, // just early exit. return false; } - // If this is a template-id, annotate the template-id token. + // If this is a template-id, annotate with a template-id or type token. if (NextToken().is(tok::less)) { DeclTy *Template; if (TemplateNameKind TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(), - CurScope, Template, &SS)) { + CurScope, Template, &SS)) AnnotateTemplateIdToken(Template, TNK, &SS); - return true; - } } - // We either have an identifier that is not a type name or we have - // just created a template-id that might be a type name. Both - // cases will be handled below. + // The current token, which is either an identifier or a + // template-id, is not part of the annotation. Fall through to + // push that token back into the stream and complete the C++ scope + // specifier annotation. } - // FIXME: check for a template-id token here, and look it up if it - // names a type. + if (Tok.is(tok::annot_template_id)) { + TemplateIdAnnotation *TemplateId + = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + if (TemplateId->Kind == TNK_Class_template) { + // A template-id that refers to a type was parsed into a + // template-id annotation in a context where we weren't allowed + // to produce a type annotation token. Update the template-id + // annotation token to a type annotation token now. + return !AnnotateTemplateIdTokenAsType(&SS); + } + } if (SS.isEmpty()) return false; @@ -825,8 +835,8 @@ bool Parser::TryAnnotateTypeOrScopeToken() { } /// TryAnnotateScopeToken - Like TryAnnotateTypeOrScopeToken but only -/// annotates C++ scope specifiers. This returns true if the token was -/// annotated. +/// annotates C++ scope specifiers and template-ids. This returns +/// true if the token was annotated. /// /// Note that this routine emits an error if you call it with ::new or ::delete /// as the current tokens, so only call it in contexts where these are invalid. @@ -838,7 +848,7 @@ bool Parser::TryAnnotateCXXScopeToken() { CXXScopeSpec SS; if (!ParseOptionalCXXScopeSpecifier(SS)) - return false; + return Tok.is(tok::annot_template_id); // Push the current token back into the token stream (or revert it if it is // cached) and use an annotation scope token for current token. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 7ee6e22bca..fed2bbdf7c 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1338,6 +1338,20 @@ public: SourceLocation CCLoc, IdentifierInfo &II); + /// ActOnCXXNestedNameSpecifier - Called during parsing of a + /// nested-name-specifier that involves a template-id, e.g., + /// "foo::bar<int, float>::", and now we need to build a scope + /// specifier. \p SS is empty or the previously parsed nested-name + /// part ("foo::"), \p Type is the already-parsed class template + /// specialization (or other template-id that names a type), \p + /// TypeRange is the source range where the type is located, and \p + /// CCLoc is the location of the trailing '::'. + virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S, + const CXXScopeSpec &SS, + TypeTy *Type, + SourceRange TypeRange, + SourceLocation CCLoc); + /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global /// scope or nested-name-specifier) is parsed, part of a declarator-id. /// After this method is called, according to [C++ 3.4.3p3], names should be diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 0d8844f95a..c8a86cfd7d 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -74,6 +74,17 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, return 0; } +Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, + const CXXScopeSpec &SS, + TypeTy *Ty, + SourceRange TypeRange, + SourceLocation CCLoc) { + QualType Type = QualType::getFromOpaquePtr(Ty); + assert(Type->isRecordType() && + "Types in a nested-name-specifier always refer to a record type"); + return cast<DeclContext>(Type->getAsRecordType()->getDecl()); +} + /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global /// scope or nested-name-specifier) is parsed, part of a declarator-id. /// After this method is called, according to [C++ 3.4.3p3], names should be diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 223094b066..e3538e8a4c 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -26,9 +26,9 @@ using namespace clang; /// declaration if II names a template. An optional CXXScope can be /// passed to indicate the C++ scope in which the identifier will be /// found. -Sema::TemplateNameKind Sema::isTemplateName(IdentifierInfo &II, Scope *S, - DeclTy *&Template, - const CXXScopeSpec *SS) { +TemplateNameKind Sema::isTemplateName(IdentifierInfo &II, Scope *S, + DeclTy *&Template, + const CXXScopeSpec *SS) { NamedDecl *IIDecl = LookupParsedName(S, SS, &II, LookupOrdinaryName); if (IIDecl) { diff --git a/test/SemaTemplate/class-template-spec.cpp b/test/SemaTemplate/class-template-spec.cpp index 9347bf5997..86cd52c3e3 100644 --- a/test/SemaTemplate/class-template-spec.cpp +++ b/test/SemaTemplate/class-template-spec.cpp @@ -40,3 +40,5 @@ void testme(X<int_type> *x1, X<float, int> *x2) { x1->foo(); // okay: refers to #1 x2->bar(); // okay: refers to #2 } + +// FIXME: diagnose specializations in a different namespace diff --git a/test/SemaTemplate/default-arguments.cpp b/test/SemaTemplate/default-arguments.cpp index 94976e9735..cc0da1942d 100644 --- a/test/SemaTemplate/default-arguments.cpp +++ b/test/SemaTemplate/default-arguments.cpp @@ -5,8 +5,7 @@ template<typename T, int N = 2> struct X; // expected-note{{template is declared X<int, 1> *x1; X<int> *x2; -X<> *x3; // expected-error{{too few template arguments for class template 'X'}} \ - // FIXME: expected-error{{expected unqualified-id}} +X<> *x3; // expected-error{{too few template arguments for class template 'X'}} template<typename U = float, int M> struct X; diff --git a/test/SemaTemplate/nested-name-spec-template.cpp b/test/SemaTemplate/nested-name-spec-template.cpp new file mode 100644 index 0000000000..4007f232c4 --- /dev/null +++ b/test/SemaTemplate/nested-name-spec-template.cpp @@ -0,0 +1,50 @@ +// RUN: clang -fsyntax-only -verify %s + +namespace N { + namespace M { + template<typename T> struct Promote; // expected-note{{previous definition is here}} + + template<> struct Promote<short> { + typedef int type; + }; + + template<> struct Promote<int> { + typedef int type; + }; + + template<> struct Promote<float> { + typedef double type; + }; + + Promote<short>::type *ret_intptr(int* ip) { return ip; } + Promote<int>::type *ret_intptr2(int* ip) { return ip; } + } + + M::Promote<int>::type *ret_intptr3(int* ip) { return ip; } + M::template Promote<int>::type *ret_intptr4(int* ip) { return ip; } +} + +N::M::Promote<int>::type *ret_intptr5(int* ip) { return ip; } +::N::M::Promote<int>::type *ret_intptr6(int* ip) { return ip; } + + +N::M::template; // expected-error{{expected template name after 'template' keyword in nested name specifier}} \ + // expected-error{{expected unqualified-id}} + +N::M::template Promote; // expected-error{{expected '<' after 'template Promote' in nested name specifier}} \ +// expected-error{{C++ requires a type specifier for all declarations}} \ +// expected-error{{redefinition of 'Promote' as different kind of symbol}} \ +// expected-error{{no member named 'Promote'}} + +namespace N { + template<typename T> struct A; + + template<> + struct A<int> { + struct X; + }; +} + +struct ::N::A<int>::X { + int foo; +}; diff --git a/test/SemaTemplate/temp_arg.cpp b/test/SemaTemplate/temp_arg.cpp index b8bb279caf..b974c622a4 100644 --- a/test/SemaTemplate/temp_arg.cpp +++ b/test/SemaTemplate/temp_arg.cpp @@ -8,7 +8,5 @@ template<typename> class X; A<int, 0, X> * a1; -A<float, 1, X, double> *a2; // expected-error{{too many template arguments for class template 'A'}} \ - // expected-error{{unqualified-id}} -A<float, 1> *a3; // expected-error{{too few template arguments for class template 'A'}} \ - // expected-error{{unqualified-id}} +A<float, 1, X, double> *a2; // expected-error{{too many template arguments for class template 'A'}} +A<float, 1> *a3; // expected-error{{too few template arguments for class template 'A'}} diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp index 89dbf237b3..d67cc4e409 100644 --- a/test/SemaTemplate/temp_arg_nontype.cpp +++ b/test/SemaTemplate/temp_arg_nontype.cpp @@ -3,26 +3,21 @@ template<int N> struct A; // expected-note 5{{template parameter is declared her A<0> *a0; -A<int()> *a1; // expected-error{{template argument for non-type template parameter is treated as type 'int (void)'}} \ - // FIXME: expected-error{{unqualified-id}} +A<int()> *a1; // expected-error{{template argument for non-type template parameter is treated as type 'int (void)'}} -A<int> *a2; // expected-error{{template argument for non-type template parameter must be an expression}} \ - // FIXME: expected-error{{unqualified-id}} +A<int> *a2; // expected-error{{template argument for non-type template parameter must be an expression}} A<1 >> 2> *a3; // C++ [temp.arg.nontype]p5: A<A> *a4; // expected-error{{must have an integral or enumeration type}} \ - // FIXME: the error message above is a bit lame \ - // FIXME: expected-error{{expected unqualified-id}} + // FIXME: the error message above is a bit lame enum E { Enumerator = 17 }; -A<E> *a5; // expected-error{{template argument for non-type template parameter must be an expression}} \ - // FIXME: expected-error{{unqualified-id}} +A<E> *a5; // expected-error{{template argument for non-type template parameter must be an expression}} template<E Value> struct A1; // expected-note{{template parameter is declared here}} A1<Enumerator> *a6; // okay -A1<17> *a7; // expected-error{{non-type template argument of type 'int' cannot be converted to a value of type 'enum E'}} \ - // FIXME: expected-error{{expected unqualified-id}} +A1<17> *a7; // expected-error{{non-type template argument of type 'int' cannot be converted to a value of type 'enum E'}} const long LongValue = 12345678; A<LongValue> *a8; @@ -30,8 +25,7 @@ const short ShortValue = 17; A<ShortValue> *a9; int f(int); -A<f(17)> *a10; // expected-error{{non-type template argument of type 'int' is not an integral constant expression}} \ - // FIXME: expected-error{{expected unqualified-id}} +A<f(17)> *a10; // expected-error{{non-type template argument of type 'int' is not an integral constant expression}} class X { public: @@ -39,8 +33,7 @@ public: X(int, int); operator int() const; }; -A<X(17, 42)> *a11; // expected-error{{non-type template argument of type 'class X' must have an integral or enumeration type}} \ - // FIXME:expected-error{{expected unqualified-id}} +A<X(17, 42)> *a11; // expected-error{{non-type template argument of type 'class X' must have an integral or enumeration type}} template<X const *Ptr> struct A2; @@ -50,8 +43,7 @@ X array_of_Xs[10]; A2<X_ptr> *a12; A2<array_of_Xs> *a13; A2<&an_X> *a13_2; -A2<(&an_X)> *a13_2; // expected-error{{non-type template argument cannot be surrounded by parentheses}} \ - // FIXME: expected-error{{unqualified-id}} +A2<(&an_X)> *a13_3; // expected-error{{non-type template argument cannot be surrounded by parentheses}} float f(float); @@ -66,10 +58,8 @@ A3<h> *a14_1; A3<&h> *a14_2; A3<f> *a14_3; A3<&f> *a14_4; -A3<h2> *a14_6; // expected-error{{non-type template argument of type 'float (*)(float)' cannot be converted to a value of type 'int (*)(int)'}} \ -// FIXME: expected-error{{expected unqualified-id}} -A3<g> *a14_7; // expected-error{{non-type template argument of type '<overloaded function type>' cannot be converted to a value of type 'int (*)(int)'}}\ -// FIXME: expected-error{{expected unqualified-id}} +A3<h2> *a14_6; // expected-error{{non-type template argument of type 'float (*)(float)' cannot be converted to a value of type 'int (*)(int)'}} +A3<g> *a14_7; // expected-error{{non-type template argument of type '<overloaded function type>' cannot be converted to a value of type 'int (*)(int)'}} // FIXME: the first error includes the string <overloaded function // type>, which makes Doug slightly unhappy. @@ -79,18 +69,15 @@ struct Y { } y; volatile X * X_volatile_ptr; template<X const &AnX> struct A4; // expected-note 2{{template parameter is declared here}} A4<an_X> *a15_1; // okay -A4<*X_volatile_ptr> *a15_2; // expected-error{{reference binding of non-type template parameter of type 'class X const &' to template argument of type 'class X volatile' ignores qualifiers}} \ - // FIXME: expected-error{{expected unqualified-id}} -A4<y> *15_3; // expected-error{{non-type template parameter of reference type 'class X const &' cannot bind to template argument of type 'struct Y'}}\ - // FIXME: expected-error{{expected unqualified-id}} +A4<*X_volatile_ptr> *a15_2; // expected-error{{reference binding of non-type template parameter of type 'class X const &' to template argument of type 'class X volatile' ignores qualifiers}} +A4<y> *15_3; // expected-error{{non-type template parameter of reference type 'class X const &' cannot bind to template argument of type 'struct Y'}} \ + // FIXME: expected-error{{expected unqualified-id}} template<int (&fr)(int)> struct A5; // expected-note 2{{template parameter is declared here}} A5<h> *a16_1; A5<f> *a16_3; -A5<h2> *a16_6; // expected-error{{non-type template argument of type 'float (float)' cannot be converted to a value of type 'int (&)(int)'}} \ -// FIXME: expected-error{{expected unqualified-id}} -A5<g> *a14_7; // expected-error{{non-type template argument of type '<overloaded function type>' cannot be converted to a value of type 'int (&)(int)'}}\ -// FIXME: expected-error{{expected unqualified-id}} +A5<h2> *a16_6; // expected-error{{non-type template argument of type 'float (float)' cannot be converted to a value of type 'int (&)(int)'}} +A5<g> *a14_7; // expected-error{{non-type template argument of type '<overloaded function type>' cannot be converted to a value of type 'int (&)(int)'}} // FIXME: the first error includes the string <overloaded function // type>, which makes Doug slightly unhappy. @@ -106,15 +93,12 @@ struct Z { template<int (Z::*pmf)(int)> struct A6; // expected-note{{template parameter is declared here}} A6<&Z::foo> *a17_1; A6<&Z::bar> *a17_2; -A6<&Z::baz> *a17_3; // expected-error{{non-type template argument of type 'double (struct Z::*)(double)' cannot be converted to a value of type 'int (struct Z::*)(int)'}} \ -// FIXME: expected-error{{expected unqualified-id}} +A6<&Z::baz> *a17_3; // expected-error{{non-type template argument of type 'double (struct Z::*)(double)' cannot be converted to a value of type 'int (struct Z::*)(int)'}} template<int Z::*pm> struct A7; // expected-note{{template parameter is declared here}} template<int Z::*pm> struct A7c; A7<&Z::int_member> *a18_1; A7c<&Z::int_member> *a18_2; -A7<&Z::float_member> *a18_3; // expected-error{{non-type template argument of type 'float struct Z::*' cannot be converted to a value of type 'int struct Z::*'}} \ - // FIXME: expected-error{{unqualified-id}} -A7c<(&Z::int_member)> *a18_3; // expected-error{{non-type template argument cannot be surrounded by parentheses}} \ - // FIXME: expected-error{{expected unqualified-id}} +A7<&Z::float_member> *a18_3; // expected-error{{non-type template argument of type 'float struct Z::*' cannot be converted to a value of type 'int struct Z::*'}} +A7c<(&Z::int_member)> *a18_3; // expected-error{{non-type template argument cannot be surrounded by parentheses}} diff --git a/test/SemaTemplate/temp_arg_template.cpp b/test/SemaTemplate/temp_arg_template.cpp index e1b9bb4874..781ada9cfe 100644 --- a/test/SemaTemplate/temp_arg_template.cpp +++ b/test/SemaTemplate/temp_arg_template.cpp @@ -20,23 +20,18 @@ A<X> *a1; A<N::Z> *a2; A< ::N::Z> *a3; -A<Y> *a4; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} \ - // FIXME::expected-error{{expected unqualified-id}} -A<TooMany> *a5; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} \ - // FIXME::expected-error{{expected unqualified-id}} -B<X> *a6; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} \ - // FIXME::expected-error{{expected unqualified-id}} +A<Y> *a4; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} +A<TooMany> *a5; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} +B<X> *a6; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} C<Y> *a7; -C<Ylong> *a8; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} \ - // FIXME::expected-error{{expected unqualified-id}} +C<Ylong> *a8; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} template<typename T> void f(int); // FIXME: we're right to provide an error message, but it should say // that we need a class template. We won't get this right until name // lookup of 'f' returns a TemplateDecl. -A<f> *a9; // expected-error{{template argument for template template parameter must be a template}} \ - // expected-error{{unqualified-id}} +A<f> *a9; // expected-error{{template argument for template template parameter must be a template}} // FIXME: The code below is ill-formed, because of the evil digraph '<:'. // We should provide a much better error message than we currently do. diff --git a/test/SemaTemplate/temp_arg_type.cpp b/test/SemaTemplate/temp_arg_type.cpp index 36764fc8e4..216a283e2e 100644 --- a/test/SemaTemplate/temp_arg_type.cpp +++ b/test/SemaTemplate/temp_arg_type.cpp @@ -2,11 +2,9 @@ template<typename T> class A; // expected-note 2 {{template parameter is declared here}} // [temp.arg.type]p1 -A<0> *a1; // expected-error{{template argument for template type parameter must be a type}} \ - // expected-error{{unqualified-id}} +A<0> *a1; // expected-error{{template argument for template type parameter must be a type}} -A<A> *a2; // expected-error{{template argument for template type parameter must be a type}} \ - // expected-error{{unqualified-id}} +A<A> *a2; // expected-error{{template argument for template type parameter must be a type}} A<int> *a3; A<int()> *a4; @@ -16,13 +14,12 @@ A<A<int> > *a6; // [temp.arg.type]p2 void f() { class X { }; - A<X> * a = 0; // expected-error{{template argument uses local type 'class X'}}\ - // FIXME: expected-error{{expected expression}} + A<X> * a = 0; // expected-error{{template argument uses local type 'class X'}} \ + // FIXME: expected-error{{use of undeclared identifier 'a'}} } struct { int x; } Unnamed; // expected-note{{unnamed type used in template argument was declared here}} -A<__typeof__(Unnamed)> *a7; // expected-error{{template argument uses unnamed type}} \ - // FIXME: expected-error{{expected unqualified-id}} +A<__typeof__(Unnamed)> *a7; // expected-error{{template argument uses unnamed type}} // FIXME: [temp.arg.type]p3. The check doesn't really belong here (it // belongs somewhere in the template instantiation section). |