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::MsSuper: return true; case NestedNameSpecifier::TypeSpec: @@ -648,6 +649,7 @@ case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: case NestedNameSpecifier::Global: + case NestedNameSpecifier::MsSuper: 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. + MsSuper }; 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 *MsSuperSpecifier(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 MakeMsSuper(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::MsSuper: return true; case NestedNameSpecifier::TypeSpec: @@ -714,6 +715,7 @@ case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: case NestedNameSpecifier::Global: + case NestedNameSpecifier::MsSuper: 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< @@ -519,6 +521,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 @@ -524,6 +524,7 @@ "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 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 MakeMsSuper(ASTContext &Context, CXXRecordDecl *RD, + SourceLocation SuperLoc, SourceLocation ColonColonLoc); + /// \brief Make a new nested-name-specifier from incomplete source-location /// information. /// Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -2608,6 +2608,7 @@ ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc, RedeclarationKind Redecl = NotForRedeclaration); + void LookupInMsSuper(LookupResult &R, CXXRecordDecl *Class); void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, @@ -4476,6 +4477,22 @@ /// \returns true if an error occurred, false otherwise. bool ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc, CXXScopeSpec &SS); + + /// \brief The parser has parsed a '__super' nested-name-specifier. + /// + /// \param S The scope in which this nested-name-specifier occurs. + /// + /// \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 ActOnMsSuperScopeSpecifier(Scope *S, 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::MsSuper: + // 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::MsSuper: + if (CXXRecordDecl *RD = + cast(Import(FromNNS->getAsRecordDecl()))) { + return NestedNameSpecifier::MsSuperSpecifier(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 @@ -1399,7 +1399,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::MsSuper) { 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::MsSuper: + llvm_unreachable("Can't mangle __super specifier"); + case NestedNameSpecifier::Namespace: if (qualifier->getPrefix()) mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, @@ -1456,6 +1459,7 @@ void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) { switch (qualifier->getKind()) { case NestedNameSpecifier::Global: + case NestedNameSpecifier::MsSuper: // nothing 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::MsSuperSpecifier(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 MsSuper; + 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 MsSuper: { + 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 MsSuper: return false; - + case TypeSpec: case TypeSpecWithTemplate: return getAsType()->isInstantiationDependentType(); @@ -209,6 +237,7 @@ case Namespace: case NamespaceAlias: case Global: + case MsSuper: return false; case TypeSpec: @@ -246,6 +275,10 @@ case Global: break; + case MsSuper: + 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::MsSuper: // 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::MsSuper: return SourceRange(LoadSourceLocation(Data, Offset), LoadSourceLocation(Data, Offset + sizeof(unsigned))); @@ -552,6 +587,17 @@ SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); } +void NestedNameSpecifierLocBuilder::MakeMsSuper(ASTContext &Context, + CXXRecordDecl *RD, + SourceLocation SuperLoc, + SourceLocation ColonColonLoc) { + Representation = NestedNameSpecifier::MsSuperSpecifier(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::MsSuper: 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 @@ -226,6 +226,17 @@ 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.ActOnMsSuperScopeSpecifier(getCurScope(), 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::MakeMsSuper(ASTContext &Context, CXXRecordDecl *RD, + SourceLocation SuperLoc, + SourceLocation ColonColonLoc) { + Builder.MakeMsSuper(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::MsSuper: + return NNS->getAsRecordDecl(); } llvm_unreachable("Invalid NestedNameSpecifier::Kind!"); @@ -246,6 +249,26 @@ return false; } +bool Sema::ActOnMsSuperScopeSpecifier(Scope *S, SourceLocation SuperLoc, + SourceLocation ColonColonLoc, + CXXScopeSpec &SS) { + CXXRecordDecl *RD = nullptr; + if (CXXMethodDecl *MD = dyn_cast(S->getEntity())) + RD = MD->getParent(); + else + RD = dyn_cast(S->getEntity()); + + assert(RD && "Not inside method or class scope!"); + + if (RD->getNumBases() == 0) { + Diag(SuperLoc, diag::err_no_base_classes) << RD->getName(); + return true; + } + + SS.MakeMsSuper(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) { @@ -950,6 +973,7 @@ case NestedNameSpecifier::Identifier: case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: + case NestedNameSpecifier::MsSuper: // These are never namespace scopes. return true; } Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -497,6 +497,9 @@ /// @endcode bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S) { if (CurContext->isRecord()) { + if (SS->getScopeRep()->getKind() == NestedNameSpecifier::MsSuper) + return true; + const Type *Ty = SS->getScopeRep()->getAsType(); CXXRecordDecl *RD = cast(CurContext); @@ -698,7 +701,11 @@ } LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); - LookupParsedName(Result, S, &SS, !CurMethod); + NestedNameSpecifier *NNS = SS.getScopeRep(); + if (NNS && NNS->getKind() == NestedNameSpecifier::MsSuper) + LookupInMsSuper(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::MsSuper: 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::MsSuper: 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::LookupInMsSuper(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::MsSuper: 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::MsSuper: 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::MsSuper) + LookupInMsSuper(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::MsSuper: 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::MsSuper: 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::MsSuper: { + CXXRecordDecl *RD = + cast_or_null(getDerived().TransformDecl( + SourceLocation(), QNNS->getAsRecordDecl())); + SS.MakeMsSuper(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 @@ -7907,6 +7907,12 @@ // No associated value, and there can't be a prefix. break; } + + case NestedNameSpecifier::MsSuper: { + CXXRecordDecl *RD = ReadDeclAs(F, Record, Idx); + NNS = NestedNameSpecifier::MsSuperSpecifier(Context, RD); + break; + } } Prev = NNS; } @@ -7963,9 +7969,16 @@ Builder.MakeGlobal(Context, ColonColonLoc); break; } + + case NestedNameSpecifier::MsSuper: { + CXXRecordDecl *RD = ReadDeclAs(F, Record, Idx); + SourceRange Range = ReadSourceRange(F, Record, Idx); + Builder.MakeMsSuper(Context, RD, Range.getBegin(), Range.getEnd()); + break; + } } } - + return Builder.getWithLocInContext(Context); } Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -5208,6 +5208,10 @@ case NestedNameSpecifier::Global: // Don't need to write an associated value. break; + + case NestedNameSpecifier::MsSuper: + AddDeclRef(NNS->getAsRecordDecl(), Record); + break; } } } @@ -5257,6 +5261,11 @@ case NestedNameSpecifier::Global: AddSourceLocation(NNS.getLocalSourceRange().getEnd(), Record); break; + + case NestedNameSpecifier::MsSuper: + 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,123 @@ _Static_assert(__alignof(s1) == 8, ""); _Static_assert(__alignof(s2) == 4, ""); } + +namespace MsSuper { +struct Errors { + using __super::foo; // expected-error {{__super cannot be used}} + __super::XXX x; // expected-error {{invalid use of '__super'}} expected-error {{expected}} +}; + +struct Base1 { + void foo(int) {} + + typedef int XXX; +}; + +struct Derived : Base1 { + __super::XXX x; + typedef __super::XXX Type; + + void foo(int i) { + __super::foo(i); + } +}; + +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::MsSuper: break; } @@ -1301,6 +1302,7 @@ case NestedNameSpecifier::Global: case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::MsSuper: 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::MsSuper: break; case NestedNameSpecifier::Namespace: