From 9c1350f5ff8658bf804509a321b0b44ab400b784 Mon Sep 17 00:00:00 2001 From: EdwardWang Date: Sat, 28 Jan 2023 20:09:54 +0800 Subject: [PATCH 1/2] [BSC]: revert to the initial --- clang/include/clang/AST/DeclBase.h | 9 +- .../include/clang/AST/DeclContextInternals.h | 4 +- .../clang/Basic/DiagnosticSemaKinds.td | 2 - clang/include/clang/Parse/Parser.h | 13 +- clang/include/clang/Sema/DeclSpec.h | 6 +- clang/include/clang/Sema/IdentifierResolver.h | 2 +- clang/include/clang/Sema/Sema.h | 8 +- clang/lib/AST/Decl.cpp | 3 +- clang/lib/AST/DeclBase.cpp | 6 +- clang/lib/Parse/ParseDecl.cpp | 48 +------ clang/lib/Parse/ParseDeclCXX.cpp | 4 +- clang/lib/Parse/ParseExpr.cpp | 2 +- clang/lib/Parse/ParseExprCXX.cpp | 131 +----------------- clang/lib/Parse/Parser.cpp | 8 +- clang/lib/Sema/SemaDecl.cpp | 53 +++---- clang/lib/Sema/SemaExpr.cpp | 47 ++----- clang/lib/Sema/SemaExprMember.cpp | 30 +--- clang/lib/Sema/SemaLookup.cpp | 10 +- 18 files changed, 61 insertions(+), 325 deletions(-) diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 0c1ef72ea4f0..e0a75d099fbe 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -99,12 +99,6 @@ public: #include "clang/AST/DeclNodes.inc" }; - /// Mark this Decl to be BSC's member function. - bool isBSCMember = false; - - // Used to mark parameters that include 'this'. - bool hasThisParam = 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). @@ -1744,8 +1738,7 @@ 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). - // 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. + mutable StoredDeclsMap *LookupPtr = nullptr; 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 74f7c9d468b2..e6a4cd4381e4 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; // getA will be stored here. + llvm::PointerUnion Data; 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/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 50cc7ce7aa99..b24dac80502f 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6454,8 +6454,6 @@ def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">; def err_no_member : Error<"no member named %0 in %1">; def err_no_member_overloaded_arrow : Error< "no member named %0 in %1; did you mean to use '->' instead of '.'?">; -def err_no_member_overloaded_colon : Error< - "no member named %0 in %1; did you mean to use '::' instead of '.'?">; def err_member_not_yet_instantiated : Error< "no member %0 in %1; it has not yet been instantiated">; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index f5b8a5272df8..11bd1704c4ce 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1868,16 +1868,6 @@ 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, @@ -2933,8 +2923,7 @@ private: DeclaratorContext DeclaratorContext, ParsedAttributes &attrs, SmallVectorImpl &ParamInfo, - SourceLocation &EllipsisLoc, - const Type *typePtr = nullptr); + SourceLocation &EllipsisLoc); void ParseBracketDeclarator(Declarator &D); void ParseMisplacedBracketDeclarator(Declarator &D); diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 9b28e1f614c1..82c892c71bd7 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 { // We need BSCScopeSpec +class CXXScopeSpec { SourceRange Range; NestedNameSpecifierLocBuilder Builder; @@ -1923,10 +1923,6 @@ public: ~Declarator() { clear(); } - - // Used to mark parameters that include 'this'. - bool hasThisParam = false; - /// getDeclSpec - Return the declaration-specifier that this declarator was /// declared with. const DeclSpec &getDeclSpec() const { return DS; } diff --git a/clang/include/clang/Sema/IdentifierResolver.h b/clang/include/clang/Sema/IdentifierResolver.h index 61590bc5b199..7c8dc46307d4 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 { // whats the diff between it and Scope, DeclContext? +class IdentifierResolver { /// 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 3938f8ae152a..cc9f94d908be 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2674,7 +2674,7 @@ public: Attr *getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD, bool IsDefinition); void CheckFunctionOrTemplateParamDeclarator(Scope *S, Declarator &D); - Decl *ActOnParamDeclarator(Scope *S, Declarator &D, int ParamSize = 0, const Type *typePtr = nullptr); + Decl *ActOnParamDeclarator(Scope *S, Declarator &D); ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC, SourceLocation Loc, QualType T); @@ -5293,7 +5293,7 @@ public: CXXScopeSpec &SS, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs, - const Scope *S, bool IsPeriod = false, + const Scope *S, ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); ExprResult @@ -5304,7 +5304,6 @@ public: const TemplateArgumentListInfo *TemplateArgs, const Scope *S, bool SuppressQualifierCheck = false, - bool IsPeriod = false, ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); ExprResult BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, @@ -11310,8 +11309,7 @@ public: SmallVectorImpl &AllArgs, VariadicCallType CallType = VariadicDoesNotApply, bool AllowExplicit = false, - bool IsListInitialization = false, - CallExpr* Call = nullptr); + bool IsListInitialization = false); // 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 46e952fd8b91..3ebcdcd3ccc2 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2074,8 +2074,7 @@ static bool isDeclExternC(const T &D) { // language linkage or no language linkage. const DeclContext *DC = D.getDeclContext(); if (DC->isRecord()) { - auto LangOpts = D.getASTContext().getLangOpts(); - assert(LangOpts.CPlusPlus || LangOpts.BSC); + assert(D.getASTContext().getLangOpts().CPlusPlus); return false; } diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 044982f7b455..c26d6d1a42ea 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(); // Will enter this for find getA in Foo::getA + return I->second.getLookupResult(); } DeclContext::lookup_result diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 1b8801e23648..4ce90b178191 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()) { // BSC should enter this. + if (D.isFunctionDeclarator()) { MaybeParseGNUAttributes(D, &LateParsedAttrs); // The _Noreturn keyword can't appear here, unlike the GNU noreturn @@ -1972,18 +1972,9 @@ 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); - TheDecl->hasThisParam = D.hasThisParam; - // 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); } @@ -3102,8 +3093,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, } case tok::coloncolon: // ::foo::bar - if (getLangOpts().BSC) - return; // C++ scope specifier. Annotate and loop, or bail out on error. if (TryAnnotateCXXScopeToken(EnteringContext)) { if (!DS.hasTypeSpecifier()) @@ -5122,8 +5111,6 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { if (NextToken().is(tok::kw_new) || // ::new NextToken().is(tok::kw_delete)) // ::delete return false; - if (getLangOpts().BSC && NextToken().is(tok::identifier)) - return true; // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. @@ -5609,7 +5596,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); // 2rd arg: call back function + ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator); } static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang, @@ -5680,18 +5667,6 @@ void Parser::ParseDeclaratorInternal(Declarator &D, if (Diags.hasAllExtensionsSilenced()) D.setExtension(); - if(getLangOpts().BSC && - 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. @@ -6520,20 +6495,12 @@ void Parser::ParseFunctionDeclarator(Declarator &D, MaybeParseCXX11Attributes(FnAttrs); ProhibitAttributes(FnAttrs); } else { - if (Tok.isNot(tok::r_paren)) { - const Type *typePtr = nullptr; - if (D.getCXXScopeSpec().isValid()) - typePtr = D.getCXXScopeSpec().getScopeRep()->getAsType()->getCanonicalTypeUnqualified().getTypePtr(); - + if (Tok.isNot(tok::r_paren)) ParseParameterDeclarationClause(D.getContext(), FirstArgAttrs, ParamInfo, - EllipsisLoc, typePtr); - } + EllipsisLoc); else if (RequiresArg) Diag(Tok, diag::err_argument_required_after_attribute); - if (ParamInfo.size() > 0) - D.hasThisParam = ParamInfo.data()[0].Param->hasThisParam; - HasProto = ParamInfo.size() || getLangOpts().CPlusPlus || getLangOpts().OpenCL; @@ -6784,8 +6751,7 @@ void Parser::ParseParameterDeclarationClause( DeclaratorContext DeclaratorCtx, ParsedAttributes &FirstArgAttrs, SmallVectorImpl &ParamInfo, - SourceLocation &EllipsisLoc, - const Type *typePtr) { + SourceLocation &EllipsisLoc) { // Avoid exceeding the maximum function scope depth. // See https://bugs.llvm.org/show_bug.cgi?id=19607 @@ -6905,7 +6871,7 @@ void Parser::ParseParameterDeclarationClause( } // Inform the actions module about the parameter declarator, so it gets // added to the current scope. - Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDeclarator, ParamInfo.size(), typePtr); + Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDeclarator); // Parse the default argument, if any. We parse the default // arguments in all dialects; the semantic analysis in // ActOnParamDefaultArgument will reject the default argument in diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index e9a90e589f39..88ebb59f9a60 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) { // This is a loop to add all decls inside a struct into DeclsInGroup. + while (1) { 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); // Put each Decl inside struct Foo into the DeclsInGroup. + DeclsInGroup.push_back(ThisDecl); if (DeclaratorInfo.isFunctionDeclarator() && DeclaratorInfo.getDeclSpec().getStorageClassSpec() != diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 9eb2e2af259f..6acf76d713fd 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1042,7 +1042,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, // constant: enumeration-constant // Turn a potentially qualified name into a annot_typename or // annot_cxxscope if it would be valid. This handles things like x::y, etc. - if (getLangOpts().CPlusPlus || getLangOpts().BSC) { + if (getLangOpts().CPlusPlus) { // Avoid the unnecessary parse-time lookup in the common case // where the syntax forbids a type. const Token &Next = NextToken(); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index d7fcdaf84dce..4b5703d79f28 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -155,7 +155,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier( CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors, bool EnteringContext, bool *MayBePseudoDestructor, bool IsTypename, IdentifierInfo **LastII, bool OnlyNamespace, bool InUsingDeclaration) { - assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && + assert(getLangOpts().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); if (Tok.is(tok::annot_cxxscope)) { @@ -554,135 +554,6 @@ 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 af07ad9dad38..2a42f058b8ec 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, // Now we do Actions in Sema, what is Scope? + Decl *Res = Actions.ActOnStartOfFunctionDef(getCurScope(), D, 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. But why? + // Break out of the ParsingDeclarator context before we parse the body. 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); // Now we are going to parse the function body. + return ParseFunctionStatementBody(Res, BodyScope); } void Parser::SkipFunctionBody() { @@ -1941,7 +1941,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() { bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope); CXXScopeSpec SS; - if (getLangOpts().CPlusPlus || getLangOpts().BSC) + if (getLangOpts().CPlusPlus) if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, /*ObjectHadErrors=*/false, /*EnteringContext*/ false)) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index b4fe9c52927f..f311f6796c5f 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); // DeclContext add Decl + CurContext->addDecl(D); // 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); // Scope adds Decl. + S->AddDecl(D); 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); // IdentifierResolver adds Decl + IdResolver.AddDecl(D); } } @@ -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(); // "getA" + DeclarationName Name = NameInfo.getName(); // 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, // try to find getA in previous context - forRedeclarationInCurContext()); // LookupOrdinaryName may not find Foo::getA + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, + forRedeclarationInCurContext()); // 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); // This is the key function for find getA in Foo::getA + LookupQualifiedName(Previous, DC); // 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, // We tried to find pre-declared getA, which is named Previous. + New = ActOnFunctionDeclarator(S, D, DC, TInfo, 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); // Adding NewDecl to the Scope. + PushOnScopeChains(New, S); 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(); // getA in Foo::getA + DeclarationName Name = NewFD->getDeclName(); 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(), // cannot find getA in previous scope/context. - IsLocalFriend ? Sema::LookupLocalFriendName // Here we know how to lookup a name. + LookupResult Prev(SemaRef, Name, NewFD->getLocation(), + IsLocalFriend ? Sema::LookupLocalFriendName : 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(); // "getA" for Declarator + DeclarationName Name = NameInfo.getName(); 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 // Why we must cast it to NameDecl? + NamedDecl *PrincipalDecl = (FunctionTemplate ? 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, // This ExtraArgs stores some info + struct ActOnFDArgs ExtraArgs = { S, D, TemplateParamLists, 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 BSC has a qualified decl like Foo::getA. + if (D.getCXXScopeSpec().isSet()) { // ...with the major exception of templated-scope or // dependent-scope friend declarations. @@ -13540,7 +13540,7 @@ void Sema::CheckFunctionOrTemplateParamDeclarator(Scope *S, Declarator &D) { /// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator() /// to introduce parameters into function prototype scope. -Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D, int ParamSize, const Type *typePtr) { +Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { const DeclSpec &DS = D.getDeclSpec(); // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'. @@ -13585,22 +13585,6 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D, int ParamSize, const T // Check for redeclaration of parameters, e.g. int foo(int x, int x); IdentifierInfo *II = D.getIdentifier(); - - bool hasThisParam = false; - if (getLangOpts().BSC && DeclarationName(II).getAsString() == "this") { - if (ParamSize == 0) { - auto thisTypePtr = parmDeclType.getTypePtr()->getPointeeType()->getCanonicalTypeUnqualified().getTypePtr(); - if (typePtr == nullptr || typePtr != thisTypePtr) { - Diag(D.getBeginLoc(), diag::err_type_unsupported) - << parmDeclType.getAsString(); - } - hasThisParam = true; - } else { - Diag(D.getIdentifierLoc(), diag::err_bad_parameter_name) - << GetNameForDeclarator(D).getName(); - } - } - if (II) { LookupResult R(*this, II, D.getIdentifierLoc(), LookupOrdinaryName, ForVisibleRedeclaration); @@ -13630,7 +13614,6 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D, int ParamSize, const T ParmVarDecl *New = CheckParameter(Context.getTranslationUnitDecl(), D.getBeginLoc(), D.getIdentifierLoc(), II, parmDeclType, TInfo, SC); - static_cast(New)->hasThisParam = hasThisParam; if (D.isInvalidType()) New->setInvalidDecl(); @@ -13864,7 +13847,7 @@ Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D, ParentScope, D, TemplateParameterLists, Bases); D.setFunctionDefinitionKind(FunctionDefinitionKind::Definition); - Decl *DP = HandleDeclarator(ParentScope, D, TemplateParameterLists); // ParentScope for FnBody? + Decl *DP = HandleDeclarator(ParentScope, D, TemplateParameterLists); Decl *Dcl = ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody); if (!Bases.empty()) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 31ea3d293d98..ae8508d6c601 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -5767,11 +5767,9 @@ 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, - // unless we are calling foo.getA() for BSC, we generate the first arg. - if (isNotBSC && Args.size() < NumParams) { + // arguments for the remaining parameters), don't make the call. + if (Args.size() < NumParams) { if (Args.size() < MinArgs) { TypoCorrection TC; if (FDecl && (TC = TryTypoCorrectionForCall(*this, Fn, FDecl, Args))) { @@ -5852,10 +5850,8 @@ 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, false, false, Call); + AllArgs, CallType); if (Invalid) return true; unsigned TotalNumArgs = AllArgs.size(); @@ -5870,7 +5866,7 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, unsigned FirstParam, ArrayRef Args, SmallVectorImpl &AllArgs, VariadicCallType CallType, bool AllowExplicit, - bool IsListInitialization, CallExpr* Call) { + bool IsListInitialization) { unsigned NumParams = Proto->getNumParams(); bool Invalid = false; size_t ArgIx = 0; @@ -5921,36 +5917,11 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, } else { assert(Param && "can't use default arguments without a known callee"); - 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(); - } + 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 c62e87213354..f5afcb76fc96 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -747,7 +747,6 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs, const Scope *S, - bool IsPeroid, ActOnMemberAccessExtraArgs *ExtraArgs) { if (BaseType->isDependentType() || (SS.isSet() && isDependentScopeSpecifier(SS))) @@ -795,7 +794,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, return BuildMemberReferenceExpr(Base, BaseType, OpLoc, IsArrow, SS, TemplateKWLoc, FirstQualifierInScope, R, TemplateArgs, S, - false, IsPeroid, ExtraArgs); + false, ExtraArgs); } ExprResult @@ -955,7 +954,6 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, const TemplateArgumentListInfo *TemplateArgs, const Scope *S, bool SuppressQualifierCheck, - bool IsPeriod, ActOnMemberAccessExtraArgs *ExtraArgs) { QualType BaseType = BaseExprType; if (IsArrow) { @@ -1117,29 +1115,6 @@ 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? - // FIXME: MemberDecl and MemberFn have different addresses? - if (FunctionDecl *MemberFn = dyn_cast(MemberDecl)) { // BSC's member function for struct Foo - ExprValueKind valueKind; - QualType type; - valueKind = VK_LValue; - type = MemberFn->getType(); - - // If the first parameter is not 'this', it cannot be called by the way of '.'. - if (getLangOpts().BSC && !MemberDecl->hasThisParam && IsPeriod) { - DeclContext *DC = (SS.isSet() - ? computeDeclContext(SS, false) - : BaseType->castAs()->getDecl()); - Diag(OpLoc, diag::err_no_member_overloaded_colon) - << MemberName << DC << FixItHint::CreateReplacement(OpLoc, "::"); - } - 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; @@ -1731,7 +1706,6 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, DeclarationName Name = NameInfo.getName(); bool IsArrow = (OpKind == tok::arrow); - bool IsPeriod = (OpKind == tok::period); NamedDecl *FirstQualifierInScope = (!SS.isSet() ? nullptr : FindFirstQualifierInScope(S, SS.getScopeRep())); @@ -1751,7 +1725,7 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl}; ExprResult Res = BuildMemberReferenceExpr( Base, Base->getType(), OpLoc, IsArrow, SS, TemplateKWLoc, - FirstQualifierInScope, NameInfo, TemplateArgs, S, IsPeriod, &ExtraArgs); + FirstQualifierInScope, NameInfo, TemplateArgs, S, &ExtraArgs); if (!Res.isInvalid() && isa(Res.get())) CheckMemberAccessOfNoDeref(cast(Res.get())); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 8de10749e083..29038ab9fe1c 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -296,9 +296,7 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, } void LookupResult::configure() { - // 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().BSC, + IDNS = getIDNS(LookupKind, getSema().getLangOpts().CPlusPlus, isForRedeclaration()); // If we're looking for one of the allocation or deallocation @@ -1053,11 +1051,11 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { DeclareImplicitMemberFunctionsWithName(S, R.getLookupName(), R.getNameLoc(), DC); - // Perform lookup into this declaration context. Key for BSC too. + // Perform lookup into this declaration context. DeclContext::lookup_result DR = DC->lookup(R.getLookupName()); for (NamedDecl *D : DR) { if ((D = R.getAcceptableDecl(D))) { - R.addDecl(D); // add founded getA from previous context to the Result. + R.addDecl(D); Found = true; } } @@ -2135,7 +2133,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, } } QL(LookupCtx); - if (LookupDirect(*this, R, LookupCtx)) { // C++ finds getA in Foo + if (LookupDirect(*this, R, LookupCtx)) { R.resolveKind(); if (isa(LookupCtx)) R.setNamingClass(cast(LookupCtx)); -- Gitee From 67ed819bd287b7f99a4226aa24deaf9ccd995431 Mon Sep 17 00:00:00 2001 From: EdwardWang Date: Mon, 30 Jan 2023 14:19:10 +0800 Subject: [PATCH 2/2] [BSC]: add unittest and regression test --- clang/test/BSC/test.cbs | 27 +++++++++++++++++++ .../Frontend/CompilerInvocationTest.cpp | 10 ------- clang/unittests/Lex/LexerTest.cpp | 11 ++++++++ 3 files changed, 38 insertions(+), 10 deletions(-) create mode 100644 clang/test/BSC/test.cbs diff --git a/clang/test/BSC/test.cbs b/clang/test/BSC/test.cbs new file mode 100644 index 000000000000..310f3121270e --- /dev/null +++ b/clang/test/BSC/test.cbs @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// expected-no-diagnostics + +/* Wait to be opened after BSC-member-function feature is implemented. +struct Foo { + int a; +}; + +int struct Foo::getA(struct Foo* this) { + return this->a; +} + +void int::increase(int *this) { + *this = *this + 1; +} + +*/ + +int main() { + /* + struct Foo foo = {.a = 42}; + int a = foo.getA(); // a is 42 + int b = 41; + b.increase(); // b is 42 + */ + return 0; +} \ No newline at end of file diff --git a/clang/unittests/Frontend/CompilerInvocationTest.cpp b/clang/unittests/Frontend/CompilerInvocationTest.cpp index 268f0d0dca45..4b042b525d38 100644 --- a/clang/unittests/Frontend/CompilerInvocationTest.cpp +++ b/clang/unittests/Frontend/CompilerInvocationTest.cpp @@ -730,14 +730,4 @@ TEST_F(CommandLineTest, DigraphsNotImplied) { ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-digraphs")))); ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdigraphs")))); } - -TEST_F(CommandLineTest, DigraphsEnabled) { - const char *Args[] = {"-std=c89", "-fdigraphs"}; - - ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); - ASSERT_TRUE(Invocation.getLangOpts()->Digraphs); - - Invocation.generateCC1CommandLine(GeneratedArgs, *this); - ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fdigraphs"))); -} } // anonymous namespace diff --git a/clang/unittests/Lex/LexerTest.cpp b/clang/unittests/Lex/LexerTest.cpp index 4cdabe042cc8..e561a28c70b3 100644 --- a/clang/unittests/Lex/LexerTest.cpp +++ b/clang/unittests/Lex/LexerTest.cpp @@ -262,6 +262,17 @@ TEST_F(LexerTest, GetSourceTextExpandsRecursively) { EXPECT_EQ("M(i)", getSourceText(toks[3], toks[3])); } +TEST_F(LexerTest, BSCTest) { + LangOpts.BSC = 1; // Make sure Lexer is in BSC mode. + std::vector ExpectedTokens; + ExpectedTokens.push_back(tok::identifier); + ExpectedTokens.push_back(tok::coloncolon); + ExpectedTokens.push_back(tok::identifier); + std::vector toks = CheckLex("Foo::getA", ExpectedTokens); + EXPECT_EQ(ExpectedTokens.size(), toks.size()); + // If new keyword in BSC is introduced like async/await, we can add test here. +} + TEST_F(LexerTest, LexAPI) { std::vector ExpectedTokens; ExpectedTokens.push_back(tok::l_square); -- Gitee