Index: include/clang/AST/DataRecursiveASTVisitor.h =================================================================== --- include/clang/AST/DataRecursiveASTVisitor.h +++ include/clang/AST/DataRecursiveASTVisitor.h @@ -624,6 +624,7 @@ case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: return true; case NestedNameSpecifier::TypeSpec: @@ -648,6 +649,7 @@ case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: return true; case NestedNameSpecifier::TypeSpec: Index: include/clang/AST/NestedNameSpecifier.h =================================================================== --- include/clang/AST/NestedNameSpecifier.h +++ include/clang/AST/NestedNameSpecifier.h @@ -22,6 +22,7 @@ namespace clang { class ASTContext; +class CXXRecordDecl; class NamespaceAliasDecl; class NamespaceDecl; class IdentifierInfo; @@ -45,7 +46,7 @@ /// \brief Enumeration describing enum StoredSpecifierKind { StoredIdentifier = 0, - StoredNamespaceOrAlias = 1, + StoredDecl = 1, StoredTypeSpec = 2, StoredTypeSpecWithTemplate = 3 }; @@ -83,7 +84,10 @@ /// stored as a Type*. TypeSpecWithTemplate, /// \brief The global specifier '::'. There is no stored value. - Global + Global, + /// \brief Microsoft's '__super' specifier, stored as a CXXRecordDecl* of + /// the class it appeared in. + Super }; private: @@ -143,6 +147,11 @@ /// scope. static NestedNameSpecifier *GlobalSpecifier(const ASTContext &Context); + /// \brief Returns the nested name specifier representing the __super scope + /// for the given CXXRecordDecl. + static NestedNameSpecifier *SuperSpecifier(const ASTContext &Context, + CXXRecordDecl *RD); + /// \brief Return the prefix of this nested name specifier. /// /// The prefix contains all of the parts of the nested name @@ -172,6 +181,10 @@ /// specifier. NamespaceAliasDecl *getAsNamespaceAlias() const; + /// \brief Retrieve the record declaration stored in this nested name + /// specifier. + CXXRecordDecl *getAsRecordDecl() const; + /// \brief Retrieve the type stored in this nested name specifier. const Type *getAsType() const { if (Prefix.getInt() == StoredTypeSpec || @@ -421,7 +434,22 @@ /// \brief Turn this (empty) nested-name-specifier into the global /// nested-name-specifier '::'. void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc); - + + /// \brief Turns this (empty) nested-name-specifier into '__super' + /// nested-name-specifier. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param RD The declaration of the class in which nested-name-specifier + /// appeared. + /// + /// \param SuperLoc The location of the '__super' keyword. + /// name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void MakeSuper(ASTContext &Context, CXXRecordDecl *RD, + SourceLocation SuperLoc, SourceLocation ColonColonLoc); /// \brief Make a new nested-name-specifier from incomplete source-location /// information. /// Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -690,6 +690,7 @@ case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: return true; case NestedNameSpecifier::TypeSpec: @@ -714,6 +715,7 @@ case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: return true; case NestedNameSpecifier::TypeSpec: Index: include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- include/clang/Basic/DiagnosticParseKinds.td +++ include/clang/Basic/DiagnosticParseKinds.td @@ -368,6 +368,8 @@ "function definition is not allowed here">; def err_expected_end_of_enumerator : Error< "expected '= constant-expression' or end of enumerator definition">; +def err_expected_coloncolon_after_super : Error< + "expected '::' after '__super'">; /// Objective-C parser diagnostics def err_expected_minus_or_plus : Error< @@ -521,6 +523,8 @@ InGroup>; def err_function_is_not_record : Error< "unexpected %0 in function call; perhaps remove the %0?">; +def err_super_in_using_declaration : Error< + "'__super' cannot be used with a using declaration">; // C++ derived classes def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">; Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -527,6 +527,9 @@ "with base classes or virtual functions">, DefaultError, InGroup; def err_section_conflict : Error<"%0 causes a section type conflict with %1">; +def err_no_base_classes : Error<"invalid use of '__super', %0 has no base classes">; +def err_invalid_super_scope : Error<"invalid use of '__super', " + "this keyword can only be used inside class or non-static member function scope">; def warn_pragma_unused_undeclared_var : Warning< "undeclared variable %0 used as an argument for '#pragma unused'">, Index: include/clang/Basic/TokenKinds.def =================================================================== --- include/clang/Basic/TokenKinds.def +++ include/clang/Basic/TokenKinds.def @@ -459,6 +459,7 @@ KEYWORD(__thiscall , KEYALL) KEYWORD(__forceinline , KEYMS) KEYWORD(__unaligned , KEYMS) +KEYWORD(__super , KEYMS) // OpenCL address space qualifiers KEYWORD(__global , KEYOPENCL) Index: include/clang/Sema/DeclSpec.h =================================================================== --- include/clang/Sema/DeclSpec.h +++ include/clang/Sema/DeclSpec.h @@ -37,6 +37,7 @@ namespace clang { class ASTContext; + class CXXRecordDecl; class TypeLoc; class LangOptions; class DiagnosticsEngine; @@ -141,6 +142,22 @@ /// nested-name-specifier '::'. void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc); + /// \brief Turns this (empty) nested-name-specifier into '__super' + /// nested-name-specifier. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param RD The declaration of the class in which nested-name-specifier + /// appeared. + /// + /// \param SuperLoc The location of the '__super' keyword. + /// name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void MakeSuper(ASTContext &Context, CXXRecordDecl *RD, + SourceLocation SuperLoc, SourceLocation ColonColonLoc); + /// \brief Make a new nested-name-specifier from incomplete source-location /// information. /// Index: include/clang/Sema/Scope.h =================================================================== --- include/clang/Sema/Scope.h +++ include/clang/Sema/Scope.h @@ -300,6 +300,9 @@ return ErrorTrap.hasUnrecoverableErrorOccurred(); } + /// isFunctionScope() - Return true if this scope is a function scope. + bool isFunctionScope() const { return (getFlags() & Scope::FnScope); } + /// isClassScope - Return true if this scope is a class/struct/union scope. bool isClassScope() const { return (getFlags() & Scope::ClassScope); Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -2613,6 +2613,7 @@ ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc, RedeclarationKind Redecl = NotForRedeclaration); + void LookupInSuper(LookupResult &R, CXXRecordDecl *Class); void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, @@ -4476,16 +4477,26 @@ /// \brief The parser has parsed a global nested-name-specifier '::'. /// - /// \param S The scope in which this nested-name-specifier occurs. - /// /// \param CCLoc The location of the '::'. /// /// \param SS The nested-name-specifier, which will be updated in-place /// to reflect the parsed nested-name-specifier. /// /// \returns true if an error occurred, false otherwise. - bool ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc, - CXXScopeSpec &SS); + bool ActOnCXXGlobalScopeSpecifier(SourceLocation CCLoc, CXXScopeSpec &SS); + + /// \brief The parser has parsed a '__super' nested-name-specifier. + /// + /// \param SuperLoc The location of the '__super' keyword. + /// + /// \param ColonColonLoc The location of the '::'. + /// + /// \param SS The nested-name-specifier, which will be updated in-place + /// to reflect the parsed nested-name-specifier. + /// + /// \returns true if an error occurred, false otherwise. + bool ActOnSuperScopeSpecifier(SourceLocation SuperLoc, + SourceLocation ColonColonLoc, CXXScopeSpec &SS); bool isAcceptableNestedNameSpecifier(const NamedDecl *SD); NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -4195,7 +4195,8 @@ } case NestedNameSpecifier::Global: - // The global specifier is canonical and unique. + case NestedNameSpecifier::Super: + // The global specifier and __super specifer are canonical and unique. return NNS; } Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -4760,6 +4760,13 @@ case NestedNameSpecifier::Global: return NestedNameSpecifier::GlobalSpecifier(ToContext); + case NestedNameSpecifier::Super: + if (CXXRecordDecl *RD = + cast(Import(FromNNS->getAsRecordDecl()))) { + return NestedNameSpecifier::SuperSpecifier(ToContext, RD); + } + return nullptr; + case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { QualType T = Import(QualType(FromNNS->getAsType(), 0u)); Index: lib/AST/ExprCXX.cpp =================================================================== --- lib/AST/ExprCXX.cpp +++ lib/AST/ExprCXX.cpp @@ -1404,7 +1404,8 @@ // It can't be dependent: after all, we were actually able to do the // lookup. CXXRecordDecl *Record = nullptr; - if (getQualifier()) { + auto *NNS = getQualifier(); + if (NNS && NNS->getKind() != NestedNameSpecifier::Super) { const Type *T = getQualifier()->getAsType(); assert(T && "qualifier in member expression does not name type"); Record = T->getAsCXXRecordDecl(); Index: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -811,6 +811,9 @@ // We never want an 'E' here. return; + case NestedNameSpecifier::Super: + llvm_unreachable("Can't mangle __super specifier"); + case NestedNameSpecifier::Namespace: if (qualifier->getPrefix()) mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, @@ -1459,6 +1462,9 @@ // nothing return; + case NestedNameSpecifier::Super: + llvm_unreachable("Can't mangle __super specifier"); + case NestedNameSpecifier::Namespace: mangleName(qualifier->getAsNamespace()); return; Index: lib/AST/NestedNameSpecifier.cpp =================================================================== --- lib/AST/NestedNameSpecifier.cpp +++ lib/AST/NestedNameSpecifier.cpp @@ -66,7 +66,7 @@ "Broken nested name specifier"); NestedNameSpecifier Mockup; Mockup.Prefix.setPointer(Prefix); - Mockup.Prefix.setInt(StoredNamespaceOrAlias); + Mockup.Prefix.setInt(StoredDecl); Mockup.Specifier = const_cast(NS); return FindOrInsert(Context, Mockup); } @@ -82,7 +82,7 @@ "Broken nested name specifier"); NestedNameSpecifier Mockup; Mockup.Prefix.setPointer(Prefix); - Mockup.Prefix.setInt(StoredNamespaceOrAlias); + Mockup.Prefix.setInt(StoredDecl); Mockup.Specifier = Alias; return FindOrInsert(Context, Mockup); } @@ -118,6 +118,16 @@ return Context.GlobalNestedNameSpecifier; } +NestedNameSpecifier * +NestedNameSpecifier::SuperSpecifier(const ASTContext &Context, + CXXRecordDecl *RD) { + NestedNameSpecifier Mockup; + Mockup.Prefix.setPointer(nullptr); + Mockup.Prefix.setInt(StoredDecl); + Mockup.Specifier = RD; + return FindOrInsert(Context, Mockup); +} + NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const { if (!Specifier) return Global; @@ -126,9 +136,12 @@ case StoredIdentifier: return Identifier; - case StoredNamespaceOrAlias: - return isa(static_cast(Specifier))? Namespace - : NamespaceAlias; + case StoredDecl: { + NamedDecl *ND = static_cast(Specifier); + if (isa(ND)) + return Super; + return isa(ND) ? Namespace : NamespaceAlias; + } case StoredTypeSpec: return TypeSpec; @@ -140,24 +153,29 @@ llvm_unreachable("Invalid NNS Kind!"); } -/// \brief Retrieve the namespace stored in this nested name -/// specifier. +/// \brief Retrieve the namespace stored in this nested name specifier. NamespaceDecl *NestedNameSpecifier::getAsNamespace() const { - if (Prefix.getInt() == StoredNamespaceOrAlias) + if (Prefix.getInt() == StoredDecl) return dyn_cast(static_cast(Specifier)); return nullptr; } -/// \brief Retrieve the namespace alias stored in this nested name -/// specifier. +/// \brief Retrieve the namespace alias stored in this nested name specifier. NamespaceAliasDecl *NestedNameSpecifier::getAsNamespaceAlias() const { - if (Prefix.getInt() == StoredNamespaceOrAlias) + if (Prefix.getInt() == StoredDecl) return dyn_cast(static_cast(Specifier)); return nullptr; } +/// \brief Retrieve the record declaration stored in this nested name specifier. +CXXRecordDecl *NestedNameSpecifier::getAsRecordDecl() const { + if (Prefix.getInt() == StoredDecl) + return dyn_cast(static_cast(Specifier)); + + return nullptr; +} /// \brief Whether this nested name specifier refers to a dependent /// type or not. @@ -172,6 +190,15 @@ case Global: return false; + case Super: { + CXXRecordDecl *RD = static_cast(Specifier); + for (const auto &Base : RD->bases()) + if (Base.getType()->isDependentType()) + return true; + + return false; + } + case TypeSpec: case TypeSpecWithTemplate: return getAsType()->isDependentType(); @@ -191,8 +218,9 @@ case Namespace: case NamespaceAlias: case Global: + case Super: return false; - + case TypeSpec: case TypeSpecWithTemplate: return getAsType()->isInstantiationDependentType(); @@ -209,6 +237,7 @@ case Namespace: case NamespaceAlias: case Global: + case Super: return false; case TypeSpec: @@ -246,6 +275,10 @@ case Global: break; + case Super: + OS << "__super"; + break; + case TypeSpecWithTemplate: OS << "template "; // Fall through to print the type. @@ -304,6 +337,7 @@ case NestedNameSpecifier::Identifier: case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: + case NestedNameSpecifier::Super: // The location of the identifier or namespace name. Length += sizeof(unsigned); break; @@ -369,6 +403,7 @@ case NestedNameSpecifier::Identifier: case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: + case NestedNameSpecifier::Super: return SourceRange(LoadSourceLocation(Data, Offset), LoadSourceLocation(Data, Offset + sizeof(unsigned))); @@ -552,6 +587,17 @@ SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); } +void NestedNameSpecifierLocBuilder::MakeSuper(ASTContext &Context, + CXXRecordDecl *RD, + SourceLocation SuperLoc, + SourceLocation ColonColonLoc) { + Representation = NestedNameSpecifier::SuperSpecifier(Context, RD); + + // Push source-location info into the buffer. + SaveSourceLocation(SuperLoc, Buffer, BufferSize, BufferCapacity); + SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); +} + void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier, SourceRange R) { @@ -583,6 +629,7 @@ } case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: break; } Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -2731,6 +2731,7 @@ goto DoneWithDeclSpec; // typedef-name + case tok::kw___super: case tok::kw_decltype: case tok::identifier: { // This identifier can only be a typedef name if we haven't already seen Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -493,6 +493,12 @@ if (TryConsumeToken(tok::kw_typename, TypenameLoc)) HasTypenameKeyword = true; + if (Tok.is(tok::kw___super)) { + Diag(Tok.getLocation(), diag::err_super_in_using_declaration); + SkipUntil(tok::semi); + return nullptr; + } + // Parse nested-name-specifier. IdentifierInfo *LastII = nullptr; ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false, @@ -2054,7 +2060,8 @@ // Access declarations. bool MalformedTypeSpec = false; if (!TemplateInfo.Kind && - (Tok.is(tok::identifier) || Tok.is(tok::coloncolon))) { + (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || + Tok.is(tok::kw___super))) { if (TryAnnotateCXXScopeToken()) MalformedTypeSpec = true; Index: lib/Parse/ParseExpr.cpp =================================================================== --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -688,11 +688,12 @@ ConsumeToken(); break; + case tok::kw___super: case tok::kw_decltype: // Annotate the token and tail recurse. if (TryAnnotateTypeOrScopeToken()) return ExprError(); - assert(Tok.isNot(tok::kw_decltype)); + assert(Tok.isNot(tok::kw_decltype) && Tok.isNot(tok::kw___super)); return ParseCastExpression(isUnaryExpression, isAddressOfOperand); case tok::identifier: { // primary-expression: identifier Index: lib/Parse/ParseExprCXX.cpp =================================================================== --- lib/Parse/ParseExprCXX.cpp +++ lib/Parse/ParseExprCXX.cpp @@ -218,7 +218,7 @@ return false; // '::' - Global scope qualifier. - if (Actions.ActOnCXXGlobalScopeSpecifier(getCurScope(), ConsumeToken(), SS)) + if (Actions.ActOnCXXGlobalScopeSpecifier(ConsumeToken(), SS)) return true; CheckForLParenAfterColonColon(); @@ -226,6 +226,16 @@ HasScopeSpecifier = true; } + if (Tok.is(tok::kw___super)) { + SourceLocation SuperLoc = ConsumeToken(); + if (!Tok.is(tok::coloncolon)) { + Diag(Tok.getLocation(), diag::err_expected_coloncolon_after_super); + return true; + } + + return Actions.ActOnSuperScopeSpecifier(SuperLoc, ConsumeToken(), SS); + } + bool CheckForDestructor = false; if (MayBePseudoDestructor && *MayBePseudoDestructor) { CheckForDestructor = true; Index: lib/Parse/ParseTentative.cpp =================================================================== --- lib/Parse/ParseTentative.cpp +++ lib/Parse/ParseTentative.cpp @@ -1181,6 +1181,7 @@ return TPResult::False; } // Fall through. + case tok::kw___super: case tok::kw_decltype: // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. Index: lib/Parse/Parser.cpp =================================================================== --- lib/Parse/Parser.cpp +++ lib/Parse/Parser.cpp @@ -1482,10 +1482,11 @@ /// Note that this routine emits an error if you call it with ::new or ::delete /// as the current tokens, so only call it in contexts where these are invalid. bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { - assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) - || Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope) - || Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id)) - && "Cannot be a type or scope token!"); + assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || + Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope) || + Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id) || + Tok.is(tok::kw___super)) && + "Cannot be a type or scope token!"); if (Tok.is(tok::kw_typename)) { // MSVC lets you do stuff like: @@ -1694,7 +1695,8 @@ "Call sites of this function should be guarded by checking for C++"); assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) || - Tok.is(tok::kw_decltype)) && "Cannot be a type or scope token!"); + Tok.is(tok::kw_decltype) || Tok.is(tok::kw___super)) && + "Cannot be a type or scope token!"); CXXScopeSpec SS; if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext)) Index: lib/Sema/DeclSpec.cpp =================================================================== --- lib/Sema/DeclSpec.cpp +++ lib/Sema/DeclSpec.cpp @@ -113,6 +113,18 @@ "NestedNameSpecifierLoc range computation incorrect"); } +void CXXScopeSpec::MakeSuper(ASTContext &Context, CXXRecordDecl *RD, + SourceLocation SuperLoc, + SourceLocation ColonColonLoc) { + Builder.MakeSuper(Context, RD, SuperLoc, ColonColonLoc); + + Range.setBegin(SuperLoc); + Range.setEnd(ColonColonLoc); + + assert(Range == Builder.getSourceRange() && + "NestedNameSpecifierLoc range computation incorrect"); +} + void CXXScopeSpec::MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier, SourceRange R) { Builder.MakeTrivial(Context, Qualifier, R); Index: lib/Sema/SemaCXXScopeSpec.cpp =================================================================== --- lib/Sema/SemaCXXScopeSpec.cpp +++ lib/Sema/SemaCXXScopeSpec.cpp @@ -148,6 +148,9 @@ case NestedNameSpecifier::Global: return Context.getTranslationUnitDecl(); + + case NestedNameSpecifier::Super: + return NNS->getAsRecordDecl(); } llvm_unreachable("Invalid NestedNameSpecifier::Kind!"); @@ -240,12 +243,43 @@ return true; } -bool Sema::ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc, +bool Sema::ActOnCXXGlobalScopeSpecifier(SourceLocation CCLoc, CXXScopeSpec &SS) { SS.MakeGlobal(Context, CCLoc); return false; } +bool Sema::ActOnSuperScopeSpecifier(SourceLocation SuperLoc, + SourceLocation ColonColonLoc, + CXXScopeSpec &SS) { + CXXRecordDecl *RD = nullptr; + for (Scope *S = getCurScope(); S; S = S->getParent()) { + if (S->isFunctionScope()) { + CXXMethodDecl *MD = dyn_cast(S->getEntity()); + if (MD && !MD->isStatic()) + RD = MD->getParent(); + break; + } + if (S->isClassScope()) { + RD = cast(S->getEntity()); + break; + } + } + + if (!RD || RD->isLambda()) { + Diag(SuperLoc, diag::err_invalid_super_scope); + return true; + } + + if (RD->getNumBases() == 0) { + Diag(SuperLoc, diag::err_no_base_classes) << RD->getName(); + return true; + } + + SS.MakeSuper(Context, RD, SuperLoc, ColonColonLoc); + return false; +} + /// \brief Determines whether the given declaration is an valid acceptable /// result for name lookup of a nested-name-specifier. bool Sema::isAcceptableNestedNameSpecifier(const NamedDecl *SD) { @@ -953,6 +987,7 @@ case NestedNameSpecifier::Identifier: case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: + case NestedNameSpecifier::Super: // These are never namespace scopes. return true; } Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -498,6 +498,9 @@ /// @endcode bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S) { if (CurContext->isRecord()) { + if (SS->getScopeRep()->getKind() == NestedNameSpecifier::Super) + return true; + const Type *Ty = SS->getScopeRep()->getAsType(); CXXRecordDecl *RD = cast(CurContext); @@ -699,7 +702,11 @@ } LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); - LookupParsedName(Result, S, &SS, !CurMethod); + NestedNameSpecifier *NNS = SS.getScopeRep(); + if (NNS && NNS->getKind() == NestedNameSpecifier::Super) + LookupInSuper(Result, NNS->getAsRecordDecl()); + else + LookupParsedName(Result, S, &SS, !CurMethod); // For unqualified lookup in a class template in MSVC mode, look into // dependent base classes where the primary class template is known. Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -67,6 +67,7 @@ break; case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: llvm_unreachable("Nested name specifier is not a type for inheriting ctor"); @@ -354,6 +355,7 @@ return true; case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: return false; Index: lib/Sema/SemaLookup.cpp =================================================================== --- lib/Sema/SemaLookup.cpp +++ lib/Sema/SemaLookup.cpp @@ -1824,6 +1824,26 @@ return LookupName(R, S, AllowBuiltinCreation); } +/// \brief Perform qualified name lookup into all base classes of the given +/// class. +/// +/// \param R captures both the lookup criteria and any lookup results found. +/// +/// \param Class The context in which qualified name lookup will +/// search. Name lookup will search in all base classes merging the results. +void Sema::LookupInSuper(LookupResult &R, CXXRecordDecl *Class) { + for (const auto &BaseSpec : Class->bases()) { + CXXRecordDecl *RD = cast( + BaseSpec.getType()->castAs()->getDecl()); + LookupResult Result(*this, R.getLookupNameInfo(), R.getLookupKind()); + Result.setBaseObjectType(Context.getRecordType(Class)); + LookupQualifiedName(Result, RD); + for (auto *Decl : Result) + R.addDecl(Decl); + } + + R.resolveKind(); +} /// \brief Produce a diagnostic describing the ambiguity that resulted /// from name lookup. @@ -3296,6 +3316,7 @@ break; case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: return; } Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -4127,6 +4127,7 @@ case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: return false; case NestedNameSpecifier::TypeSpec: @@ -7900,7 +7901,11 @@ DeclarationName Name(&II); LookupResult Result(*this, Name, IILoc, LookupOrdinaryName); - LookupQualifiedName(Result, Ctx); + NestedNameSpecifier *NNS = SS.getScopeRep(); + if (NNS->getKind() == NestedNameSpecifier::Super) + LookupInSuper(Result, NNS->getAsRecordDecl()); + else + LookupQualifiedName(Result, Ctx); unsigned DiagID = 0; Decl *Referenced = nullptr; switch (Result.getResultKind()) { Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -3021,6 +3021,7 @@ case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: llvm_unreachable("Nested-name-specifier must name a type"); case NestedNameSpecifier::TypeSpec: @@ -3717,6 +3718,7 @@ case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: llvm_unreachable("Nested-name-specifier must name a type"); } Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -3100,6 +3100,14 @@ SS.MakeGlobal(SemaRef.Context, Q.getBeginLoc()); break; + case NestedNameSpecifier::Super: { + CXXRecordDecl *RD = + cast_or_null(getDerived().TransformDecl( + SourceLocation(), QNNS->getAsRecordDecl())); + SS.MakeSuper(SemaRef.Context, RD, Q.getBeginLoc(), Q.getEndLoc()); + break; + } + case NestedNameSpecifier::TypeSpecWithTemplate: case NestedNameSpecifier::TypeSpec: { TypeLoc TL = TransformTypeInObjectScope(Q.getTypeLoc(), ObjectType, Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -7927,6 +7927,12 @@ // No associated value, and there can't be a prefix. break; } + + case NestedNameSpecifier::Super: { + CXXRecordDecl *RD = ReadDeclAs(F, Record, Idx); + NNS = NestedNameSpecifier::SuperSpecifier(Context, RD); + break; + } } Prev = NNS; } @@ -7983,9 +7989,16 @@ Builder.MakeGlobal(Context, ColonColonLoc); break; } + + case NestedNameSpecifier::Super: { + CXXRecordDecl *RD = ReadDeclAs(F, Record, Idx); + SourceRange Range = ReadSourceRange(F, Record, Idx); + Builder.MakeSuper(Context, RD, Range.getBegin(), Range.getEnd()); + break; + } } } - + return Builder.getWithLocInContext(Context); } Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -5245,6 +5245,10 @@ case NestedNameSpecifier::Global: // Don't need to write an associated value. break; + + case NestedNameSpecifier::Super: + AddDeclRef(NNS->getAsRecordDecl(), Record); + break; } } } @@ -5294,6 +5298,11 @@ case NestedNameSpecifier::Global: AddSourceLocation(NNS.getLocalSourceRange().getEnd(), Record); break; + + case NestedNameSpecifier::Super: + AddDeclRef(NNS.getNestedNameSpecifier()->getAsRecordDecl(), Record); + AddSourceRange(NNS.getLocalSourceRange(), Record); + break; } } } Index: test/SemaCXX/MicrosoftExtensions.cpp =================================================================== --- test/SemaCXX/MicrosoftExtensions.cpp +++ test/SemaCXX/MicrosoftExtensions.cpp @@ -398,3 +398,147 @@ _Static_assert(__alignof(s1) == 8, ""); _Static_assert(__alignof(s2) == 4, ""); } + +namespace Super { +struct Errors { + using __super::foo; // expected-error {{'__super' cannot be used with a using declaration}} + __super::XXX x; // expected-error {{invalid use of '__super', Errors has no base classes}} expected-error {{expected}} + + // expected-error@+4 {{C++ requires a type specifier for all declarations}} + // expected-warning@+3 {{empty parentheses interpreted as a function declaration}} + // expected-note@+2 {{replace parentheses with an initializer to declare a variable}} + static void foo() { + __super::foo(); // expected-error {{invalid use of '__super', this keyword}} + } + + // expected-error@+4 {{C++ requires a type specifier for all declarations}} + // expected-warning@+3 {{empty parentheses interpreted as a function declaration}} + // expected-note@+2 {{replace parentheses with an initializer to declare a variable}} + void bar() { + auto a = [] { __super::foo(); }; // expected-error {{invalid use of '__super', this keyword}} + } +}; + +struct Base1 { + void foo(int) {} + + typedef int XXX; +}; + +struct Derived : Base1 { + __super::XXX x; + typedef __super::XXX Type; + + enum E { + X = sizeof(__super::XXX) + }; + + void foo(int i) { + __super::foo(i); + } +}; + +struct Outer { + struct Inner : Base1 { + static const int x = sizeof(__super::XXX); + }; +}; + +struct Base2 { + void foo(char) {} +}; + +struct MemberFunctionInMultipleBases : Base1, Base2 { + void foo() { + __super::foo('x'); + } +}; + +struct Base3 { + void foo(int) {} + void foo(char) {} +}; + +struct OverloadedMemberFunction : Base3 { + void foo() { + __super::foo('x'); + } +}; + +struct PointerToMember : Base1 { + template + struct Wrapper { + static void bar() {} + }; + + static void baz(); +}; + +void PointerToMember::baz() { + Wrapper<&__super::foo>::bar(); +} + +template +struct BaseTemplate { + typedef int XXX; + + void foo() {} +}; + +struct DerivedFromKnownSpecialization : BaseTemplate { + __super::XXX a; + typedef __super::XXX b; + + void test() { + __super::XXX c; + typedef __super::XXX d; + + __super::foo(); + } +}; + +template +struct DerivedFromDependentBase : BaseTemplate { + typename __super::XXX a; + typedef typename __super::XXX b; + + __super::XXX c; // expected-error {{missing 'typename'}} + typedef __super::XXX d; // expected-error {{missing 'typename'}} + + void test() { + typename __super::XXX e; + typedef typename __super::XXX f; + + __super::XXX g; // expected-error {{missing 'typename'}} + typedef __super::XXX h; // expected-error {{missing 'typename'}} + + __super::foo(); + } +}; + +template +struct DerivedFromTemplateParameter : T { + typename __super::XXX a; + typedef typename __super::XXX b; + + __super::XXX c; // expected-error {{missing 'typename'}} + typedef __super::XXX d; // expected-error {{missing 'typename'}} + + void test() { + typename __super::XXX e; + typedef typename __super::XXX f; + + __super::XXX g; // expected-error {{missing 'typename'}} + typedef __super::XXX h; // expected-error {{missing 'typename'}} + + __super::foo(1); + } +}; + +void instantiate() { + DerivedFromDependentBase d; + d.test(); + DerivedFromTemplateParameter t; + t.test(); +} +} Index: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -1260,6 +1260,7 @@ case NestedNameSpecifier::TypeSpecWithTemplate: case NestedNameSpecifier::Global: case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Super: break; } @@ -1301,6 +1302,7 @@ case NestedNameSpecifier::Global: case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Super: break; } } Index: tools/libclang/IndexTypeSourceInfo.cpp =================================================================== --- tools/libclang/IndexTypeSourceInfo.cpp +++ tools/libclang/IndexTypeSourceInfo.cpp @@ -129,6 +129,7 @@ switch (NNS.getNestedNameSpecifier()->getKind()) { case NestedNameSpecifier::Identifier: case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: break; case NestedNameSpecifier::Namespace: