From 3f9a0566e6793151b99a65ab936220971cf96c1b Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 3 Nov 2009 01:35:08 +0000 Subject: [PATCH] Introduce a new class, UnqualifiedId, that provides a parsed representation of a C++ unqualified-id, along with a single parsing function (Parser::ParseUnqualifiedId) that will parse all of the various forms of unqualified-id in C++. Replace the representation of the declarator name in Declarator with the new UnqualifiedId class, simplifying declarator-id parsing considerably and providing more source-location information to Sema. In the future, I hope to migrate all of the other unqualified-id-parsing code over to this single representation, then begin to merge actions that are currently only different because we didn't have a unqualified notion of the name in the parser. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@85851 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticParseKinds.td | 4 +- include/clang/Parse/DeclSpec.h | 339 +++++++++------ include/clang/Parse/Parser.h | 10 + lib/Parse/DeclSpec.cpp | 25 ++ lib/Parse/ParseDecl.cpp | 113 ++--- lib/Parse/ParseDeclCXX.cpp | 1 + lib/Parse/ParseExprCXX.cpp | 413 +++++++++++++++++++ lib/Sema/SemaDecl.cpp | 71 ++-- lib/Sema/SemaDeclCXX.cpp | 14 +- lib/Sema/SemaTemplate.cpp | 6 +- lib/Sema/SemaType.cpp | 20 +- test/CXX/temp/temp.spec/temp.explicit/p3.cpp | 4 +- test/SemaCXX/constructor.cpp | 2 +- test/SemaTemplate/constructor-template.cpp | 1 + 14 files changed, 754 insertions(+), 269 deletions(-) diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 1773f4c56c..7329dde195 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -292,7 +292,9 @@ def err_variadic_templates : Error< // 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 def warn_pragma_expected_lparen : Warning< diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index 9e7b340e2c..4fb4c8cc0c 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -459,6 +459,193 @@ public: } }; +/// \brief Represents a C++ unqualified-id that has been parsed. +class UnqualifiedId { +private: + const UnqualifiedId &operator=(const UnqualifiedId &); // DO NOT IMPLEMENT + +public: + /// \brief Describes the kind of unqualified-id parsed. + enum IdKind { + /// \brief An identifier. + IK_Identifier, + /// \brief An overloaded operator name, e.g., operator+. + IK_OperatorFunctionId, + /// \brief A conversion function name, e.g., operator int. + IK_ConversionFunctionId, + /// \brief A constructor name. + IK_ConstructorName, + /// \brief A destructor name. + IK_DestructorName, + /// \brief A template-id, e.g., f. + IK_TemplateId + } Kind; + + /// \brief Anonymous union that holds extra data associated with the + /// parsed unqualified-id. + union { + /// \brief When Kind == IK_Identifier, the parsed identifier. + IdentifierInfo *Identifier; + + /// \brief When Kind == IK_OperatorFunctionId, the overloaded operator + /// that we parsed. + struct { + /// \brief The kind of overloaded operator. + OverloadedOperatorKind Operator; + + /// \brief The source locations of the individual tokens that name + /// the operator, e.g., the "new", "[", and "]" tokens in + /// operator new []. + /// + /// Different operators have different numbers of tokens in their name, + /// up to three. Any remaining source locations in this array will be + /// set to an invalid value for operators with fewer than three tokens. + unsigned SymbolLocations[3]; + } OperatorFunctionId; + + /// \brief When Kind == IK_ConversionFunctionId, the type that the + /// conversion function names. + ActionBase::TypeTy *ConversionFunctionId; + + /// \brief When Kind == IK_ConstructorName, the class-name of the type + /// whose constructor is being referenced. + ActionBase::TypeTy *ConstructorName; + + /// \brief When Kind == IK_DestructorName, the type referred to by the + /// class-name. + ActionBase::TypeTy *DestructorName; + + /// \brief When Kind == IK_TemplateId, the template-id annotation that + /// contains the template name and template arguments. + TemplateIdAnnotation *TemplateId; + }; + + /// \brief The location of the first token that describes this unqualified-id, + /// which will be the location of the identifier, "operator" keyword, + /// tilde (for a destructor), or the template name of a template-id. + SourceLocation StartLocation; + + /// \brief The location of the last token that describes this unqualified-id. + SourceLocation EndLocation; + + UnqualifiedId() : Kind(IK_Identifier), Identifier(0) { } + + /// \brief Do not use this copy constructor. It is temporary, and only + /// exists because we are holding FieldDeclarators in a SmallVector when we + /// don't actually need them. + /// + /// FIXME: Kill this copy constructor. + UnqualifiedId(const UnqualifiedId &Other) + : Kind(IK_Identifier), Identifier(Other.Identifier), + StartLocation(Other.StartLocation), EndLocation(Other.EndLocation) { + assert(Other.Kind == IK_Identifier && "Cannot copy non-identifiers"); + } + + /// \brief Destroy this unqualified-id. + ~UnqualifiedId() { clear(); } + + /// \brief Clear out this unqualified-id, setting it to default (invalid) + /// state. + void clear(); + + /// \brief Determine whether this unqualified-id refers to a valid name. + bool isValid() const { return StartLocation.isValid(); } + + /// \brief Determine whether this unqualified-id refers to an invalid name. + bool isInvalid() const { return !isValid(); } + + /// \brief Determine what kind of name we have. + IdKind getKind() const { return Kind; } + + /// \brief Specify that this unqualified-id was parsed as an identifier. + /// + /// \param Id the parsed identifier. + /// \param IdLoc the location of the parsed identifier. + void setIdentifier(IdentifierInfo *Id, SourceLocation IdLoc) { + Kind = IK_Identifier; + Identifier = Id; + StartLocation = EndLocation = IdLoc; + } + + /// \brief Specify that this unqualified-id was parsed as an + /// operator-function-id. + /// + /// \param OperatorLoc the location of the 'operator' keyword. + /// + /// \param Op the overloaded operator. + /// + /// \param SymbolLocations the locations of the individual operator symbols + /// in the operator. + void setOperatorFunctionId(SourceLocation OperatorLoc, + OverloadedOperatorKind Op, + SourceLocation SymbolLocations[3]); + + /// \brief Specify that this unqualified-id was parsed as a + /// conversion-function-id. + /// + /// \param OperatorLoc the location of the 'operator' keyword. + /// + /// \param Ty the type to which this conversion function is converting. + /// + /// \param EndLoc the location of the last token that makes up the type name. + void setConversionFunctionId(SourceLocation OperatorLoc, + ActionBase::TypeTy *Ty, + SourceLocation EndLoc) { + Kind = IK_ConversionFunctionId; + StartLocation = OperatorLoc; + EndLocation = EndLoc; + ConversionFunctionId = Ty; + } + + /// \brief Specify that this unqualified-id was parsed as a constructor name. + /// + /// \param ClassType the class type referred to by the constructor name. + /// + /// \param ClassNameLoc the location of the class name. + /// + /// \param EndLoc the location of the last token that makes up the type name. + void setConstructorName(ActionBase::TypeTy *ClassType, + SourceLocation ClassNameLoc, + SourceLocation EndLoc) { + Kind = IK_ConstructorName; + StartLocation = ClassNameLoc; + EndLocation = EndLoc; + ConstructorName = ClassType; + } + + /// \brief Specify that this unqualified-id was parsed as a destructor name. + /// + /// \param TildeLoc the location of the '~' that introduces the destructor + /// name. + /// + /// \param ClassType the name of the class referred to by the destructor name. + void setDestructorName(SourceLocation TildeLoc, ActionBase::TypeTy *ClassType, + SourceLocation EndLoc) { + Kind = IK_DestructorName; + StartLocation = TildeLoc; + EndLocation = EndLoc; + DestructorName = ClassType; + } + + /// \brief Specify that this unqualified-id was parsed as a template-id. + /// + /// \param TemplateId the template-id annotation that describes the parsed + /// template-id. This UnqualifiedId instance will take ownership of the + /// \p TemplateId and will free it on destruction. + void setTemplateId(TemplateIdAnnotation *TemplateId) { + assert(TemplateId && "NULL template-id annotation?"); + Kind = IK_TemplateId; + this->TemplateId = TemplateId; + StartLocation = TemplateId->TemplateNameLoc; + EndLocation = TemplateId->RAngleLoc; + } + + /// \brief Return the source range that covers this unqualified-id. + SourceRange getSourceRange() const { + return SourceRange(StartLocation, EndLocation); + } +}; + /// CachedTokens - A set of tokens that has been cached for later /// parsing. typedef llvm::SmallVector CachedTokens; @@ -793,33 +980,16 @@ public: BlockLiteralContext // Block literal declarator. }; - /// DeclaratorKind - The kind of declarator this represents. - enum DeclaratorKind { - DK_Abstract, // An abstract declarator (has no identifier) - DK_Normal, // A normal declarator (has an identifier). - DK_Constructor, // A C++ constructor (identifier is the class name) - DK_Destructor, // A C++ destructor (identifier is ~class name) - DK_Operator, // A C++ overloaded operator name - DK_Conversion, // A C++ conversion function (identifier is - // "operator " then the type name) - DK_TemplateId // A C++ template-id naming a function template - // specialization. - }; - private: const DeclSpec &DS; CXXScopeSpec SS; - IdentifierInfo *Identifier; - SourceLocation IdentifierLoc; + UnqualifiedId Name; SourceRange Range; /// Context - Where we are parsing this declarator. /// TheContext Context; - /// Kind - What kind of declarator this is. - DeclaratorKind Kind; - /// DeclTypeInfo - This holds each type that the declarator includes as it is /// parsed. This is pushed from the identifier out, which means that element /// #0 will be the most closely bound to the identifier, and @@ -838,21 +1008,6 @@ private: /// AsmLabel - The asm label, if specified. ActionBase::ExprTy *AsmLabel; - union { - // When Kind is DK_Constructor, DK_Destructor, or DK_Conversion, the - // type associated with the constructor, destructor, or conversion - // operator. - ActionBase::TypeTy *Type; - - /// When Kind is DK_Operator, this is the actual overloaded - /// operator that this declarator names. - OverloadedOperatorKind OperatorKind; - - /// When Kind is DK_TemplateId, this is the template-id annotation that - /// contains the template and its template arguments. - TemplateIdAnnotation *TemplateId; - }; - /// InlineParams - This is a local array used for the first function decl /// chunk to avoid going to the heap for the common case when we have one /// function chunk in the declarator. @@ -866,10 +1021,9 @@ private: public: Declarator(const DeclSpec &ds, TheContext C) - : DS(ds), Identifier(0), Range(ds.getSourceRange()), Context(C), - Kind(DK_Abstract), + : DS(ds), Range(ds.getSourceRange()), Context(C), InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error), - GroupingParens(false), AttrList(0), AsmLabel(0), Type(0), + GroupingParens(false), AttrList(0), AsmLabel(0), InlineParamsUsed(false), Extension(false) { } @@ -893,8 +1047,10 @@ public: const CXXScopeSpec &getCXXScopeSpec() const { return SS; } CXXScopeSpec &getCXXScopeSpec() { return SS; } + /// \brief Retrieve the name specified by this declarator. + UnqualifiedId &getName() { return Name; } + TheContext getContext() const { return Context; } - DeclaratorKind getKind() const { return Kind; } /// getSourceRange - Get the source range that spans this declarator. const SourceRange &getSourceRange() const { return Range; } @@ -925,22 +1081,15 @@ public: /// clear - Reset the contents of this Declarator. void clear() { SS.clear(); - Identifier = 0; - IdentifierLoc = SourceLocation(); + Name.clear(); Range = DS.getSourceRange(); - if (Kind == DK_TemplateId) - TemplateId->Destroy(); - - Kind = DK_Abstract; - for (unsigned i = 0, e = DeclTypeInfo.size(); i != e; ++i) DeclTypeInfo[i].destroy(); DeclTypeInfo.clear(); delete AttrList; AttrList = 0; AsmLabel = 0; - Type = 0; InlineParamsUsed = false; } @@ -971,84 +1120,28 @@ public: /// isPastIdentifier - Return true if we have parsed beyond the point where /// the - bool isPastIdentifier() const { return IdentifierLoc.isValid(); } + bool isPastIdentifier() const { return Name.isValid(); } /// hasName - Whether this declarator has a name, which might be an /// identifier (accessible via getIdentifier()) or some kind of /// special C++ name (constructor, destructor, etc.). - bool hasName() const { return getKind() != DK_Abstract; } - - IdentifierInfo *getIdentifier() const { return Identifier; } - SourceLocation getIdentifierLoc() const { return IdentifierLoc; } - - void SetIdentifier(IdentifierInfo *ID, SourceLocation Loc) { - Identifier = ID; - IdentifierLoc = Loc; - if (ID) - Kind = DK_Normal; - else - Kind = DK_Abstract; - SetRangeEnd(Loc); - } - - /// setConstructor - Set this declarator to be a C++ constructor - /// declarator. Also extends the range. - void setConstructor(ActionBase::TypeTy *Ty, SourceLocation Loc) { - IdentifierLoc = Loc; - Kind = DK_Constructor; - Type = Ty; - SetRangeEnd(Loc); + bool hasName() const { + return Name.getKind() != UnqualifiedId::IK_Identifier || Name.Identifier; } - /// setDestructor - Set this declarator to be a C++ destructor - /// declarator. Also extends the range to End, which should be the identifier - /// token. - void setDestructor(ActionBase::TypeTy *Ty, SourceLocation Loc, - SourceLocation EndLoc) { - IdentifierLoc = Loc; - Kind = DK_Destructor; - Type = Ty; - if (!EndLoc.isInvalid()) - SetRangeEnd(EndLoc); - } - - /// setConversionFunction - Set this declarator to be a C++ - /// conversion function declarator (e.g., @c operator int const *). - /// Also extends the range to EndLoc, which should be the last token of the - /// type name. - void setConversionFunction(ActionBase::TypeTy *Ty, SourceLocation Loc, - SourceLocation EndLoc) { - Identifier = 0; - IdentifierLoc = Loc; - Kind = DK_Conversion; - Type = Ty; - if (!EndLoc.isInvalid()) - SetRangeEnd(EndLoc); - } - - /// setOverloadedOperator - Set this declaration to be a C++ - /// overloaded operator declarator (e.g., @c operator+). - /// Also extends the range to EndLoc, which should be the last token of the - /// operator. - void setOverloadedOperator(OverloadedOperatorKind Op, SourceLocation Loc, - SourceLocation EndLoc) { - IdentifierLoc = Loc; - Kind = DK_Operator; - OperatorKind = Op; - if (!EndLoc.isInvalid()) - SetRangeEnd(EndLoc); + IdentifierInfo *getIdentifier() const { + if (Name.getKind() == UnqualifiedId::IK_Identifier) + return Name.Identifier; + + return 0; } + SourceLocation getIdentifierLoc() const { return Name.StartLocation; } - /// \brief Set this declaration to be a C++ template-id, which includes the - /// template (or set of function templates) along with template arguments. - void setTemplateId(TemplateIdAnnotation *TemplateId) { - assert(TemplateId && "NULL template-id provided to declarator?"); - IdentifierLoc = TemplateId->TemplateNameLoc; - Kind = DK_TemplateId; - SetRangeEnd(TemplateId->RAngleLoc); - this->TemplateId = TemplateId; + /// \brief Set the name of this declarator to be the given identifier. + void SetIdentifier(IdentifierInfo *Id, SourceLocation IdLoc) { + Name.setIdentifier(Id, IdLoc); } - + /// AddTypeInfo - Add a chunk to this declarator. Also extend the range to /// EndLoc, which should be the last token of the chunk. void AddTypeInfo(const DeclaratorChunk &TI, SourceLocation EndLoc) { @@ -1118,22 +1211,6 @@ public: void setExtension(bool Val = true) { Extension = Val; } bool getExtension() const { return Extension; } - ActionBase::TypeTy *getDeclaratorIdType() const { - assert((Kind == DK_Constructor || Kind == DK_Destructor || - Kind == DK_Conversion) && "Declarator kind does not have a type"); - return Type; - } - - OverloadedOperatorKind getOverloadedOperator() const { - assert(Kind == DK_Operator && "Declarator is not an overloaded operator"); - return OperatorKind; - } - - TemplateIdAnnotation *getTemplateId() { - assert(Kind == DK_TemplateId && "Declarator is not a template-id"); - return TemplateId; - } - void setInvalidType(bool Val = true) { InvalidType = Val; } bool isInvalidType() const { return InvalidType || DS.getTypeSpecType() == DeclSpec::TST_error; @@ -1152,7 +1229,7 @@ struct FieldDeclarator { BitfieldSize = 0; } }; - + } // end namespace clang #endif diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 4c7aa27d51..239d68a1ba 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1203,6 +1203,16 @@ private: BaseResult ParseBaseSpecifier(DeclPtrTy ClassDecl); AccessSpecifier getAccessSpecifierIfPresent() const; + bool ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool EnteringContext, + UnqualifiedId &Id); + bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, + bool IsExpressionContext, + bool IsDeclarator, + UnqualifiedId &Result); + //===--------------------------------------------------------------------===// // C++ 13.5: Overloaded operators [over.oper] // EndLoc, if non-NULL, is filled with the location of the last token of diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index b8422aad5a..3436900027 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -446,3 +446,28 @@ bool DeclSpec::isMissingDeclaratorOk() { || tst == TST_enum ) && getTypeRep() != 0 && StorageClassSpec != DeclSpec::SCS_typedef; } + +void UnqualifiedId::clear() { + if (Kind == IK_TemplateId) + TemplateId->Destroy(); + + Kind = IK_Identifier; + Identifier = 0; + StartLocation = SourceLocation(); + EndLocation = SourceLocation(); +} + +void UnqualifiedId::setOperatorFunctionId(SourceLocation OperatorLoc, + OverloadedOperatorKind Op, + SourceLocation SymbolLocations[3]) { + Kind = IK_OperatorFunctionId; + StartLocation = OperatorLoc; + EndLocation = OperatorLoc; + OperatorFunctionId.Operator = Op; + for (unsigned I = 0; I != 3; ++I) { + OperatorFunctionId.SymbolLocations[I] = SymbolLocations[I].getRawEncoding(); + + if (SymbolLocations[I].isValid()) + EndLocation = SymbolLocations[I]; + } +} diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index b56c33170c..55970c0c8c 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2270,97 +2270,46 @@ void Parser::ParseDeclaratorInternal(Declarator &D, void Parser::ParseDirectDeclarator(Declarator &D) { DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec()); - if (getLang().CPlusPlus) { - if (D.mayHaveIdentifier()) { - // ParseDeclaratorInternal might already have parsed the scope. - bool afterCXXScope = D.getCXXScopeSpec().isSet() || - ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0, - true); - if (afterCXXScope) { - // Change the declaration context for name lookup, until this function - // is exited (and the declarator has been parsed). - DeclScopeObj.EnterDeclaratorScope(); - } - - if (Tok.is(tok::identifier)) { - assert(Tok.getIdentifierInfo() && "Not an identifier?"); - - // If this identifier is the name of the current class, it's a - // constructor name. - if (!D.getDeclSpec().hasTypeSpecifier() && - Actions.isCurrentClassName(*Tok.getIdentifierInfo(),CurScope)) { - CXXScopeSpec *SS = afterCXXScope? &D.getCXXScopeSpec() : 0; - D.setConstructor(Actions.getTypeName(*Tok.getIdentifierInfo(), - Tok.getLocation(), CurScope, SS), - Tok.getLocation()); - // This is a normal identifier. - } else - D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); - ConsumeToken(); - goto PastIdentifier; - } else if (Tok.is(tok::annot_template_id)) { - TemplateIdAnnotation *TemplateId - = static_cast(Tok.getAnnotationValue()); - - D.setTemplateId(TemplateId); - ConsumeToken(); - goto PastIdentifier; - } else if (Tok.is(tok::kw_operator)) { - SourceLocation OperatorLoc = Tok.getLocation(); - SourceLocation EndLoc; - - // First try the name of an overloaded operator - if (OverloadedOperatorKind Op = TryParseOperatorFunctionId(&EndLoc)) { - D.setOverloadedOperator(Op, OperatorLoc, EndLoc); - } else { - // This must be a conversion function (C++ [class.conv.fct]). - if (TypeTy *ConvType = ParseConversionFunctionId(&EndLoc)) - D.setConversionFunction(ConvType, OperatorLoc, EndLoc); - else { - D.SetIdentifier(0, Tok.getLocation()); - } - } - goto PastIdentifier; - } else if (Tok.is(tok::tilde)) { - // This should be a C++ destructor. - SourceLocation TildeLoc = ConsumeToken(); - if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) { - // FIXME: Inaccurate. - SourceLocation NameLoc = Tok.getLocation(); - SourceLocation EndLoc; - CXXScopeSpec *SS = afterCXXScope? &D.getCXXScopeSpec() : 0; - TypeResult Type = ParseClassName(EndLoc, SS, true); - if (Type.isInvalid()) - D.SetIdentifier(0, TildeLoc); - else - D.setDestructor(Type.get(), TildeLoc, NameLoc); - } else { - Diag(Tok, diag::err_destructor_class_name); - D.SetIdentifier(0, TildeLoc); - } - goto PastIdentifier; - } - - // If we reached this point, token is not identifier and not '~'. - - if (afterCXXScope) { - Diag(Tok, diag::err_expected_unqualified_id); + if (getLang().CPlusPlus && D.mayHaveIdentifier()) { + // ParseDeclaratorInternal might already have parsed the scope. + bool afterCXXScope = D.getCXXScopeSpec().isSet() || + ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0, + true); + if (afterCXXScope) { + // Change the declaration context for name lookup, until this function + // is exited (and the declarator has been parsed). + DeclScopeObj.EnterDeclaratorScope(); + } + + if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) || + Tok.is(tok::annot_template_id) || Tok.is(tok::tilde)) { + // We found something that indicates the start of an unqualified-id. + // Parse that unqualified-id. + if (ParseUnqualifiedId(D.getCXXScopeSpec(), + /*EnteringContext=*/true, + /*AllowDestructorName=*/true, + /*AllowConstructorName=*/!D.getDeclSpec().hasTypeSpecifier(), + D.getName())) { D.SetIdentifier(0, Tok.getLocation()); D.setInvalidType(true); - goto PastIdentifier; + } else { + // Parsed the unqualified-id; update range information and move along. + if (D.getSourceRange().getBegin().isInvalid()) + D.SetRangeBegin(D.getName().getSourceRange().getBegin()); + D.SetRangeEnd(D.getName().getSourceRange().getEnd()); } + goto PastIdentifier; } - } - - // If we reached this point, we are either in C/ObjC or the token didn't - // satisfy any of the C++-specific checks. - if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) { + } else if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) { assert(!getLang().CPlusPlus && "There's a C++-specific check for tok::identifier above"); assert(Tok.getIdentifierInfo() && "Not an identifier?"); D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); ConsumeToken(); - } else if (Tok.is(tok::l_paren)) { + goto PastIdentifier; + } + + if (Tok.is(tok::l_paren)) { // direct-declarator: '(' declarator ')' // direct-declarator: '(' attributes declarator ')' // Example: 'char (*X)' or 'int (*XX)(void)' diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 65265afa91..a8e127610c 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -323,6 +323,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, SkipUntil(tok::semi); return DeclPtrTy(); } + // FIXME: what about conversion functions? } else if (Tok.is(tok::identifier)) { // Parse identifier. TargetName = Tok.getIdentifierInfo(); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index fa651569f8..dc7974135d 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -14,6 +14,8 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/DeclSpec.h" +#include "llvm/Support/ErrorHandling.h" + using namespace clang; /// \brief Parse global scope or nested-name-specifier if present. @@ -761,6 +763,417 @@ bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) { return false; } +/// \brief Finish parsing a C++ unqualified-id that is a template-id of +/// some form. +/// +/// This routine is invoked when a '<' is encountered after an identifier or +/// operator-function-id is parsed by \c ParseUnqualifiedId() to determine +/// whether the unqualified-id is actually a template-id. This routine will +/// then parse the template arguments and form the appropriate template-id to +/// return to the caller. +/// +/// \param SS the nested-name-specifier that precedes this template-id, if +/// we're actually parsing a qualified-id. +/// +/// \param Name for constructor and destructor names, this is the actual +/// identifier that may be a template-name. +/// +/// \param NameLoc the location of the class-name in a constructor or +/// destructor. +/// +/// \param EnteringContext whether we're entering the scope of the +/// nested-name-specifier. +/// +/// \param Id as input, describes the template-name or operator-function-id +/// that precedes the '<'. If template arguments were parsed successfully, +/// will be updated with the template-id. +/// +/// \returns true if a parse error occurred, false otherwise. +bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool EnteringContext, + UnqualifiedId &Id) { + assert(Tok.is(tok::less) && "Expected '<' to finish parsing a template-id"); + + TemplateTy Template; + TemplateNameKind TNK = TNK_Non_template; + switch (Id.getKind()) { + case UnqualifiedId::IK_Identifier: + TNK = Actions.isTemplateName(CurScope, *Id.Identifier, Id.StartLocation, + &SS, /*ObjectType=*/0, 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. + 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=*/0, EnteringContext, + Template); + break; + + case UnqualifiedId::IK_DestructorName: + TNK = Actions.isTemplateName(CurScope, *Name, NameLoc, + &SS, /*ObjectType=*/0, EnteringContext, + Template); + break; + + default: + return false; + } + + if (TNK == TNK_Non_template) + return false; + + // Parse the enclosed template argument list. + SourceLocation LAngleLoc, RAngleLoc; + TemplateArgList TemplateArgs; + TemplateArgIsTypeList TemplateArgIsType; + TemplateArgLocationList TemplateArgLocations; + if (ParseTemplateIdAfterTemplateName(Template, Id.StartLocation, + &SS, true, LAngleLoc, + TemplateArgs, + TemplateArgIsType, + TemplateArgLocations, + RAngleLoc)) + return true; + + if (Id.getKind() == UnqualifiedId::IK_Identifier || + Id.getKind() == UnqualifiedId::IK_OperatorFunctionId) { + // Form a parsed representation of the template-id to be stored in the + // UnqualifiedId. + TemplateIdAnnotation *TemplateId + = TemplateIdAnnotation::Allocate(TemplateArgs.size()); + + if (Id.getKind() == UnqualifiedId::IK_Identifier) { + TemplateId->Name = Id.Identifier; + TemplateId->TemplateNameLoc = Id.StartLocation; + } else { + // FIXME: Handle IK_OperatorFunctionId + } + + TemplateId->Template = Template.getAs(); + TemplateId->Kind = TNK; + TemplateId->LAngleLoc = LAngleLoc; + 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]; + } + + Id.setTemplateId(TemplateId); + return false; + } + + // Bundle the template arguments together. + ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(), + TemplateArgIsType.data(), + TemplateArgs.size()); + + // Constructor and destructor names. + Action::TypeResult Type + = Actions.ActOnTemplateIdType(Template, NameLoc, + LAngleLoc, TemplateArgsPtr, + &TemplateArgLocations[0], + RAngleLoc); + if (Type.isInvalid()) + return true; + + if (Id.getKind() == UnqualifiedId::IK_ConstructorName) + Id.setConstructorName(Type.get(), NameLoc, RAngleLoc); + else + Id.setDestructorName(Id.StartLocation, Type.get(), RAngleLoc); + + 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 +/// +/// operator-function-id: [C++ 13.5] +/// 'operator' operator +/// +/// operator: one of +/// new delete new[] delete[] +/// + - * / % ^ & | ~ +/// ! = < > += -= *= /= %= +/// ^= &= |= << >> >>= <<= == != +/// <= >= && || ++ -- , ->* -> +/// () [] +/// +/// 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] +/// \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. +/// +/// \param Result on a successful parse, contains the parsed unqualified-id. +/// +/// \returns true if parsing fails, false otherwise. +bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, + bool AllowDestructorName, + bool AllowConstructorName, + UnqualifiedId &Result) { + // unqualified-id: + // identifier + // template-id (when it hasn't already been annotated) + if (Tok.is(tok::identifier)) { + // Consume the identifier. + IdentifierInfo *Id = Tok.getIdentifierInfo(); + SourceLocation IdLoc = ConsumeToken(); + + if (AllowConstructorName && + Actions.isCurrentClassName(*Id, CurScope, &SS)) { + // We have parsed a constructor name. + Result.setConstructorName(Actions.getTypeName(*Id, IdLoc, CurScope, + &SS, false), + IdLoc, IdLoc); + } else { + // We have parsed an identifier. + Result.setIdentifier(Id, IdLoc); + } + + // If the next token is a '<', we may have a template. + if (Tok.is(tok::less)) + return ParseUnqualifiedIdTemplateId(SS, Id, IdLoc, EnteringContext, + Result); + + return false; + } + + // unqualified-id: + // template-id (already parsed and annotated) + if (Tok.is(tok::annot_template_id)) { + // FIXME: Could this be a constructor name??? + + // We have already parsed a template-id; consume the annotation token as + // our unqualified-id. + Result.setTemplateId( + static_cast(Tok.getAnnotationValue())); + ConsumeToken(); + return false; + } + + // unqualified-id: + // 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, 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)) + 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; + } + + if ((AllowDestructorName || SS.isSet()) && Tok.is(tok::tilde)) { + // C++ [expr.unary.op]p10: + // There is an ambiguity in the unary-expression ~X(), where X is a + // class-name. The ambiguity is resolved in favor of treating ~ as a + // unary complement rather than treating ~X as referring to a destructor. + + // Parse the '~'. + SourceLocation TildeLoc = ConsumeToken(); + + // Parse the class-name. + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_destructor_class_name); + return true; + } + + // Parse the class-name (or template-name in a simple-template-id). + IdentifierInfo *ClassName = Tok.getIdentifierInfo(); + SourceLocation ClassNameLoc = ConsumeToken(); + + // Note that this is a destructor name. + Action::TypeTy *Ty = Actions.getTypeName(*ClassName, ClassNameLoc, + CurScope, &SS); + if (!Ty) { + Diag(ClassNameLoc, diag::err_destructor_class_name); + return true; + } + + Result.setDestructorName(TildeLoc, Ty, ClassNameLoc); + + if (Tok.is(tok::less)) + return ParseUnqualifiedIdTemplateId(SS, ClassName, ClassNameLoc, + EnteringContext, Result); + + return false; + } + + Diag(Tok, diag::err_expected_unqualified_id); + return true; +} + /// TryParseOperatorFunctionId - Attempts to parse a C++ overloaded /// operator name (C++ [over.oper]). If successful, returns the /// predefined identifier that corresponds to that overloaded diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 71afe68916..8d00c09f30 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1606,45 +1606,48 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, /// GetNameForDeclarator - Determine the full declaration name for the /// given Declarator. DeclarationName Sema::GetNameForDeclarator(Declarator &D) { - switch (D.getKind()) { - case Declarator::DK_Abstract: - assert(D.getIdentifier() == 0 && "abstract declarators have no name"); - return DeclarationName(); + UnqualifiedId &Name = D.getName(); + switch (Name.getKind()) { + case UnqualifiedId::IK_Identifier: + return DeclarationName(Name.Identifier); - case Declarator::DK_Normal: - assert (D.getIdentifier() != 0 && "normal declarators have an identifier"); - return DeclarationName(D.getIdentifier()); + case UnqualifiedId::IK_OperatorFunctionId: + return Context.DeclarationNames.getCXXOperatorName( + Name.OperatorFunctionId.Operator); - case Declarator::DK_Constructor: { - QualType Ty = GetTypeFromParser(D.getDeclaratorIdType()); + case UnqualifiedId::IK_ConversionFunctionId: { + QualType Ty = GetTypeFromParser(Name.ConversionFunctionId); + if (Ty.isNull()) + return DeclarationName(); + + return Context.DeclarationNames.getCXXConversionFunctionName( + Context.getCanonicalType(Ty)); + } + + case UnqualifiedId::IK_ConstructorName: { + QualType Ty = GetTypeFromParser(Name.ConstructorName); + if (Ty.isNull()) + return DeclarationName(); + return Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(Ty)); } - - case Declarator::DK_Destructor: { - QualType Ty = GetTypeFromParser(D.getDeclaratorIdType()); + + case UnqualifiedId::IK_DestructorName: { + QualType Ty = GetTypeFromParser(Name.DestructorName); + if (Ty.isNull()) + return DeclarationName(); + return Context.DeclarationNames.getCXXDestructorName( Context.getCanonicalType(Ty)); } - - case Declarator::DK_Conversion: { - // FIXME: We'd like to keep the non-canonical type for diagnostics! - QualType Ty = GetTypeFromParser(D.getDeclaratorIdType()); - return Context.DeclarationNames.getCXXConversionFunctionName( - Context.getCanonicalType(Ty)); - } - - case Declarator::DK_Operator: - assert(D.getIdentifier() == 0 && "operator names have no identifier"); - return Context.DeclarationNames.getCXXOperatorName( - D.getOverloadedOperator()); - case Declarator::DK_TemplateId: { - TemplateName Name - = TemplateName::getFromVoidPointer(D.getTemplateId()->Template); - if (TemplateDecl *Template = Name.getAsTemplateDecl()) + case UnqualifiedId::IK_TemplateId: { + TemplateName TName + = TemplateName::getFromVoidPointer(Name.TemplateId->Template); + if (TemplateDecl *Template = TName.getAsTemplateDecl()) return Template->getDeclName(); - if (OverloadedFunctionDecl *Ovl = Name.getAsOverloadedFunctionDecl()) + if (OverloadedFunctionDecl *Ovl = TName.getAsOverloadedFunctionDecl()) return Ovl->getDeclName(); return DeclarationName(); @@ -2517,7 +2520,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, isInline |= IsFunctionDefinition; } - if (D.getKind() == Declarator::DK_Constructor) { + if (Name.getNameKind() == DeclarationName::CXXConstructorName) { // This is a C++ constructor declaration. assert(DC->isRecord() && "Constructors can only be declared in a member context"); @@ -2530,7 +2533,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, D.getIdentifierLoc(), Name, R, DInfo, isExplicit, isInline, /*isImplicitlyDeclared=*/false); - } else if (D.getKind() == Declarator::DK_Destructor) { + } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { // This is a C++ destructor declaration. if (DC->isRecord()) { R = CheckDestructorDeclarator(D, SC); @@ -2552,7 +2555,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, /*hasPrototype=*/true); D.setInvalidType(); } - } else if (D.getKind() == Declarator::DK_Conversion) { + } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { if (!DC->isRecord()) { Diag(D.getIdentifierLoc(), diag::err_conv_function_not_member); @@ -2798,8 +2801,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, bool HasExplicitTemplateArgs = false; llvm::SmallVector TemplateArgs; SourceLocation LAngleLoc, RAngleLoc; - if (D.getKind() == Declarator::DK_TemplateId) { - TemplateIdAnnotation *TemplateId = D.getTemplateId(); + if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { + TemplateIdAnnotation *TemplateId = D.getName().TemplateId; ASTTemplateArgsPtr TemplateArgsPtr(*this, TemplateId->getTemplateArgs(), TemplateId->getTemplateArgIsType(), diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 90aef21637..bc255137fc 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2295,7 +2295,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, // (7.1.3); however, a typedef-name that names a class shall not // be used as the identifier in the declarator for a destructor // declaration. - QualType DeclaratorType = GetTypeFromParser(D.getDeclaratorIdType()); + QualType DeclaratorType = GetTypeFromParser(D.getName().DestructorName); if (isa(DeclaratorType)) { Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) << DeclaratorType; @@ -2421,7 +2421,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, // C++ [class.conv.fct]p4: // The conversion-type-id shall not represent a function type nor // an array type. - QualType ConvType = GetTypeFromParser(D.getDeclaratorIdType()); + QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId); if (ConvType->isArrayType()) { Diag(D.getIdentifierLoc(), diag::err_conv_function_to_array); ConvType = Context.getPointerType(ConvType); @@ -4515,12 +4515,12 @@ Sema::ActOnFriendFunctionDecl(Scope *S, if (DC->isFileContext()) { // This implies that it has to be an operator or function. - if (D.getKind() == Declarator::DK_Constructor || - D.getKind() == Declarator::DK_Destructor || - D.getKind() == Declarator::DK_Conversion) { + if (D.getName().getKind() == UnqualifiedId::IK_ConstructorName || + D.getName().getKind() == UnqualifiedId::IK_DestructorName || + D.getName().getKind() == UnqualifiedId::IK_ConversionFunctionId) { Diag(Loc, diag::err_introducing_special_friend) << - (D.getKind() == Declarator::DK_Constructor ? 0 : - D.getKind() == Declarator::DK_Destructor ? 1 : 2); + (D.getName().getKind() == UnqualifiedId::IK_ConstructorName ? 0 : + D.getName().getKind() == UnqualifiedId::IK_DestructorName ? 1 : 2); return DeclPtrTy(); } } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index f7a22d2eb0..7182992d42 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -4043,8 +4043,8 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // argument list into our AST format. bool HasExplicitTemplateArgs = false; llvm::SmallVector TemplateArgs; - if (D.getKind() == Declarator::DK_TemplateId) { - TemplateIdAnnotation *TemplateId = D.getTemplateId(); + if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { + TemplateIdAnnotation *TemplateId = D.getName().TemplateId; ASTTemplateArgsPtr TemplateArgsPtr(*this, TemplateId->getTemplateArgs(), TemplateId->getTemplateArgIsType(), @@ -4147,7 +4147,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // // C++98 has the same restriction, just worded differently. FunctionTemplateDecl *FunTmpl = Specialization->getPrimaryTemplate(); - if (D.getKind() != Declarator::DK_TemplateId && !FunTmpl && + if (D.getName().getKind() != UnqualifiedId::IK_TemplateId && !FunTmpl && D.getCXXScopeSpec().isSet() && !ScopeSpecifierHasTemplateId(D.getCXXScopeSpec())) Diag(D.getIdentifierLoc(), diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index d2652c9864..94b74fbcd1 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -870,6 +870,11 @@ QualType Sema::BuildBlockPointerType(QualType T, unsigned CVR, QualType Sema::GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo) { QualType QT = QualType::getFromOpaquePtr(Ty); + if (QT.isNull()) { + if (DInfo) *DInfo = 0; + return QualType(); + } + DeclaratorInfo *DI = 0; if (LocInfoType *LIT = dyn_cast(QT)) { QT = LIT->getType(); @@ -893,20 +898,19 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // have a type. QualType T; - switch (D.getKind()) { - case Declarator::DK_Abstract: - case Declarator::DK_Normal: - case Declarator::DK_Operator: - case Declarator::DK_TemplateId: + switch (D.getName().getKind()) { + case UnqualifiedId::IK_Identifier: + case UnqualifiedId::IK_OperatorFunctionId: + case UnqualifiedId::IK_TemplateId: T = ConvertDeclSpecToType(D, *this); if (!D.isInvalidType() && OwnedDecl && D.getDeclSpec().isTypeSpecOwned()) *OwnedDecl = cast((Decl *)D.getDeclSpec().getTypeRep()); break; - case Declarator::DK_Constructor: - case Declarator::DK_Destructor: - case Declarator::DK_Conversion: + case UnqualifiedId::IK_ConstructorName: + case UnqualifiedId::IK_DestructorName: + case UnqualifiedId::IK_ConversionFunctionId: // Constructors and destructors don't have return types. Use // "void" instead. Conversion operators will check their return // types separately. diff --git a/test/CXX/temp/temp.spec/temp.explicit/p3.cpp b/test/CXX/temp/temp.spec/temp.explicit/p3.cpp index 00484e9894..9057971a5b 100644 --- a/test/CXX/temp/temp.spec/temp.explicit/p3.cpp +++ b/test/CXX/temp/temp.spec/temp.explicit/p3.cpp @@ -13,9 +13,9 @@ template struct X1; // expected-note 5{{declared here}} // FIXME: Repeated diagnostics here! template void X0::f0(int); // expected-error 2{{incomplete type}} \ - // expected-error{{invalid token after}} + // expected-error{{does not refer}} template void X1::f0(int); // expected-error 2{{implicit instantiation of undefined template}} \ - // expected-error{{invalid token}} + // expected-error{{does not refer}} // A definition of a class template or class member template shall be in scope // at the point of the explicit instantiation of the class template or class diff --git a/test/SemaCXX/constructor.cpp b/test/SemaCXX/constructor.cpp index 5ce595cdce..58d28b5518 100644 --- a/test/SemaCXX/constructor.cpp +++ b/test/SemaCXX/constructor.cpp @@ -14,7 +14,7 @@ class Foo { static Foo(short, short); // expected-error{{constructor cannot be declared 'static'}} virtual Foo(double); // expected-error{{constructor cannot be declared 'virtual'}} Foo(long) const; // expected-error{{'const' qualifier is not allowed on a constructor}} - + int Foo(int, int); // expected-error{{constructor cannot have a return type}} }; diff --git a/test/SemaTemplate/constructor-template.cpp b/test/SemaTemplate/constructor-template.cpp index acd845bc2f..79bf7c585e 100644 --- a/test/SemaTemplate/constructor-template.cpp +++ b/test/SemaTemplate/constructor-template.cpp @@ -51,3 +51,4 @@ void test_X1(X1 xi) { template struct A {}; template <> struct A{A(const A&);}; struct B { A x; B(B& a) : x(a.x) {} }; + -- 2.40.0