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
