[PATCH] PR13236 - Microsoft compatibility: support __super specifier to access members of base classes

Aaron Ballman aaron.ballman at gmail.com
Tue Aug 12 08:04:16 PDT 2014


On Tue, Aug 12, 2014 at 2:09 AM, Nikola Smiljanić <popizdeh at gmail.com> wrote:
> I've gone full circle on this, Richard suggested resolving 'super' right away. I consumed tokens and annotated the trailing identifier as either type or primary expression. It was so simple and worked perfectly, until dependent bases showed up...
>
> I started hacking and soon enough ended up with something that looks very much like the original patch with few minor changes. NNS now stores the CXXRecordDecl of the class 'super' appeared in, this is replaced by appropriate instantiation in case of templates. This makes us handle the 'derive from template parameter' case just fine, unlike msvc, but I'm fine with it. I guess we could produce an error like them if we wanted but I don't see the point.
>
> I played with printfs to check if the right overload was selected but having tests would be nice. Do I emit IR, dump ast, or to something else?

I think CodeGenCXX tests would make sense.

Also (perhaps dumb question), is there a way this could bite someone
compiling an ObjC file with -fms-compatibility? Eg) [__super
someMethod];

> http://reviews.llvm.org/D4468
>
> Files:
>   include/clang/AST/DataRecursiveASTVisitor.h
>   include/clang/AST/NestedNameSpecifier.h
>   include/clang/AST/RecursiveASTVisitor.h
>   include/clang/Basic/DiagnosticParseKinds.td
>   include/clang/Basic/DiagnosticSemaKinds.td
>   include/clang/Basic/TokenKinds.def
>   include/clang/Sema/DeclSpec.h
>   include/clang/Sema/Sema.h
>   lib/AST/ASTContext.cpp
>   lib/AST/ASTImporter.cpp
>   lib/AST/ItaniumMangle.cpp
>   lib/AST/NestedNameSpecifier.cpp
>   lib/Parse/ParseDecl.cpp
>   lib/Parse/ParseDeclCXX.cpp
>   lib/Parse/ParseExpr.cpp
>   lib/Parse/ParseExprCXX.cpp
>   lib/Parse/ParseTentative.cpp
>   lib/Parse/Parser.cpp
>   lib/Sema/DeclSpec.cpp
>   lib/Sema/SemaCXXScopeSpec.cpp
>   lib/Sema/SemaDecl.cpp
>   lib/Sema/SemaExprCXX.cpp
>   lib/Sema/SemaLookup.cpp
>   lib/Sema/SemaOverload.cpp
>   lib/Sema/SemaTemplate.cpp
>   lib/Sema/SemaType.cpp
>   lib/Sema/TreeTransform.h
>   lib/Serialization/ASTReader.cpp
>   lib/Serialization/ASTWriter.cpp
>   test/SemaCXX/MicrosoftExtensions.cpp

Mostly minor comments below:

> Index: include/clang/AST/DataRecursiveASTVisitor.h
> ===================================================================
> --- include/clang/AST/DataRecursiveASTVisitor.h
> +++ include/clang/AST/DataRecursiveASTVisitor.h
> @@ -623,6 +623,7 @@
>    case NestedNameSpecifier::Namespace:
>    case NestedNameSpecifier::NamespaceAlias:
>    case NestedNameSpecifier::Global:
> +  case NestedNameSpecifier::MsSuper:
>      return true;
>
>    case NestedNameSpecifier::TypeSpec:
> @@ -647,6 +648,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
> @@ -689,6 +689,7 @@
>    case NestedNameSpecifier::Namespace:
>    case NestedNameSpecifier::NamespaceAlias:
>    case NestedNameSpecifier::Global:
> +  case NestedNameSpecifier::MsSuper:
>      return true;
>
>    case NestedNameSpecifier::TypeSpec:
> @@ -713,6 +714,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
> @@ -366,6 +366,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<
> @@ -506,6 +508,8 @@
>    InGroup<DiagGroup<"anonymous-pack-parens">>;
>  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<IncompatibleMSStruct>;
>  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">;

Did you mean '__super' here instead of 'super'?

>
>  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
> @@ -2605,6 +2605,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,
> @@ -4460,6 +4461,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<CXXRecordDecl>(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/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<NamespaceDecl *>(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,17 +118,30 @@
>    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;
>
>    switch (Prefix.getInt()) {
>    case StoredIdentifier:
>      return Identifier;
>
> -  case StoredNamespaceOrAlias:
> -    return isa<NamespaceDecl>(static_cast<NamedDecl *>(Specifier))? Namespace
> -                                                            : NamespaceAlias;
> +  case StoredDecl: {
> +    NamedDecl *ND = static_cast<NamedDecl *>(Specifier);
> +    if (isa<CXXRecordDecl>(ND))
> +      return MsSuper;
> +    return isa<NamespaceDecl>(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<NamespaceDecl>(static_cast<NamedDecl *>(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<NamespaceAliasDecl>(static_cast<NamedDecl *>(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<CXXRecordDecl>(static_cast<NamedDecl *>(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<CXXRecordDecl *>(Specifier);
> +    for (auto Base : RD->bases())

const auto &?

> +      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,15 @@
>    SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
>  }
>
> +void NestedNameSpecifierLocBuilder::MakeMsSuper(ASTContext &Context, CXXRecordDecl *RD,
> +                                               SourceLocation SuperLoc, SourceLocation ColonColonLoc) {

80-col.

> +  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 +627,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,
> @@ -2030,7 +2036,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<CXXMethodDecl>(S->getEntity()))
> +    RD = MD->getParent();
> +  else
> +    RD = dyn_cast<CXXRecordDecl>(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) {
> @@ -945,6 +968,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
> @@ -494,6 +494,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<CXXRecordDecl>(CurContext);
> @@ -695,7 +698,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,25 @@
>    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<CXXRecordDecl>(
> +        BaseSpec.getType()->castAs<RecordType>()->getDecl());
> +    LookupResult Result(*this, R.getLookupNameInfo(), R.getLookupKind());
> +    LookupQualifiedName(Result, RD);
> +    for (auto Decl : Result)

auto *?

> +      R.addDecl(Decl);
> +  }
> +
> +  R.resolveKind();
> +}
>
>  /// \brief Produce a diagnostic describing the ambiguity that resulted
>  /// from name lookup.
> @@ -3296,6 +3315,7 @@
>      break;
>
>    case NestedNameSpecifier::Global:
> +  case NestedNameSpecifier::MsSuper:
>      return;
>    }
>
> Index: lib/Sema/SemaOverload.cpp
> ===================================================================
> --- lib/Sema/SemaOverload.cpp
> +++ lib/Sema/SemaOverload.cpp
> @@ -4774,6 +4774,8 @@
>    // affects the conversion rank.
>    QualType ClassTypeCanon = S.Context.getCanonicalType(ClassType);
>    ImplicitConversionKind SecondKind;
> +  FromType.dump();
> +  ClassType.dump();

I think these probably don't belong here.

>    if (ClassTypeCanon == FromTypeCanon.getLocalUnqualifiedType()) {
>      SecondKind = ICK_Identity;
>    } else if (S.IsDerivedFrom(FromType, ClassType))
> Index: lib/Sema/SemaTemplate.cpp
> ===================================================================
> --- lib/Sema/SemaTemplate.cpp
> +++ lib/Sema/SemaTemplate.cpp
> @@ -4123,6 +4123,7 @@
>    case NestedNameSpecifier::Namespace:
>    case NestedNameSpecifier::NamespaceAlias:
>    case NestedNameSpecifier::Global:
> +  case NestedNameSpecifier::MsSuper:
>      return false;
>
>    case NestedNameSpecifier::TypeSpec:
> @@ -7896,7 +7897,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<CXXRecordDecl>(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
> @@ -7834,6 +7834,12 @@
>        // No associated value, and there can't be a prefix.
>        break;
>      }
> +
> +    case NestedNameSpecifier::MsSuper: {
> +      CXXRecordDecl *RD = ReadDeclAs<CXXRecordDecl>(F, Record, Idx);
> +      NNS = NestedNameSpecifier::MsSuperSpecifier(Context, RD);
> +      break;
> +    }
>      }
>      Prev = NNS;
>    }
> @@ -7890,6 +7896,13 @@
>        Builder.MakeGlobal(Context, ColonColonLoc);
>        break;
>      }
> +
> +    case NestedNameSpecifier::MsSuper: {
> + CXXRecordDecl *RD = ReadDeclAs<CXXRecordDecl>(F, Record, Idx);
> + SourceRange Range = ReadSourceRange(F, Record, Idx);
> + Builder.MakeMsSuper(Context, RD, Range.getBegin(), Range.getEnd());
> + break;
> +    }

Should be using spaces instead of tabs here.

>      }
>    }
>
> Index: lib/Serialization/ASTWriter.cpp
> ===================================================================
> --- lib/Serialization/ASTWriter.cpp
> +++ lib/Serialization/ASTWriter.cpp
> @@ -5167,6 +5167,10 @@
>      case NestedNameSpecifier::Global:
>        // Don't need to write an associated value.
>        break;
> +
> +    case NestedNameSpecifier::MsSuper:
> +      AddDeclRef(NNS->getAsRecordDecl(), Record);
> +      break;
>      }
>    }
>  }
> @@ -5216,6 +5220,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 <void (Base1::*MP)(int)>
> +  struct Wrapper {
> +    static void bar() {}
> +  };
> +
> +  static void baz();
> +};
> +
> +void PointerToMember::baz() {
> +  Wrapper<&__super::foo>::bar();
> +}
> +
> +template <typename T>
> +struct BaseTemplate {
> +  typedef int XXX;
> +
> +  void foo() {}
> +};
> +
> +struct DerivedFromKnownSpecialization : BaseTemplate<int> {
> +  __super::XXX a;
> +  typedef __super::XXX b;
> +
> +  void test() {
> +    __super::XXX c;
> +    typedef __super::XXX d;
> +
> +    __super::foo();
> +  }
> +};
> +
> +template <typename T>
> +struct DerivedFromDependentBase : BaseTemplate<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();
> +  }
> +};
> +
> +template <typename T>
> +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<int> d;
> +  d.test();
> +  DerivedFromTemplateParameter<Base1> t;
> +  t.test();
> +}
> +}
>

When I have the chance to do something more comprehensive, I will
(unless others beat me to it).

Thanks!

~Aaron




More information about the cfe-commits mailing list