[cfe-commits] r85966 - in /cfe/trunk: include/clang/Basic/DiagnosticParseKinds.td include/clang/Lex/Token.h include/clang/Parse/Action.h include/clang/Parse/DeclSpec.h lib/Parse/MinimalAction.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/Parser.cpp lib/Sema/Sema.h lib/Sema/SemaTemplate.cpp lib/Sema/TreeTransform.h test/SemaTemplate/operator-function-id-template.cpp
Douglas Gregor
dgregor at apple.com
Tue Nov 3 15:16:33 PST 2009
Author: dgregor
Date: Tue Nov 3 17:16:33 2009
New Revision: 85966
URL: http://llvm.org/viewvc/llvm-project?rev=85966&view=rev
Log:
Parsing and semantic analysis for template-ids that name overloaded
operators, e.g.,
operator+<int>
which now works in declarators, id-expressions, and member access
expressions. This commit only implements the non-dependent case, where
we can resolve the template-id to an actual declaration.
Added:
cfe/trunk/test/SemaTemplate/operator-function-id-template.cpp
Modified:
cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
cfe/trunk/include/clang/Lex/Token.h
cfe/trunk/include/clang/Parse/Action.h
cfe/trunk/include/clang/Parse/DeclSpec.h
cfe/trunk/lib/Parse/MinimalAction.cpp
cfe/trunk/lib/Parse/ParseExprCXX.cpp
cfe/trunk/lib/Parse/Parser.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/TreeTransform.h
Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=85966&r1=85965&r2=85966&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Tue Nov 3 17:16:33 2009
@@ -295,8 +295,6 @@
// C++ declarations
def err_friend_decl_defines_class : Error<
"cannot define a type in a friend declaration">;
-def warn_operator_template_id_ignores_args : Error<
- "clang bug: ignoring template arguments provided for operator">;
// Language specific pragmas
// - Generic warnings
Modified: cfe/trunk/include/clang/Lex/Token.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Token.h?rev=85966&r1=85965&r2=85966&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Token.h (original)
+++ cfe/trunk/include/clang/Lex/Token.h Tue Nov 3 17:16:33 2009
@@ -17,6 +17,7 @@
#include "clang/Basic/TemplateKinds.h"
#include "clang/Basic/TokenKinds.h"
#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/OperatorKinds.h"
#include <cstdlib>
namespace clang {
@@ -261,6 +262,9 @@
/// FIXME: Temporarily stores the name of a specialization
IdentifierInfo *Name;
+ /// FIXME: Temporarily stores the overloaded operator kind.
+ OverloadedOperatorKind Operator;
+
/// The declaration of the template corresponding to the
/// template-name. This is an Action::DeclTy*.
void *Template;
Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=85966&r1=85965&r2=85966&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Tue Nov 3 17:16:33 2009
@@ -236,30 +236,36 @@
virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S,
const CXXScopeSpec *SS = 0) = 0;
- /// \brief Determine whether the given identifier refers to the name of a
+ /// \brief Determine whether the given name refers to a template.
+ ///
+ /// This callback is used by the parser after it has seen a '<' to determine
+ /// whether the given name refers to a template and, if so, what kind of
/// template.
///
- /// \param S the scope in which name lookup occurs
+ /// \param S the scope in which the name occurs.
///
- /// \param II the identifier that we are querying to determine whether it
- /// is a template.
+ /// \param SS the C++ nested-name-specifier that precedes the template name,
+ /// if any.
///
- /// \param IdLoc the source location of the identifier
+ /// \param Name the name that we are querying to determine whether it is
+ /// a template.
///
- /// \param SS the C++ scope specifier that precedes the template name, if
- /// any.
+ /// \param ObjectType if we are determining whether the given name is a
+ /// template name in the context of a member access expression (e.g.,
+ /// \c p->X<int>), this is the type of the object referred to by the
+ /// member access (e.g., \c p).
///
/// \param EnteringContext whether we are potentially entering the context
- /// referred to by the scope specifier \p SS
+ /// referred to by the nested-name-specifier \p SS, which allows semantic
+ /// analysis to look into uninstantiated templates.
///
/// \param Template if the name does refer to a template, the declaration
/// of the template that the name refers to.
///
/// \returns the kind of template that this name refers to.
virtual TemplateNameKind isTemplateName(Scope *S,
- const IdentifierInfo &II,
- SourceLocation IdLoc,
- const CXXScopeSpec *SS,
+ const CXXScopeSpec &SS,
+ UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringContext,
TemplateTy &Template) = 0;
@@ -1616,22 +1622,19 @@
///
/// \param TemplateKWLoc the location of the "template" keyword (if any).
///
- /// \param Name the name of the template (an identifier)
- ///
- /// \param NameLoc the location of the identifier
- ///
/// \param SS the nested-name-specifier that precedes the "template" keyword
- /// or the template name. FIXME: If the dependent template name occurs in
+ /// or the template name. If the dependent template name occurs in
/// a member access expression, e.g., "x.template f<T>", this
/// nested-name-specifier will be empty.
///
+ /// \param Name the name of the template.
+ ///
/// \param ObjectType if this dependent template name occurs in the
/// context of a member access expression, the type of the object being
/// accessed.
virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
- const IdentifierInfo &Name,
- SourceLocation NameLoc,
const CXXScopeSpec &SS,
+ UnqualifiedId &Name,
TypeTy *ObjectType) {
return TemplateTy();
}
@@ -2333,13 +2336,12 @@
const CXXScopeSpec *SS);
virtual TemplateNameKind isTemplateName(Scope *S,
- const IdentifierInfo &II,
- SourceLocation IdLoc,
- const CXXScopeSpec *SS,
+ const CXXScopeSpec &SS,
+ UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringContext,
TemplateTy &Template);
-
+
/// ActOnDeclarator - If this is a typedef declarator, we modify the
/// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is
/// popped.
Modified: cfe/trunk/include/clang/Parse/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/DeclSpec.h?rev=85966&r1=85965&r2=85966&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Parse/DeclSpec.h Tue Nov 3 17:16:33 2009
@@ -561,9 +561,9 @@
///
/// \param Id the parsed identifier.
/// \param IdLoc the location of the parsed identifier.
- void setIdentifier(IdentifierInfo *Id, SourceLocation IdLoc) {
+ void setIdentifier(const IdentifierInfo *Id, SourceLocation IdLoc) {
Kind = IK_Identifier;
- Identifier = Id;
+ Identifier = const_cast<IdentifierInfo *>(Id);
StartLocation = EndLocation = IdLoc;
}
Modified: cfe/trunk/lib/Parse/MinimalAction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/MinimalAction.cpp?rev=85966&r1=85965&r2=85966&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/MinimalAction.cpp (original)
+++ cfe/trunk/lib/Parse/MinimalAction.cpp Tue Nov 3 17:16:33 2009
@@ -161,9 +161,8 @@
TemplateNameKind
MinimalAction::isTemplateName(Scope *S,
- const IdentifierInfo &II,
- SourceLocation IdLoc,
- const CXXScopeSpec *SS,
+ const CXXScopeSpec &SS,
+ UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringScope,
TemplateTy &TemplateDecl) {
Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=85966&r1=85965&r2=85966&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Tue Nov 3 17:16:33 2009
@@ -125,10 +125,10 @@
break;
}
+ UnqualifiedId TemplateName;
+ TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
TemplateTy Template
- = Actions.ActOnDependentTemplateName(TemplateKWLoc,
- *Tok.getIdentifierInfo(),
- Tok.getLocation(), SS,
+ = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, TemplateName,
ObjectType);
if (!Template)
break;
@@ -220,9 +220,10 @@
// type-name '<'
if (Next.is(tok::less)) {
TemplateTy Template;
- if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, II,
- Tok.getLocation(),
- &SS,
+ UnqualifiedId TemplateName;
+ TemplateName.setIdentifier(&II, Tok.getLocation());
+ if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS,
+ TemplateName,
ObjectType,
EnteringContext,
Template)) {
@@ -741,45 +742,30 @@
TemplateNameKind TNK = TNK_Non_template;
switch (Id.getKind()) {
case UnqualifiedId::IK_Identifier:
- TNK = Actions.isTemplateName(CurScope, *Id.Identifier, Id.StartLocation,
- &SS, ObjectType, EnteringContext, Template);
+ case UnqualifiedId::IK_OperatorFunctionId:
+ TNK = Actions.isTemplateName(CurScope, SS, Id, ObjectType, EnteringContext,
+ Template);
break;
- case UnqualifiedId::IK_OperatorFunctionId: {
- // FIXME: Temporary hack: warn that we are completely ignoring the
- // template arguments for now.
- // Parse the enclosed template argument list and throw it away.
- SourceLocation LAngleLoc, RAngleLoc;
- TemplateArgList TemplateArgs;
- TemplateArgIsTypeList TemplateArgIsType;
- TemplateArgLocationList TemplateArgLocations;
- if (ParseTemplateIdAfterTemplateName(Template, Id.StartLocation,
- &SS, true, LAngleLoc,
- TemplateArgs,
- TemplateArgIsType,
- TemplateArgLocations,
- RAngleLoc))
- return true;
-
- Diag(Id.StartLocation, diag::warn_operator_template_id_ignores_args)
- << SourceRange(LAngleLoc, RAngleLoc);
- break;
- }
-
- case UnqualifiedId::IK_ConstructorName:
- TNK = Actions.isTemplateName(CurScope, *Name, NameLoc, &SS, ObjectType,
+ case UnqualifiedId::IK_ConstructorName: {
+ UnqualifiedId TemplateName;
+ TemplateName.setIdentifier(Name, NameLoc);
+ TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType,
EnteringContext, Template);
break;
+ }
- case UnqualifiedId::IK_DestructorName:
+ case UnqualifiedId::IK_DestructorName: {
+ UnqualifiedId TemplateName;
+ TemplateName.setIdentifier(Name, NameLoc);
if (ObjectType) {
- Template = Actions.ActOnDependentTemplateName(SourceLocation(), *Name,
- NameLoc, SS, ObjectType);
+ Template = Actions.ActOnDependentTemplateName(SourceLocation(), SS,
+ TemplateName, ObjectType);
TNK = TNK_Dependent_template_name;
if (!Template.get())
return true;
} else {
- TNK = Actions.isTemplateName(CurScope, *Name, NameLoc, &SS, ObjectType,
+ TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType,
EnteringContext, Template);
if (TNK == TNK_Non_template && Id.DestructorName == 0) {
@@ -794,6 +780,7 @@
}
}
break;
+ }
default:
return false;
@@ -824,9 +811,12 @@
if (Id.getKind() == UnqualifiedId::IK_Identifier) {
TemplateId->Name = Id.Identifier;
+ TemplateId->Operator = OO_None;
TemplateId->TemplateNameLoc = Id.StartLocation;
} else {
- // FIXME: Handle IK_OperatorFunctionId
+ TemplateId->Name = 0;
+ TemplateId->Operator = Id.OperatorFunctionId.Operator;
+ TemplateId->TemplateNameLoc = Id.StartLocation;
}
TemplateId->Template = Template.getAs<void*>();
Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=85966&r1=85965&r2=85966&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Tue Nov 3 17:16:33 2009
@@ -935,9 +935,10 @@
// If this is a template-id, annotate with a template-id or type token.
if (NextToken().is(tok::less)) {
TemplateTy Template;
+ UnqualifiedId TemplateName;
+ TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
if (TemplateNameKind TNK
- = Actions.isTemplateName(CurScope, *Tok.getIdentifierInfo(),
- Tok.getLocation(), &SS,
+ = Actions.isTemplateName(CurScope, SS, TemplateName,
/*ObjectType=*/0, EnteringContext,
Template))
if (AnnotateTemplateIdToken(Template, TNK, &SS)) {
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=85966&r1=85965&r2=85966&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Nov 3 17:16:33 2009
@@ -2397,9 +2397,8 @@
// C++ Templates [C++ 14]
//
virtual TemplateNameKind isTemplateName(Scope *S,
- const IdentifierInfo &II,
- SourceLocation IdLoc,
- const CXXScopeSpec *SS,
+ const CXXScopeSpec &SS,
+ UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringContext,
TemplateTy &Template);
@@ -2499,9 +2498,8 @@
SourceLocation RAngleLoc);
virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
- const IdentifierInfo &Name,
- SourceLocation NameLoc,
const CXXScopeSpec &SS,
+ UnqualifiedId &Name,
TypeTy *ObjectType);
bool CheckClassTemplatePartialSpecializationArgs(
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=85966&r1=85965&r2=85966&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Nov 3 17:16:33 2009
@@ -98,29 +98,43 @@
}
TemplateNameKind Sema::isTemplateName(Scope *S,
- const IdentifierInfo &II,
- SourceLocation IdLoc,
- const CXXScopeSpec *SS,
+ const CXXScopeSpec &SS,
+ UnqualifiedId &Name,
TypeTy *ObjectTypePtr,
bool EnteringContext,
TemplateTy &TemplateResult) {
+ DeclarationName TName;
+
+ switch (Name.getKind()) {
+ case UnqualifiedId::IK_Identifier:
+ TName = DeclarationName(Name.Identifier);
+ break;
+
+ case UnqualifiedId::IK_OperatorFunctionId:
+ TName = Context.DeclarationNames.getCXXOperatorName(
+ Name.OperatorFunctionId.Operator);
+ break;
+
+ default:
+ return TNK_Non_template;
+ }
+
// Determine where to perform name lookup
DeclContext *LookupCtx = 0;
bool isDependent = false;
if (ObjectTypePtr) {
// This nested-name-specifier occurs in a member access expression, e.g.,
// x->B::f, and we are looking into the type of the object.
- assert((!SS || !SS->isSet()) &&
- "ObjectType and scope specifier cannot coexist");
+ assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr);
LookupCtx = computeDeclContext(ObjectType);
isDependent = ObjectType->isDependentType();
- } else if (SS && SS->isSet()) {
+ } else if (SS.isSet()) {
// This nested-name-specifier occurs after another nested-name-specifier,
// so long into the context associated with the prior nested-name-specifier.
- LookupCtx = computeDeclContext(*SS, EnteringContext);
- isDependent = isDependentScopeSpecifier(*SS);
+ LookupCtx = computeDeclContext(SS, EnteringContext);
+ isDependent = isDependentScopeSpecifier(SS);
}
LookupResult Found;
@@ -132,10 +146,10 @@
// nested-name-specifier.
// The declaration context must be complete.
- if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS))
+ if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS))
return TNK_Non_template;
- LookupQualifiedName(Found, LookupCtx, &II, LookupOrdinaryName);
+ LookupQualifiedName(Found, LookupCtx, TName, LookupOrdinaryName);
if (ObjectTypePtr && Found.getKind() == LookupResult::NotFound) {
// C++ [basic.lookup.classref]p1:
@@ -150,7 +164,7 @@
//
// FIXME: When we're instantiating a template, do we actually have to
// look in the scope of the template? Seems fishy...
- LookupName(Found, S, &II, LookupOrdinaryName);
+ LookupName(Found, S, TName, LookupOrdinaryName);
ObjectTypeSearchedInScope = true;
}
} else if (isDependent) {
@@ -158,7 +172,7 @@
return TNK_Non_template;
} else {
// Perform unqualified name lookup in the current scope.
- LookupName(Found, S, &II, LookupOrdinaryName);
+ LookupName(Found, S, TName, LookupOrdinaryName);
}
// FIXME: Cope with ambiguous name-lookup results.
@@ -177,7 +191,7 @@
// postfix-expression and [...]
//
LookupResult FoundOuter;
- LookupName(FoundOuter, S, &II, LookupOrdinaryName);
+ LookupName(FoundOuter, S, TName, LookupOrdinaryName);
// FIXME: Handle ambiguities in this lookup better
NamedDecl *OuterTemplate
= isAcceptableTemplateName(Context, FoundOuter.getAsSingleDecl(Context));
@@ -194,8 +208,10 @@
// entity as the one found in the class of the object expression,
// otherwise the program is ill-formed.
if (OuterTemplate->getCanonicalDecl() != Template->getCanonicalDecl()) {
- Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous)
- << &II;
+ Diag(Name.getSourceRange().getBegin(),
+ diag::err_nested_name_member_ref_lookup_ambiguous)
+ << TName
+ << Name.getSourceRange();
Diag(Template->getLocation(), diag::note_ambig_member_ref_object_type)
<< QualType::getFromOpaquePtr(ObjectTypePtr);
Diag(OuterTemplate->getLocation(), diag::note_ambig_member_ref_scope);
@@ -206,9 +222,9 @@
}
}
- if (SS && SS->isSet() && !SS->isInvalid()) {
+ if (SS.isSet() && !SS.isInvalid()) {
NestedNameSpecifier *Qualifier
- = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
if (OverloadedFunctionDecl *Ovl
= dyn_cast<OverloadedFunctionDecl>(Template))
TemplateResult
@@ -1345,9 +1361,8 @@
/// of the "template" keyword, and "apply" is the \p Name.
Sema::TemplateTy
Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
- const IdentifierInfo &Name,
- SourceLocation NameLoc,
const CXXScopeSpec &SS,
+ UnqualifiedId &Name,
TypeTy *ObjectType) {
if ((ObjectType &&
computeDeclContext(QualType::getFromOpaquePtr(ObjectType))) ||
@@ -1369,11 +1384,13 @@
// "template" keyword is now permitted). We follow the C++0x
// rules, even in C++03 mode, retroactively applying the DR.
TemplateTy Template;
- TemplateNameKind TNK = isTemplateName(0, Name, NameLoc, &SS, ObjectType,
+ TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType,
false, Template);
if (TNK == TNK_Non_template) {
- Diag(NameLoc, diag::err_template_kw_refers_to_non_template)
- << &Name;
+ Diag(Name.getSourceRange().getBegin(),
+ diag::err_template_kw_refers_to_non_template)
+ << GetNameFromUnqualifiedId(Name)
+ << Name.getSourceRange();
return TemplateTy();
}
@@ -1382,7 +1399,21 @@
NestedNameSpecifier *Qualifier
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
- return TemplateTy::make(Context.getDependentTemplateName(Qualifier, &Name));
+
+ switch (Name.getKind()) {
+ case UnqualifiedId::IK_Identifier:
+ return TemplateTy::make(Context.getDependentTemplateName(Qualifier,
+ Name.Identifier));
+
+ default:
+ break;
+ }
+
+ Diag(Name.getSourceRange().getBegin(),
+ diag::err_template_kw_refers_to_non_template)
+ << GetNameFromUnqualifiedId(Name)
+ << Name.getSourceRange();
+ return TemplateTy();
}
bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=85966&r1=85965&r2=85966&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Tue Nov 3 17:16:33 2009
@@ -5184,11 +5184,12 @@
CXXScopeSpec SS;
SS.setRange(SourceRange(getDerived().getBaseLocation()));
SS.setScopeRep(Qualifier);
+ UnqualifiedId Name;
+ Name.setIdentifier(&II, /*FIXME:*/getDerived().getBaseLocation());
return getSema().ActOnDependentTemplateName(
/*FIXME:*/getDerived().getBaseLocation(),
- II,
- /*FIXME:*/getDerived().getBaseLocation(),
SS,
+ Name,
ObjectType.getAsOpaquePtr())
.template getAsVal<TemplateName>();
}
Added: cfe/trunk/test/SemaTemplate/operator-function-id-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/operator-function-id-template.cpp?rev=85966&view=auto
==============================================================================
--- cfe/trunk/test/SemaTemplate/operator-function-id-template.cpp (added)
+++ cfe/trunk/test/SemaTemplate/operator-function-id-template.cpp Tue Nov 3 17:16:33 2009
@@ -0,0 +1,27 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+struct A {
+ template<typename U> A<T> operator+(U);
+};
+
+template<int Value, typename T> bool operator==(A<T>, A<T>);
+
+template<> bool operator==<0>(A<int>, A<int>);
+
+bool test_qualified_id(A<int> ai) {
+ return ::operator==<0, int>(ai, ai);
+}
+
+void test_op(A<int> a, int i) {
+ const A<int> &air = a.operator+<int>(i);
+}
+
+template<typename T>
+void test_op_template(A<T> at, T x) {
+ // FIXME: Not yet implemented.
+ // const A<T> &atr = at.template operator+<T>(x);
+ // const A<T> &atr2 = at.A<T>::template operator+<T>(x);
+}
+
+template void test_op_template<float>(A<float>, float);
More information about the cfe-commits
mailing list