[cfe-commits] r85989 - in /cfe/trunk: include/clang/AST/ASTContext.h include/clang/AST/TemplateName.h include/clang/Basic/OperatorKinds.h include/clang/Parse/Parser.h lib/AST/ASTContext.cpp lib/AST/TemplateName.cpp lib/Basic/IdentifierTable.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/ParseTemplate.cpp lib/Parse/Parser.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaTemplate.cpp lib/Sema/TreeTransform.h test/SemaCXX/invalid-template-specifier.cpp test/SemaTemplate/operator-function-id-template.cpp
Douglas Gregor
dgregor at apple.com
Tue Nov 3 16:56:37 PST 2009
Author: dgregor
Date: Tue Nov 3 18:56:37 2009
New Revision: 85989
URL: http://llvm.org/viewvc/llvm-project?rev=85989&view=rev
Log:
Implement support for parsing dependent template-ids that refer to
overloaded operators, e.g.,
p->template operator+<T>()
Modified:
cfe/trunk/include/clang/AST/ASTContext.h
cfe/trunk/include/clang/AST/TemplateName.h
cfe/trunk/include/clang/Basic/OperatorKinds.h
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/lib/AST/ASTContext.cpp
cfe/trunk/lib/AST/TemplateName.cpp
cfe/trunk/lib/Basic/IdentifierTable.cpp
cfe/trunk/lib/Parse/ParseExprCXX.cpp
cfe/trunk/lib/Parse/ParseTemplate.cpp
cfe/trunk/lib/Parse/Parser.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/TreeTransform.h
cfe/trunk/test/SemaCXX/invalid-template-specifier.cpp
cfe/trunk/test/SemaTemplate/operator-function-id-template.cpp
Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=85989&r1=85988&r2=85989&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Tue Nov 3 18:56:37 2009
@@ -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 @@
TemplateName getDependentTemplateName(NestedNameSpecifier *NNS,
const IdentifierInfo *Name);
+ TemplateName getDependentTemplateName(NestedNameSpecifier *NNS,
+ OverloadedOperatorKind Operator);
enum GetBuiltinTypeError {
GE_None, //< No error
Modified: cfe/trunk/include/clang/AST/TemplateName.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TemplateName.h?rev=85989&r1=85988&r2=85989&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/TemplateName.h (original)
+++ cfe/trunk/include/clang/AST/TemplateName.h Tue Nov 3 18:56:37 2009
@@ -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 @@
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 @@
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);
}
};
Modified: cfe/trunk/include/clang/Basic/OperatorKinds.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/OperatorKinds.h?rev=85989&r1=85988&r2=85989&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/OperatorKinds.h (original)
+++ cfe/trunk/include/clang/Basic/OperatorKinds.h Tue Nov 3 18:56:37 2009
@@ -26,7 +26,10 @@
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
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=85989&r1=85988&r2=85989&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Tue Nov 3 18:56:37 2009
@@ -1218,6 +1218,9 @@
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 @@
bool AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
const CXXScopeSpec *SS,
+ UnqualifiedId &TemplateName,
SourceLocation TemplateKWLoc = SourceLocation(),
bool AllowTypeAnnotation = true);
void AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS = 0);
Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=85989&r1=85988&r2=85989&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Tue Nov 3 18:56:37 2009
@@ -3662,6 +3662,36 @@
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.
Modified: cfe/trunk/lib/AST/TemplateName.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TemplateName.cpp?rev=85989&r1=85988&r2=85989&view=diff
==============================================================================
--- cfe/trunk/lib/AST/TemplateName.cpp (original)
+++ cfe/trunk/lib/AST/TemplateName.cpp Tue Nov 3 18:56:37 2009
@@ -56,7 +56,7 @@
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 @@
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());
}
}
Modified: cfe/trunk/lib/Basic/IdentifierTable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/IdentifierTable.cpp?rev=85989&r1=85988&r2=85989&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/IdentifierTable.cpp (original)
+++ cfe/trunk/lib/Basic/IdentifierTable.cpp Tue Nov 3 18:56:37 2009
@@ -381,3 +381,17 @@
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;
+}
+
Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=85989&r1=85988&r2=85989&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Tue Nov 3 18:56:37 2009
@@ -109,31 +109,58 @@
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 @@
// 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 @@
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 @@
/// \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 @@
// 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;
}
Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=85989&r1=85988&r2=85989&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Tue Nov 3 18:56:37 2009
@@ -672,22 +672,23 @@
///
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 @@
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;
Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=85989&r1=85988&r2=85989&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Tue Nov 3 18:56:37 2009
@@ -940,13 +940,16 @@
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
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=85989&r1=85988&r2=85989&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Nov 3 18:56:37 2009
@@ -2498,8 +2498,13 @@
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,
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=85989&r1=85988&r2=85989&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Nov 3 18:56:37 2009
@@ -1405,6 +1405,10 @@
return TemplateTy::make(Context.getDependentTemplateName(Qualifier,
Name.Identifier));
+ case UnqualifiedId::IK_OperatorFunctionId:
+ return TemplateTy::make(Context.getDependentTemplateName(Qualifier,
+ Name.OperatorFunctionId.Operator));
+
default:
break;
}
Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=85989&r1=85988&r2=85989&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Tue Nov 3 18:56:37 2009
@@ -605,7 +605,17 @@
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 @@
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 = SemaRef.Context.DeclarationNames.getCXXOperatorName(
+ DTN->getOperator());
+ }
return SemaRef.BuildMemberReferenceExpr(/*Scope=*/0, move(Base),
OperatorLoc, OpKind,
TemplateNameLoc, Name, true,
@@ -1873,7 +1888,12 @@
ObjectType.isNull())
return Name;
- return getDerived().RebuildTemplateName(NNS, *DTN->getName(), ObjectType);
+ if (DTN->isIdentifier())
+ return getDerived().RebuildTemplateName(NNS, *DTN->getIdentifier(),
+ ObjectType);
+
+ return getDerived().RebuildTemplateName(NNS, DTN->getOperator(),
+ ObjectType);
}
if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
@@ -4749,9 +4769,14 @@
// FIXME: This is an ugly hack, which forces the same template name to
// be looked up multiple times. Yuck!
- // FIXME: This also won't work for, e.g., x->template operator+<int>
- TemplateName OrigTemplateName
- = SemaRef.Context.getDependentTemplateName(0, Name.getAsIdentifierInfo());
+ TemporaryBase Rebase(*this, E->getMemberLoc(), DeclarationName());
+ TemplateName OrigTemplateName;
+ if (const IdentifierInfo *II = Name.getAsIdentifierInfo())
+ OrigTemplateName = SemaRef.Context.getDependentTemplateName(0, II);
+ else
+ OrigTemplateName
+ = SemaRef.Context.getDependentTemplateName(0,
+ Name.getCXXOverloadedOperator());
TemplateName Template
= getDerived().TransformTemplateName(OrigTemplateName,
@@ -5195,6 +5220,26 @@
}
template<typename Derived>
+TemplateName
+TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
+ OverloadedOperatorKind Operator,
+ QualType ObjectType) {
+ CXXScopeSpec SS;
+ SS.setRange(SourceRange(getDerived().getBaseLocation()));
+ SS.setScopeRep(Qualifier);
+ UnqualifiedId Name;
+ SourceLocation SymbolLocations[3]; // FIXME: Bogus location information.
+ Name.setOperatorFunctionId(/*FIXME:*/getDerived().getBaseLocation(),
+ Operator, SymbolLocations);
+ return getSema().ActOnDependentTemplateName(
+ /*FIXME:*/getDerived().getBaseLocation(),
+ SS,
+ Name,
+ ObjectType.getAsOpaquePtr())
+ .template getAsVal<TemplateName>();
+}
+
+template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
SourceLocation OpLoc,
Modified: cfe/trunk/test/SemaCXX/invalid-template-specifier.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/invalid-template-specifier.cpp?rev=85989&r1=85988&r2=85989&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/invalid-template-specifier.cpp (original)
+++ cfe/trunk/test/SemaCXX/invalid-template-specifier.cpp Tue Nov 3 18:56:37 2009
@@ -8,5 +8,5 @@
namespace S {}
template <class X> class Y {
void x() { S::template y<char>(1); } // expected-error {{does not refer to a template}} \
- // expected-error {{no member named 'y'}}
+ // expected-error {{unqualified-id}}
};
Modified: 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=85989&r1=85988&r2=85989&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/operator-function-id-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/operator-function-id-template.cpp Tue Nov 3 18:56:37 2009
@@ -19,9 +19,10 @@
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);
+ const A<T> &atr = at.template operator+<T>(x);
+ const A<T> &atr2 = at.A::template operator+<T>(x);
+ // FIXME: unrelated template-name instantiation issue
+ // const A<T> &atr3 = at.template A<T>::template operator+<T>(x);
}
template void test_op_template<float>(A<float>, float);
More information about the cfe-commits
mailing list