On Tue, Aug 12, 2014 at 2:09 AM, Nikola Smiljanić <[email protected]> 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

_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to