aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-11-04 00:56:37 +0000
committerDouglas Gregor <dgregor@apple.com>2009-11-04 00:56:37 +0000
commitca1bdd7c269a2390d43c040a60511edd017ee130 (patch)
tree3310f54698515fedd46cc4c59468b2ea7bcd1759
parentd0fe5366d4040545d5f72c547ae54e2c21e4cb68 (diff)
Implement support for parsing dependent template-ids that refer to
overloaded operators, e.g., p->template operator+<T>() git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@85989 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/ASTContext.h3
-rw-r--r--include/clang/AST/TemplateName.h81
-rw-r--r--include/clang/Basic/OperatorKinds.h5
-rw-r--r--include/clang/Parse/Parser.h4
-rw-r--r--lib/AST/ASTContext.cpp30
-rw-r--r--lib/AST/TemplateName.cpp9
-rw-r--r--lib/Basic/IdentifierTable.cpp14
-rw-r--r--lib/Parse/ParseExprCXX.cpp362
-rw-r--r--lib/Parse/ParseTemplate.cpp17
-rw-r--r--lib/Parse/Parser.cpp7
-rw-r--r--lib/Sema/SemaExpr.cpp9
-rw-r--r--lib/Sema/SemaTemplate.cpp4
-rw-r--r--lib/Sema/TreeTransform.h61
-rw-r--r--test/SemaCXX/invalid-template-specifier.cpp2
-rw-r--r--test/SemaTemplate/operator-function-id-template.cpp7
15 files changed, 428 insertions, 187 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index a51a3d6167..7392170be9 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -16,6 +16,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/OperatorKinds.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/NestedNameSpecifier.h"
@@ -739,6 +740,8 @@ public:
TemplateName getDependentTemplateName(NestedNameSpecifier *NNS,
const IdentifierInfo *Name);
+ TemplateName getDependentTemplateName(NestedNameSpecifier *NNS,
+ OverloadedOperatorKind Operator);
enum GetBuiltinTypeError {
GE_None, //< No error
diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h
index 66ff34cf1e..8ef8fb5141 100644
--- a/include/clang/AST/TemplateName.h
+++ b/include/clang/AST/TemplateName.h
@@ -16,6 +16,7 @@
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerUnion.h"
+#include "clang/Basic/OperatorKinds.h"
namespace llvm {
class raw_ostream;
@@ -224,10 +225,24 @@ public:
class DependentTemplateName : public llvm::FoldingSetNode {
/// \brief The nested name specifier that qualifies the template
/// name.
- NestedNameSpecifier *Qualifier;
+ ///
+ /// The bit stored in this qualifier describes whether the \c Name field
+ /// is interpreted as an IdentifierInfo pointer (when clear) or as an
+ /// overloaded operator kind (when set).
+ llvm::PointerIntPair<NestedNameSpecifier *, 1, bool> Qualifier;
/// \brief The dependent template name.
- const IdentifierInfo *Name;
+ union {
+ /// \brief The identifier template name.
+ ///
+ /// Only valid when the bit on \c Qualifier is clear.
+ const IdentifierInfo *Identifier;
+
+ /// \brief The overloaded operator name.
+ ///
+ /// Only valid when the bit on \c Qualifier is set.
+ OverloadedOperatorKind Operator;
+ };
/// \brief The canonical template name to which this dependent
/// template name refers.
@@ -240,30 +255,70 @@ class DependentTemplateName : public llvm::FoldingSetNode {
friend class ASTContext;
DependentTemplateName(NestedNameSpecifier *Qualifier,
- const IdentifierInfo *Name)
- : Qualifier(Qualifier), Name(Name), CanonicalTemplateName(this) { }
+ const IdentifierInfo *Identifier)
+ : Qualifier(Qualifier, false), Identifier(Identifier),
+ CanonicalTemplateName(this) { }
DependentTemplateName(NestedNameSpecifier *Qualifier,
- const IdentifierInfo *Name,
+ const IdentifierInfo *Identifier,
TemplateName Canon)
- : Qualifier(Qualifier), Name(Name), CanonicalTemplateName(Canon) { }
+ : Qualifier(Qualifier, false), Identifier(Identifier),
+ CanonicalTemplateName(Canon) { }
+ DependentTemplateName(NestedNameSpecifier *Qualifier,
+ OverloadedOperatorKind Operator)
+ : Qualifier(Qualifier, true), Operator(Operator),
+ CanonicalTemplateName(this) { }
+
+ DependentTemplateName(NestedNameSpecifier *Qualifier,
+ OverloadedOperatorKind Operator,
+ TemplateName Canon)
+ : Qualifier(Qualifier, true), Operator(Operator),
+ CanonicalTemplateName(Canon) { }
+
public:
/// \brief Return the nested name specifier that qualifies this name.
- NestedNameSpecifier *getQualifier() const { return Qualifier; }
+ NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); }
- /// \brief Return the name to which this dependent template name
- /// refers.
- const IdentifierInfo *getName() const { return Name; }
+ /// \brief Determine whether this template name refers to an identifier.
+ bool isIdentifier() const { return !Qualifier.getInt(); }
+ /// \brief Returns the identifier to which this template name refers.
+ const IdentifierInfo *getIdentifier() const {
+ assert(isIdentifier() && "Template name isn't an identifier?");
+ return Identifier;
+ }
+
+ /// \brief Determine whether this template name refers to an overloaded
+ /// operator.
+ bool isOverloadedOperator() const { return Qualifier.getInt(); }
+
+ /// \brief Return the overloaded operator to which this template name refers.
+ OverloadedOperatorKind getOperator() const {
+ assert(isOverloadedOperator() &&
+ "Template name isn't an overloaded operator?");
+ return Operator;
+ }
+
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getQualifier(), getName());
+ if (isIdentifier())
+ Profile(ID, getQualifier(), getIdentifier());
+ else
+ Profile(ID, getQualifier(), getOperator());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
+ const IdentifierInfo *Identifier) {
+ ID.AddPointer(NNS);
+ ID.AddBoolean(false);
+ ID.AddPointer(Identifier);
}
static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
- const IdentifierInfo *Name) {
+ OverloadedOperatorKind Operator) {
ID.AddPointer(NNS);
- ID.AddPointer(Name);
+ ID.AddBoolean(true);
+ ID.AddInteger(Operator);
}
};
diff --git a/include/clang/Basic/OperatorKinds.h b/include/clang/Basic/OperatorKinds.h
index 790b75ba3a..c0a95051a7 100644
--- a/include/clang/Basic/OperatorKinds.h
+++ b/include/clang/Basic/OperatorKinds.h
@@ -26,7 +26,10 @@ enum OverloadedOperatorKind {
NUM_OVERLOADED_OPERATORS
};
-
+/// \brief Retrieve the spelling of the given overloaded operator, without
+/// the preceding "operator" keyword.
+const char *getOperatorSpelling(OverloadedOperatorKind Operator);
+
} // end namespace clang
#endif
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 3c0bfccd0d..eb2ec53e6f 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -1218,6 +1218,9 @@ private:
bool EnteringContext,
TypeTy *ObjectType,
UnqualifiedId &Id);
+ bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
+ TypeTy *ObjectType,
+ UnqualifiedId &Result);
bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
bool AllowDestructorName,
bool AllowConstructorName,
@@ -1274,6 +1277,7 @@ private:
bool AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
const CXXScopeSpec *SS,
+ UnqualifiedId &TemplateName,
SourceLocation TemplateKWLoc = SourceLocation(),
bool AllowTypeAnnotation = true);
void AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS = 0);
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index d445125459..aef3d29894 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -3662,6 +3662,36 @@ TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
return TemplateName(QTN);
}
+/// \brief Retrieve the template name that represents a dependent
+/// template name such as \c MetaFun::template operator+.
+TemplateName
+ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
+ OverloadedOperatorKind Operator) {
+ assert((!NNS || NNS->isDependent()) &&
+ "Nested name specifier must be dependent");
+
+ llvm::FoldingSetNodeID ID;
+ DependentTemplateName::Profile(ID, NNS, Operator);
+
+ void *InsertPos = 0;
+ DependentTemplateName *QTN =
+ DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
+
+ if (QTN)
+ return TemplateName(QTN);
+
+ NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
+ if (CanonNNS == NNS) {
+ QTN = new (*this,4) DependentTemplateName(NNS, Operator);
+ } else {
+ TemplateName Canon = getDependentTemplateName(CanonNNS, Operator);
+ QTN = new (*this,4) DependentTemplateName(NNS, Operator, Canon);
+ }
+
+ DependentTemplateNames.InsertNode(QTN, InsertPos);
+ return TemplateName(QTN);
+}
+
/// getFromTargetType - Given one of the integer types provided by
/// TargetInfo, produce the corresponding type. The unsigned @p Type
/// is actually a value of type @c TargetInfo::IntType.
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index 24588bc5f1..5b4cf0ad94 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -56,7 +56,7 @@ void
TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
bool SuppressNNS) const {
if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
- OS << Template->getIdentifier()->getName();
+ OS << Template->getNameAsString();
else if (OverloadedFunctionDecl *Ovl
= Storage.dyn_cast<OverloadedFunctionDecl *>())
OS << Ovl->getNameAsString();
@@ -70,8 +70,11 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
if (!SuppressNNS && DTN->getQualifier())
DTN->getQualifier()->print(OS, Policy);
OS << "template ";
- // FIXME: Shouldn't we have a more general kind of name?
- OS << DTN->getName()->getName();
+
+ if (DTN->isIdentifier())
+ OS << DTN->getIdentifier()->getName();
+ else
+ OS << "operator " << getOperatorSpelling(DTN->getOperator());
}
}
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 16aa0c5484..401e6cba06 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -381,3 +381,17 @@ SelectorTable::~SelectorTable() {
delete &getSelectorTableImpl(Impl);
}
+const char *clang::getOperatorSpelling(OverloadedOperatorKind Operator) {
+ switch (Operator) {
+ case OO_None:
+ case NUM_OVERLOADED_OPERATORS:
+ return 0;
+
+#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
+ case OO_##Name: return Spelling;
+#include "clang/Basic/OperatorKinds.def"
+ }
+
+ return 0;
+}
+
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index d0e2f70319..a7ca0c54db 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -109,31 +109,58 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
break;
SourceLocation TemplateKWLoc = ConsumeToken();
-
- if (Tok.isNot(tok::identifier)) {
+
+ UnqualifiedId TemplateName;
+ if (Tok.is(tok::identifier)) {
+ TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
+
+ // If the next token is not '<', we may have a stray 'template' keyword.
+ // Complain and suggest removing the template keyword, but otherwise
+ // allow parsing to continue.
+ if (NextToken().isNot(tok::less)) {
+ Diag(NextToken().getLocation(),
+ diag::err_less_after_template_name_in_nested_name_spec)
+ << Tok.getIdentifierInfo()->getName()
+ << CodeModificationHint::CreateRemoval(SourceRange(TemplateKWLoc));
+ break;
+ }
+
+ // Consume the identifier.
+ ConsumeToken();
+ } else if (Tok.is(tok::kw_operator)) {
+ if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType,
+ TemplateName))
+ break;
+
+ if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId) {
+ Diag(TemplateName.getSourceRange().getBegin(),
+ diag::err_id_after_template_in_nested_name_spec)
+ << TemplateName.getSourceRange();
+ break;
+ } else if (Tok.isNot(tok::less)) {
+ std::string OperatorName = "operator ";
+ OperatorName += getOperatorSpelling(
+ TemplateName.OperatorFunctionId.Operator);
+ Diag(Tok.getLocation(),
+ diag::err_less_after_template_name_in_nested_name_spec)
+ << OperatorName
+ << TemplateName.getSourceRange();
+ break;
+ }
+ } else {
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;
- }
-
- UnqualifiedId TemplateName;
- TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
TemplateTy Template
= Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, TemplateName,
ObjectType);
if (!Template)
break;
if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name,
- &SS, TemplateKWLoc, false))
+ &SS, TemplateName, TemplateKWLoc, false))
break;
continue;
@@ -233,8 +260,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// because some clients (e.g., the parsing of class template
// specializations) still want to see the original template-id
// token.
- if (AnnotateTemplateIdToken(Template, TNK, &SS, SourceLocation(),
- false))
+ ConsumeToken();
+ if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName,
+ SourceLocation(), false))
break;
continue;
}
@@ -859,22 +887,17 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
return false;
}
-/// \brief Parse a C++ unqualified-id (or a C identifier), which describes the
-/// name of an entity.
+/// \brief Parse an operator-function-id or conversion-function-id as part
+/// of a C++ unqualified-id.
///
-/// \code
-/// unqualified-id: [C++ expr.prim.general]
-/// identifier
-/// operator-function-id
-/// conversion-function-id
-/// [C++0x] literal-operator-id [TODO]
-/// ~ class-name
-/// template-id
+/// This routine is responsible only for parsing the operator-function-id or
+/// conversion-function-id; it does not handle template arguments in any way.
///
+/// \code
/// operator-function-id: [C++ 13.5]
/// 'operator' operator
///
-/// operator: one of
+/// operator: one of
/// new delete new[] delete[]
/// + - * / % ^ & | ~
/// ! = < > += -= *= /= %=
@@ -898,6 +921,159 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
/// \param EnteringContext whether we are entering the scope of the
/// nested-name-specifier.
///
+/// \param ObjectType if this unqualified-id occurs within a member access
+/// expression, the type of the base object whose member is being accessed.
+///
+/// \param Result on a successful parse, contains the parsed unqualified-id.
+///
+/// \returns true if parsing fails, false otherwise.
+bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
+ TypeTy *ObjectType,
+ UnqualifiedId &Result) {
+ assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
+
+ // Consume the 'operator' keyword.
+ SourceLocation KeywordLoc = ConsumeToken();
+
+ // Determine what kind of operator name we have.
+ unsigned SymbolIdx = 0;
+ SourceLocation SymbolLocations[3];
+ OverloadedOperatorKind Op = OO_None;
+ switch (Tok.getKind()) {
+ case tok::kw_new:
+ case tok::kw_delete: {
+ bool isNew = Tok.getKind() == tok::kw_new;
+ // Consume the 'new' or 'delete'.
+ SymbolLocations[SymbolIdx++] = ConsumeToken();
+ if (Tok.is(tok::l_square)) {
+ // Consume the '['.
+ SourceLocation LBracketLoc = ConsumeBracket();
+ // Consume the ']'.
+ SourceLocation RBracketLoc = MatchRHSPunctuation(tok::r_square,
+ LBracketLoc);
+ if (RBracketLoc.isInvalid())
+ return true;
+
+ SymbolLocations[SymbolIdx++] = LBracketLoc;
+ SymbolLocations[SymbolIdx++] = RBracketLoc;
+ Op = isNew? OO_Array_New : OO_Array_Delete;
+ } else {
+ Op = isNew? OO_New : OO_Delete;
+ }
+ break;
+ }
+
+#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
+ case tok::Token: \
+ SymbolLocations[SymbolIdx++] = ConsumeToken(); \
+ Op = OO_##Name; \
+ break;
+#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly)
+#include "clang/Basic/OperatorKinds.def"
+
+ case tok::l_paren: {
+ // Consume the '('.
+ SourceLocation LParenLoc = ConsumeParen();
+ // Consume the ')'.
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren,
+ LParenLoc);
+ if (RParenLoc.isInvalid())
+ return true;
+
+ SymbolLocations[SymbolIdx++] = LParenLoc;
+ SymbolLocations[SymbolIdx++] = RParenLoc;
+ Op = OO_Call;
+ break;
+ }
+
+ case tok::l_square: {
+ // Consume the '['.
+ SourceLocation LBracketLoc = ConsumeBracket();
+ // Consume the ']'.
+ SourceLocation RBracketLoc = MatchRHSPunctuation(tok::r_square,
+ LBracketLoc);
+ if (RBracketLoc.isInvalid())
+ return true;
+
+ SymbolLocations[SymbolIdx++] = LBracketLoc;
+ SymbolLocations[SymbolIdx++] = RBracketLoc;
+ Op = OO_Subscript;
+ break;
+ }
+
+ case tok::code_completion: {
+ // Code completion for the operator name.
+ Actions.CodeCompleteOperatorName(CurScope);
+
+ // Consume the operator token.
+ ConsumeToken();
+
+ // Don't try to parse any further.
+ return true;
+ }
+
+ default:
+ break;
+ }
+
+ if (Op != OO_None) {
+ // We have parsed an operator-function-id.
+ Result.setOperatorFunctionId(KeywordLoc, Op, SymbolLocations);
+ return false;
+ }
+
+ // Parse a conversion-function-id.
+ //
+ // conversion-function-id: [C++ 12.3.2]
+ // operator conversion-type-id
+ //
+ // conversion-type-id:
+ // type-specifier-seq conversion-declarator[opt]
+ //
+ // conversion-declarator:
+ // ptr-operator conversion-declarator[opt]
+
+ // Parse the type-specifier-seq.
+ DeclSpec DS;
+ if (ParseCXXTypeSpecifierSeq(DS))
+ return true;
+
+ // Parse the conversion-declarator, which is merely a sequence of
+ // ptr-operators.
+ Declarator D(DS, Declarator::TypeNameContext);
+ ParseDeclaratorInternal(D, /*DirectDeclParser=*/0);
+
+ // Finish up the type.
+ Action::TypeResult Ty = Actions.ActOnTypeName(CurScope, D);
+ if (Ty.isInvalid())
+ return true;
+
+ // Note that this is a conversion-function-id.
+ Result.setConversionFunctionId(KeywordLoc, Ty.get(),
+ D.getSourceRange().getEnd());
+ return false;
+}
+
+/// \brief Parse a C++ unqualified-id (or a C identifier), which describes the
+/// name of an entity.
+///
+/// \code
+/// unqualified-id: [C++ expr.prim.general]
+/// identifier
+/// operator-function-id
+/// conversion-function-id
+/// [C++0x] literal-operator-id [TODO]
+/// ~ class-name
+/// template-id
+///
+/// \endcode
+///
+/// \param The nested-name-specifier that preceded this unqualified-id. If
+/// non-empty, then we are parsing the unqualified-id of a qualified-id.
+///
+/// \param EnteringContext whether we are entering the scope of the
+/// nested-name-specifier.
+///
/// \param AllowDestructorName whether we allow parsing of a destructor name.
///
/// \param AllowConstructorName whether we allow parsing a constructor name.
@@ -957,132 +1133,20 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
// operator-function-id
// conversion-function-id
if (Tok.is(tok::kw_operator)) {
- // Consume the 'operator' keyword.
- SourceLocation KeywordLoc = ConsumeToken();
-
- // Determine what kind of operator name we have.
- unsigned SymbolIdx = 0;
- SourceLocation SymbolLocations[3];
- OverloadedOperatorKind Op = OO_None;
- switch (Tok.getKind()) {
- case tok::kw_new:
- case tok::kw_delete: {
- bool isNew = Tok.getKind() == tok::kw_new;
- // Consume the 'new' or 'delete'.
- SymbolLocations[SymbolIdx++] = ConsumeToken();
- if (Tok.is(tok::l_square)) {
- // Consume the '['.
- SourceLocation LBracketLoc = ConsumeBracket();
- // Consume the ']'.
- SourceLocation RBracketLoc = MatchRHSPunctuation(tok::r_square,
- LBracketLoc);
- if (RBracketLoc.isInvalid())
- return true;
-
- SymbolLocations[SymbolIdx++] = LBracketLoc;
- SymbolLocations[SymbolIdx++] = RBracketLoc;
- Op = isNew? OO_Array_New : OO_Array_Delete;
- } else {
- Op = isNew? OO_New : OO_Delete;
- }
- break;
- }
-
- #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
- case tok::Token: \
- SymbolLocations[SymbolIdx++] = ConsumeToken(); \
- Op = OO_##Name; \
- break;
- #define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly)
- #include "clang/Basic/OperatorKinds.def"
-
- case tok::l_paren: {
- // Consume the '('.
- SourceLocation LParenLoc = ConsumeParen();
- // Consume the ')'.
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren,
- LParenLoc);
- if (RParenLoc.isInvalid())
- return true;
-
- SymbolLocations[SymbolIdx++] = LParenLoc;
- SymbolLocations[SymbolIdx++] = RParenLoc;
- Op = OO_Call;
- break;
- }
-
- case tok::l_square: {
- // Consume the '['.
- SourceLocation LBracketLoc = ConsumeBracket();
- // Consume the ']'.
- SourceLocation RBracketLoc = MatchRHSPunctuation(tok::r_square,
- LBracketLoc);
- if (RBracketLoc.isInvalid())
- return true;
-
- SymbolLocations[SymbolIdx++] = LBracketLoc;
- SymbolLocations[SymbolIdx++] = RBracketLoc;
- Op = OO_Subscript;
- break;
- }
-
- case tok::code_completion: {
- // Code completion for the operator name.
- Actions.CodeCompleteOperatorName(CurScope);
-
- // Consume the operator token.
- ConsumeToken();
-
- // Don't try to parse any further.
- return true;
- }
-
- default:
- break;
- }
-
- if (Op != OO_None) {
- // We have parsed an operator-function-id.
- Result.setOperatorFunctionId(KeywordLoc, Op, SymbolLocations);
-
- // If the next token is a '<', we may have a template.
- if (Tok.is(tok::less))
- return ParseUnqualifiedIdTemplateId(SS, 0, SourceLocation(),
- EnteringContext, ObjectType,
- Result);
-
- return false;
- }
-
- // Parse a conversion-function-id.
- //
- // conversion-function-id: [C++ 12.3.2]
- // operator conversion-type-id
- //
- // conversion-type-id:
- // type-specifier-seq conversion-declarator[opt]
- //
- // conversion-declarator:
- // ptr-operator conversion-declarator[opt]
-
- // Parse the type-specifier-seq.
- DeclSpec DS;
- if (ParseCXXTypeSpecifierSeq(DS))
+ if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, Result))
return true;
- // Parse the conversion-declarator, which is merely a sequence of
- // ptr-operators.
- Declarator D(DS, Declarator::TypeNameContext);
- ParseDeclaratorInternal(D, /*DirectDeclParser=*/0);
-
- // Finish up the type.
- Action::TypeResult Ty = Actions.ActOnTypeName(CurScope, D);
- if (Ty.isInvalid())
- return true;
+ // If we have an operator-function-id and the next token is a '<', we may
+ // have a
+ //
+ // template-id:
+ // operator-function-id < template-argument-list[opt] >
+ if (Result.getKind() == UnqualifiedId::IK_OperatorFunctionId &&
+ Tok.is(tok::less))
+ return ParseUnqualifiedIdTemplateId(SS, 0, SourceLocation(),
+ EnteringContext, ObjectType,
+ Result);
- // Note that this is a conversion-function-id.
- Result.setConversionFunctionId(KeywordLoc, Ty.get(),
- D.getSourceRange().getEnd());
return false;
}
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 64c5a08933..a647720fb9 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -672,22 +672,23 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
///
bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
const CXXScopeSpec *SS,
+ UnqualifiedId &TemplateName,
SourceLocation TemplateKWLoc,
bool AllowTypeAnnotation) {
assert(getLang().CPlusPlus && "Can only annotate template-ids in C++");
- assert(Template && Tok.is(tok::identifier) && NextToken().is(tok::less) &&
+ assert(Template && Tok.is(tok::less) &&
"Parser isn't at the beginning of a template-id");
// Consume the template-name.
- IdentifierInfo *Name = Tok.getIdentifierInfo();
- SourceLocation TemplateNameLoc = ConsumeToken();
+ SourceLocation TemplateNameLoc = TemplateName.getSourceRange().getBegin();
// Parse the enclosed template argument list.
SourceLocation LAngleLoc, RAngleLoc;
TemplateArgList TemplateArgs;
TemplateArgIsTypeList TemplateArgIsType;
TemplateArgLocationList TemplateArgLocations;
- bool Invalid = ParseTemplateIdAfterTemplateName(Template, TemplateNameLoc,
+ bool Invalid = ParseTemplateIdAfterTemplateName(Template,
+ TemplateNameLoc,
SS, false, LAngleLoc,
TemplateArgs,
TemplateArgIsType,
@@ -736,7 +737,13 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
TemplateIdAnnotation *TemplateId
= TemplateIdAnnotation::Allocate(TemplateArgs.size());
TemplateId->TemplateNameLoc = TemplateNameLoc;
- TemplateId->Name = Name;
+ if (TemplateName.getKind() == UnqualifiedId::IK_Identifier) {
+ TemplateId->Name = TemplateName.Identifier;
+ TemplateId->Operator = OO_None;
+ } else {
+ TemplateId->Name = 0;
+ TemplateId->Operator = TemplateName.OperatorFunctionId.Operator;
+ }
TemplateId->Template = Template.getAs<void*>();
TemplateId->Kind = TNK;
TemplateId->LAngleLoc = LAngleLoc;
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index d1baa91b65..6836c307d3 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -940,13 +940,16 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
if (TemplateNameKind TNK
= Actions.isTemplateName(CurScope, SS, TemplateName,
/*ObjectType=*/0, EnteringContext,
- Template))
- if (AnnotateTemplateIdToken(Template, TNK, &SS)) {
+ Template)) {
+ // Consume the identifier.
+ ConsumeToken();
+ if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName)) {
// If an unrecoverable error occurred, we need to return true here,
// because the token stream is in a damaged state. We may not return
// a valid identifier.
return Tok.isNot(tok::identifier);
}
+ }
}
// The current token, which is either an identifier or a
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index bdf1a7e010..4dd3c2dbef 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -2498,8 +2498,13 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg Base,
Name = ActualTemplate->getDeclName();
else if (OverloadedFunctionDecl *Ovl = Template.getAsOverloadedFunctionDecl())
Name = Ovl->getDeclName();
- else
- Name = Template.getAsDependentTemplateName()->getName();
+ else {
+ DependentTemplateName *DTN = Template.getAsDependentTemplateName();
+ if (DTN->isIdentifier())
+ Name = DTN->getIdentifier();
+ else
+ Name = Context.DeclarationNames.getCXXOperatorName(DTN->getOperator());
+ }
// Translate the parser's template argument list in our AST format.
ASTTemplateArgsPtr TemplateArgsPtr(*this,
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 2e1a89e658..3c56358d5a 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1405,6 +1405,10 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
return TemplateTy::make(Context.getDependentTemplateName(Qualifier,
Name.Identifier));
+ case UnqualifiedId::IK_OperatorFunctionId:
+ return TemplateTy::make(Context.getDependentTemplateName(Qualifier,
+ Name.OperatorFunctionId.Operator));
+
default:
break;
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 2a4fa8bcef..8a5699e7ec 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -605,7 +605,17 @@ public:
const IdentifierInfo &II,
QualType ObjectType);
-
+ /// \brief Build a new template name given a nested name specifier and the
+ /// overloaded operator name that is referred to as a template.
+ ///
+ /// By default, performs semantic analysis to determine whether the name can
+ /// be resolved to a specific template, then builds the appropriate kind of
+ /// template name. Subclasses may override this routine to provide different
+ /// behavior.
+ TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier,
+ OverloadedOperatorKind Operator,
+ QualType ObjectType);
+
/// \brief Build a new compound statement.
///
/// By default, performs semantic analysis to build the new statement.
@@ -1575,9 +1585,14 @@ public:
else if (OverloadedFunctionDecl *O