diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 36 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 22 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 37 |
3 files changed, 82 insertions, 13 deletions
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index aa2c0f512a..d7f8e982aa 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -468,7 +468,10 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, } // Parse nested-name-specifier. - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + IdentifierInfo *LastII = 0; + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false, + /*MayBePseudoDtor=*/0, /*IsTypename=*/false, + /*LastII=*/&LastII); // Check nested-name specifier. if (SS.isInvalid()) { @@ -476,18 +479,31 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, return 0; } + SourceLocation TemplateKWLoc; + UnqualifiedId Name; + // Parse the unqualified-id. We allow parsing of both constructor and // destructor names and allow the action module to diagnose any semantic // errors. - SourceLocation TemplateKWLoc; - UnqualifiedId Name; - if (ParseUnqualifiedId(SS, - /*EnteringContext=*/false, - /*AllowDestructorName=*/true, - /*AllowConstructorName=*/true, - ParsedType(), - TemplateKWLoc, - Name)) { + // + // C++11 [class.qual]p2: + // [...] in a using-declaration that is a member-declaration, if the name + // specified after the nested-name-specifier is the same as the identifier + // or the simple-template-id's template-name in the last component of the + // nested-name-specifier, the name is [...] considered to name the + // constructor. + if (getLangOpts().CPlusPlus11 && Context == Declarator::MemberContext && + Tok.is(tok::identifier) && NextToken().is(tok::semi) && + SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() && + !SS.getScopeRep()->getAsNamespace() && + !SS.getScopeRep()->getAsNamespaceAlias()) { + SourceLocation IdLoc = ConsumeToken(); + ParsedType Type = Actions.getInheritingConstructorName(SS, IdLoc, *LastII); + Name.setConstructorName(Type, IdLoc, IdLoc); + } else if (ParseUnqualifiedId(SS, /*EnteringContext=*/ false, + /*AllowDestructorName=*/ true, + /*AllowConstructorName=*/ true, ParsedType(), + TemplateKWLoc, Name)) { SkipUntil(tok::semi); return 0; } diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index f72e68e2a1..22938afede 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -168,19 +168,26 @@ void Parser::CheckForLParenAfterColonColon() { /// if we do end up determining that we are parsing a destructor name, /// the last component of the nested-name-specifier is not parsed as /// part of the scope specifier. - -/// member access expression, e.g., the \p T:: in \p p->T::m. +/// +/// \param IsTypename If \c true, this nested-name-specifier is known to be +/// part of a type name. This is used to improve error recovery. +/// +/// \param LastII When non-NULL, points to an IdentifierInfo* that will be +/// filled in with the leading identifier in the last component of the +/// nested-name-specifier, if any. /// /// \returns true if there was an error parsing a scope specifier bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, ParsedType ObjectType, bool EnteringContext, bool *MayBePseudoDestructor, - bool IsTypename) { + bool IsTypename, + IdentifierInfo **LastII) { assert(getLangOpts().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); if (Tok.is(tok::annot_cxxscope)) { + assert(!LastII && "want last identifier but have already annotated scope"); Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), Tok.getAnnotationRange(), SS); @@ -188,6 +195,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, return false; } + if (LastII) + *LastII = 0; + bool HasScopeSpecifier = false; if (Tok.is(tok::coloncolon)) { @@ -334,6 +344,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, return false; } + if (LastII) + *LastII = TemplateId->Name; + // Consume the template-id token. ConsumeToken(); @@ -405,6 +418,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, return false; } + if (LastII) + *LastII = &II; + // We have an identifier followed by a '::'. Lookup this name // as the name in a nested-name-specifier. SourceLocation IdLoc = ConsumeToken(); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 4b426bf62e..1724624fe3 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -38,6 +38,43 @@ using namespace clang; using namespace sema; +/// \brief Handle the result of the special case name lookup for inheriting +/// constructor declarations. 'NS::X::X' and 'NS::X<...>::X' are treated as +/// constructor names in member using declarations, even if 'X' is not the +/// name of the corresponding type. +ParsedType Sema::getInheritingConstructorName(CXXScopeSpec &SS, + SourceLocation NameLoc, + IdentifierInfo &Name) { + NestedNameSpecifier *NNS = SS.getScopeRep(); + + // Convert the nested-name-specifier into a type. + QualType Type; + switch (NNS->getKind()) { + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + Type = QualType(NNS->getAsType(), 0); + break; + + case NestedNameSpecifier::Identifier: + // Strip off the last layer of the nested-name-specifier and build a + // typename type for it. + assert(NNS->getAsIdentifier() == &Name && "not a constructor name"); + Type = Context.getDependentNameType(ETK_None, NNS->getPrefix(), + NNS->getAsIdentifier()); + break; + + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + llvm_unreachable("Nested name specifier is not a type for inheriting ctor"); + } + + // This reference to the type is located entirely at the location of the + // final identifier in the qualified-id. + return CreateParsedType(Type, + Context.getTrivialTypeSourceInfo(Type, NameLoc)); +} + ParsedType Sema::getDestructorName(SourceLocation TildeLoc, IdentifierInfo &II, SourceLocation NameLoc, |