From 53d38b0d0c87d4e38e25888470d49c1da073b4f3 Mon Sep 17 00:00:00 2001 From: EdwardWang Date: Sat, 7 Jan 2023 12:36:27 +0800 Subject: [PATCH] [BSC]: support member function for struct ``` typedef struct Foo { int a; } Foo; int Foo::getA(Foo* this) { return this->a; } ... Foo foo; int a = foo.getA(); ``` 1. Lexing: support coloncolon(::) Token 2. Parsing: introduce BSCScopeSpec for Foo in Foo::getA 3. Sema: support foo.getA(), we need to generate call args for getA --- clang/include/clang/AST/DeclBase.h | 6 +- .../include/clang/AST/DeclContextInternals.h | 4 +- clang/include/clang/Parse/Parser.h | 10 ++ clang/include/clang/Sema/DeclSpec.h | 2 +- clang/include/clang/Sema/IdentifierResolver.h | 2 +- clang/include/clang/Sema/Sema.h | 3 +- clang/lib/AST/Decl.cpp | 4 +- clang/lib/AST/DeclBase.cpp | 6 +- clang/lib/Lex/Lexer.cpp | 2 +- clang/lib/Parse/ParseDecl.cpp | 30 +++- clang/lib/Parse/ParseDeclCXX.cpp | 4 +- clang/lib/Parse/ParseExprCXX.cpp | 129 ++++++++++++++++++ clang/lib/Parse/Parser.cpp | 6 +- clang/lib/Sema/SemaDecl.cpp | 34 ++--- clang/lib/Sema/SemaExpr.cpp | 47 +++++-- clang/lib/Sema/SemaExprMember.cpp | 13 ++ clang/lib/Sema/SemaLookup.cpp | 10 +- 17 files changed, 263 insertions(+), 49 deletions(-) diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index e0a75d099fbe..bb82ca0c861d 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -99,6 +99,9 @@ public: #include "clang/AST/DeclNodes.inc" }; + /// Mark this Decl to be BSC's member function. + bool isBSCMember = false; + /// A placeholder type used to construct an empty shell of a /// decl-derived type that will be filled in later (e.g., by some /// deserialization method). @@ -1738,7 +1741,8 @@ class DeclContext { /// contains an entry for a DeclarationName (and we haven't lazily /// omitted anything), then it contains all relevant entries for that /// name (modulo the hasExternalDecls() flag). - mutable StoredDeclsMap *LookupPtr = nullptr; + // For each DeclContext, we have this LookupPtr to store the Lookup Table for this context. + mutable StoredDeclsMap *LookupPtr = nullptr; // key poiter to the Lookup Table. protected: /// This anonymous union stores the bits belonging to DeclContext and classes diff --git a/clang/include/clang/AST/DeclContextInternals.h b/clang/include/clang/AST/DeclContextInternals.h index e6a4cd4381e4..74f7c9d468b2 100644 --- a/clang/include/clang/AST/DeclContextInternals.h +++ b/clang/include/clang/AST/DeclContextInternals.h @@ -42,7 +42,7 @@ struct StoredDeclsList { /// The stored data, which will be either a pointer to a NamedDecl, /// or a pointer to a vector with a flag to indicate if there are further /// external declarations. - llvm::PointerUnion Data; + llvm::PointerUnion Data; // getA will be stored here. public: StoredDeclsList() = default; @@ -235,7 +235,7 @@ public: } }; -class StoredDeclsMap +class StoredDeclsMap // : public llvm::SmallDenseMap { public: static void DestroyAll(StoredDeclsMap *Map, bool Dependent); diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 11bd1704c4ce..01da2ad370d8 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1868,6 +1868,16 @@ private: ExprResult ParseFoldExpression(ExprResult LHS, BalancedDelimiterTracker &T); + //===--------------------------------------------------------------------===// + // BSC Expressions + bool ParseOptionalBSCScopeSpecifier(CXXScopeSpec &SS, + ParsedType ObjectType, + bool ObjectHasErrors, + bool EnteringContext, + bool IsTypename = false, + IdentifierInfo **LastII = nullptr); + + //===--------------------------------------------------------------------===// // C++ Expressions ExprResult tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOperand, diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 82c892c71bd7..d9d411621f0b 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -61,7 +61,7 @@ namespace clang { /// often used as if it meant "present". /// /// The actual scope is described by getScopeRep(). -class CXXScopeSpec { +class CXXScopeSpec { // We need BSCScopeSpec SourceRange Range; NestedNameSpecifierLocBuilder Builder; diff --git a/clang/include/clang/Sema/IdentifierResolver.h b/clang/include/clang/Sema/IdentifierResolver.h index 7c8dc46307d4..61590bc5b199 100644 --- a/clang/include/clang/Sema/IdentifierResolver.h +++ b/clang/include/clang/Sema/IdentifierResolver.h @@ -35,7 +35,7 @@ class Scope; /// IdentifierResolver - Keeps track of shadowed decls on enclosing /// scopes. It manages the shadowing chains of declaration names and /// implements efficient decl lookup based on a declaration name. -class IdentifierResolver { +class IdentifierResolver { // whats the diff between it and Scope, DeclContext? /// IdDeclInfo - Keeps track of information about decls associated /// to a particular declaration name. IdDeclInfos are lazily /// constructed and assigned to a declaration name the first time a diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index cc9f94d908be..809e488921e6 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11309,7 +11309,8 @@ public: SmallVectorImpl &AllArgs, VariadicCallType CallType = VariadicDoesNotApply, bool AllowExplicit = false, - bool IsListInitialization = false); + bool IsListInitialization = false, + CallExpr* Call = nullptr); // DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but // will create a runtime trap if the resulting type is not a POD type. diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 3ebcdcd3ccc2..b8ece032b90d 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2074,7 +2074,9 @@ static bool isDeclExternC(const T &D) { // language linkage or no language linkage. const DeclContext *DC = D.getDeclContext(); if (DC->isRecord()) { - assert(D.getASTContext().getLangOpts().CPlusPlus); + auto LangOpts = D.getASTContext().getLangOpts(); + // FIXME: We need introduce LangOpts.BSC + assert(LangOpts.CPlusPlus || LangOpts.C11); return false; } diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index c26d6d1a42ea..044982f7b455 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -1548,8 +1548,8 @@ void DeclContext::removeDecl(Decl *D) { } void DeclContext::addHiddenDecl(Decl *D) { - assert(D->getLexicalDeclContext() == this && - "Decl inserted into wrong lexical context"); + // assert(D->getLexicalDeclContext() == this && + // "Decl inserted into wrong lexical context"); assert(!D->getNextDeclInContext() && D != LastDecl && "Decl already inserted into a DeclContext"); @@ -1722,7 +1722,7 @@ DeclContext::lookup(DeclarationName Name) const { if (I == Map->end()) return {}; - return I->second.getLookupResult(); + return I->second.getLookupResult(); // Will enter this for find getA in Foo::getA } DeclContext::lookup_result diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index 34732b659771..9b07acb42e47 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -3833,7 +3833,7 @@ LexNextToken: if (LangOpts.Digraphs && Char == '>') { Kind = tok::r_square; // ':>' -> ']' CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else if ((LangOpts.CPlusPlus || + } else if ((LangOpts.CPlusPlus || LangOpts.C11 || // FIXME: use CBS LangOpts.DoubleSquareBracketAttributes) && Char == ':') { Kind = tok::coloncolon; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 4ce90b178191..a8eb1643b1b6 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1925,7 +1925,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // appropriate function scope after the function Decl has been constructed. // These will be parsed in ParseFunctionDefinition or ParseLexedAttrList. LateParsedAttrList LateParsedAttrs(true); - if (D.isFunctionDeclarator()) { + if (D.isFunctionDeclarator()) { // BSC should enter this. MaybeParseGNUAttributes(D, &LateParsedAttrs); // The _Noreturn keyword can't appear here, unlike the GNU noreturn @@ -1972,9 +1972,17 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // Recover by treating the 'typedef' as spurious. DS.ClearStorageClassSpecs(); } - + // BSC will enter this for parsing "{YYY}" in "::getA(XXX){YYY}" Decl *TheDecl = ParseFunctionDefinition(D, ParsedTemplateInfo(), &LateParsedAttrs); + // If D has the form "Foo::getA", after parsing `getA`, we add it to struct Foo's + // DeclContext. We need to search getA within Foo's DeclContext later. Now it seems + // that getA is in both Foo's DeclContext and toplevel Context. Need to be fixed. + if (D.getCXXScopeSpec().isSet()) { + DeclContext* DC = Actions.computeDeclContext(D.getCXXScopeSpec(), true); + DC->addDeclInternal(TheDecl); // add getA into struct Foo + TheDecl->isBSCMember = true; + } return Actions.ConvertDeclToDeclGroup(TheDecl); } @@ -3093,6 +3101,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, } case tok::coloncolon: // ::foo::bar + if (getLangOpts().C11) // FIXME later + return; // C++ scope specifier. Annotate and loop, or bail out on error. if (TryAnnotateCXXScopeToken(EnteringContext)) { if (!DS.hasTypeSpecifier()) @@ -5111,6 +5121,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { if (NextToken().is(tok::kw_new) || // ::new NextToken().is(tok::kw_delete)) // ::delete return false; + if (getLangOpts().C11 && NextToken().is(tok::identifier)) + return true; // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. @@ -5596,7 +5608,7 @@ void Parser::ParseTypeQualifierListOpt( void Parser::ParseDeclarator(Declarator &D) { /// This implements the 'declarator' production in the C grammar, then checks /// for well-formedness and issues diagnostics. - ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator); + ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator); // 2rd arg: call back function } static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang, @@ -5667,6 +5679,18 @@ void Parser::ParseDeclaratorInternal(Declarator &D, if (Diags.hasAllExtensionsSilenced()) D.setExtension(); + if(getLangOpts().C11 && + Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) { + CXXScopeSpec SS; + ParseOptionalBSCScopeSpecifier(SS, nullptr,false,false); + if (SS.isNotEmpty()) { + if (D.mayHaveIdentifier()) // Set Declarator's CXXScopeSpec to SS, which was just parsed and updated. + D.getCXXScopeSpec() = SS; + // Recurse to parse whatever is left, "getA(XXX){}" + ParseDeclaratorInternal(D, DirectDeclParser); + return; + } + } // C++ member pointers start with a '::' or a nested-name. // Member pointers get special handling, since there's no place for the // scope spec in the generic path below. diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 88ebb59f9a60..e9a90e589f39 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -2797,7 +2797,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // member-declarator // member-declarator-list ',' member-declarator - while (1) { + while (1) { // This is a loop to add all decls inside a struct into DeclsInGroup. InClassInitStyle HasInClassInit = ICIS_NoInit; bool HasStaticInitializer = false; if (Tok.isOneOf(tok::equal, tok::l_brace) && PureSpecLoc.isInvalid()) { @@ -2919,7 +2919,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, LateParsedAttrs[i]->addDecl(ThisDecl); } Actions.FinalizeDeclaration(ThisDecl); - DeclsInGroup.push_back(ThisDecl); + DeclsInGroup.push_back(ThisDecl); // Put each Decl inside struct Foo into the DeclsInGroup. if (DeclaratorInfo.isFunctionDeclarator() && DeclaratorInfo.getDeclSpec().getStorageClassSpec() != diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 4b5703d79f28..bdbd4be9249b 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -554,6 +554,135 @@ bool Parser::ParseOptionalCXXScopeSpecifier( return false; } +bool Parser::ParseOptionalBSCScopeSpecifier( + CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHasErrors, + bool EnteringContext, bool IsTypename, IdentifierInfo **LastII) { + // FIXME: CXXScopeSepc is for Foo in Foo::getA, we may need to have our own BSCScopeSpec later. + // This function is mainly copied from C++'s version and we remove a lot of useless code + // for BSC. This function needs to be rewritten later. + + // They have assert(CPlusPlus) before for C++ + if (LastII) + *LastII = nullptr; + + if (Tok.is(tok::coloncolon)) { + // ::new and ::delete aren't nested-name-specifiers. + tok::TokenKind NextKind = NextToken().getKind(); + if (NextKind == tok::kw_new || NextKind == tok::kw_delete) + return false; + + if (NextKind == tok::l_brace) { + // It is invalid to have :: {, consume the scope qualifier and pretend + // like we never saw it. + Diag(ConsumeToken(), diag::err_expected) << tok::identifier; + } else { + // '::' - Global scope qualifier. + if (Actions.ActOnCXXGlobalScopeSpecifier(ConsumeToken(), SS)) + return true; + } + } + + // Preferred type might change when parsing qualifiers, we need the original. + while (true) { + // nested-name-specifier: + // nested-name-specifier 'template'[opt] simple-template-id '::' + // Parse the optional 'template' keyword, then make sure we have + // 'identifier <' after it. + + + // The rest of the nested-name-specifier possibilities start with + // tok::identifier. + if (Tok.isNot(tok::identifier)) + break; + + IdentifierInfo &II = *Tok.getIdentifierInfo(); + + // nested-name-specifier: + // type-name '::' + // namespace-name '::' + // nested-name-specifier identifier '::' + Token Next = NextToken(); + Sema::NestedNameSpecInfo IdInfo(&II, Tok.getLocation(), Next.getLocation(), + ObjectType); + + // If we get foo:bar, this is almost certainly a typo for foo::bar. Recover + // and emit a fixit hint for it. + if (Next.is(tok::colon) && !ColonIsSacred) { + if (Actions.IsInvalidUnlessNestedName(getCurScope(), SS, IdInfo, + EnteringContext) && + // If the token after the colon isn't an identifier, it's still an + // error, but they probably meant something else strange so don't + // recover like this. + PP.LookAhead(1).is(tok::identifier)) { + Diag(Next, diag::err_unexpected_colon_in_nested_name_spec) + << FixItHint::CreateReplacement(Next.getLocation(), "::"); + // Recover as if the user wrote '::'. + Next.setKind(tok::coloncolon); + } + } + + if (Next.is(tok::coloncolon) && GetLookAheadToken(2).is(tok::l_brace)) { + // It is invalid to have :: {, consume the scope qualifier and pretend + // like we never saw it. + Token Identifier = Tok; // Stash away the identifier. + ConsumeToken(); // Eat the identifier, current token is now '::'. + Diag(PP.getLocForEndOfToken(ConsumeToken()), diag::err_expected) + << tok::identifier; + UnconsumeToken(Identifier); // Stick the identifier back. + Next = NextToken(); // Point Next at the '{' token. + } + + if (Next.is(tok::coloncolon)) { + if (ColonIsSacred) { + const Token &Next2 = GetLookAheadToken(2); + if (Next2.is(tok::kw_private) || Next2.is(tok::kw_protected) || + Next2.is(tok::kw_public) || Next2.is(tok::kw_virtual)) { + Diag(Next2, diag::err_unexpected_token_in_nested_name_spec) + << Next2.getName() + << FixItHint::CreateReplacement(Next.getLocation(), ":"); + Token ColonColon; + PP.Lex(ColonColon); + ColonColon.setKind(tok::colon); + PP.EnterToken(ColonColon, /*IsReinject*/ true); + break; + } + } + + if (LastII) + *LastII = &II; + + // We have an identifier followed by a '::'. Lookup this name + // as the name in a nested-name-specifier. + Token Identifier = Tok; + SourceLocation IdLoc = ConsumeToken(); + assert(Tok.isOneOf(tok::coloncolon, tok::colon) && + "NextToken() not working properly!"); + Token ColonColon = Tok; + SourceLocation CCLoc = ConsumeToken(); + + bool IsCorrectedToColon = false; + bool *CorrectionFlagPtr = ColonIsSacred ? &IsCorrectedToColon : nullptr; + if (Actions.ActOnCXXNestedNameSpecifier( // This is the key Sema action for name lookup + getCurScope(), IdInfo, EnteringContext, SS, false, + CorrectionFlagPtr, false)) { // Do we need OnlyNamespace? + // Identifier is not recognized as a nested name, but we can have + // mistyped '::' instead of ':'. + if (CorrectionFlagPtr && IsCorrectedToColon) { + ColonColon.setKind(tok::colon); + PP.EnterToken(Tok, /*IsReinject*/ true); + PP.EnterToken(ColonColon, /*IsReinject*/ true); + Tok = Identifier; + break; + } + SS.SetInvalid(SourceRange(IdLoc, CCLoc)); + } + continue; + } + break; + } + return true; +} + ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOperand, Token &Replacement) { diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 2a42f058b8ec..f0b1a28a6e43 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1284,7 +1284,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // Tell the actions module that we have entered a function definition with the // specified Declarator for the function. Sema::SkipBodyInfo SkipBody; - Decl *Res = Actions.ActOnStartOfFunctionDef(getCurScope(), D, + Decl *Res = Actions.ActOnStartOfFunctionDef(getCurScope(), D, // Now we do Actions in Sema, what is Scope? TemplateInfo.TemplateParams ? *TemplateInfo.TemplateParams : MultiTemplateParamsArg(), @@ -1295,7 +1295,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, return Res; } - // Break out of the ParsingDeclarator context before we parse the body. + // Break out of the ParsingDeclarator context before we parse the body. But why? D.complete(Res); // Break out of the ParsingDeclSpec context, too. This const_cast is @@ -1375,7 +1375,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, if (LateParsedAttrs) ParseLexedAttributeList(*LateParsedAttrs, Res, false, true); - return ParseFunctionStatementBody(Res, BodyScope); + return ParseFunctionStatementBody(Res, BodyScope); // Now we are going to parse the function body. } void Parser::SkipFunctionBody() { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index f311f6796c5f..7c814a1f4499 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1472,7 +1472,7 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { // found later. Declarations without a context won't be inserted // into any context. if (AddToContext) - CurContext->addDecl(D); + CurContext->addDecl(D); // DeclContext add Decl // Out-of-line definitions shouldn't be pushed into scope in C++, unless they // are function-local declarations. @@ -1497,7 +1497,7 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { } } - S->AddDecl(D); + S->AddDecl(D); // Scope adds Decl. if (isa(D) && !cast(D)->isGnuLocal()) { // Implicitly-generated labels may end up getting generated in an order that @@ -1514,7 +1514,7 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { IdResolver.InsertDeclAfter(I, D); } else { - IdResolver.AddDecl(D); + IdResolver.AddDecl(D); // IdentifierResolver adds Decl } } @@ -5690,7 +5690,7 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParamLists) { // TODO: consider using NameInfo for diagnostic. DeclarationNameInfo NameInfo = GetNameForDeclarator(D); - DeclarationName Name = NameInfo.getName(); + DeclarationName Name = NameInfo.getName(); // "getA" // All of these full declarators require an identifier. If it doesn't have // one, the ParsedFreeStandingDeclSpec action should be used. @@ -5772,8 +5772,8 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, UPPC_DeclarationType)) D.setInvalidType(); - LookupResult Previous(*this, NameInfo, LookupOrdinaryName, - forRedeclarationInCurContext()); + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, // try to find getA in previous context + forRedeclarationInCurContext()); // LookupOrdinaryName may not find Foo::getA // See if this is a redefinition of a variable in the same scope. if (!D.getCXXScopeSpec().isSet()) { @@ -5806,7 +5806,7 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, LookupName(Previous, S, CreateBuiltins); } else { // Something like "int foo::x;" - LookupQualifiedName(Previous, DC); + LookupQualifiedName(Previous, DC); // This is the key function for find getA in Foo::getA // C++ [dcl.meaning]p1: // When the declarator-id is qualified, the declaration shall refer to a @@ -5877,7 +5877,7 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, New = ActOnTypedefDeclarator(S, D, DC, TInfo, Previous); } else if (R->isFunctionType()) { - New = ActOnFunctionDeclarator(S, D, DC, TInfo, Previous, + New = ActOnFunctionDeclarator(S, D, DC, TInfo, Previous, // We tried to find pre-declared getA, which is named Previous. TemplateParamLists, AddToScope); } else { @@ -5891,7 +5891,7 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, // If this has an identifier and is not a function template specialization, // add it to the scope stack. if (New->getDeclName() && AddToScope) - PushOnScopeChains(New, S); + PushOnScopeChains(New, S); // Adding NewDecl to the Scope. if (isInOpenMPDeclareTargetContext()) checkDeclIsAllowedInOpenMPTarget(nullptr, New); @@ -8245,7 +8245,7 @@ void Sema::MarkTypoCorrectedFunctionDefinition(const NamedDecl *F) { static NamedDecl *DiagnoseInvalidRedeclaration( Sema &SemaRef, LookupResult &Previous, FunctionDecl *NewFD, ActOnFDArgs &ExtraArgs, bool IsLocalFriend, Scope *S) { - DeclarationName Name = NewFD->getDeclName(); + DeclarationName Name = NewFD->getDeclName(); // getA in Foo::getA DeclContext *NewDC = NewFD->getDeclContext(); SmallVector MismatchedParams; SmallVector, 1> NearMatches; @@ -8255,8 +8255,8 @@ static NamedDecl *DiagnoseInvalidRedeclaration( IsLocalFriend ? diag::err_no_matching_local_friend : NewFD->getFriendObjectKind() ? diag::err_qualified_friend_no_match : diag::err_member_decl_does_not_match; - LookupResult Prev(SemaRef, Name, NewFD->getLocation(), - IsLocalFriend ? Sema::LookupLocalFriendName + LookupResult Prev(SemaRef, Name, NewFD->getLocation(), // cannot find getA in previous scope/context. + IsLocalFriend ? Sema::LookupLocalFriendName // Here we know how to lookup a name. : Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration); @@ -8890,7 +8890,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // TODO: consider using NameInfo for diagnostic. DeclarationNameInfo NameInfo = GetNameForDeclarator(D); - DeclarationName Name = NameInfo.getName(); + DeclarationName Name = NameInfo.getName(); // "getA" for Declarator StorageClass SC = getFunctionStorageClass(*this, D); if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) @@ -9599,7 +9599,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); - NamedDecl *PrincipalDecl = (FunctionTemplate + NamedDecl *PrincipalDecl = (FunctionTemplate // Why we must cast it to NameDecl? ? cast(FunctionTemplate) : NewFD); @@ -9638,14 +9638,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (NewFD->isInvalidDecl()) { // Ignore all the rest of this. } else if (!D.isRedeclaration()) { - struct ActOnFDArgs ExtraArgs = { S, D, TemplateParamLists, + struct ActOnFDArgs ExtraArgs = { S, D, TemplateParamLists, // This ExtraArgs stores some info AddToScope }; // Fake up an access specifier if it's supposed to be a class member. if (isa(NewFD->getDeclContext())) NewFD->setAccess(AS_public); // Qualified decls generally require a previous declaration. - if (D.getCXXScopeSpec().isSet()) { + if (D.getCXXScopeSpec().isSet()) { // If BSC has a qualified decl like Foo::getA. // ...with the major exception of templated-scope or // dependent-scope friend declarations. @@ -13847,7 +13847,7 @@ Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D, ParentScope, D, TemplateParameterLists, Bases); D.setFunctionDefinitionKind(FunctionDefinitionKind::Definition); - Decl *DP = HandleDeclarator(ParentScope, D, TemplateParameterLists); + Decl *DP = HandleDeclarator(ParentScope, D, TemplateParameterLists); // ParentScope for FnBody? Decl *Dcl = ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody); if (!Bases.empty()) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index ae8508d6c601..31ea3d293d98 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -5767,9 +5767,11 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, : (IsExecConfig ? 3 /* kernel function (exec config) */ : 0 /* function */); + bool isNotBSC = FDecl ? !FDecl->isBSCMember : true; // If too few arguments are available (and we don't have default - // arguments for the remaining parameters), don't make the call. - if (Args.size() < NumParams) { + // arguments for the remaining parameters), don't make the call, + // unless we are calling foo.getA() for BSC, we generate the first arg. + if (isNotBSC && Args.size() < NumParams) { if (Args.size() < MinArgs) { TypoCorrection TC; if (FDecl && (TC = TryTypoCorrectionForCall(*this, Fn, FDecl, Args))) { @@ -5850,8 +5852,10 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, SmallVector AllArgs; VariadicCallType CallType = getVariadicCallType(FDecl, Proto, Fn); + // Now for BSC, we are handling the call foo.getA(), aiming for foo.get(&foo). + // FIXME: We need to pass the whole CallExpr foo.getA(). This API can be improved for sure. Invalid = GatherArgumentsForCall(Call->getBeginLoc(), FDecl, Proto, 0, Args, - AllArgs, CallType); + AllArgs, CallType, false, false, Call); if (Invalid) return true; unsigned TotalNumArgs = AllArgs.size(); @@ -5866,7 +5870,7 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, unsigned FirstParam, ArrayRef Args, SmallVectorImpl &AllArgs, VariadicCallType CallType, bool AllowExplicit, - bool IsListInitialization) { + bool IsListInitialization, CallExpr* Call) { unsigned NumParams = Proto->getNumParams(); bool Invalid = false; size_t ArgIx = 0; @@ -5917,11 +5921,36 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, } else { assert(Param && "can't use default arguments without a known callee"); - ExprResult ArgExpr = BuildCXXDefaultArgExpr(CallLoc, FDecl, Param); - if (ArgExpr.isInvalid()) - return true; - - Arg = ArgExpr.getAs(); + if (FDecl->isBSCMember) { + // FIXME: This is just a hack for the demo `foo.getA()` case. Need more analysis to make + // sure its a general solution. + // For foo.getA(&foo), it has the AST form like: + // =================== + // CallExpr 'int' + // |-ImplicitCastExpr 'int (*)(struct Foo *)' + // | `-MemberExpr 'int (struct Foo *)' lvalue .getA + // | `-DeclRefExpr 'struct Foo':'struct Foo' lvalue Var 'foo' 'struct Foo':'struct Foo' + // | `-UnaryOperator 'struct Foo *' prefix '&' + // | `-DeclRefExpr 'struct Foo':'struct Foo' lvalue Var 'foo' 'struct Foo':'struct Foo' + // =================== + Expr* Callee = Call->getCallee(); + if (ImplicitCastExpr* ICE = dyn_cast(Callee)) { // Hack, if Callee is ImplicitCastExpr* + Expr* SE = ICE->getSubExpr(); + MemberExpr* Member = dyn_cast(SE); // MemberExpr foo.getA + if (!Member) return true; + DeclRefExpr* DRE = dyn_cast(Member->getBase()); + if (!DRE) return true; + UnaryOperator* UO = UnaryOperator::Create( + this->Context, DRE, UO_AddrOf, this->Context.getPointerType(DRE->getType()), + VK_RValue, OK_Ordinary, SourceLocation(), false, this->CurFPFeatureOverrides()); + Arg = UO; + } + } else { + ExprResult ArgExpr = BuildCXXDefaultArgExpr(CallLoc, FDecl, Param); + if (ArgExpr.isInvalid()) + return true; + Arg = ArgExpr.getAs(); + } } // Check for array bounds violations for each argument to the call. This diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index f5afcb76fc96..d7ce54dc0a4d 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -1115,6 +1115,19 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, VK_LValue, OK_Ordinary); } + // Normally, when we reach here we are dealing sth like foo.getA, getA is MemberDecl, + // in C++, getA is definitely a CXXMethodDecl, but now our BSC treats it as FunctionDecl. + // Do we need to have some BSCMethodDecl for getA in Foo::getA? + if (FunctionDecl *MemberFn = dyn_cast(MemberDecl)) { // BSC's member function for struct Foo + ExprValueKind valueKind; + QualType type; + valueKind = VK_LValue; + type = MemberFn->getType(); + return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, + MemberFn, FoundDecl, /*HadMultipleCandidates=*/false, + MemberNameInfo, type, valueKind, OK_Ordinary); + } + if (CXXMethodDecl *MemberFn = dyn_cast(MemberDecl)) { ExprValueKind valueKind; QualType type; diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 29038ab9fe1c..c0817c40a6b2 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -296,7 +296,9 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, } void LookupResult::configure() { - IDNS = getIDNS(LookupKind, getSema().getLangOpts().CPlusPlus, + // Not sure how getIDNS's affects the findings of names for different languages(C++/C/BSC) + // It can find getA by allowing searching if LangOpts is C. It just works. + IDNS = getIDNS(LookupKind, getSema().getLangOpts().CPlusPlus || getSema().getLangOpts().C11, isForRedeclaration()); // If we're looking for one of the allocation or deallocation @@ -1051,11 +1053,11 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { DeclareImplicitMemberFunctionsWithName(S, R.getLookupName(), R.getNameLoc(), DC); - // Perform lookup into this declaration context. + // Perform lookup into this declaration context. Key for BSC too. DeclContext::lookup_result DR = DC->lookup(R.getLookupName()); for (NamedDecl *D : DR) { if ((D = R.getAcceptableDecl(D))) { - R.addDecl(D); + R.addDecl(D); // add founded getA from previous context to the Result. Found = true; } } @@ -2133,7 +2135,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, } } QL(LookupCtx); - if (LookupDirect(*this, R, LookupCtx)) { + if (LookupDirect(*this, R, LookupCtx)) { // C++ finds getA in Foo R.resolveKind(); if (isa(LookupCtx)) R.setNamingClass(cast(LookupCtx)); -- Gitee