From 0b1bb798b900e0458a0b8a83371d1fb75f4be4f0 Mon Sep 17 00:00:00 2001 From: qinziang Date: Tue, 21 Feb 2023 12:14:47 +0800 Subject: [PATCH 01/22] [generic] parse BSC template function param list in BNF style --- clang/include/clang/Basic/TokenKinds.h | 24 +++ clang/include/clang/Lex/Token.h | 5 + clang/include/clang/Parse/Parser.h | 5 + clang/lib/Lex/Preprocessor.cpp | 2 +- clang/lib/Parse/ParseDecl.cpp | 59 +++++- clang/lib/Parse/ParseExprCXX.cpp | 37 +++- clang/lib/Parse/ParseTemplate.cpp | 260 +++++++++++++++++++++++-- clang/lib/Parse/Parser.cpp | 46 ++++- 8 files changed, 404 insertions(+), 34 deletions(-) diff --git a/clang/include/clang/Basic/TokenKinds.h b/clang/include/clang/Basic/TokenKinds.h index 4e66aa1c8c2d..b70360cd7854 100644 --- a/clang/include/clang/Basic/TokenKinds.h +++ b/clang/include/clang/Basic/TokenKinds.h @@ -73,6 +73,30 @@ inline bool isAnyIdentifier(TokenKind K) { return (K == tok::identifier) || (K == tok::raw_identifier); } +/// Return true if this token kind could be type specifier. +inline bool isAnyTypeSpecifierKind(TokenKind K) { + // Type Specifier: see c11 spec 6.7.2 + return (K == tok::kw__Atomic) || + (K == tok::kw_union) || + (K == tok::kw_struct) || + (K == tok::kw_class) || + (K == tok::kw_enum) || + (K == tok::kw_typedef) || + (K == tok::kw__Complex) || + (K == tok::kw_void) || + (K == tok::kw_bool) || + (K == tok::kw__Bool) || + (K == tok::kw_char) || + (K == tok::kw_short) || + (K == tok::kw_int) || + (K == tok::kw_long) || + (K == tok::kw_float) || + (K == tok::kw_double) || + (K == tok::kw_signed) || + (K == tok::kw_unsigned) || + (K == tok::identifier); +} + /// Return true if this is a C or C++ string-literal (or /// C++11 user-defined-string-literal) token. inline bool isStringLiteral(TokenKind K) { diff --git a/clang/include/clang/Lex/Token.h b/clang/include/clang/Lex/Token.h index 89042a674fec..819da8734245 100644 --- a/clang/include/clang/Lex/Token.h +++ b/clang/include/clang/Lex/Token.h @@ -110,6 +110,11 @@ public: return tok::isAnyIdentifier(getKind()); } + /// Return true if this token kind could be type specifier. + bool isAnyTypeSpecifierKind() const { + return tok::isAnyTypeSpecifierKind(getKind()); + } + /// Return true if this is a "literal", like a numeric /// constant, string, etc. bool isLiteral() const { diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 9e8008926447..5886c90d8067 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3303,6 +3303,11 @@ private: SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, AccessSpecifier AS); + // DEV: ADD BSC-ParseTemplateDeclarationOrSpecialization + Decl *ParseBSCTemplateDeclarationOrSpecialization(DeclaratorContext Context, + SourceLocation &DeclEnd, + ParsedAttributes &AccessAttrs, + AccessSpecifier AS); Decl *ParseSingleDeclarationAfterTemplate( DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject &DiagsFromParams, SourceLocation &DeclEnd, diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 177786d90390..6a86a7f97a84 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -897,7 +897,7 @@ void Preprocessor::Lex(Token &Result) { ReturnedToken = CurTokenLexer->Lex(Result); break; case CLK_CachingLexer: - CachingLex(Result); + CachingLex(Result); // DEV: in ConsumeToken(),read Token from global Cache s.t. token consumption is linear ReturnedToken = true; break; case CLK_LexAfterModuleImport: diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 4f5315c176f7..d55a0835a396 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1661,8 +1661,46 @@ Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, case tok::kw_template: case tok::kw_export: ProhibitAttributes(attrs); - SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); + SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); // DEV: C++ template function parsing branch break; + // DEV: BSC Template Function Declare + // Type Specifier: see c11 spec 6.7.2 + case tok::kw__Atomic: // not verified + case tok::kw_union: // not verified + case tok::kw_struct: // not supported! + case tok::kw_class: // not verified + case tok::kw_enum: // not verified + case tok::kw_typedef: // not verified + case tok::kw__Complex: // not verified + case tok::kw_void: // not supported! + case tok::kw_bool: // not supported! + case tok::kw__Bool: // not supported! + case tok::kw_char: + case tok::kw_short: + case tok::kw_int: + case tok::kw_long: + case tok::kw_float: + case tok::kw_double: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::identifier: + { + assert(Tok.isAnyTypeSpecifierKind() && "Tok should be Type Specifier!"); + // DEV: BSC template function parsing branch + bool isBSCTemplateDecl = getLangOpts().BSC && + ((NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::less) || + (NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::identifier + && PP.LookAhead(2).getKind() == tok::less) + ); + if (isBSCTemplateDecl) { + // parsing function(enter next layer parsing method) + ProhibitAttributes(attrs); + SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); + } else { + goto dont_know; + } + break; + } case tok::kw_inline: // Could be the start of an inline namespace. Allowed as an ext in C++03. if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_namespace)) { @@ -1684,6 +1722,7 @@ Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, SingleDecl = ParseStaticAssertDeclaration(DeclEnd); break; default: + dont_know: return ParseSimpleDeclaration(Context, DeclEnd, attrs, true, nullptr, DeclSpecStart); } @@ -3383,7 +3422,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (Tok.isNot(tok::identifier)) continue; ParsedAttributesWithRange Attrs(AttrFactory); - if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) { + if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) { // DEV: the "T" in BSC miss-parsed here if (!Attrs.empty()) { AttrsLastTime = true; attrs.takeAllFrom(Attrs); @@ -5945,7 +5984,9 @@ static SourceLocation getMissingDeclaratorIdLoc(Declarator &D, void Parser::ParseDirectDeclarator(Declarator &D) { DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec()); - if (getLangOpts().CPlusPlus && D.mayHaveIdentifier()) { + // DEV: adding BSC entrance condition! + // if (getLangOpts().CPlusPlus && D.mayHaveIdentifier()) { + if ((getLangOpts().CPlusPlus || getLangOpts().BSC) && D.mayHaveIdentifier()) { // This might be a C++17 structured binding. if (Tok.is(tok::l_square) && !D.mayOmitIdentifier() && D.getCXXScopeSpec().isEmpty()) @@ -5965,7 +6006,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { D.getContext() == DeclaratorContext::Member; ParseOptionalCXXScopeSpecifier( D.getCXXScopeSpec(), /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, EnteringContext); + /*ObjectHadErrors=*/false, EnteringContext); // BSC compacity problem exists, non-critic } if (D.getCXXScopeSpec().isValid()) { @@ -6033,6 +6074,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { D.getContext() == DeclaratorContext::Member); } + // DEV: [to check] | D.getName() returns (clang::UnqualifiedIdKind::IK_Identifier), witch is incorrect. Identifier,StartLocation,EndLocation not instantialized bool HadScope = D.getCXXScopeSpec().isValid(); if (ParseUnqualifiedId(D.getCXXScopeSpec(), /*ObjectType=*/nullptr, @@ -6218,7 +6260,10 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // In such a case, check if we actually have a function declarator; if it // is not, the declarator has been fully parsed. bool IsAmbiguous = false; - if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) { + // if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) { + + // DEV: Change branch entering condition | BSC syntax reusing C++ parsing code + if ((getLangOpts().CPlusPlus || getLangOpts().BSC) && D.mayBeFollowedByCXXDirectInit()) { // The name of the declarator, if any, is tentatively declared within // a possible direct initializer. TentativelyDeclaredIdentifiers.push_back(D.getIdentifier()); @@ -6579,7 +6624,9 @@ void Parser::ParseFunctionDeclarator(Declarator &D, LocalEndLoc = RParenLoc; EndLoc = RParenLoc; - if (getLangOpts().CPlusPlus) { + // DEV: Change branch entering condition | reusing C++ parse code when parsing BSC syntax + // if (getLangOpts().CPlusPlus) { + if (getLangOpts().CPlusPlus || getLangOpts().BSC) { // FIXME: Accept these components in any order, and produce fixits to // correct the order if the user gets it wrong. Ideally we should deal // with the pure-specifier in the same way. diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 4b5703d79f28..929b7f1febe8 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 && + assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && "Call sites of this function should be guarded by checking for C++"); if (Tok.is(tok::annot_cxxscope)) { @@ -386,7 +386,26 @@ bool Parser::ParseOptionalCXXScopeSpecifier( // type-name '::' // namespace-name '::' // nested-name-specifier identifier '::' - Token Next = NextToken(); + // Token Next = NextToken(); + + // DEV: skip template template param list after function name: "T max (T a, T b) {...}" + // ^^^ + Token Next; + bool parsingBSCTemplateFunction = getLangOpts().BSC && + Tok.is(tok::identifier) && + PP.LookAhead(0).getKind() == tok::less && + PP.LookAhead(1).getKind() == tok::identifier && + (PP.LookAhead(2).getKind() == tok::comma || PP.LookAhead(2).getKind() == tok::greater); + if (parsingBSCTemplateFunction) { + int lParenOffset = 0; + while (PP.LookAhead(lParenOffset).getKind() != tok::l_paren) { + lParenOffset += 1; + } + Next = PP.LookAhead(lParenOffset); + } else { + Next = NextToken(); + } + Sema::NestedNameSpecInfo IdInfo(&II, Tok.getLocation(), Next.getLocation(), ObjectType); @@ -2794,6 +2813,18 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, SourceLocation IdLoc = ConsumeToken(); if (!getLangOpts().CPlusPlus) { + // DEV: if BSC syntax T max(T a, T b) {...} + // ^ + if(getLangOpts().BSC && Tok.is(tok::less)) { + assert(Tok.is(tok::less) && "expected 'loss' token"); + while (!Tok.is(tok::greater)) { + ConsumeToken(); + } + assert(Tok.is(tok::greater) && "expected 'greater' token"); + ConsumeToken(); + assert(Tok.is(tok::l_paren) && "expected 'l_paren' token"); + } + // If we're not in C++, only identifiers matter. Record the // identifier and return. Result.setIdentifier(Id, IdLoc); @@ -2821,7 +2852,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, } // If the next token is a '<', we may have a template. - TemplateTy Template; + TemplateTy Template; if (Tok.is(tok::less)) return ParseUnqualifiedIdTemplateId( SS, ObjectType, ObjectHadErrors, diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 828b9b2277ff..0c0594e1de94 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -43,10 +43,198 @@ Decl *Parser::ParseDeclarationStartingWithTemplate( return ParseExplicitInstantiation(Context, SourceLocation(), ConsumeToken(), DeclEnd, AccessAttrs, AS); } + // DEV: at BSC template definition parse this declaration in a independent branch + bool isBSCTemplateDeclOrSpc = getLangOpts().BSC && + ((NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::less) || + (NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::identifier + && PP.LookAhead(2).getKind() == tok::less) + ); + if (isBSCTemplateDeclOrSpc) { + return ParseBSCTemplateDeclarationOrSpecialization(Context, DeclEnd, AccessAttrs, + AS); + } + // DEV: Warning: Debug: use continue, step-into will fail! return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AccessAttrs, AS); } +/// DEV: DIY BSC-ParseTemplateDeclarationOrSpecialization +Decl *Parser::ParseBSCTemplateDeclarationOrSpecialization( + DeclaratorContext Context, SourceLocation &DeclEnd, + ParsedAttributes &AccessAttrs, AccessSpecifier AS) { + + // DEV: 1) Parsing BSC Generics Method Declaration, make assersion as clang-c++ does + bool isBSCTemplateFunctionDecl = getLangOpts().BSC && + ((NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::less) || + (NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::identifier + && PP.LookAhead(2).getKind() == tok::less) + ); + assert((isBSCTemplateFunctionDecl) && "Token does not start a BSC template declaration."); + + // DEV: 2) create context parameters & handle scopes + MultiParseScope TemplateParamScopes(*this); // Introduces 0 or more scopes for parsing. Scopes will be exited when the object destroyed. // TODO: Scope is single after removing nesting, consider abandon this argument + ParsingDeclRAIIObject ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent); // Tell the action that names should be checked in the context of the declaration to come. // tell Sema that clang is parsing parameter declaration(non-class, non-function) + TemplateParamScopes.Enter(Scope::TemplateParamScope); + + // DEV: 3) handle explicit template function declaration, abandon do-while structure in clang-C++ since there is no template nesting in BSC + // T foo() + // {...} + SmallVector TemplateParams; + int lookAheadOffset = -1; // offset starts from 0, representing the next token; lookAheadOffset starts from -1 is not safe (-1 it self is invalid). + + // Dev: 3-1) skip(consume) irrelevant token for parsing template parsing list. + // SourceLocation StructLoc; + // TryConsumeToken(tok::kw_struct, StructLoc); + if (Tok.getKind() == tok::kw_struct) { + lookAheadOffset += 1; + } + // SourceLocation TemplateSpecifierLoc; + // TryConsumeToken(tok::identifier, TemplateSpecifierLoc); + // SourceLocation TemplateIdentifierLoc; + // TryConsumeToken(tok::identifier, TemplateIdentifierLoc); + lookAheadOffset += 2; + + // DEV: 3-2) [typename list] registration + // DEV: 3-2-1) parse template specifie list + // TryConsumeToken(tok::less, TemplateIdentifierLoc); + assert(PP.LookAhead(lookAheadOffset).getKind() == tok::less && "Error! Tok should be tok::less."); + lookAheadOffset += 1; + // TemplateScopes.Enter(Scope::TemplateParamScope); + // Failed = ParseTemplateParameterList(Depth, TemplateParams); + // ParseTemplateParameters() + do { + NamedDecl *TmpParam; + // Grab the template parameter name (if given) + // SourceLocation NameLoc = Tok.getLocation(); + SourceLocation NameLoc = PP.LookAhead(lookAheadOffset).getLocation(); + IdentifierInfo *ParamName = nullptr; + // if (Tok.is(tok::identifier)) { + if (PP.LookAhead(lookAheadOffset).is(tok::identifier)) { + // ParamName = Tok.getIdentifierInfo(); + ParamName = PP.LookAhead(lookAheadOffset).getIdentifierInfo(); + // ConsumeToken(); + lookAheadOffset += 1; + } else { + // Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; + Diag(PP.LookAhead(lookAheadOffset).getLocation(), diag::err_expected) << tok::identifier; + return nullptr; + } + bool TypenameKeyword = false; + SourceLocation FakeEllipsisLoc; + SourceLocation FakeKeyLoc; + SourceLocation FakeEqualLoc; + ParsedType DefaultArg; + TemplateIdAnnotation *TypeConstraint = nullptr; + unsigned Depth = 0; + unsigned Position = TemplateParams.size(); + NamedDecl *NewDecl = Actions.ActOnTypeParameter(getCurScope(), + TypenameKeyword, FakeEllipsisLoc, + FakeKeyLoc, ParamName, NameLoc, + Depth, Position, FakeEqualLoc, + DefaultArg, + TypeConstraint != nullptr); + TmpParam = NewDecl; + TemplateParams.push_back(TmpParam); + + // if (Tok.getKind() == tok::comma) + // ConsumeToken(); + if (PP.LookAhead(lookAheadOffset).getKind() == tok::comma) + lookAheadOffset += 1; + + // if (TypeConstraint) { + // Actions.ActOnTypeConstraint(TypeConstraintSS, TypeConstraint, + // cast(NewDecl), + // EllipsisLoc); + // } + // } while(Tok.getKind() != tok::greater); + } while(PP.LookAhead(lookAheadOffset).getKind() != tok::greater); + // ConsumeToken(); + lookAheadOffset += 1; + + // DEV: 3-2-2) parse information of newly added template + SourceLocation FakeTemplateLoc; + SourceLocation LAngleLoc, RAngleLoc; + ExprResult OptionalRequiresClauseConstraintER; + TemplateParameterLists ParamLists; + + TemplateParameterList *ParamList = TemplateParameterList::Create( + Actions.Context, FakeTemplateLoc, LAngleLoc, + llvm::makeArrayRef(TemplateParams.data(), TemplateParams.size()), + RAngleLoc, OptionalRequiresClauseConstraintER.get()); // encapsulate the TemplateTypeParamDecl as template parameter list + ParamLists.push_back(ParamList); // clang-c++ further encapsulate this template parameter list, clang-BSC will abandon this finally + + // ParamLists.push_back(Actions.ActOnTemplateParameterList( + // CurTemplateDepthTracker.getDepth(), ExportLoc, TemplateLoc, LAngleLoc, + // TemplateParams, RAngleLoc, OptionalRequiresClauseConstraintER.get())); + + bool fakeIsSpecialization = false; + bool fakeLastParamListWasEmpty = false; + const ParsedTemplateInfo ParsedTemplateInfo(&ParamLists, fakeIsSpecialization, fakeLastParamListWasEmpty); + + // DEV: 4) parsing template function body + // Parse the actual template declaration. + // ParseConceptDefinition(); + // ParseSingleDeclarationAfterTemplate(); + + // Dev: 4-1) paring Declare Specifier + ParsedAttributesWithRange prefixAttrs(AttrFactory); // handle attributes + MaybeParseCXX11Attributes(prefixAttrs); + + assert(((NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::less) || + (NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::identifier && PP.LookAhead(2).getKind() == tok::less)) + && "Tok Error - struct^ T^ max<"); + + ParsingDeclSpec DS(*this, &ParsingTemplateParams); // define Declaration Spec + ParseDeclarationSpecifiers(DS, ParsedTemplateInfo, AS, + getDeclSpecContextFromDeclaratorContext(Context)); + + assert((Tok.getKind() == tok::identifier && NextToken().getKind() == tok::less) && "Tok Error - T max^<"); + + // Dev: 4-2) Declare Formalize DclaratiobSpecifier + // Move the attributes from the prefix into the DS. + if (ParsedTemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) + ProhibitAttributes(prefixAttrs); + else + DS.takeAttributesFrom(prefixAttrs); + + // Parse the declarator. + ParsingDeclarator DeclaratorInfo(*this, DS, (DeclaratorContext)Context); + if (ParsedTemplateInfo.TemplateParams) + DeclaratorInfo.setTemplateParameterLists(*ParsedTemplateInfo.TemplateParams); + ParseDeclarator(DeclaratorInfo); + // Error parsing the declarator? + if (!DeclaratorInfo.hasName()) { + // If so, skip until the semi-colon or a }. + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); + if (Tok.is(tok::semi)) + ConsumeToken(); + return nullptr; + } + + // Un-Clarified + llvm::TimeTraceScope TimeScope("ParseTemplate", [&]() { + return std::string(DeclaratorInfo.getIdentifier() != nullptr + ? DeclaratorInfo.getIdentifier()->getName() + : ""); + }); + + LateParsedAttrList LateParsedAttrs(true); + if (DeclaratorInfo.isFunctionDeclarator()) { + if (Tok.is(tok::kw_requires)) + ParseTrailingRequiresClause(DeclaratorInfo); + + MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); + } + + // Dev: 4-3) Parsing Function Definition(Body) + assert(DeclaratorInfo.isFunctionDeclarator() && isStartOfFunctionDefinition(DeclaratorInfo) && "asume function declaration here."); + + Decl *TemplateFunctionDecl = ParseFunctionDefinition(DeclaratorInfo, ParsedTemplateInfo, + &LateParsedAttrs); + + // return TemplateFunctionDecl; // DEV: return this Decl will casue code-gen error +} + /// Parse a template declaration or an explicit specialization. /// /// Template declarations include one or more template parameter lists @@ -63,19 +251,15 @@ Decl *Parser::ParseDeclarationStartingWithTemplate( /// template-declaration: [C++2a] /// template-head declaration /// template-head concept-definition -/// -/// TODO: requires-clause -/// template-head: [C++2a] -/// 'template' '<' template-parameter-list '>' -/// requires-clause[opt] -/// /// explicit-specialization: [ C++ temp.expl.spec] /// 'template' '<' '>' declaration Decl *Parser::ParseTemplateDeclarationOrSpecialization( DeclaratorContext Context, SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, AccessSpecifier AS) { - assert(Tok.isOneOf(tok::kw_export, tok::kw_template) && - "Token does not start a template declaration."); + // DEV: + bool isBSCTemplateFunctionDecl = getLangOpts().BSC && NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::less; + assert(( Tok.isOneOf(tok::kw_export, tok::kw_template) or isBSCTemplateFunctionDecl) && + "Token does not start a template declaration."); // adding BSC template parsing condition MultiParseScope TemplateParamScopes(*this); @@ -86,7 +270,7 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization( // Parse multiple levels of template headers within this template // parameter scope, e.g., - // + //ParseSingleDeclarationAfterTemplate // template // template // class A::B { ... }; @@ -116,13 +300,31 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization( TryConsumeToken(tok::kw_export, ExportLoc); // Consume the 'template', which should be here. + // DEV: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + bool isBSCTemplateDecl = getLangOpts().BSC && + ((NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::less) || + (NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::identifier + && PP.LookAhead(2).getKind() == tok::less) + ); SourceLocation TemplateLoc; if (!TryConsumeToken(tok::kw_template, TemplateLoc)) { - Diag(Tok.getLocation(), diag::err_expected_template); - return nullptr; + //DEV: Exception - BSC template function definition + if (!isBSCTemplateDecl) { + Diag(Tok.getLocation(), diag::err_expected_template); + return nullptr; + } + } + + // DEV: + if (isBSCTemplateDecl){ + // T foo() {} + // ^ ^ + // now goto + Tok = GetLookAheadToken(2); // skip"<",enter template param list parsing method } // Parse the '<' template-parameter-list '>' + // DEV: parsing strin “, Tok has to skip function name(identifier) SourceLocation LAngleLoc, RAngleLoc; SmallVector TemplateParams; if (ParseTemplateParameters(TemplateParamScopes, @@ -439,7 +641,6 @@ bool Parser::ParseTemplateParameters( MultiParseScope &TemplateScopes, unsigned Depth, SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, SourceLocation &RAngleLoc) { - // Get the template parameter list. if (!TryConsumeToken(tok::less, LAngleLoc)) { Diag(Tok.getLocation(), diag::err_expected_less_after) << "template"; return true; @@ -514,6 +715,7 @@ Parser::ParseTemplateParameterList(const unsigned Depth, /// Determine whether the parser is at the start of a template /// type parameter. Parser::TPResult Parser::isStartOfTemplateTypeParameter() { + // DEV: Log if (Tok.is(tok::kw_class)) { // "class" may be the start of an elaborated-type-specifier or a // type-parameter. Per C++ [temp.param]p3, we prefer the type-parameter. @@ -556,6 +758,14 @@ Parser::TPResult Parser::isStartOfTemplateTypeParameter() { !GetLookAheadToken(Tok.is(tok::annot_cxxscope) ? 2 : 1) .isOneOf(tok::kw_auto, tok::kw_decltype)) return TPResult::True; + + // DEV: parsing template param list + bool isStartOfBSCTemplateTypeParam = getLangOpts().BSC && Tok.getKind() == tok::identifier && + (NextToken().getKind() == tok::comma || NextToken().getKind() == tok::greater); // DEV: this judgement condition May be nogod + if (isStartOfBSCTemplateTypeParam) + { + return TPResult::True; + } // 'typedef' is a reasonably-common typo/thinko for 'typename', and is // ill-formed otherwise. @@ -629,7 +839,7 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { Tok.getEndLoc()), "typename"); - Tok.setKind(tok::kw_typename); + Tok.setKind(tok::kw_typename); // DEV: unkown operation, rename "typedef" as "typename" } return ParseTypeParameter(Depth, Position); @@ -662,7 +872,7 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { } if (Tok.is(tok::kw_template)) - return ParseTemplateTemplateParameter(Depth, Position); + return ParseTemplateTemplateParameter(Depth, Position); // DEV: call upper layer method recursively to parse nested template param list "template >" // If it's none of the above, then it must be a parameter declaration. // NOTE: This will pick up errors in the closure of the template parameter @@ -757,10 +967,12 @@ bool Parser::TryAnnotateTypeConstraint() { /// 'typename' ...[opt][C++0x] identifier[opt] /// 'typename' identifier[opt] '=' type-id NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { - assert((Tok.isOneOf(tok::kw_class, tok::kw_typename) || - isTypeConstraintAnnotation()) && - "A type-parameter starts with 'class', 'typename' or a " - "type-constraint"); + // DEV: Check Tok location: in BSC, template param list w/o template definition + bool isBSCTemplateTypeParameter = getLangOpts().BSC && Tok.getKind() == tok::identifier && NextToken().getKind() == tok::greater; + assert(((Tok.isOneOf(tok::kw_class, tok::kw_typename) || + isTypeConstraintAnnotation()) || + isBSCTemplateTypeParameter) && + "A type-parameter starts with 'class', 'typename' or a type-constraint"); CXXScopeSpec TypeConstraintSS; TemplateIdAnnotation *TypeConstraint = nullptr; @@ -781,8 +993,14 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { "expected type constraint after scope specifier"); // Consume the 'class' or 'typename' keyword. - TypenameKeyword = Tok.is(tok::kw_typename); - KeyLoc = ConsumeToken(); + if (isBSCTemplateTypeParameter) { + // DEV: BSC syntax does not contains "typename", assume TypenameKeyword is true when reusing Actions.ActOnTypeParameter + TypenameKeyword = true; + KeyLoc = Tok.getLocation(); // DEV: skip typename token + } else { + TypenameKeyword = Tok.is(tok::kw_typename); + KeyLoc = ConsumeToken(); // DEV: skip typename token + } } // Grab the ellipsis (if given). @@ -798,7 +1016,7 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { SourceLocation NameLoc = Tok.getLocation(); IdentifierInfo *ParamName = nullptr; if (Tok.is(tok::identifier)) { - ParamName = Tok.getIdentifierInfo(); + ParamName = Tok.getIdentifierInfo(); // DEV: Critical- parsing T token ConsumeToken(); } else if (Tok.isOneOf(tok::equal, tok::comma, tok::greater, tok::greatergreater)) { diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 815d078f0c79..7087a8914883 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -23,7 +23,6 @@ #include "llvm/Support/Path.h" using namespace clang; - namespace { /// A comment handler that passes comments found by the preprocessor /// to the parser action. @@ -924,7 +923,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, // A function definition cannot start with any of these keywords. { SourceLocation DeclEnd; - return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs); + return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs); // DEV: entrance of parsing “template ” } case tok::kw_static: @@ -983,6 +982,47 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, SkipUntil(tok::semi); return nullptr; + // DEV: BSC Template Function Declaration Structure + // "^[]specifier-identifier--(paramlist) {body}" structure + // static inline int int foo(T a, int b) {return b;} + // TODO: parse high-level syntax (structure, inline, ...) + // Type Specifier: see c11 spec 6.7.2 + case tok::kw__Atomic: // not verified + case tok::kw_union: // not verified + case tok::kw_struct: // not supported! + case tok::kw_class: // not verified + case tok::kw_enum: // not verified + // case tok::kw_typedef: // typedef will be parsed in another branch + case tok::kw__Complex: // not verified + case tok::kw_void: // not verified + case tok::kw_bool: // not supported! + case tok::kw__Bool: // not supported! + case tok::kw_char: + case tok::kw_short: + case tok::kw_int: + case tok::kw_long: + case tok::kw_float: + case tok::kw_double: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::identifier: + { + assert(Tok.isAnyTypeSpecifierKind() && "Tok should be Type Specifier!"); + // branch of parsing BSC template function + bool isBSCTemplateDecl = getLangOpts().BSC && + ((NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::less) || + (NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::identifier + && PP.LookAhead(2).getKind() == tok::less) + ); + if (isBSCTemplateDecl) { + // parsing function (enter next level of parsing function) + SourceLocation DeclEnd; + return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs); + } else { + goto dont_know; + } + } + default: dont_know: if (Tok.isEditorPlaceholder()) { @@ -990,7 +1030,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, return nullptr; } // We can't tell whether this is a function-definition or declaration yet. - return ParseDeclarationOrFunctionDefinition(attrs, DS); + return ParseDeclarationOrFunctionDefinition(attrs, DS); // DEV: entrance of parsing “T max(T a, T b)” & “int max(int a, int b)” } // This routine returns a DeclGroup, if the thing we parsed only contains a -- Gitee From dced9cad49eee6fcd20ed80c8b763e78b07dee6f Mon Sep 17 00:00:00 2001 From: Aperzer Date: Thu, 23 Feb 2023 19:35:25 +0800 Subject: [PATCH 02/22] [generic] Generic demo support for BSC Now we can parse BSC template demo like: #include T1 max(T1 a, T2 b) { return a > b ? a : b; } int main() { float a = 41.0; float b = 42.1; float res = max(a, b); printf("res = %f\n",res); return 0; } Now both initial part and instantiation part can work. --- clang/lib/Parse/ParseDecl.cpp | 8 +- clang/lib/Parse/ParseExpr.cpp | 2 +- clang/lib/Parse/ParseTemplate.cpp | 3 +- clang/lib/Parse/Parser.cpp | 5 +- clang/lib/Sema/SemaDecl.cpp | 197 +++++++++++++++++++++++++++++- clang/lib/Sema/SemaExpr.cpp | 22 ++++ clang/lib/Sema/SemaTemplate.cpp | 3 +- 7 files changed, 229 insertions(+), 11 deletions(-) diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index d55a0835a396..7de078f68f9b 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -5984,9 +5984,11 @@ static SourceLocation getMissingDeclaratorIdLoc(Declarator &D, void Parser::ParseDirectDeclarator(Declarator &D) { DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec()); + // BSC Mark: Add language judgement for BSC template situation. // DEV: adding BSC entrance condition! // if (getLangOpts().CPlusPlus && D.mayHaveIdentifier()) { - if ((getLangOpts().CPlusPlus || getLangOpts().BSC) && D.mayHaveIdentifier()) { + if ((getLangOpts().CPlusPlus || getLangOpts().BSC) + && D.mayHaveIdentifier()) { // This might be a C++17 structured binding. if (Tok.is(tok::l_square) && !D.mayOmitIdentifier() && D.getCXXScopeSpec().isEmpty()) @@ -6262,8 +6264,10 @@ void Parser::ParseDirectDeclarator(Declarator &D) { bool IsAmbiguous = false; // if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) { + // BSC Mark: Add language judgement for BSC template situation. // DEV: Change branch entering condition | BSC syntax reusing C++ parsing code - if ((getLangOpts().CPlusPlus || getLangOpts().BSC) && D.mayBeFollowedByCXXDirectInit()) { + if ((getLangOpts().CPlusPlus || getLangOpts().BSC) + && D.mayBeFollowedByCXXDirectInit()) { // The name of the declarator, if any, is tentatively declared within // a possible direct initializer. TentativelyDeclaredIdentifiers.push_back(D.getIdentifier()); diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 9cdd191aec4f..625e8e0453b7 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1075,7 +1075,7 @@ Parser::ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand, } // 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) { + if (getLangOpts().CPlusPlus || getLangOpts().BSC) { // 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/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 0c0594e1de94..9a93944e9717 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -1510,7 +1510,8 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, UnqualifiedId &TemplateName, bool AllowTypeAnnotation, bool TypeConstraint) { - assert(getLangOpts().CPlusPlus && "Can only annotate template-ids in C++"); + assert((getLangOpts().CPlusPlus || getLangOpts().BSC) + && "Can only annotate template-ids in C++"); assert((Tok.is(tok::less) || TypeConstraint) && "Parser isn't at the beginning of a template-id"); assert(!(TypeConstraint && AllowTypeAnnotation) && "type-constraint can't be " diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 7087a8914883..1cfd99b86c83 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -2000,7 +2000,10 @@ bool Parser::TryAnnotateTypeOrScopeToken() { bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope); CXXScopeSpec SS; - if (getLangOpts().CPlusPlus) + // BSC Mark: Add BSC language judgement. + // This will help us parse the instantiation + // part of BSC template situation. + if (getLangOpts().CPlusPlus || getLangOpts().BSC) if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, /*ObjectHadErrors=*/false, /*EnteringContext*/ false)) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index fd712ce8fc5b..379a02333046 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9290,6 +9290,163 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, FPT->getExtProtoInfo().withExceptionSpec(EST_BasicNoexcept))); } + // BSC Mark: This is for BSC template case. + if (getLangOpts().BSC) { + bool isInline = D.getDeclSpec().isInlineSpecified(); + bool isVirtual = D.getDeclSpec().isVirtualSpecified(); + bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier(); + isFriend = D.getDeclSpec().isFriendSpecified(); + if (isFriend && !isInline && D.isFunctionDefinition()) { + // C++ [class.friend]p5 + // A function can be defined in a friend declaration of a + // class . . . . Such a function is implicitly inline. + NewFD->setImplicitlyInline(); + } + + // If this is a method defined in an __interface, and is not a constructor + // or an overloaded operator, then set the pure flag (isVirtual will already + // return true). + if (const CXXRecordDecl *Parent = + dyn_cast(NewFD->getDeclContext())) { + if (Parent->isInterface() && cast(NewFD)->isUserProvided()) + NewFD->setPure(true); + + // C++ [class.union]p2 + // A union can have member functions, but not virtual functions. + if (isVirtual && Parent->isUnion()) + Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_in_union); + } + + SetNestedNameSpecifier(*this, NewFD, D); + isMemberSpecialization = false; + isFunctionTemplateSpecialization = false; + if (D.isInvalidType()) + NewFD->setInvalidDecl(); + + // Match up the template parameter lists with the scope specifier, then + // determine whether we have a template or a template specialization. + bool Invalid = false; + TemplateParameterList *TemplateParams = + MatchTemplateParametersToScopeSpecifier( + D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(), + D.getCXXScopeSpec(), + D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId + ? D.getName().TemplateId + : nullptr, + TemplateParamLists, isFriend, isMemberSpecialization, + Invalid); + if (TemplateParams) { + // Check that we can declare a template here. + if (CheckTemplateDeclScope(S, TemplateParams)) + NewFD->setInvalidDecl(); + + if (TemplateParams->size() > 0) { + // This is a function template + + // A destructor cannot be a template. + if (Name.getNameKind() == DeclarationName::CXXDestructorName) { + Diag(NewFD->getLocation(), diag::err_destructor_template); + NewFD->setInvalidDecl(); + } + + // If we're adding a template to a dependent context, we may need to + // rebuilding some of the types used within the template parameter list, + // now that we know what the current instantiation is. + if (DC->isDependentContext()) { + ContextRAII SavedContext(*this, DC); + if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams)) + Invalid = true; + } + + FunctionTemplate = FunctionTemplateDecl::Create(Context, DC, + NewFD->getLocation(), + Name, TemplateParams, + NewFD); + FunctionTemplate->setLexicalDeclContext(CurContext); + NewFD->setDescribedFunctionTemplate(FunctionTemplate); + + // For source fidelity, store the other template param lists. + if (TemplateParamLists.size() > 1) { + NewFD->setTemplateParameterListsInfo(Context, + ArrayRef(TemplateParamLists) + .drop_back(1)); + } + } else { + // This is a function template specialization. + isFunctionTemplateSpecialization = true; + // For source fidelity, store all the template param lists. + if (TemplateParamLists.size() > 0) + NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists); + + // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);". + if (isFriend) { + // We want to remove the "template<>", found here. + SourceRange RemoveRange = TemplateParams->getSourceRange(); + + // If we remove the template<> and the name is not a + // template-id, we're actually silently creating a problem: + // the friend declaration will refer to an untemplated decl, + // and clearly the user wants a template specialization. So + // we need to insert '<>' after the name. + SourceLocation InsertLoc; + if (D.getName().getKind() != UnqualifiedIdKind::IK_TemplateId) { + InsertLoc = D.getName().getSourceRange().getEnd(); + InsertLoc = getLocForEndOfToken(InsertLoc); + } + + Diag(D.getIdentifierLoc(), diag::err_template_spec_decl_friend) + << Name << RemoveRange + << FixItHint::CreateRemoval(RemoveRange) + << FixItHint::CreateInsertion(InsertLoc, "<>"); + } + } + } else { + // Check that we can declare a template here. + if (!TemplateParamLists.empty() && isMemberSpecialization && + CheckTemplateDeclScope(S, TemplateParamLists.back())) + NewFD->setInvalidDecl(); + + // All template param lists were matched against the scope specifier: + // this is NOT (an explicit specialization of) a template. + if (TemplateParamLists.size() > 0) + // For source fidelity, store all the template param lists. + NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists); + } + + if (Invalid) { + NewFD->setInvalidDecl(); + if (FunctionTemplate) + FunctionTemplate->setInvalidDecl(); + } + + // If a function is defined as defaulted or deleted, mark it as such now. + // We'll do the relevant checks on defaulted / deleted functions later. + switch (D.getFunctionDefinitionKind()) { + case FunctionDefinitionKind::Declaration: + case FunctionDefinitionKind::Definition: + break; + + case FunctionDefinitionKind::Defaulted: + NewFD->setDefaulted(); + break; + + case FunctionDefinitionKind::Deleted: + NewFD->setDeletedAsWritten(); + break; + } + + // C++11 [except.spec]p15: + // A deallocation function with no exception-specification is treated + // as if it were specified with noexcept(true). + const FunctionProtoType *FPT = R->getAs(); + if ((Name.getCXXOverloadedOperator() == OO_Delete || + Name.getCXXOverloadedOperator() == OO_Array_Delete) && + getLangOpts().CPlusPlus11 && FPT && !FPT->hasExceptionSpec()) + NewFD->setType(Context.getFunctionType( + FPT->getReturnType(), FPT->getParamTypes(), + FPT->getExtProtoInfo().withExceptionSpec(EST_BasicNoexcept))); + } + // Filter out previous declarations that don't match the scope. FilterLookupForScope(Previous, OriginalDC, S, shouldConsiderLinkage(NewFD), D.getCXXScopeSpec().isNotEmpty() || @@ -9493,11 +9650,31 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } - if (NewFD->getReturnType().hasNonTrivialToPrimitiveDestructCUnion() || - NewFD->getReturnType().hasNonTrivialToPrimitiveCopyCUnion()) - checkNonTrivialCUnion(NewFD->getReturnType(), - NewFD->getReturnTypeSourceRange().getBegin(), - NTCUC_FunctionReturn, NTCUK_Destruct|NTCUK_Copy); + if (NewFD->getReturnType().hasNonTrivialToPrimitiveDestructCUnion() || + NewFD->getReturnType().hasNonTrivialToPrimitiveCopyCUnion()) + checkNonTrivialCUnion(NewFD->getReturnType(), + NewFD->getReturnTypeSourceRange().getBegin(), + NTCUC_FunctionReturn, NTCUK_Destruct|NTCUK_Copy); + + // BSC Mark: We need this API for BSC template situation. + // If we have a function template, check the template parameter + // list. This will check and merge default template arguments. + if (FunctionTemplate) { + FunctionTemplateDecl *PrevTemplate = + FunctionTemplate->getPreviousDecl(); + CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(), + PrevTemplate ? PrevTemplate->getTemplateParameters() + : nullptr, + D.getDeclSpec().isFriendSpecified() + ? (D.isFunctionDefinition() + ? TPC_FriendFunctionTemplateDefinition + : TPC_FriendFunctionTemplate) + : (D.getCXXScopeSpec().isSet() && + DC && DC->isRecord() && + DC->isDependentContext()) + ? TPC_ClassTemplateMember + : TPC_FunctionTemplate); + } } else { // C++11 [replacement.functions]p3: // The program's definitions shall not be specified as inline. @@ -9895,6 +10072,16 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, CompleteMemberSpecialization(NewFD, Previous); } + // BSC Mark: This is for BSC template case. + // This can return a 'FunctionTemplateDecl' for the AST Context. + if (getLangOpts().BSC) { + if (FunctionTemplate) { + if (NewFD->isInvalidDecl()) + FunctionTemplate->setInvalidDecl(); + return FunctionTemplate; + } + } + for (const ParmVarDecl *Param : NewFD->parameters()) { QualType PT = Param->getType(); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 7d53cc7cdcce..45f0436d59b4 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -8231,6 +8231,13 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // C++ is sufficiently different to merit its own checker. if (getLangOpts().CPlusPlus) return CXXCheckConditionalOperands(Cond, LHS, RHS, VK, OK, QuestionLoc); + + // BSC Mark: We do this for BSC template situation. + // This avoids errors during the comparison phase. + if (getLangOpts().BSC && + (Cond.get()->isTypeDependent() || LHS.get()->isTypeDependent() || + RHS.get()->isTypeDependent())) + return CXXCheckConditionalOperands(Cond, LHS, RHS, VK, OK, QuestionLoc); VK = VK_RValue; OK = OK_Ordinary; @@ -14570,6 +14577,21 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); } + // BSC Mark: This is for BSC template situation. + // API "isTypeDependent()" only deal with template situation. + if (getLangOpts().BSC) { + // If either expression is type-dependent, always build an + // overloaded op. + if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent()) + return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); + + // Otherwise, build an overloaded op if either expression has an + // overloadable type. + if (LHSExpr->getType()->isOverloadableType() || + RHSExpr->getType()->isOverloadableType()) + return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); + } + if (getLangOpts().RecoveryAST && (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent())) { assert(!getLangOpts().CPlusPlus); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 12880b95b9c6..84a3d35b3e3a 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -176,7 +176,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S, TemplateTy &TemplateResult, bool &MemberOfUnknownSpecialization, bool Disambiguation) { - assert(getLangOpts().CPlusPlus && "No template names in C!"); + assert((getLangOpts().CPlusPlus || getLangOpts().BSC) + && "No template names in C!"); DeclarationName TName; MemberOfUnknownSpecialization = false; -- Gitee From e083a30849ca77ae579dcaf952e13b0689fd6485 Mon Sep 17 00:00:00 2001 From: EdwardWang Date: Thu, 23 Feb 2023 01:00:07 +0800 Subject: [PATCH 03/22] [BSC] add mangling for BSC generic function For max(1,2) and max(1.0,2.0), we should have two different function names for CodeGen. --- clang/lib/AST/Mangle.cpp | 7 ++++++ clang/test/BSC/Generic/multi_type_params.cbs | 19 ++++++++++++++++ clang/test/BSC/Generic/return_type_int.cbs | 16 ++++++++++++++ clang/test/BSC/Generic/single_type_param.cbs | 23 ++++++++++++++++++++ 4 files changed, 65 insertions(+) create mode 100644 clang/test/BSC/Generic/multi_type_params.cbs create mode 100644 clang/test/BSC/Generic/return_type_int.cbs create mode 100644 clang/test/BSC/Generic/single_type_param.cbs diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp index 3e4a497aef98..d3056a3edec3 100644 --- a/clang/lib/AST/Mangle.cpp +++ b/clang/lib/AST/Mangle.cpp @@ -120,6 +120,13 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) { if (!D->hasExternalFormalLinkage() && D->getOwningModuleForLinkage()) return true; + // In BSC, generic function always does mangling. + if (getASTContext().getLangOpts().BSC) { + if (auto FD = dyn_cast(D)) { + return FD->getTemplatedKind() == FunctionDecl::TemplatedKind::TK_FunctionTemplateSpecialization; + } + } + // In C, functions with no attributes never need to be mangled. Fastpath them. if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs()) return false; diff --git a/clang/test/BSC/Generic/multi_type_params.cbs b/clang/test/BSC/Generic/multi_type_params.cbs new file mode 100644 index 000000000000..2493aa70d42b --- /dev/null +++ b/clang/test/BSC/Generic/multi_type_params.cbs @@ -0,0 +1,19 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include +T2 foo(T1 a, T2 b, T3 c) { + return b; +} + +int main() { + int f1 = foo(1, 2, 3); + float f2 = foo(1, 2.0, 3); + const char* c = "123"; + const char* f3 = foo(2, c, 3); + printf("f1 is %d\n", f1); + printf("f2 is %f\n", f2); + printf("f3 is %s\n", f3); + return 0; +} diff --git a/clang/test/BSC/Generic/return_type_int.cbs b/clang/test/BSC/Generic/return_type_int.cbs new file mode 100644 index 000000000000..448b8ccee79b --- /dev/null +++ b/clang/test/BSC/Generic/return_type_int.cbs @@ -0,0 +1,16 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include +int bar(T1 a, T2 b) { + return 42; +} + + +int main() { + int x1 = bar(1, 2); + int x2 = bar(1.0, 2.0); + printf("%d %d\n", x1, x2); + return 0; +} diff --git a/clang/test/BSC/Generic/single_type_param.cbs b/clang/test/BSC/Generic/single_type_param.cbs new file mode 100644 index 000000000000..4a10ea27c2f5 --- /dev/null +++ b/clang/test/BSC/Generic/single_type_param.cbs @@ -0,0 +1,23 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include + +T max(T a, T b) { + return a > b ? a : b; +} + +int main() { + int a = 10; + int b = 11; + int m1 = max(a, b); + int m2 = max(12, a); + double m3 = max(1.2, 1.3); + float m4 = max(2.12, 2.123); + printf("m1 is %d\n", m1); + printf("m2 is %d\n", m2); + printf("m3 is %f\n", m3); + printf("m4 is %f\n", m4); + return 0; +} -- Gitee From 1e902e10a322c763091ad7c1e67307de4a77c53b Mon Sep 17 00:00:00 2001 From: qinziang Date: Fri, 24 Feb 2023 15:47:59 +0800 Subject: [PATCH 04/22] [generic] fix return value for ParseBSCTemplateDeclarationOrSpecialization 1) add return Decl for ParseBSCTemplateDeclarationOrSpecialization() 2) add structure return-type template function test case --- clang/lib/Parse/ParseTemplate.cpp | 44 ++++++++++--------- clang/test/BSC/Generic/return_type_struct.cbs | 24 ++++++++++ 2 files changed, 47 insertions(+), 21 deletions(-) create mode 100644 clang/test/BSC/Generic/return_type_struct.cbs diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 9a93944e9717..1a52064cc497 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -96,8 +96,8 @@ Decl *Parser::ParseBSCTemplateDeclarationOrSpecialization( // DEV: 3-2) [typename list] registration // DEV: 3-2-1) parse template specifie list - // TryConsumeToken(tok::less, TemplateIdentifierLoc); assert(PP.LookAhead(lookAheadOffset).getKind() == tok::less && "Error! Tok should be tok::less."); + // TryConsumeToken(tok::less, TemplateIdentifierLoc); lookAheadOffset += 1; // TemplateScopes.Enter(Scope::TemplateParamScope); // Failed = ParseTemplateParameterList(Depth, TemplateParams); @@ -111,7 +111,7 @@ Decl *Parser::ParseBSCTemplateDeclarationOrSpecialization( // if (Tok.is(tok::identifier)) { if (PP.LookAhead(lookAheadOffset).is(tok::identifier)) { // ParamName = Tok.getIdentifierInfo(); - ParamName = PP.LookAhead(lookAheadOffset).getIdentifierInfo(); + ParamName = PP.LookAhead(lookAheadOffset).getIdentifierInfo(); // extract template param info // ConsumeToken(); lookAheadOffset += 1; } else { @@ -132,7 +132,7 @@ Decl *Parser::ParseBSCTemplateDeclarationOrSpecialization( FakeKeyLoc, ParamName, NameLoc, Depth, Position, FakeEqualLoc, DefaultArg, - TypeConstraint != nullptr); + TypeConstraint != nullptr); // build template param declaration TmpParam = NewDecl; TemplateParams.push_back(TmpParam); @@ -141,17 +141,23 @@ Decl *Parser::ParseBSCTemplateDeclarationOrSpecialization( if (PP.LookAhead(lookAheadOffset).getKind() == tok::comma) lookAheadOffset += 1; - // if (TypeConstraint) { - // Actions.ActOnTypeConstraint(TypeConstraintSS, TypeConstraint, - // cast(NewDecl), - // EllipsisLoc); - // } + // apply type constraint checking + CXXScopeSpec TypeConstraintSS; + SourceLocation EllipsisLoc; + ParseOptionalCXXScopeSpecifier(TypeConstraintSS, /*ObjectType=*/nullptr, + /*ObjectHadErrors=*/false, + /*EnteringContext*/ false); + if (TypeConstraint) { + Actions.ActOnTypeConstraint(TypeConstraintSS, TypeConstraint, + cast(NewDecl), + EllipsisLoc); + } // } while(Tok.getKind() != tok::greater); } while(PP.LookAhead(lookAheadOffset).getKind() != tok::greater); - // ConsumeToken(); + // ConsumeToken(); // comsume tok::greater lookAheadOffset += 1; - // DEV: 3-2-2) parse information of newly added template + // DEV: 3-2-2) parse information of newly added template parameters SourceLocation FakeTemplateLoc; SourceLocation LAngleLoc, RAngleLoc; ExprResult OptionalRequiresClauseConstraintER; @@ -169,7 +175,7 @@ Decl *Parser::ParseBSCTemplateDeclarationOrSpecialization( bool fakeIsSpecialization = false; bool fakeLastParamListWasEmpty = false; - const ParsedTemplateInfo ParsedTemplateInfo(&ParamLists, fakeIsSpecialization, fakeLastParamListWasEmpty); + const ParsedTemplateInfo TemplateInfo(&ParamLists, fakeIsSpecialization, fakeLastParamListWasEmpty); // DEV: 4) parsing template function body // Parse the actual template declaration. @@ -185,22 +191,22 @@ Decl *Parser::ParseBSCTemplateDeclarationOrSpecialization( && "Tok Error - struct^ T^ max<"); ParsingDeclSpec DS(*this, &ParsingTemplateParams); // define Declaration Spec - ParseDeclarationSpecifiers(DS, ParsedTemplateInfo, AS, + ParseDeclarationSpecifiers(DS, TemplateInfo, AS, getDeclSpecContextFromDeclaratorContext(Context)); assert((Tok.getKind() == tok::identifier && NextToken().getKind() == tok::less) && "Tok Error - T max^<"); // Dev: 4-2) Declare Formalize DclaratiobSpecifier // Move the attributes from the prefix into the DS. - if (ParsedTemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) ProhibitAttributes(prefixAttrs); else DS.takeAttributesFrom(prefixAttrs); // Parse the declarator. ParsingDeclarator DeclaratorInfo(*this, DS, (DeclaratorContext)Context); - if (ParsedTemplateInfo.TemplateParams) - DeclaratorInfo.setTemplateParameterLists(*ParsedTemplateInfo.TemplateParams); + if (TemplateInfo.TemplateParams) + DeclaratorInfo.setTemplateParameterLists(*TemplateInfo.TemplateParams); ParseDeclarator(DeclaratorInfo); // Error parsing the declarator? if (!DeclaratorInfo.hasName()) { @@ -211,7 +217,6 @@ Decl *Parser::ParseBSCTemplateDeclarationOrSpecialization( return nullptr; } - // Un-Clarified llvm::TimeTraceScope TimeScope("ParseTemplate", [&]() { return std::string(DeclaratorInfo.getIdentifier() != nullptr ? DeclaratorInfo.getIdentifier()->getName() @@ -229,10 +234,7 @@ Decl *Parser::ParseBSCTemplateDeclarationOrSpecialization( // Dev: 4-3) Parsing Function Definition(Body) assert(DeclaratorInfo.isFunctionDeclarator() && isStartOfFunctionDefinition(DeclaratorInfo) && "asume function declaration here."); - Decl *TemplateFunctionDecl = ParseFunctionDefinition(DeclaratorInfo, ParsedTemplateInfo, - &LateParsedAttrs); - - // return TemplateFunctionDecl; // DEV: return this Decl will casue code-gen error + return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo, &LateParsedAttrs); } /// Parse a template declaration or an explicit specialization. @@ -256,7 +258,7 @@ Decl *Parser::ParseBSCTemplateDeclarationOrSpecialization( Decl *Parser::ParseTemplateDeclarationOrSpecialization( DeclaratorContext Context, SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, AccessSpecifier AS) { - // DEV: + // DEV: add BSC language in status checking assertion bool isBSCTemplateFunctionDecl = getLangOpts().BSC && NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::less; assert(( Tok.isOneOf(tok::kw_export, tok::kw_template) or isBSCTemplateFunctionDecl) && "Token does not start a template declaration."); // adding BSC template parsing condition diff --git a/clang/test/BSC/Generic/return_type_struct.cbs b/clang/test/BSC/Generic/return_type_struct.cbs new file mode 100644 index 000000000000..9dfd920c0cb7 --- /dev/null +++ b/clang/test/BSC/Generic/return_type_struct.cbs @@ -0,0 +1,24 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include + +struct Brick { + char* color; + int size; +}; + +struct Brick bar(T1 a, T2 b) { + struct Brick brick = {.color="red", .size=2}; + return brick; +} + + +int main() { + struct Brick br1 = bar(1, 2); + struct Brick br2 = bar(1.0, 2.0); + printf("%s %d\n", br1.color, br1.size); + printf("%s %d\n", br2.color, br2.size); + return 0; +} -- Gitee From 3f124b6f42e246ce255b1b1c0acc3e9546e1b856 Mon Sep 17 00:00:00 2001 From: qinziang Date: Sat, 25 Feb 2023 18:02:00 +0800 Subject: [PATCH 05/22] [generic] fix segfault when parsing incomplete template function we provide better diagnostic info for case like bellow: T foo(T a, T b { // missing ")" return a; } --- clang/lib/Parse/ParseTemplate.cpp | 22 +++++++++++++++++-- clang/test/BSC/Generic/diagnose.cbs | 8 +++++++ clang/test/BSC/Generic/return_type_struct.cbs | 22 +++++++++++-------- 3 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 clang/test/BSC/Generic/diagnose.cbs diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 1a52064cc497..6a44c996950a 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -232,9 +232,27 @@ Decl *Parser::ParseBSCTemplateDeclarationOrSpecialization( } // Dev: 4-3) Parsing Function Definition(Body) - assert(DeclaratorInfo.isFunctionDeclarator() && isStartOfFunctionDefinition(DeclaratorInfo) && "asume function declaration here."); + // assert(DeclaratorInfo.isFunctionDeclarator() && isStartOfFunctionDefinition(DeclaratorInfo) && "asume function declaration here."); + if (DeclaratorInfo.isFunctionDeclarator() && isStartOfFunctionDefinition(DeclaratorInfo)) { + return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo, &LateParsedAttrs); + } + + // Parse this declaration. + Decl *ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo, TemplateInfo); + + if (Tok.is(tok::comma)) { + Diag(Tok, diag::err_multiple_template_declarators) + << (int)TemplateInfo.Kind; + SkipUntil(tok::semi); + return ThisDecl; + } - return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo, &LateParsedAttrs); + // Eat the semi colon after the declaration. + ExpectAndConsumeSemi(diag::err_expected_semi_declaration); + if (LateParsedAttrs.size() > 0) + ParseLexedAttributeList(LateParsedAttrs, ThisDecl, true, false); + DeclaratorInfo.complete(ThisDecl); + return ThisDecl; } /// Parse a template declaration or an explicit specialization. diff --git a/clang/test/BSC/Generic/diagnose.cbs b/clang/test/BSC/Generic/diagnose.cbs new file mode 100644 index 000000000000..2df056a7d7d4 --- /dev/null +++ b/clang/test/BSC/Generic/diagnose.cbs @@ -0,0 +1,8 @@ +T foo(T a, T b { // missing ")" + return a; +} + +int main() { + int res = foo(1, 2); + return 0; +} diff --git a/clang/test/BSC/Generic/return_type_struct.cbs b/clang/test/BSC/Generic/return_type_struct.cbs index 9dfd920c0cb7..ce94d097bf09 100644 --- a/clang/test/BSC/Generic/return_type_struct.cbs +++ b/clang/test/BSC/Generic/return_type_struct.cbs @@ -4,21 +4,25 @@ #include -struct Brick { +struct Block { // MineCraft Block char* color; - int size; + int blood; }; -struct Brick bar(T1 a, T2 b) { - struct Brick brick = {.color="red", .size=2}; - return brick; +struct Block bar(T1 a, T2 b) { + struct Block grass = {"green", 1}; + struct Block obsidian = {.color="black", .blood=100}; + struct Block oak; + oak.color = "yellow"; + oak.blood = 15; + return grass; } int main() { - struct Brick br1 = bar(1, 2); - struct Brick br2 = bar(1.0, 2.0); - printf("%s %d\n", br1.color, br1.size); - printf("%s %d\n", br2.color, br2.size); + struct Block br1 = bar(1, 2); + struct Block br2 = bar(1.0, 2.0); + printf("%s %d\n", br1.color, br1.blood); + printf("%s %d\n", br2.color, br2.blood); return 0; } -- Gitee From 1145423e25fe0a1a27fe556b93ff027c7669322c Mon Sep 17 00:00:00 2001 From: Aperzer Date: Tue, 28 Feb 2023 10:09:20 +0800 Subject: [PATCH 06/22] [generic] support function call add annotation 1)Now we can parse a function-call in the definition of the template function. Such as: T1 Misc(T1 a, T2 b) { a.foo(); } Test case has also been added. 2)Added some annotation for the instantiation part. --- clang/lib/Parse/ParseTemplate.cpp | 9 +++++++++ clang/lib/Sema/SemaExpr.cpp | 19 +++++++++++++++++++ clang/test/BSC/Generic/function_call.cbs | 16 ++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 clang/test/BSC/Generic/function_call.cbs diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 6a44c996950a..3fdd94b9b113 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -1466,6 +1466,8 @@ Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken, if (!Tok.isOneOf(tok::greater, tok::greatergreater, tok::greatergreatergreater, tok::greaterequal, tok::greatergreaterequal)) + // BSC Mark: Template arguments will be parsed at here. + // Pay attention to this API if we want to figure out how template arguements being parsed. Invalid = ParseTemplateArgumentList(TemplateArgs); if (Invalid) { @@ -1548,6 +1550,11 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, TemplateArgList TemplateArgs; bool ArgsInvalid = false; if (!TypeConstraint || Tok.is(tok::less)) { + // BSC Mark: The template args will be parsed at here. + // Pay attention to this API if we want to figure out how template arguements being parsed. + // @Code: + // int res = max(a, b); + // ^^^^^^^^^^^^ <-these are template args ArgsInvalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc, TemplateArgs, RAngleLoc); // If we couldn't recover from invalid arguments, don't form an annotation @@ -1807,6 +1814,8 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { ColonProtectionRAIIObject ColonProtection(*this, false); do { + // BSC Mark: Template arguments will be parsed at here. + // Pay attention to this API if we want to figure out how template arguements being parsed. ParsedTemplateArgument Arg = ParseTemplateArgument(); SourceLocation EllipsisLoc; if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 45f0436d59b4..2fb614de536a 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6502,6 +6502,25 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, } } + // BSC Mark: This branch is for when attempting to parse a function-call + // in the body of template function. Such as: + // @Code: + // T1 Misc(T1 a, T2 b) + // { + // a.foo(); + // } + if (getLangOpts().BSC) { + // Determine whether this is a dependent call inside a C++ template, + // in which case we won't do any semantic analysis now. + if (Fn->isTypeDependent() || Expr::hasAnyTypeDependentArguments(ArgExprs)) { + tryImplicitlyCaptureThisIfImplicitMemberFunctionAccessWithDependentArgs( + *this, dyn_cast(Fn->IgnoreParens()), + Fn->getBeginLoc()); + return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy, + VK_RValue, RParenLoc, CurFPFeatureOverrides()); + } + } + // Check for overloaded calls. This can happen even in C due to extensions. if (Fn->getType() == Context.OverloadTy) { OverloadExpr::FindResult find = OverloadExpr::find(Fn); diff --git a/clang/test/BSC/Generic/function_call.cbs b/clang/test/BSC/Generic/function_call.cbs new file mode 100644 index 000000000000..26712d67df2f --- /dev/null +++ b/clang/test/BSC/Generic/function_call.cbs @@ -0,0 +1,16 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include + +T1 FunctionCall(T1 a, T2 b) +{ + a.foo(); + b.foo(); +} + +int main() { + // Cannot combine with member function now, so we cannot have the instantiation behavior. + return 0; +} \ No newline at end of file -- Gitee From 1ac13e099941fb0d4797f7a5c78ce5c5fbb0ef34 Mon Sep 17 00:00:00 2001 From: Aperzer Date: Thu, 2 Mar 2023 15:38:56 +0800 Subject: [PATCH 07/22] [generic] support instantiation part without LHS Now we can parse the instantiation part without left expression and "=". Such as: int main(){ foo(1, 2); //without left expression } --- clang/lib/Parse/Parser.cpp | 6 +++- .../BSC/Generic/Instantiation_without_LHS.cbs | 36 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 clang/test/BSC/Generic/Instantiation_without_LHS.cbs diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 1cfd99b86c83..ca8ebb4664a0 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1691,7 +1691,11 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) { const bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope); CXXScopeSpec SS; - if (getLangOpts().CPlusPlus && + // BSC Mark: Add BSC language judgement, when instantiates BSC template + // function without LHS and "=", we need enter this. + // @Code + // int main(){ foo(1, 2); } + if ((getLangOpts().CPlusPlus || getLangOpts().BSC) && ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, /*ObjectHadErrors=*/false, EnteringContext)) diff --git a/clang/test/BSC/Generic/Instantiation_without_LHS.cbs b/clang/test/BSC/Generic/Instantiation_without_LHS.cbs new file mode 100644 index 000000000000..406b7df4dc29 --- /dev/null +++ b/clang/test/BSC/Generic/Instantiation_without_LHS.cbs @@ -0,0 +1,36 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include + +struct A{ + int x; + float y; +}; + +struct B{ + int x; + float y; +}; + +void foo (T1 a, T2 b) { + int x1 = a.x + b.x; + printf("x1 = %d\n", x1); + float x2 = a.y + b.y; + printf("x2 = %f\n", x2); +} + +void foo2 (T1 a, T2 b) { + int x3 = a + b; + printf("x3 = %f\n", x3); +} + +int main(){ + struct A a = {.x = 2022, .y = 1.5}; + struct B b = {.x = 2023, .y = 1.6}; + foo(a, b); + foo2(1, 2); + return 0; +} + -- Gitee From d4e40ecf3283a5e06edc05f404bc2b0b082cf10d Mon Sep 17 00:00:00 2001 From: qinziang Date: Thu, 2 Mar 2023 19:29:14 +0800 Subject: [PATCH 08/22] [generic] refactor ParseBSCTemplateDeclarationOrSpecialization method modification: 1) code-refactor: wrapped ParseBSCTemplateDeclarationOrSpecialization and related lower-level apis using 'peeking trick'; 2) code-clean: remove irrelevant code in ParseTemplate.cpp & adjust other code changes. "long long" return type not supported yet; struct template parsing is not realized yet; --- clang/include/clang/Parse/Parser.h | 16 + clang/lib/Parse/ParseDecl.cpp | 16 +- clang/lib/Parse/ParseDeclCXX.cpp | 14 +- clang/lib/Parse/ParseExprCXX.cpp | 19 +- clang/lib/Parse/ParseTemplate.cpp | 534 +++++++++++-------- clang/lib/Parse/Parser.cpp | 20 +- clang/test/BSC/Generic/diagnose.cbs | 7 +- clang/test/BSC/Generic/return_type_multi.cbs | 26 + 8 files changed, 390 insertions(+), 262 deletions(-) create mode 100644 clang/test/BSC/Generic/return_type_multi.cbs diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 5886c90d8067..08d3414ecfca 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3308,6 +3308,10 @@ private: SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, AccessSpecifier AS); + Decl *ParseTemplateDeclarationOrSpecializationBSCCompact(DeclaratorContext Context, + SourceLocation &DeclEnd, + ParsedAttributes &AccessAttrs, + AccessSpecifier AS); Decl *ParseSingleDeclarationAfterTemplate( DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject &DiagsFromParams, SourceLocation &DeclEnd, @@ -3316,11 +3320,23 @@ private: SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, SourceLocation &RAngleLoc); + // DEV: Declare ParseBSCTemplateParameters + bool ParseBSCTemplateParameters(MultiParseScope &TemplateScopes, unsigned Depth, + SmallVectorImpl &TemplateParams, + SourceLocation &LAngleLoc, + SourceLocation &RAngleLoc, + int &lookAheadOffset); bool ParseTemplateParameterList(unsigned Depth, SmallVectorImpl &TemplateParams); + // DEV: Declare ParseBSCTemplateParameterList + bool ParseBSCTemplateParameterList(unsigned Depth, + SmallVectorImpl &TemplateParams, + int &lookAheadOffset); TPResult isStartOfTemplateTypeParameter(); NamedDecl *ParseTemplateParameter(unsigned Depth, unsigned Position); NamedDecl *ParseTypeParameter(unsigned Depth, unsigned Position); + // DEV: Declare ParseBSCTypeParameter + NamedDecl *ParseBSCTypeParameter(unsigned Depth, unsigned Position, int &lookAheadOffset); NamedDecl *ParseTemplateTemplateParameter(unsigned Depth, unsigned Position); NamedDecl *ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position); bool isTypeConstraintAnnotation(); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 7de078f68f9b..da87bbb69129 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1663,7 +1663,7 @@ Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, ProhibitAttributes(attrs); SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); // DEV: C++ template function parsing branch break; - // DEV: BSC Template Function Declare + // DEV: BSC Template Function Declare | TODO: long long, refactor // Type Specifier: see c11 spec 6.7.2 case tok::kw__Atomic: // not verified case tok::kw_union: // not verified @@ -1686,11 +1686,11 @@ Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, case tok::identifier: { assert(Tok.isAnyTypeSpecifierKind() && "Tok should be Type Specifier!"); - // DEV: BSC template function parsing branch + // DEV: BSC template function parsing branch | TODO: refactor bool isBSCTemplateDecl = getLangOpts().BSC && - ((NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::less) || - (NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::identifier - && PP.LookAhead(2).getKind() == tok::less) + ((NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::less)) || + (NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::identifier) + && PP.LookAhead(2).is(tok::less)) ); if (isBSCTemplateDecl) { // parsing function(enter next layer parsing method) @@ -3370,7 +3370,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // In C++, check to see if this is a scope specifier like foo::bar::, if // so handle it as such. This is important for ctor parsing. - if (getLangOpts().CPlusPlus) { + if (getLangOpts().CPlusPlus || getLangOpts().BSC) { if (TryAnnotateCXXScopeToken(EnteringContext)) { DS.SetTypeSpecError(); goto DoneWithDeclSpec; @@ -3422,7 +3422,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (Tok.isNot(tok::identifier)) continue; ParsedAttributesWithRange Attrs(AttrFactory); - if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) { // DEV: the "T" in BSC miss-parsed here + if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) { // DEV: template parameter "T" in BSC will be miss-parsed here if (!Attrs.empty()) { AttrsLastTime = true; attrs.takeAllFrom(Attrs); @@ -3984,7 +3984,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___interface: case tok::kw_union: { tok::TokenKind Kind = Tok.getKind(); - ConsumeToken(); + ConsumeToken(); // consume 'struct keyword' // These are attributes following class specifiers. // To produce better diagnostic, we parse them when diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 88ebb59f9a60..d08664ee5824 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1604,10 +1604,20 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, IdentifierInfo *Name = nullptr; SourceLocation NameLoc; TemplateIdAnnotation *TemplateId = nullptr; + bool isBSCTemplateStructParsing = getLangOpts().BSC && Tok.is(tok::identifier) && NextToken().is(tok::less); if (Tok.is(tok::identifier)) { Name = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); + // DEV: BSC Sturct Template Declaration may have "" syntax. + // This param list must been parsed, skip it. + if (isBSCTemplateStructParsing) { + while (Tok.getKind() != tok::greater) { + ConsumeToken(); + } + assert(TryConsumeToken(tok::greater) && "comsuming BSC struct template param list fail!"); + } + if (Tok.is(tok::less) && getLangOpts().CPlusPlus) { // The name was supposed to refer to a template, but didn't. // Eat the template argument list and try to continue parsing this as @@ -1965,7 +1975,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (SkipBody.ShouldSkip) SkipCXXMemberSpecification(StartLoc, AttrFixitLoc, TagType, TagOrTempResult.get()); - else if (getLangOpts().CPlusPlus) + // DEV: add BSC entrance condition + // else if (getLangOpts().CPlusPlus) + else if (getLangOpts().CPlusPlus || (getLangOpts().BSC && isBSCTemplateStructParsing)) ParseCXXMemberSpecification(StartLoc, AttrFixitLoc, attrs, TagType, TagOrTempResult.get()); else { diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 929b7f1febe8..f6f3c9ccaf0c 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -388,17 +388,17 @@ bool Parser::ParseOptionalCXXScopeSpecifier( // nested-name-specifier identifier '::' // Token Next = NextToken(); - // DEV: skip template template param list after function name: "T max (T a, T b) {...}" - // ^^^ + // DEV: skip template template param list in template function declaration: "T max (T a, T b) {...}" + // ^^^ Token Next; bool parsingBSCTemplateFunction = getLangOpts().BSC && Tok.is(tok::identifier) && - PP.LookAhead(0).getKind() == tok::less && - PP.LookAhead(1).getKind() == tok::identifier && - (PP.LookAhead(2).getKind() == tok::comma || PP.LookAhead(2).getKind() == tok::greater); + PP.LookAhead(0).is(tok::less) && + PP.LookAhead(1).is(tok::identifier) && + (PP.LookAhead(2).is(tok::comma) || PP.LookAhead(2).is(tok::greater)); if (parsingBSCTemplateFunction) { int lParenOffset = 0; - while (PP.LookAhead(lParenOffset).getKind() != tok::l_paren) { + while (!PP.LookAhead(lParenOffset).is(tok::l_paren)) { lParenOffset += 1; } Next = PP.LookAhead(lParenOffset); @@ -2813,15 +2813,14 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, SourceLocation IdLoc = ConsumeToken(); if (!getLangOpts().CPlusPlus) { - // DEV: if BSC syntax T max(T a, T b) {...} + // DEV: at BSC syntax T max(T a, T b) {...} // ^ if(getLangOpts().BSC && Tok.is(tok::less)) { - assert(Tok.is(tok::less) && "expected 'loss' token"); + assert(Tok.is(tok::less) && "expected 'less' token"); while (!Tok.is(tok::greater)) { ConsumeToken(); } - assert(Tok.is(tok::greater) && "expected 'greater' token"); - ConsumeToken(); + assert(TryConsumeToken(tok::greater) && "expected 'greater' token"); assert(Tok.is(tok::l_paren) && "expected 'l_paren' token"); } diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 3fdd94b9b113..df448540b204 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -43,218 +43,105 @@ Decl *Parser::ParseDeclarationStartingWithTemplate( return ParseExplicitInstantiation(Context, SourceLocation(), ConsumeToken(), DeclEnd, AccessAttrs, AS); } - // DEV: at BSC template definition parse this declaration in a independent branch + // DEV: at BSC template declaration, parse this in a independent branch bool isBSCTemplateDeclOrSpc = getLangOpts().BSC && - ((NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::less) || - (NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::identifier - && PP.LookAhead(2).getKind() == tok::less) + ((NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::less)) || + (NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::identifier) + && PP.LookAhead(2).is(tok::less)) ); if (isBSCTemplateDeclOrSpc) { return ParseBSCTemplateDeclarationOrSpecialization(Context, DeclEnd, AccessAttrs, AS); } - // DEV: Warning: Debug: use continue, step-into will fail! + // DEV: Warning: Debug: use continue, otherwise, using step-into will fail! return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AccessAttrs, AS); } -/// DEV: DIY BSC-ParseTemplateDeclarationOrSpecialization +/// DEV: DIY rewrite ParseTemplateDeclarationOrSpecialization for BSC Decl *Parser::ParseBSCTemplateDeclarationOrSpecialization( DeclaratorContext Context, SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, AccessSpecifier AS) { + assert(getLangOpts().BSC && "Error enter BSC template declaration parsing function."); - // DEV: 1) Parsing BSC Generics Method Declaration, make assersion as clang-c++ does - bool isBSCTemplateFunctionDecl = getLangOpts().BSC && - ((NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::less) || - (NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::identifier - && PP.LookAhead(2).getKind() == tok::less) - ); - assert((isBSCTemplateFunctionDecl) && "Token does not start a BSC template declaration."); + MultiParseScope TemplateParamScopes(*this); + + // Tell the action that names should be checked in the context of + // the declaration to come. + ParsingDeclRAIIObject + ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent); // not sure - // DEV: 2) create context parameters & handle scopes - MultiParseScope TemplateParamScopes(*this); // Introduces 0 or more scopes for parsing. Scopes will be exited when the object destroyed. // TODO: Scope is single after removing nesting, consider abandon this argument - ParsingDeclRAIIObject ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent); // Tell the action that names should be checked in the context of the declaration to come. // tell Sema that clang is parsing parameter declaration(non-class, non-function) - TemplateParamScopes.Enter(Scope::TemplateParamScope); + // Parse multiple levels of template headers within this template // make sure each parameter pass same branch & branch condition is fully considered + bool isSpecialization = true; // changed in (2), shuold be false : Kind(isSpecialization? ExplicitSpecialization : Template) + bool LastParamListWasEmpty = false; // changed in (2), should be false: Whether the last template parameter list was empty. + TemplateParameterLists ParamLists; // changed in (2), only called onece at ParamLists.push_back + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); // changed in (2), - // DEV: 3) handle explicit template function declaration, abandon do-while structure in clang-C++ since there is no template nesting in BSC - // T foo() - // {...} - SmallVector TemplateParams; - int lookAheadOffset = -1; // offset starts from 0, representing the next token; lookAheadOffset starts from -1 is not safe (-1 it self is invalid). + // Consume the 'export', if any. // no corresponding syntax + SourceLocation ExportLoc; + TryConsumeToken(tok::kw_export, ExportLoc); - // Dev: 3-1) skip(consume) irrelevant token for parsing template parsing list. - // SourceLocation StructLoc; - // TryConsumeToken(tok::kw_struct, StructLoc); - if (Tok.getKind() == tok::kw_struct) { + // Consume the 'template', which should be here. // no corresponding syntax + SourceLocation TemplateLoc; + TryConsumeToken(tok::kw_template, TemplateLoc); + + int lookAheadOffset = 0; // lookAheadOffset starts from 0, assume the first token we see must not be '<' + while (!PP.LookAhead(lookAheadOffset).is(tok::less)) { // use while since the template function definition struct is not solid in BSC lookAheadOffset += 1; } - // SourceLocation TemplateSpecifierLoc; - // TryConsumeToken(tok::identifier, TemplateSpecifierLoc); - // SourceLocation TemplateIdentifierLoc; - // TryConsumeToken(tok::identifier, TemplateIdentifierLoc); - lookAheadOffset += 2; - - // DEV: 3-2) [typename list] registration - // DEV: 3-2-1) parse template specifie list - assert(PP.LookAhead(lookAheadOffset).getKind() == tok::less && "Error! Tok should be tok::less."); - // TryConsumeToken(tok::less, TemplateIdentifierLoc); - lookAheadOffset += 1; - // TemplateScopes.Enter(Scope::TemplateParamScope); - // Failed = ParseTemplateParameterList(Depth, TemplateParams); - // ParseTemplateParameters() - do { - NamedDecl *TmpParam; - // Grab the template parameter name (if given) - // SourceLocation NameLoc = Tok.getLocation(); - SourceLocation NameLoc = PP.LookAhead(lookAheadOffset).getLocation(); - IdentifierInfo *ParamName = nullptr; - // if (Tok.is(tok::identifier)) { - if (PP.LookAhead(lookAheadOffset).is(tok::identifier)) { - // ParamName = Tok.getIdentifierInfo(); - ParamName = PP.LookAhead(lookAheadOffset).getIdentifierInfo(); // extract template param info - // ConsumeToken(); - lookAheadOffset += 1; - } else { - // Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; - Diag(PP.LookAhead(lookAheadOffset).getLocation(), diag::err_expected) << tok::identifier; - return nullptr; - } - bool TypenameKeyword = false; - SourceLocation FakeEllipsisLoc; - SourceLocation FakeKeyLoc; - SourceLocation FakeEqualLoc; - ParsedType DefaultArg; - TemplateIdAnnotation *TypeConstraint = nullptr; - unsigned Depth = 0; - unsigned Position = TemplateParams.size(); - NamedDecl *NewDecl = Actions.ActOnTypeParameter(getCurScope(), - TypenameKeyword, FakeEllipsisLoc, - FakeKeyLoc, ParamName, NameLoc, - Depth, Position, FakeEqualLoc, - DefaultArg, - TypeConstraint != nullptr); // build template param declaration - TmpParam = NewDecl; - TemplateParams.push_back(TmpParam); + assert(PP.LookAhead(lookAheadOffset).is(tok::less) && "BSC template function parameter list does not begin with tok::less"); - // if (Tok.getKind() == tok::comma) - // ConsumeToken(); - if (PP.LookAhead(lookAheadOffset).getKind() == tok::comma) - lookAheadOffset += 1; - - // apply type constraint checking - CXXScopeSpec TypeConstraintSS; - SourceLocation EllipsisLoc; - ParseOptionalCXXScopeSpecifier(TypeConstraintSS, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, - /*EnteringContext*/ false); - if (TypeConstraint) { - Actions.ActOnTypeConstraint(TypeConstraintSS, TypeConstraint, - cast(NewDecl), - EllipsisLoc); - } - // } while(Tok.getKind() != tok::greater); - } while(PP.LookAhead(lookAheadOffset).getKind() != tok::greater); - // ConsumeToken(); // comsume tok::greater - lookAheadOffset += 1; - - // DEV: 3-2-2) parse information of newly added template parameters - SourceLocation FakeTemplateLoc; + // Parse the '<' template-parameter-list '>' SourceLocation LAngleLoc, RAngleLoc; - ExprResult OptionalRequiresClauseConstraintER; - TemplateParameterLists ParamLists; - - TemplateParameterList *ParamList = TemplateParameterList::Create( - Actions.Context, FakeTemplateLoc, LAngleLoc, - llvm::makeArrayRef(TemplateParams.data(), TemplateParams.size()), - RAngleLoc, OptionalRequiresClauseConstraintER.get()); // encapsulate the TemplateTypeParamDecl as template parameter list - ParamLists.push_back(ParamList); // clang-c++ further encapsulate this template parameter list, clang-BSC will abandon this finally - - // ParamLists.push_back(Actions.ActOnTemplateParameterList( - // CurTemplateDepthTracker.getDepth(), ExportLoc, TemplateLoc, LAngleLoc, - // TemplateParams, RAngleLoc, OptionalRequiresClauseConstraintER.get())); - - bool fakeIsSpecialization = false; - bool fakeLastParamListWasEmpty = false; - const ParsedTemplateInfo TemplateInfo(&ParamLists, fakeIsSpecialization, fakeLastParamListWasEmpty); - - // DEV: 4) parsing template function body - // Parse the actual template declaration. - // ParseConceptDefinition(); - // ParseSingleDeclarationAfterTemplate(); - - // Dev: 4-1) paring Declare Specifier - ParsedAttributesWithRange prefixAttrs(AttrFactory); // handle attributes - MaybeParseCXX11Attributes(prefixAttrs); - - assert(((NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::less) || - (NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::identifier && PP.LookAhead(2).getKind() == tok::less)) - && "Tok Error - struct^ T^ max<"); - - ParsingDeclSpec DS(*this, &ParsingTemplateParams); // define Declaration Spec - ParseDeclarationSpecifiers(DS, TemplateInfo, AS, - getDeclSpecContextFromDeclaratorContext(Context)); - - assert((Tok.getKind() == tok::identifier && NextToken().getKind() == tok::less) && "Tok Error - T max^<"); - - // Dev: 4-2) Declare Formalize DclaratiobSpecifier - // Move the attributes from the prefix into the DS. - if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) - ProhibitAttributes(prefixAttrs); - else - DS.takeAttributesFrom(prefixAttrs); - - // Parse the declarator. - ParsingDeclarator DeclaratorInfo(*this, DS, (DeclaratorContext)Context); - if (TemplateInfo.TemplateParams) - DeclaratorInfo.setTemplateParameterLists(*TemplateInfo.TemplateParams); - ParseDeclarator(DeclaratorInfo); - // Error parsing the declarator? - if (!DeclaratorInfo.hasName()) { - // If so, skip until the semi-colon or a }. - SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); - if (Tok.is(tok::semi)) - ConsumeToken(); + SmallVector TemplateParams; + if (ParseBSCTemplateParameters(TemplateParamScopes, + CurTemplateDepthTracker.getDepth(), + TemplateParams, LAngleLoc, RAngleLoc, + lookAheadOffset)) { // open this + // Skip until the semi-colon or a '}'. + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); // error handel + TryConsumeToken(tok::semi); return nullptr; } - llvm::TimeTraceScope TimeScope("ParseTemplate", [&]() { - return std::string(DeclaratorInfo.getIdentifier() != nullptr - ? DeclaratorInfo.getIdentifier()->getName() - : ""); - }); - - LateParsedAttrList LateParsedAttrs(true); - if (DeclaratorInfo.isFunctionDeclarator()) { - if (Tok.is(tok::kw_requires)) - ParseTrailingRequiresClause(DeclaratorInfo); - - MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); + ExprResult OptionalRequiresClauseConstraintER; + if (!TemplateParams.empty()) { + isSpecialization = false; // keep this + ++CurTemplateDepthTracker; // keep this + + if (TryConsumeToken(tok::kw_requires)) { // C++ concept-requries clause + OptionalRequiresClauseConstraintER = + Actions.ActOnRequiresClause(ParseConstraintLogicalOrExpression( + /*IsTrailingRequiresClause=*/false)); + if (!OptionalRequiresClauseConstraintER.isUsable()) { + // Skip until the semi-colon or a '}'. + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); + TryConsumeToken(tok::semi); + return nullptr; + } + } + } else { + LastParamListWasEmpty = true; } - // Dev: 4-3) Parsing Function Definition(Body) - // assert(DeclaratorInfo.isFunctionDeclarator() && isStartOfFunctionDefinition(DeclaratorInfo) && "asume function declaration here."); - if (DeclaratorInfo.isFunctionDeclarator() && isStartOfFunctionDefinition(DeclaratorInfo)) { - return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo, &LateParsedAttrs); - } + ParamLists.push_back(Actions.ActOnTemplateParameterList( // make sure parameters input is same as C++, for both func and struct + CurTemplateDepthTracker.getDepth(), ExportLoc, TemplateLoc, LAngleLoc, + TemplateParams, RAngleLoc, OptionalRequiresClauseConstraintER.get())); - // Parse this declaration. - Decl *ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo, TemplateInfo); - - if (Tok.is(tok::comma)) { - Diag(Tok, diag::err_multiple_template_declarators) - << (int)TemplateInfo.Kind; - SkipUntil(tok::semi); - return ThisDecl; - } + // Parse the actual template declaration. + if (Tok.is(tok::kw_concept)) // C++ concept-requires clause, no corresponding syntax in BSC + return ParseConceptDefinition( + ParsedTemplateInfo(&ParamLists, isSpecialization, + LastParamListWasEmpty), + DeclEnd); - // Eat the semi colon after the declaration. - ExpectAndConsumeSemi(diag::err_expected_semi_declaration); - if (LateParsedAttrs.size() > 0) - ParseLexedAttributeList(LateParsedAttrs, ThisDecl, true, false); - DeclaratorInfo.complete(ThisDecl); - return ThisDecl; + return ParseSingleDeclarationAfterTemplate( // make sure parameters input is same as C++, for both func and struct + Context, + ParsedTemplateInfo(&ParamLists, isSpecialization, LastParamListWasEmpty), + ParsingTemplateParams, DeclEnd, AccessAttrs, AS); } + /// Parse a template declaration or an explicit specialization. /// /// Template declarations include one or more template parameter lists @@ -271,15 +158,19 @@ Decl *Parser::ParseBSCTemplateDeclarationOrSpecialization( /// template-declaration: [C++2a] /// template-head declaration /// template-head concept-definition +/// +/// TODO: requires-clause +/// template-head: [C++2a] +/// 'template' '<' template-parameter-list '>' +/// requires-clause[opt] +/// /// explicit-specialization: [ C++ temp.expl.spec] /// 'template' '<' '>' declaration Decl *Parser::ParseTemplateDeclarationOrSpecialization( DeclaratorContext Context, SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, AccessSpecifier AS) { - // DEV: add BSC language in status checking assertion - bool isBSCTemplateFunctionDecl = getLangOpts().BSC && NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::less; - assert(( Tok.isOneOf(tok::kw_export, tok::kw_template) or isBSCTemplateFunctionDecl) && - "Token does not start a template declaration."); // adding BSC template parsing condition + assert(Tok.isOneOf(tok::kw_export, tok::kw_template) && + "Token does not start a template declaration."); MultiParseScope TemplateParamScopes(*this); @@ -290,7 +181,7 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization( // Parse multiple levels of template headers within this template // parameter scope, e.g., - //ParseSingleDeclarationAfterTemplate + // // template // template // class A::B { ... }; @@ -320,31 +211,13 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization( TryConsumeToken(tok::kw_export, ExportLoc); // Consume the 'template', which should be here. - // DEV: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - bool isBSCTemplateDecl = getLangOpts().BSC && - ((NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::less) || - (NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::identifier - && PP.LookAhead(2).getKind() == tok::less) - ); SourceLocation TemplateLoc; if (!TryConsumeToken(tok::kw_template, TemplateLoc)) { - //DEV: Exception - BSC template function definition - if (!isBSCTemplateDecl) { - Diag(Tok.getLocation(), diag::err_expected_template); - return nullptr; - } - } - - // DEV: - if (isBSCTemplateDecl){ - // T foo() {} - // ^ ^ - // now goto - Tok = GetLookAheadToken(2); // skip"<",enter template param list parsing method + Diag(Tok.getLocation(), diag::err_expected_template); + return nullptr; } // Parse the '<' template-parameter-list '>' - // DEV: parsing strin “, Tok has to skip function name(identifier) SourceLocation LAngleLoc, RAngleLoc; SmallVector TemplateParams; if (ParseTemplateParameters(TemplateParamScopes, @@ -661,6 +534,7 @@ bool Parser::ParseTemplateParameters( MultiParseScope &TemplateScopes, unsigned Depth, SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, SourceLocation &RAngleLoc) { + // Get the template parameter list. if (!TryConsumeToken(tok::less, LAngleLoc)) { Diag(Tok.getLocation(), diag::err_expected_less_after) << "template"; return true; @@ -690,6 +564,68 @@ bool Parser::ParseTemplateParameters( return false; } + +// DEV: ParseBSCTemplateParameters - rewrite ParseTemplateParameters for cross-order BSC syntax, use Peeking +bool Parser::ParseBSCTemplateParameters( + MultiParseScope &TemplateScopes, unsigned Depth, + SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, + SourceLocation &RAngleLoc, int &lookAheadOffset) { + // if (!TryConsumeToken(tok::less, LAngleLoc)) { + // Diag(Tok.getLocation(), diag::err_expected_less_after) << "template"; + // return true; + // } + Token peekTok = PP.LookAhead(lookAheadOffset); + if (peekTok.is(tok::less)) { + lookAheadOffset += 1; + LAngleLoc = peekTok.getLocation(); + } + else { + Diag(peekTok.getLocation(), diag::err_expected_less_after) << "template"; + return true; + } + peekTok = PP.LookAhead(lookAheadOffset); + + // Try to parse the template parameter list. + bool Failed = false; + // FIXME: Missing greatergreatergreater support. + // if (!Tok.is(tok::greater) && !Tok.is(tok::greatergreater)) { + // TemplateScopes.Enter(Scope::TemplateParamScope); + // Failed = ParseTemplateParameterList(Depth, TemplateParams); + // } + if (!peekTok.is(tok::greater)) { + TemplateScopes.Enter(Scope::TemplateParamScope); + Failed = ParseBSCTemplateParameterList(Depth, TemplateParams, lookAheadOffset); + } + peekTok = PP.LookAhead(lookAheadOffset); + + // if (Tok.is(tok::greatergreater)) { + // // No diagnostic required here: a template-parameter-list can only be + // // followed by a declaration or, for a template template parameter, the + // // 'class' keyword. Therefore, the second '>' will be diagnosed later. + // // This matters for elegant diagnosis of: + // // template> struct S; + // Tok.setKind(tok::greater); + // RAngleLoc = Tok.getLocation(); + // Tok.setLocation(Tok.getLocation().getLocWithOffset(1)); + // } else if (!TryConsumeToken(tok::greater, RAngleLoc) && Failed) { + // Diag(Tok.getLocation(), diag::err_expected) << tok::greater; + // return true; + // } + + if (peekTok.getKind() == tok::greater) { + lookAheadOffset += 1; + RAngleLoc = peekTok.getLocation(); + } else { + if (Failed) { + Diag(peekTok.getLocation(), diag::err_expected) << tok::greater; + return true; + } + } + + return false; +} + + /// ParseTemplateParameterList - Parse a template parameter list. If /// the parsing fails badly (i.e., closing bracket was left out), this /// will try to put the token stream in a reasonable position (closing @@ -732,10 +668,57 @@ Parser::ParseTemplateParameterList(const unsigned Depth, return true; } +// ParseBSCTemplateParameterList - rewrite ParseTemplateParameterList, for cross-order BSC syntax, use Peeking +bool +Parser::ParseBSCTemplateParameterList(const unsigned Depth, + SmallVectorImpl &TemplateParams, + int &lookAheadOffset) { + Token peekTok = PP.LookAhead(lookAheadOffset); + while (1) { + + // if (NamedDecl *TmpParam + // = ParseTemplateParameter(Depth, TemplateParams.size())) { + if (NamedDecl *TmpParam + = ParseBSCTypeParameter(Depth, TemplateParams.size(), lookAheadOffset)) { + TemplateParams.push_back(TmpParam); + } else { + // If we failed to parse a template parameter, skip until we find + // a comma or closing brace. + // SkipUntil(tok::comma, tok::greater, tok::greatergreater, + // StopAtSemi | StopBeforeMatch); + SkipUntil(tok::comma, tok::greater, + StopAtSemi | StopBeforeMatch); + } + peekTok = PP.LookAhead(lookAheadOffset); + + // Did we find a comma or the end of the template parameter list? + if (peekTok.is(tok::comma)) { + // ConsumeToken(); + lookAheadOffset += 1; + peekTok = PP.LookAhead(lookAheadOffset); + // } else if (peekTok.isOneOf(tok::greater, tok::greatergreater)) { + } else if (peekTok.is(tok::greater)) { + // Don't consume this... that's done by template parser. + break; + } else { + // Somebody probably forgot to close the template. Skip ahead and + // try to get out of the expression. This error is currently + // subsumed by whatever goes on in ParseTemplateParameter. + // Diag(Tok.getLocation(), diag::err_expected_comma_greater); + // SkipUntil(tok::comma, tok::greater, tok::greatergreater, + // StopAtSemi | StopBeforeMatch); + Diag(peekTok.getLocation(), diag::err_expected_comma_greater); + SkipUntil(tok::comma, tok::greater, + StopAtSemi | StopBeforeMatch); + return false; + } + } + return true; +} + /// Determine whether the parser is at the start of a template /// type parameter. Parser::TPResult Parser::isStartOfTemplateTypeParameter() { - // DEV: Log if (Tok.is(tok::kw_class)) { // "class" may be the start of an elaborated-type-specifier or a // type-parameter. Per C++ [temp.param]p3, we prefer the type-parameter. @@ -778,14 +761,6 @@ Parser::TPResult Parser::isStartOfTemplateTypeParameter() { !GetLookAheadToken(Tok.is(tok::annot_cxxscope) ? 2 : 1) .isOneOf(tok::kw_auto, tok::kw_decltype)) return TPResult::True; - - // DEV: parsing template param list - bool isStartOfBSCTemplateTypeParam = getLangOpts().BSC && Tok.getKind() == tok::identifier && - (NextToken().getKind() == tok::comma || NextToken().getKind() == tok::greater); // DEV: this judgement condition May be nogod - if (isStartOfBSCTemplateTypeParam) - { - return TPResult::True; - } // 'typedef' is a reasonably-common typo/thinko for 'typename', and is // ill-formed otherwise. @@ -859,7 +834,7 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { Tok.getEndLoc()), "typename"); - Tok.setKind(tok::kw_typename); // DEV: unkown operation, rename "typedef" as "typename" + Tok.setKind(tok::kw_typename); // DEV: unkown manipulation, rename "typedef" as "typename" } return ParseTypeParameter(Depth, Position); @@ -891,8 +866,10 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { llvm_unreachable("template param classification can't be ambiguous"); } + // DEV: call upper layer method recursively to parse nested template param list + // template > if (Tok.is(tok::kw_template)) - return ParseTemplateTemplateParameter(Depth, Position); // DEV: call upper layer method recursively to parse nested template param list "template >" + return ParseTemplateTemplateParameter(Depth, Position); // If it's none of the above, then it must be a parameter declaration. // NOTE: This will pick up errors in the closure of the template parameter @@ -987,12 +964,10 @@ bool Parser::TryAnnotateTypeConstraint() { /// 'typename' ...[opt][C++0x] identifier[opt] /// 'typename' identifier[opt] '=' type-id NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { - // DEV: Check Tok location: in BSC, template param list w/o template definition - bool isBSCTemplateTypeParameter = getLangOpts().BSC && Tok.getKind() == tok::identifier && NextToken().getKind() == tok::greater; - assert(((Tok.isOneOf(tok::kw_class, tok::kw_typename) || - isTypeConstraintAnnotation()) || - isBSCTemplateTypeParameter) && - "A type-parameter starts with 'class', 'typename' or a type-constraint"); + assert((Tok.isOneOf(tok::kw_class, tok::kw_typename) || + isTypeConstraintAnnotation()) && + "A type-parameter starts with 'class', 'typename' or a " + "type-constraint"); CXXScopeSpec TypeConstraintSS; TemplateIdAnnotation *TypeConstraint = nullptr; @@ -1013,14 +988,8 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { "expected type constraint after scope specifier"); // Consume the 'class' or 'typename' keyword. - if (isBSCTemplateTypeParameter) { - // DEV: BSC syntax does not contains "typename", assume TypenameKeyword is true when reusing Actions.ActOnTypeParameter - TypenameKeyword = true; - KeyLoc = Tok.getLocation(); // DEV: skip typename token - } else { - TypenameKeyword = Tok.is(tok::kw_typename); - KeyLoc = ConsumeToken(); // DEV: skip typename token - } + TypenameKeyword = Tok.is(tok::kw_typename); + KeyLoc = ConsumeToken(); } // Grab the ellipsis (if given). @@ -1036,7 +1005,7 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { SourceLocation NameLoc = Tok.getLocation(); IdentifierInfo *ParamName = nullptr; if (Tok.is(tok::identifier)) { - ParamName = Tok.getIdentifierInfo(); // DEV: Critical- parsing T token + ParamName = Tok.getIdentifierInfo(); ConsumeToken(); } else if (Tok.isOneOf(tok::equal, tok::comma, tok::greater, tok::greatergreater)) { @@ -1078,6 +1047,105 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { return NewDecl; } + +// DEV: ParseBSCTypeParameter - rewrite ParseTypeParameter for cross-order BSC syntax, use Peeking +NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, int &lookAheadOffset) { + // DEV: Check Tok location + Token peekTok = PP.LookAhead(lookAheadOffset); + bool isBSCTemplateTypeParameter = getLangOpts().BSC && peekTok.getKind() == tok::identifier; + assert(isBSCTemplateTypeParameter && "A type-parameter starts with 'class', 'typename' or a type-constraint"); + + CXXScopeSpec TypeConstraintSS; + TemplateIdAnnotation *TypeConstraint = nullptr; + bool TypenameKeyword = false; + SourceLocation KeyLoc; + ParseOptionalCXXScopeSpecifier(TypeConstraintSS, /*ObjectType=*/nullptr, + /*ObjectHadErrors=*/false, + /*EnteringContext*/ false); + if (peekTok.is(tok::annot_template_id)) { + // Consume the 'type-constraint'. + TypeConstraint = + static_cast(peekTok.getAnnotationValue()); + assert(TypeConstraint->Kind == TNK_Concept_template && + "stray non-concept template-id annotation"); + // KeyLoc = ConsumeAnnotationToken(); // no annot_template_id in BSC, KeyLoc remain at init status + } else { + assert(TypeConstraintSS.isEmpty() && + "expected type constraint after scope specifier"); + + // Consume the 'class' or 'typename' keyword. + TypenameKeyword = false; + // KeyLoc = ConsumeToken(); // no typename in BSC, KeyLoc remain at init status + } + + // Grab the ellipsis (if given). + SourceLocation EllipsisLoc; + if (peekTok.is(tok::ellipsis)) { + EllipsisLoc = peekTok.getLocation(); + lookAheadOffset += 1; + peekTok = PP.LookAhead(lookAheadOffset); + Diag(EllipsisLoc, + getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_variadic_templates + : diag::ext_variadic_templates); + } + + // Grab the template parameter name (if given) + SourceLocation NameLoc = peekTok.getLocation(); + IdentifierInfo *ParamName = nullptr; + if (peekTok.is(tok::identifier)) { + ParamName = peekTok.getIdentifierInfo(); // DEV: unknown manipulation parsing T token + lookAheadOffset += 1; + peekTok = PP.LookAhead(lookAheadOffset); + } else if (peekTok.isOneOf(tok::equal, tok::comma, tok::greater, + tok::greatergreater)) { + // Unnamed template parameter. Don't have to do anything here, just + // don't consume this token. + } else { + Diag(peekTok.getLocation(), diag::err_expected) << tok::identifier; + return nullptr; + } + + // Recover from misplaced ellipsis. + bool AlreadyHasEllipsis = EllipsisLoc.isValid(); + if (PP.LookAhead(lookAheadOffset).is(tok::ellipsis)) { + EllipsisLoc = peekTok.getLocation(); + lookAheadOffset += 1; + peekTok = PP.LookAhead(lookAheadOffset); + DiagnoseMisplacedEllipsis(EllipsisLoc, NameLoc, AlreadyHasEllipsis, true); + } + + // Grab a default argument (if available). + // Per C++0x [basic.scope.pdecl]p9, we parse the default argument before + // we introduce the type parameter into the local scope. + SourceLocation EqualLoc; + ParsedType DefaultArg; + if (peekTok.is(tok::equal)) { + EqualLoc = peekTok.getLocation(); + lookAheadOffset += 1; + peekTok = PP.LookAhead(lookAheadOffset); + DefaultArg = + ParseTypeName(/*Range=*/nullptr, DeclaratorContext::TemplateTypeArg) + .get(); + } + + NamedDecl *NewDecl = Actions.ActOnTypeParameter(getCurScope(), + TypenameKeyword, EllipsisLoc, + KeyLoc, ParamName, NameLoc, + Depth, Position, EqualLoc, + DefaultArg, + TypeConstraint != nullptr); + + if (TypeConstraint) { + Actions.ActOnTypeConstraint(TypeConstraintSS, TypeConstraint, + cast(NewDecl), + EllipsisLoc); + } + + return NewDecl; +} + + /// ParseTemplateTemplateParameter - Handle the parsing of template /// template parameters. /// diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index ca8ebb4664a0..07153899a144 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -922,8 +922,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::kw__Static_assert: // A function definition cannot start with any of these keywords. { + // DEV: entrance of parsing template function parameter list “template ” SourceLocation DeclEnd; - return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs); // DEV: entrance of parsing “template ” + return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs); } case tok::kw_static: @@ -982,7 +983,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, SkipUntil(tok::semi); return nullptr; - // DEV: BSC Template Function Declaration Structure + // DEV: BSC Template Function Declaration Structure | TODO, refactor, long long // "^[]specifier-identifier--(paramlist) {body}" structure // static inline int int foo(T a, int b) {return b;} // TODO: parse high-level syntax (structure, inline, ...) @@ -1009,10 +1010,11 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, { assert(Tok.isAnyTypeSpecifierKind() && "Tok should be Type Specifier!"); // branch of parsing BSC template function + // DEV: entrance condition: [] type-specifier | TODO: refactor bool isBSCTemplateDecl = getLangOpts().BSC && - ((NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::less) || - (NextToken().getKind() == tok::identifier && PP.LookAhead(1).getKind() == tok::identifier - && PP.LookAhead(2).getKind() == tok::less) + ((NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::less)) || + (NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::identifier) + && PP.LookAhead(2).is(tok::less)) ); if (isBSCTemplateDecl) { // parsing function (enter next level of parsing function) @@ -1030,7 +1032,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, return nullptr; } // We can't tell whether this is a function-definition or declaration yet. - return ParseDeclarationOrFunctionDefinition(attrs, DS); // DEV: entrance of parsing “T max(T a, T b)” & “int max(int a, int b)” + // DEV: entrance of parsing template function declaration “T max(T a, T b)” + // and function declaration “int max(int a, int b)” + return ParseDeclarationOrFunctionDefinition(attrs, DS); } // This routine returns a DeclGroup, if the thing we parsed only contains a @@ -2134,8 +2138,8 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS, /// 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::TryAnnotateCXXScopeToken(bool EnteringContext) { - assert(getLangOpts().CPlusPlus && - "Call sites of this function should be guarded by checking for C++"); + assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && + "Call sites of this function should be guarded by checking for C++ and BSC"); assert(MightBeCXXScopeToken() && "Cannot be a type or scope token!"); CXXScopeSpec SS; diff --git a/clang/test/BSC/Generic/diagnose.cbs b/clang/test/BSC/Generic/diagnose.cbs index 2df056a7d7d4..428ae46e7f65 100644 --- a/clang/test/BSC/Generic/diagnose.cbs +++ b/clang/test/BSC/Generic/diagnose.cbs @@ -1,8 +1,11 @@ -T foo(T a, T b { // missing ")" +// RUN: %clang_cc1 -verify %s + +T foo(T a, T b { // expected-error {{expected ')'}} expected-note {{to match this '('}} return a; } int main() { int res = foo(1, 2); return 0; -} +} // expected-error {{expected ';' at end of declaration}} + diff --git a/clang/test/BSC/Generic/return_type_multi.cbs b/clang/test/BSC/Generic/return_type_multi.cbs new file mode 100644 index 000000000000..e18ffda94f25 --- /dev/null +++ b/clang/test/BSC/Generic/return_type_multi.cbs @@ -0,0 +1,26 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include + +unsigned bar(T1 a, T2 b) { + return 33; +} + +long long foo(T1 a, T2 b) { + return 44; +} + + +int main() { + unsigned x1 = bar(1, 2); + unsigned x2 = bar(1.0, 2.0); + + long long y1 = foo(1, 1.0); + long long y2 = foo(3.0, 99.0); + + printf("%uand %uand\n", x1, x2); + printf("%lld, %lld\n", y1, y2); + return 0; +} -- Gitee From 5b3fc8d42a29d589c9d8d73e8eed2769b8cb476f Mon Sep 17 00:00:00 2001 From: EdwardWang Date: Thu, 9 Mar 2023 22:05:09 +0800 Subject: [PATCH 09/22] [generic]: try to make generic struct work Now we can parse generic-struct definition struct S { T a; }; Next step: make generic instantiation for struct work. --- clang/include/clang/Parse/Parser.h | 2 +- clang/lib/Parse/ParseDecl.cpp | 4 ++-- clang/lib/Parse/ParseDeclCXX.cpp | 12 ++++++++---- clang/lib/Parse/ParseTemplate.cpp | 4 ++-- clang/lib/Sema/SemaDecl.cpp | 14 +++++++++----- clang/lib/Sema/SemaTemplate.cpp | 31 +++++++++++++++++------------- 6 files changed, 40 insertions(+), 27 deletions(-) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 08d3414ecfca..504785f476cd 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3304,7 +3304,7 @@ private: ParsedAttributes &AccessAttrs, AccessSpecifier AS); // DEV: ADD BSC-ParseTemplateDeclarationOrSpecialization - Decl *ParseBSCTemplateDeclarationOrSpecialization(DeclaratorContext Context, + Decl *ParseBSCGenericDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, AccessSpecifier AS); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index da87bbb69129..c0b377b3f36f 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1695,7 +1695,7 @@ Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, if (isBSCTemplateDecl) { // parsing function(enter next layer parsing method) ProhibitAttributes(attrs); - SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); + SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); // OK: ClassTemplateDecl with RecordDecl. } else { goto dont_know; } @@ -3409,7 +3409,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isConstructorDeclarator(/*Unqualified*/true)) goto DoneWithDeclSpec; - ParsedType TypeRep = Actions.getTypeName( + ParsedType TypeRep = Actions.getTypeName( // `T a;` resolve T now *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), nullptr, false, false, nullptr, false, false, isClassTemplateDeductionContext(DSContext)); diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index d08664ee5824..152dbfd4074e 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1977,12 +1977,17 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TagOrTempResult.get()); // DEV: add BSC entrance condition // else if (getLangOpts().CPlusPlus) - else if (getLangOpts().CPlusPlus || (getLangOpts().BSC && isBSCTemplateStructParsing)) + else if (getLangOpts().CPlusPlus) ParseCXXMemberSpecification(StartLoc, AttrFixitLoc, attrs, TagType, TagOrTempResult.get()); else { - Decl *D = - SkipBody.CheckSameAsPrevious ? SkipBody.New : TagOrTempResult.get(); + Decl* D = nullptr; + if (isBSCTemplateStructParsing) { + // TODO: add more check + D = static_cast(TagOrTempResult.get())->getTemplatedDecl(); + } else { + D = SkipBody.CheckSameAsPrevious ? SkipBody.New : TagOrTempResult.get(); + } // Parse the definition body. ParseStructUnionBody(StartLoc, TagType, cast(D)); if (SkipBody.CheckSameAsPrevious && @@ -3109,7 +3114,6 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas( AccessSpecifier &AS, ParsedAttributesWithRange &AccessAttrs, DeclSpec::TST TagType, Decl *TagDecl) { ParenBraceBracketBalancer BalancerRAIIObj(*this); - switch (Tok.getKind()) { case tok::kw___if_exists: case tok::kw___if_not_exists: diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index df448540b204..4b64ebb763ba 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -50,7 +50,7 @@ Decl *Parser::ParseDeclarationStartingWithTemplate( && PP.LookAhead(2).is(tok::less)) ); if (isBSCTemplateDeclOrSpc) { - return ParseBSCTemplateDeclarationOrSpecialization(Context, DeclEnd, AccessAttrs, + return ParseBSCGenericDeclaration(Context, DeclEnd, AccessAttrs, AS); } // DEV: Warning: Debug: use continue, otherwise, using step-into will fail! @@ -59,7 +59,7 @@ Decl *Parser::ParseDeclarationStartingWithTemplate( } /// DEV: DIY rewrite ParseTemplateDeclarationOrSpecialization for BSC -Decl *Parser::ParseBSCTemplateDeclarationOrSpecialization( +Decl *Parser::ParseBSCGenericDeclaration( DeclaratorContext Context, SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, AccessSpecifier AS) { assert(getLangOpts().BSC && "Error enter BSC template declaration parsing function."); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 379a02333046..32e029ff2cfa 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -4571,7 +4571,7 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, DS.getTypeSpecType() == DeclSpec::TST_interface || DS.getTypeSpecType() == DeclSpec::TST_union || DS.getTypeSpecType() == DeclSpec::TST_enum) { - TagD = DS.getRepAsDecl(); + TagD = DS.getRepAsDecl(); // ClassTemplateDecl: struct S {T a}; if (!TagD) // We probably had an error return nullptr; @@ -4582,7 +4582,7 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, if (isa(TagD)) Tag = cast(TagD); else if (ClassTemplateDecl *CTD = dyn_cast(TagD)) - Tag = CTD->getTemplatedDecl(); + Tag = CTD->getTemplatedDecl(); // RecordDecl: struct S{T a;}; } if (Tag) { @@ -4631,7 +4631,7 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, return ActOnFriendTypeDecl(S, DS, TemplateParams); } - const CXXScopeSpec &SS = DS.getTypeSpecScope(); + const CXXScopeSpec &SS = DS.getTypeSpecScope(); // what happens to BSC? We dont have the CXXScopeSpec. bool IsExplicitSpecialization = !TemplateParams.empty() && TemplateParams.back()->size() == 0; if (Tag && SS.isNotEmpty() && !Tag->isCompleteDefinition() && @@ -17672,9 +17672,13 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, } else { ++NonBitFields; QualType FieldType = I->getType(); - if (FieldType->isIncompleteType() || - !Context.getTypeSizeInChars(FieldType).isZero()) + if (getLangOpts().BSC) { ZeroSize = false; + } else { + if (FieldType->isIncompleteType() || + !Context.getTypeSizeInChars(FieldType).isZero()) + ZeroSize = false; + } } } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 84a3d35b3e3a..8aee47c55638 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1952,14 +1952,19 @@ DeclResult Sema::CheckClassTemplate( bool ShouldAddRedecl = !(TUK == TUK_Friend && CurContext->isDependentContext()); - CXXRecordDecl *NewClass = - CXXRecordDecl::Create(Context, Kind, SemanticContext, KWLoc, NameLoc, Name, - PrevClassTemplate && ShouldAddRedecl ? - PrevClassTemplate->getTemplatedDecl() : nullptr, - /*DelayTypeCreation=*/true); + RecordDecl *NewClass; + if(getLangOpts().CPlusPlus) { + NewClass = + CXXRecordDecl::Create(Context, Kind, SemanticContext, KWLoc, NameLoc, Name, + PrevClassTemplate && ShouldAddRedecl ? + PrevClassTemplate->getTemplatedDecl() : nullptr, + /*DelayTypeCreation=*/true); + } else { + NewClass = RecordDecl::Create(Context, Kind, SemanticContext, KWLoc, NameLoc, Name); + } SetNestedNameSpecifier(*this, NewClass, SS); if (NumOuterTemplateParamLists > 0) - NewClass->setTemplateParameterListsInfo( + NewClass->setTemplateParameterListsInfo( // [1]: set template parameters Context, llvm::makeArrayRef(OuterTemplateParamLists, NumOuterTemplateParamLists)); @@ -1970,7 +1975,7 @@ DeclResult Sema::CheckClassTemplate( AddMsStructLayoutForRecord(NewClass); } - ClassTemplateDecl *NewTemplate + ClassTemplateDecl *NewTemplate // [2]: ClassTemplateDecl is created = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, DeclarationName(Name), TemplateParams, NewClass); @@ -1978,16 +1983,16 @@ DeclResult Sema::CheckClassTemplate( if (ShouldAddRedecl) NewTemplate->setPreviousDecl(PrevClassTemplate); - NewClass->setDescribedClassTemplate(NewTemplate); + // NewClass->setDescribedClassTemplate(NewTemplate); if (ModulePrivateLoc.isValid()) NewTemplate->setModulePrivate(); // Build the type for the class template declaration now. - QualType T = NewTemplate->getInjectedClassNameSpecialization(); - T = Context.getInjectedClassNameType(NewClass, T); - assert(T->isDependentType() && "Class template type is not dependent?"); - (void)T; + //QualType T = NewTemplate->getInjectedClassNameSpecialization(); + //T = Context.getInjectedClassNameType(NewClass, T); + //assert(T->isDependentType() && "Class template type is not dependent?"); + //(void)T; // If we are providing an explicit specialization of a member that is a // class template, make a note of that. @@ -2012,7 +2017,7 @@ DeclResult Sema::CheckClassTemplate( mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl()); AddPushedVisibilityAttribute(NewClass); - inferGslOwnerPointerAttribute(NewClass); + //inferGslOwnerPointerAttribute(NewClass); if (TUK != TUK_Friend) { // Per C++ [basic.scope.temp]p2, skip the template parameter scopes. -- Gitee From 562e8ec4fe4d2099811bd506c077e09d180d6532 Mon Sep 17 00:00:00 2001 From: EdwardWang Date: Sat, 11 Mar 2023 14:26:54 +0800 Subject: [PATCH 10/22] [generic] fix cpp template segfault --- clang/lib/Sema/SemaTemplate.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 8aee47c55638..d73254a048fc 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1983,16 +1983,20 @@ DeclResult Sema::CheckClassTemplate( if (ShouldAddRedecl) NewTemplate->setPreviousDecl(PrevClassTemplate); - // NewClass->setDescribedClassTemplate(NewTemplate); + if (!getLangOpts().BSC) { + static_cast(NewClass)->setDescribedClassTemplate(NewTemplate); + } if (ModulePrivateLoc.isValid()) NewTemplate->setModulePrivate(); // Build the type for the class template declaration now. - //QualType T = NewTemplate->getInjectedClassNameSpecialization(); - //T = Context.getInjectedClassNameType(NewClass, T); - //assert(T->isDependentType() && "Class template type is not dependent?"); - //(void)T; + if (!getLangOpts().BSC) { + QualType T = NewTemplate->getInjectedClassNameSpecialization(); + T = Context.getInjectedClassNameType(static_cast(NewClass), T); + assert(T->isDependentType() && "Class template type is not dependent?"); + (void)T; + } // If we are providing an explicit specialization of a member that is a // class template, make a note of that. @@ -2017,7 +2021,9 @@ DeclResult Sema::CheckClassTemplate( mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl()); AddPushedVisibilityAttribute(NewClass); - //inferGslOwnerPointerAttribute(NewClass); + if (!getLangOpts().BSC) { + inferGslOwnerPointerAttribute(static_cast(NewClass)); + } if (TUK != TUK_Friend) { // Per C++ [basic.scope.temp]p2, skip the template parameter scopes. -- Gitee From 80149997225a1c5ca392f778db84bcd7e24c4328 Mon Sep 17 00:00:00 2001 From: EdwardWang Date: Sat, 11 Mar 2023 15:37:13 +0800 Subject: [PATCH 11/22] [generic] specialization for "struct S" --- clang/include/clang/AST/DeclTemplate.h | 4 ++ clang/include/clang/Sema/Sema.h | 2 +- clang/include/clang/Sema/Template.h | 2 +- clang/lib/Parse/ParseDecl.cpp | 6 +- clang/lib/Parse/ParseDeclCXX.cpp | 6 +- clang/lib/Parse/ParseExprCXX.cpp | 2 +- clang/lib/Parse/ParseStmt.cpp | 4 +- clang/lib/Parse/ParseTemplate.cpp | 5 +- clang/lib/Sema/SemaDecl.cpp | 4 +- clang/lib/Sema/SemaTemplateInstantiate.cpp | 74 +++++++++++++--------- clang/lib/Sema/SemaType.cpp | 14 ++-- clang/test/BSC/Generic/bsc_generic.cbs | 20 ++++++ 12 files changed, 95 insertions(+), 48 deletions(-) create mode 100644 clang/test/BSC/Generic/bsc_generic.cbs diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 7fbf6294970e..018e47dadcd9 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -2291,6 +2291,10 @@ public: return static_cast(TemplatedDecl); } + RecordDecl *getBSCTemplatedDecl() const { + return static_cast(TemplatedDecl); + } + /// Returns whether this template declaration defines the primary /// class pattern. bool isThisDeclarationADefinition() const { diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index fd5ed2f95055..c884da9f94b2 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9297,7 +9297,7 @@ public: bool InstantiateClass(SourceLocation PointOfInstantiation, - CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, + RecordDecl *Instantiation, RecordDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK, bool Complain = true); diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index 8c3fc70d26be..81af1a12a7c3 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -460,7 +460,7 @@ enum class TemplateSubstitutionKind : char { bool isLocalPackExpansion(const Decl *D); }; - class TemplateDeclInstantiator + class TemplateDeclInstantiator // yt: Key for BSC. : public DeclVisitor { Sema &SemaRef; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index c0b377b3f36f..94e145398b6b 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1688,11 +1688,11 @@ Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, assert(Tok.isAnyTypeSpecifierKind() && "Tok should be Type Specifier!"); // DEV: BSC template function parsing branch | TODO: refactor bool isBSCTemplateDecl = getLangOpts().BSC && - ((NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::less)) || + ((NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::less) && PP.LookAhead(2).is(tok::identifier) ) || (NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::identifier) - && PP.LookAhead(2).is(tok::less)) + && PP.LookAhead(2).is(tok::less) && PP.LookAhead(3).is(tok::identifier)) ); - if (isBSCTemplateDecl) { + if (isBSCTemplateDecl) { // Here we have the BUG. 'struct S s1' will enter here too. Above add the cond that its 'T' instead of `int` in `` // parsing function(enter next layer parsing method) ProhibitAttributes(attrs); SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); // OK: ClassTemplateDecl with RecordDecl. diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 152dbfd4074e..611bdb484060 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1546,14 +1546,14 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Parse the (optional) nested-name-specifier. CXXScopeSpec &SS = DS.getTypeSpecScope(); - if (getLangOpts().CPlusPlus) { + if (getLangOpts().CPlusPlus || getLangOpts().BSC) { // 'struct S s1' should enter here // "FOO : BAR" is not a potential typo for "FOO::BAR". In this context it // is a base-specifier-list. ColonProtectionRAIIObject X(*this); CXXScopeSpec Spec; bool HasValidSpec = true; - if (ParseOptionalCXXScopeSpecifier(Spec, /*ObjectType=*/nullptr, + if (ParseOptionalCXXScopeSpecifier(Spec, /*ObjectType=*/nullptr, // After this, TokenKind is tok::annot_template_id! /*ObjectHadErrors=*/false, EnteringContext)) { DS.SetTypeSpecError(); @@ -1819,7 +1819,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, bool Owned = false; Sema::SkipBodyInfo SkipBody; - if (TemplateId) { + if (TemplateId) { // specialization for BSC generic: `struct S` // Explicit specialization, class template partial specialization, // or explicit instantiation. ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index f6f3c9ccaf0c..2de5b4644580 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -493,7 +493,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier( // nested-name-specifier: // type-name '<' - if (Next.is(tok::less)) { + if (Next.is(tok::less)) { // 'S', then 'S' is set to tok::annote_template_id TemplateTy Template; UnqualifiedId TemplateName; diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 0170003db76e..e3b3a2760045 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -208,7 +208,7 @@ Retry: Default: default: { - if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || + if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || getLangOpts().BSC || // let `struct S s1 = {}` enter here. (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) != ParsedStmtContext()) && (GNUAttributeLoc.isValid() || @@ -1126,7 +1126,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr, SafeScopeSpecifie StmtResult R; if (Tok.isNot(tok::kw___extension__)) { - R = ParseStatementOrDeclaration(Stmts, SubStmtCtx); + R = ParseStatementOrDeclaration(Stmts, SubStmtCtx); // see `struct` in `struct S` } else { // __extension__ can start declarations and it can also be a unary // operator for expressions. Consume multiple __extension__ markers here diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 4b64ebb763ba..8373f8651181 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -1052,7 +1052,8 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, int &lookAheadOffset) { // DEV: Check Tok location Token peekTok = PP.LookAhead(lookAheadOffset); - bool isBSCTemplateTypeParameter = getLangOpts().BSC && peekTok.getKind() == tok::identifier; + bool isBSCTemplateTypeParameter = getLangOpts().BSC; // FIXME: fix the cond + //bool isBSCTemplateTypeParameter = getLangOpts().BSC && (peekTok.getKind() == tok::identifier); assert(isBSCTemplateTypeParameter && "A type-parameter starts with 'class', 'typename' or a type-constraint"); CXXScopeSpec TypeConstraintSS; @@ -1893,7 +1894,7 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { return true; // Save this template argument. - TemplateArgs.push_back(Arg); + TemplateArgs.push_back(Arg); // ex: Arg is 'int' in S // If the next token is a comma, consume it and keep reading // arguments. diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 32e029ff2cfa..73c659b13cbf 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -15654,7 +15654,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, return nullptr; OwnedDecl = false; - DeclResult Result = CheckClassTemplate( + DeclResult Result = CheckClassTemplate( // for 'struct S' it will enter here too. S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attrs, TemplateParams, AS, ModulePrivateLoc, /*FriendLoc*/ SourceLocation(), TemplateParameterLists.size() - 1, @@ -16018,7 +16018,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // technically forbidden by the current standard but which is // okay according to the likely resolution of an open issue; // see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#407 - if (getLangOpts().CPlusPlus) { + if (getLangOpts().CPlusPlus || getLangOpts().BSC) { if (TypedefNameDecl *TD = dyn_cast(PrevDecl)) { if (const TagType *TT = TD->getUnderlyingType()->getAs()) { TagDecl *Tag = TT->getDecl(); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 8bd812b39de4..ea2d31644de6 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2623,16 +2623,18 @@ namespace clang { /// \returns true if an error occurred, false otherwise. bool Sema::InstantiateClass(SourceLocation PointOfInstantiation, - CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, + RecordDecl *Instantiation, RecordDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK, bool Complain) { - CXXRecordDecl *PatternDef - = cast_or_null(Pattern->getDefinition()); - if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Instantiation, - Instantiation->getInstantiatedFromMemberClass(), - Pattern, PatternDef, TSK, Complain)) - return true; + RecordDecl *PatternDef + = cast_or_null(Pattern->getDefinition()); + if (getLangOpts().CPlusPlus) { + if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Instantiation, + (static_cast(Instantiation))->getInstantiatedFromMemberClass(), + Pattern, PatternDef, TSK, Complain)) + return true; + } llvm::TimeTraceScope TimeScope("InstantiateClass", [&]() { std::string Name; @@ -2645,12 +2647,14 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Pattern = PatternDef; // Record the point of instantiation. - if (MemberSpecializationInfo *MSInfo - = Instantiation->getMemberSpecializationInfo()) { - MSInfo->setTemplateSpecializationKind(TSK); - MSInfo->setPointOfInstantiation(PointOfInstantiation); + if (getLangOpts().CPlusPlus) { + if(MemberSpecializationInfo *MSInfo + = (static_cast(Instantiation))->getMemberSpecializationInfo()) { + MSInfo->setTemplateSpecializationKind(TSK); + MSInfo->setPointOfInstantiation(PointOfInstantiation); + } } else if (ClassTemplateSpecializationDecl *Spec - = dyn_cast(Instantiation)) { + = dyn_cast(Instantiation)) { // yt: should be true for BSC Spec->setTemplateSpecializationKind(TSK); Spec->setPointOfInstantiation(PointOfInstantiation); } @@ -2684,7 +2688,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, InstantiateAttrs(TemplateArgs, Pattern, Instantiation); // Start the definition of this instantiation. - Instantiation->startDefinition(); + Instantiation->startDefinition(); // yt: start the instantiation! // The instantiation is visible here, even if it was first declared in an // unimported module. @@ -2694,8 +2698,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Instantiation->setTagKind(Pattern->getTagKind()); // Do substitution on the base class specifiers. - if (SubstBaseSpecifiers(Instantiation, Pattern, TemplateArgs)) - Instantiation->setInvalidDecl(); + if (getLangOpts().CPlusPlus) { + if (SubstBaseSpecifiers(static_cast(Instantiation), static_cast(Pattern), TemplateArgs)) + Instantiation->setInvalidDecl(); + } TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs); SmallVector Fields; @@ -2730,7 +2736,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, continue; } - Decl *NewMember = Instantiator.Visit(Member); + Decl *NewMember = Instantiator.Visit(Member); // yt: (1)before: Member 'T a;' (2)after: NewMember 'int a;' if (NewMember) { if (FieldDecl *Field = dyn_cast(NewMember)) { Fields.push_back(Field); @@ -2754,8 +2760,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, break; } } else if (CXXMethodDecl *MD = dyn_cast(NewMember)) { - if (MD->isConstexpr() && !MD->getFriendObjectKind() && - (MD->isVirtualAsWritten() || Instantiation->getNumBases())) + if (getLangOpts().CPlusPlus && MD->isConstexpr() && !MD->getFriendObjectKind() && + (MD->isVirtualAsWritten() || (static_cast(Instantiation))->getNumBases())) MightHaveConstexprVirtualFunctions = true; } @@ -2772,7 +2778,9 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Finish checking fields. ActOnFields(nullptr, Instantiation->getLocation(), Instantiation, Fields, SourceLocation(), SourceLocation(), ParsedAttributesView()); - CheckCompletedCXXClass(nullptr, Instantiation); + if(getLangOpts().CPlusPlus) { + CheckCompletedCXXClass(nullptr, (static_cast(Instantiation))); // FIXME: make it work for BSC RecordDecl + } // Default arguments are parsed, if not instantiated. We can go instantiate // default arg exprs for default constructors if necessary now. Unless we're @@ -2816,7 +2824,9 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, if (!Instantiation->isInvalidDecl()) { // Perform any dependent diagnostics from the pattern. - PerformDependentDiagnostics(Pattern, TemplateArgs); + if (getLangOpts().CPlusPlus) { + PerformDependentDiagnostics(Pattern, TemplateArgs); + } // Instantiate any out-of-line class template partial // specializations now. @@ -2853,11 +2863,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // of a polymorphic class template specialization. Otherwise, eagerly // instantiate only constexpr virtual functions in preparation for their use // in constant evaluation. - if (TSK == TSK_ExplicitInstantiationDefinition) - MarkVTableUsed(PointOfInstantiation, Instantiation, true); - else if (MightHaveConstexprVirtualFunctions) - MarkVirtualMembersReferenced(PointOfInstantiation, Instantiation, - /*ConstexprOnly*/ true); + if(getLangOpts().CPlusPlus) { + if (TSK == TSK_ExplicitInstantiationDefinition) + MarkVTableUsed(PointOfInstantiation, (static_cast(Instantiation)), true); + else if (MightHaveConstexprVirtualFunctions) + MarkVirtualMembersReferenced(PointOfInstantiation, static_cast(Instantiation), + /*ConstexprOnly*/ true); + } } Consumer.HandleTagDeclDefinition(Instantiation); @@ -3040,7 +3052,7 @@ bool Sema::usesPartialOrExplicitSpecialization( /// Get the instantiation pattern to use to instantiate the definition of a /// given ClassTemplateSpecializationDecl (either the pattern of the primary /// template or of a partial specialization). -static ActionResult +static ActionResult getPatternForClassTemplateSpecialization( Sema &S, SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, @@ -3157,7 +3169,7 @@ getPatternForClassTemplateSpecialization( } } - CXXRecordDecl *Pattern = nullptr; + RecordDecl *Pattern = nullptr; // yt: RecordDecl for BSC. Specialized = ClassTemplateSpec->getSpecializedTemplateOrPartial(); if (auto *PartialSpec = Specialized.dyn_cast()) { @@ -3181,7 +3193,11 @@ getPatternForClassTemplateSpecialization( Template = Template->getInstantiatedFromMemberTemplate(); } - Pattern = Template->getTemplatedDecl(); + if (S.Context.getLangOpts().BSC) { + Pattern = Template->getBSCTemplatedDecl(); + } else { + Pattern = Template->getTemplatedDecl(); + } } return Pattern; @@ -3197,7 +3213,7 @@ bool Sema::InstantiateClassTemplateSpecialization( if (ClassTemplateSpec->isInvalidDecl()) return true; - ActionResult Pattern = + ActionResult Pattern = // yt: here BSC is RecordDecl getPatternForClassTemplateSpecialization(*this, PointOfInstantiation, ClassTemplateSpec, TSK); if (!Pattern.isUsable()) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 75e8e350bd48..5a97a46ddfde 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8619,7 +8619,13 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, // If we have a class template specialization or a class member of a // class template specialization, or an array with known size of such, // try to instantiate it. - if (auto *RD = dyn_cast_or_null(Tag)) { + RecordDecl* RD = nullptr; + if (getLangOpts().BSC) { + RD = dyn_cast_or_null(Tag); + } else { + RD = dyn_cast_or_null(Tag); + } + if (RD) { bool Instantiated = false; bool Diagnosed = false; if (RD->isDependentContext()) { @@ -8637,15 +8643,15 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, Instantiated = true; } } else { - CXXRecordDecl *Pattern = RD->getInstantiatedFromMemberClass(); + CXXRecordDecl *Pattern = (static_cast(RD))->getInstantiatedFromMemberClass(); if (!RD->isBeingDefined() && Pattern) { - MemberSpecializationInfo *MSI = RD->getMemberSpecializationInfo(); + MemberSpecializationInfo *MSI = (static_cast(RD))->getMemberSpecializationInfo(); assert(MSI && "Missing member specialization information?"); // This record was instantiated from a class within a template. if (MSI->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) { runWithSufficientStackSpace(Loc, [&] { - Diagnosed = InstantiateClass(Loc, RD, Pattern, + Diagnosed = InstantiateClass(Loc, (static_cast(RD)), Pattern, getTemplateInstantiationArgs(RD), TSK_ImplicitInstantiation, /*Complain=*/Diagnoser); diff --git a/clang/test/BSC/Generic/bsc_generic.cbs b/clang/test/BSC/Generic/bsc_generic.cbs new file mode 100644 index 000000000000..dc2ab6889ff3 --- /dev/null +++ b/clang/test/BSC/Generic/bsc_generic.cbs @@ -0,0 +1,20 @@ +#include + +struct S{ + T a; +}; + +T max(T a, T b) { + return a > b ? a : b; +} + +int main() { + struct S s1 = {.a = 42}; // ClassTemplateSpecializationDecl + int a = s1.a; + printf("Generic Struct Works!\n"); + printf("a is %d\n", a); + int b = max(2023, 2022); + printf("Generic Function Works!\n"); + printf("b is %d\n", b); + return 0; +} -- Gitee From 0a2086a7a899da4418fb2c5476f56a1967123ac3 Mon Sep 17 00:00:00 2001 From: Aperzer Date: Sun, 19 Mar 2023 18:50:49 +0800 Subject: [PATCH 12/22] [Generic]fix segfault and error for function and struct Mainly fixed some segfalut when we excepting to throw an error, plus fixed some unexcepted error situations. Test cases has beed added. e.g. 1)When calling a member which is not defined before, we expected to throw error, but it was segfault (fixed by this commit): struct S1{ T a; }; void test1() { struct S1 s1; int a = s1.x; // expected to throw error } 2)Two different type added when not supported, we expected to throw error, but it was segfault (fixed by this commit): struct S{ int a; }; T f4(T a) { struct S s1; int y = 1; T z = s1 + y; // expected to throw error } 3)When calling a function which is not defined before, we expected to throw error, but it didn't(fixed by this commit): T1 f3(T1 a, T2 b, int c) { T1 x1 = a + b; foo(c); // expected to throw error: undefined identifier 'foo' return x1; } 4)This demo should be ok with this grammer, but there was err (fixed by this commit): long int f2(long int x, T a) { // error: T is not defined. return x; } --- clang/lib/AST/ASTContext.cpp | 3 +- clang/lib/Parse/ParseDecl.cpp | 4 +- clang/lib/Parse/ParseTemplate.cpp | 6 +- clang/lib/Parse/Parser.cpp | 4 +- clang/lib/Sema/SemaDecl.cpp | 4 +- clang/lib/Sema/SemaLookup.cpp | 4 + clang/lib/Sema/SemaOverload.cpp | 92 ++++++++++--------- clang/test/BSC/Generic/illegal_type_add.cbs | 18 ++++ .../test/BSC/Generic/return_type_long_int.cbs | 14 +++ .../test/BSC/Generic/undefined_func_call.cbs | 14 +++ .../BSC/Generic/undefined_member_call.cbs | 10 ++ 11 files changed, 125 insertions(+), 48 deletions(-) create mode 100644 clang/test/BSC/Generic/illegal_type_add.cbs create mode 100644 clang/test/BSC/Generic/return_type_long_int.cbs create mode 100644 clang/test/BSC/Generic/undefined_func_call.cbs create mode 100644 clang/test/BSC/Generic/undefined_member_call.cbs diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index cb7f00abf9e9..86f719831c93 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -880,7 +880,8 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( } CXXABI *ASTContext::createCXXABI(const TargetInfo &T) { - if (!LangOpts.CPlusPlus) return nullptr; + // BSC Mark: add BSC language judgement. + if (!(LangOpts.CPlusPlus || LangOpts.BSC)) return nullptr; switch (T.getCXXABI().getKind()) { case TargetCXXABI::AppleARM64: diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 94e145398b6b..33d864b46737 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1690,7 +1690,9 @@ Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, bool isBSCTemplateDecl = getLangOpts().BSC && ((NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::less) && PP.LookAhead(2).is(tok::identifier) ) || (NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::identifier) - && PP.LookAhead(2).is(tok::less) && PP.LookAhead(3).is(tok::identifier)) + && PP.LookAhead(2).is(tok::less) && PP.LookAhead(3).is(tok::identifier)) || + // BSC Mark: Temporarily add judgement for "long int foo" situation. + (NextToken().is(tok::kw_int) && PP.LookAhead(1).is(tok::identifier) && PP.LookAhead(2).is(tok::less)) ); if (isBSCTemplateDecl) { // Here we have the BUG. 'struct S s1' will enter here too. Above add the cond that its 'T' instead of `int` in `` // parsing function(enter next layer parsing method) diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 8373f8651181..6713831abf7c 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -46,8 +46,10 @@ Decl *Parser::ParseDeclarationStartingWithTemplate( // DEV: at BSC template declaration, parse this in a independent branch bool isBSCTemplateDeclOrSpc = getLangOpts().BSC && ((NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::less)) || - (NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::identifier) - && PP.LookAhead(2).is(tok::less)) + (NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::identifier) + && PP.LookAhead(2).is(tok::less)) || + // BSC Mark: Temporarily add judgement for "long int foo" situation. + (NextToken().is(tok::kw_int) && PP.LookAhead(1).is(tok::identifier) && PP.LookAhead(2).is(tok::less)) ); if (isBSCTemplateDeclOrSpc) { return ParseBSCGenericDeclaration(Context, DeclEnd, AccessAttrs, diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 07153899a144..dead6e8e3ba0 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1014,7 +1014,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, bool isBSCTemplateDecl = getLangOpts().BSC && ((NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::less)) || (NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::identifier) - && PP.LookAhead(2).is(tok::less)) + && PP.LookAhead(2).is(tok::less)) || + // BSC Mark: Temporarily add judgement for "long int foo" situation. + (NextToken().is(tok::kw_int) && PP.LookAhead(1).is(tok::identifier) && PP.LookAhead(2).is(tok::less)) ); if (isBSCTemplateDecl) { // parsing function (enter next level of parsing function) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 73c659b13cbf..4274e42e308f 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -909,7 +909,7 @@ Corrected: if (SS.isEmpty() && NextToken.is(tok::l_paren)) { // In C++, this is an ADL-only call. // FIXME: Reference? - if (getLangOpts().CPlusPlus) + if (getLangOpts().CPlusPlus || getLangOpts().BSC) // BSC Mark: key of check undefined function name. return NameClassification::UndeclaredNonType(); // C90 6.3.2.2: @@ -1201,7 +1201,7 @@ Corrected: ExprResult Sema::ActOnNameClassifiedAsUndeclaredNonType(IdentifierInfo *Name, SourceLocation NameLoc) { - assert(getLangOpts().CPlusPlus && "ADL-only call in C?"); + assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && "ADL-only call in C?"); // BSC Mark: key of check undefined function name. CXXScopeSpec SS; LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 96da78ea7164..a1a369674555 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -2826,6 +2826,10 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { // Its associated namespaces are the innermost enclosing // namespaces of its associated classes. case Type::Record: { + // BSC Mark: try to avoid cast. + if(Result.S.getLangOpts().BSC){ + break; + } CXXRecordDecl *Class = cast(cast(T)->getDecl()); addAssociatedClassesAndNamespaces(Result, Class); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 7fe7466725fa..ca41b550e8f9 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -8040,22 +8040,27 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, if (!SemaRef.isCompleteType(Loc, Ty)) return; - CXXRecordDecl *ClassDecl = cast(TyRec->getDecl()); - for (NamedDecl *D : ClassDecl->getVisibleConversionFunctions()) { - if (isa(D)) - D = cast(D)->getTargetDecl(); - - // Skip conversion function templates; they don't tell us anything - // about which builtin types we can convert to. - if (isa(D)) - continue; + if (SemaRef.getLangOpts().BSC) { + // BSC Mark: Don`t do anything here to avoid cast. + } else { + CXXRecordDecl *ClassDecl = cast(TyRec->getDecl()); + for (NamedDecl *D : ClassDecl->getVisibleConversionFunctions()) { + if (isa(D)) + D = cast(D)->getTargetDecl(); - CXXConversionDecl *Conv = cast(D); - if (AllowExplicitConversions || !Conv->isExplicit()) { - AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false, - VisibleQuals); + // Skip conversion function templates; they don't tell us anything + // about which builtin types we can convert to. + if (isa(D)) + continue; + + CXXConversionDecl *Conv = cast(D); + if (AllowExplicitConversions || !Conv->isExplicit()) { + AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false, + VisibleQuals); + } } } + } } /// Helper function for adjusting address spaces for the pointer or reference @@ -8109,37 +8114,42 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { return VRQuals; } - CXXRecordDecl *ClassDecl = cast(TyRec->getDecl()); - if (!ClassDecl->hasDefinition()) - return VRQuals; + if(Context.getLangOpts().BSC) { + // BSC Mark: Don`t do anything here to avoid cast. + } else { + CXXRecordDecl *ClassDecl = cast(TyRec->getDecl()); + if (!ClassDecl->hasDefinition()) + return VRQuals; - for (NamedDecl *D : ClassDecl->getVisibleConversionFunctions()) { - if (isa(D)) - D = cast(D)->getTargetDecl(); - if (CXXConversionDecl *Conv = dyn_cast(D)) { - QualType CanTy = Context.getCanonicalType(Conv->getConversionType()); - if (const ReferenceType *ResTypeRef = CanTy->getAs()) - CanTy = ResTypeRef->getPointeeType(); - // Need to go down the pointer/mempointer chain and add qualifiers - // as see them. - bool done = false; - while (!done) { - if (CanTy.isRestrictQualified()) - VRQuals.addRestrict(); - if (const PointerType *ResTypePtr = CanTy->getAs()) - CanTy = ResTypePtr->getPointeeType(); - else if (const MemberPointerType *ResTypeMPtr = - CanTy->getAs()) - CanTy = ResTypeMPtr->getPointeeType(); - else - done = true; - if (CanTy.isVolatileQualified()) - VRQuals.addVolatile(); - if (VRQuals.hasRestrict() && VRQuals.hasVolatile()) - return VRQuals; + for (NamedDecl *D : ClassDecl->getVisibleConversionFunctions()) { + if (isa(D)) + D = cast(D)->getTargetDecl(); + if (CXXConversionDecl *Conv = dyn_cast(D)) { + QualType CanTy = Context.getCanonicalType(Conv->getConversionType()); + if (const ReferenceType *ResTypeRef = CanTy->getAs()) + CanTy = ResTypeRef->getPointeeType(); + // Need to go down the pointer/mempointer chain and add qualifiers + // as see them. + bool done = false; + while (!done) { + if (CanTy.isRestrictQualified()) + VRQuals.addRestrict(); + if (const PointerType *ResTypePtr = CanTy->getAs()) + CanTy = ResTypePtr->getPointeeType(); + else if (const MemberPointerType *ResTypeMPtr = + CanTy->getAs()) + CanTy = ResTypeMPtr->getPointeeType(); + else + done = true; + if (CanTy.isVolatileQualified()) + VRQuals.addVolatile(); + if (VRQuals.hasRestrict() && VRQuals.hasVolatile()) + return VRQuals; + } } } } + return VRQuals; } @@ -12971,7 +12981,7 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn, llvm_unreachable("performing ADL for builtin"); // We don't perform ADL in C. - assert(getLangOpts().CPlusPlus && "ADL enabled in C"); + assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && "ADL enabled in C"); // BSC Mark: key of check undefined function name. } #endif diff --git a/clang/test/BSC/Generic/illegal_type_add.cbs b/clang/test/BSC/Generic/illegal_type_add.cbs new file mode 100644 index 000000000000..73c299f9d1b4 --- /dev/null +++ b/clang/test/BSC/Generic/illegal_type_add.cbs @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -verify %s + +struct S{ + int a; +}; + +T f4(T a) { + struct S s1; + int y = 1; + T z = s1 + y; // expected-error {{invalid operands to binary expression ('struct S' and 'int')}} + return z; +} + +int main(){ + int a = 1; + int b = f4(a); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/return_type_long_int.cbs b/clang/test/BSC/Generic/return_type_long_int.cbs new file mode 100644 index 000000000000..4e71a9de9e55 --- /dev/null +++ b/clang/test/BSC/Generic/return_type_long_int.cbs @@ -0,0 +1,14 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include + +long int f2(long int x, T a) { // FIXME Ok but there is err now + return x; +} + +int main() { + float b = 1.5; + long int a = f2(a, b); +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/undefined_func_call.cbs b/clang/test/BSC/Generic/undefined_func_call.cbs new file mode 100644 index 000000000000..404d5482fbb0 --- /dev/null +++ b/clang/test/BSC/Generic/undefined_func_call.cbs @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -verify %s + +T1 f3(T1 a, T2 b, int c) { + T1 x1 = a + b; + foo(c); // expected-error {{use of undeclared identifier 'foo'}} + return x1; +} + +int main() { + int a = 1; + float b = 1.5; + int c = 2; + int d = f3(a, b, c); +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/undefined_member_call.cbs b/clang/test/BSC/Generic/undefined_member_call.cbs new file mode 100644 index 000000000000..2c2b43585816 --- /dev/null +++ b/clang/test/BSC/Generic/undefined_member_call.cbs @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -verify %s + +struct S{ // expected-error {{conflicting types for 'S'}} expected-note {{while declaring the implicit copy constructor for 'S'}} expected-note {{previous definition is here}} + T a; +}; + +void test() { + struct S s1; + int a = s1.x; // expected-error {{no member named 'x' in 'struct S'}} +} \ No newline at end of file -- Gitee From 11bd549cf5730787c33456064cb7310e1b03e6f3 Mon Sep 17 00:00:00 2001 From: qinziang Date: Mon, 20 Mar 2023 10:53:05 +0800 Subject: [PATCH 13/22] [generic] support more template function return type: multi-token type specifiers & pointer Template function now is able to return multi-token type specifiers: long long, long double; signed char, unsigned char, unsigned int, unsigned short, unsigned long; unsigned long long, signed long long; this comment modifies the the judgement of BSC template declaration using isBSCTemplateDecl() method. exaple #1, multi-tok: long long max (T a, T b) { return a >= b ? a : b; } example #2, array: int * Bar (T a, T b) { static int array[] = {0, 1, 2}; return array; } TODO: 1. support attribute sequence (attr-spec-seq) before template function / template struct declaration. 2. support struct template parameter in template struct --- clang/include/clang/Parse/Parser.h | 3 + clang/lib/Parse/ParseDecl.cpp | 48 ++----------- clang/lib/Parse/ParseTemplate.cpp | 20 +++--- clang/lib/Parse/ParseTentative.cpp | 66 +++++++++++++++++ clang/lib/Parse/Parser.cpp | 50 ++----------- clang/test/BSC/Generic/return_type_multi.cbs | 2 +- .../BSC/Generic/return_type_multi_tok.cbs | 71 +++++++++++++++++++ .../test/BSC/Generic/return_type_pointer.cbs | 29 ++++++++ 8 files changed, 194 insertions(+), 95 deletions(-) create mode 100644 clang/test/BSC/Generic/return_type_multi_tok.cbs create mode 100644 clang/test/BSC/Generic/return_type_pointer.cbs diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 504785f476cd..6b6fd2bfc723 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2560,6 +2560,9 @@ private: /// during a tentative parse, but also should not be annotated as a non-type. bool isTentativelyDeclared(IdentifierInfo *II); + // DEV: Determine whether Tok at BSC template declaration clause. + bool isBSCTemplateDecl(Token tok); + // "Tentative parsing" functions, used for disambiguation. If a parsing error // is encountered they will return TPResult::Error. // Returning TPResult::True/False indicates that the ambiguity was diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 33d864b46737..ab95877ef78a 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1663,46 +1663,6 @@ Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, ProhibitAttributes(attrs); SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); // DEV: C++ template function parsing branch break; - // DEV: BSC Template Function Declare | TODO: long long, refactor - // Type Specifier: see c11 spec 6.7.2 - case tok::kw__Atomic: // not verified - case tok::kw_union: // not verified - case tok::kw_struct: // not supported! - case tok::kw_class: // not verified - case tok::kw_enum: // not verified - case tok::kw_typedef: // not verified - case tok::kw__Complex: // not verified - case tok::kw_void: // not supported! - case tok::kw_bool: // not supported! - case tok::kw__Bool: // not supported! - case tok::kw_char: - case tok::kw_short: - case tok::kw_int: - case tok::kw_long: - case tok::kw_float: - case tok::kw_double: - case tok::kw_signed: - case tok::kw_unsigned: - case tok::identifier: - { - assert(Tok.isAnyTypeSpecifierKind() && "Tok should be Type Specifier!"); - // DEV: BSC template function parsing branch | TODO: refactor - bool isBSCTemplateDecl = getLangOpts().BSC && - ((NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::less) && PP.LookAhead(2).is(tok::identifier) ) || - (NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::identifier) - && PP.LookAhead(2).is(tok::less) && PP.LookAhead(3).is(tok::identifier)) || - // BSC Mark: Temporarily add judgement for "long int foo" situation. - (NextToken().is(tok::kw_int) && PP.LookAhead(1).is(tok::identifier) && PP.LookAhead(2).is(tok::less)) - ); - if (isBSCTemplateDecl) { // Here we have the BUG. 'struct S s1' will enter here too. Above add the cond that its 'T' instead of `int` in `` - // parsing function(enter next layer parsing method) - ProhibitAttributes(attrs); - SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); // OK: ClassTemplateDecl with RecordDecl. - } else { - goto dont_know; - } - break; - } case tok::kw_inline: // Could be the start of an inline namespace. Allowed as an ext in C++03. if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_namespace)) { @@ -1724,7 +1684,13 @@ Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, SingleDecl = ParseStaticAssertDeclaration(DeclEnd); break; default: - dont_know: + // DEV: parse BSC template declaration + if (isBSCTemplateDecl(Tok)) { + ProhibitAttributes(attrs); + SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); // OK: ClassTemplateDecl with RecordDecl. + break; + } + return ParseSimpleDeclaration(Context, DeclEnd, attrs, true, nullptr, DeclSpecStart); } diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 6713831abf7c..216e2f1501b3 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -43,15 +43,15 @@ Decl *Parser::ParseDeclarationStartingWithTemplate( return ParseExplicitInstantiation(Context, SourceLocation(), ConsumeToken(), DeclEnd, AccessAttrs, AS); } - // DEV: at BSC template declaration, parse this in a independent branch - bool isBSCTemplateDeclOrSpc = getLangOpts().BSC && - ((NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::less)) || - (NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::identifier) - && PP.LookAhead(2).is(tok::less)) || - // BSC Mark: Temporarily add judgement for "long int foo" situation. - (NextToken().is(tok::kw_int) && PP.LookAhead(1).is(tok::identifier) && PP.LookAhead(2).is(tok::less)) - ); - if (isBSCTemplateDeclOrSpc) { + // // DEV: at BSC template declaration, parse this in a independent branch + // bool isBSCTemplateDeclOrSpc = getLangOpts().BSC && + // ((NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::less)) || + // (NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::identifier) + // && PP.LookAhead(2).is(tok::less)) + // ); + + // DEV: parse BSC template declaration + if (isBSCTemplateDecl(Tok)) { return ParseBSCGenericDeclaration(Context, DeclEnd, AccessAttrs, AS); } @@ -688,7 +688,7 @@ Parser::ParseBSCTemplateParameterList(const unsigned Depth, // a comma or closing brace. // SkipUntil(tok::comma, tok::greater, tok::greatergreater, // StopAtSemi | StopBeforeMatch); - SkipUntil(tok::comma, tok::greater, + SkipUntil(tok::comma, tok::greater, // DEV: fix-me: logic error StopAtSemi | StopBeforeMatch); } peekTok = PP.LookAhead(lookAheadOffset); diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 3bf2bc455bfe..ac5a069f246c 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1106,6 +1106,72 @@ bool Parser::isTentativelyDeclared(IdentifierInfo *II) { != TentativelyDeclaredIdentifiers.end(); } +bool Parser::isBSCTemplateDecl(Token tok) { + /* + check structure in BSC syntax: + "T Foo(T a) {..}" or + "struct S {..};" + */ + // 1. check language + if (!getLangOpts().BSC) + return false; + // 2. check "Foo<>" structure + // ^^^^ + int MaxLessTokenLookAheadOffset = 6; // tok::less must appear with in 6 more token: "static inline unsigned long long Foo<" + int LessOffset = 0; + bool FoundLess = false; + Token tmpTok = PP.LookAhead(LessOffset); + for (; LessOffset < MaxLessTokenLookAheadOffset; LessOffset++) { + tmpTok = PP.LookAhead(LessOffset); + if (tmpTok.is(tok::l_paren) || tmpTok.is(tok::l_brace) || tmpTok.is(tok::equal)) // "<>" must appear neighboring with function/struct identtifier + return false; + if (tmpTok.is(tok::less) && PP.LookAhead(LessOffset - 1).is(tok::identifier)) { + FoundLess = true; + break; // when ">" missing, leave tis diagnose work in deeper api. + } + } + if (!FoundLess) + return false; + // 3. check "<> {}" structure in struct declaration + // ^^^ + int LBraceOffset = 1; + tmpTok = PP.LookAhead(LessOffset + LBraceOffset); + for (; !tmpTok.is(tok::eof); LBraceOffset++) { // check "Foo<>" structure + tmpTok = PP.LookAhead(LessOffset + LBraceOffset); + if (tmpTok.is(tok::l_paren)) // might be function declaration, skip current check + break; + if (tmpTok.is(tok::semi) || tmpTok.is(tok::equal)) // no "{" in current sentence + return false; + if (tmpTok.is(tok::l_brace)) { + return true; + } + } + // 4. check "<>(..) {}" structure in function declaration + // ^^ ^^^ + int LParenOffset = 1; + tmpTok = PP.LookAhead(LessOffset + LParenOffset); + for (; !tmpTok.is(tok::eof); LParenOffset++) { // check "Foo<>" structure + tmpTok = PP.LookAhead(LessOffset + LParenOffset); + if (tmpTok.is(tok::semi) || tmpTok.is(tok::equal)) // no "{" in current sentence + return false; + if (tmpTok.is(tok::l_paren)) { + break; // when ")" missing, leave tis diagnose work in deeper api. + } + } + LBraceOffset = 1; + tmpTok = PP.LookAhead(LessOffset + LParenOffset + LBraceOffset); + for (; !tmpTok.is(tok::eof); LBraceOffset++) { // check "Foo<>" structure + tmpTok = PP.LookAhead(LessOffset + LParenOffset + LBraceOffset); + if (tmpTok.is(tok::semi) || tmpTok.is(tok::equal)) // no "{" in current sentence + return false; + if (tmpTok.is(tok::l_brace)) { + return true; + } + } + + return false; +} + namespace { class TentativeParseCCC final : public CorrectionCandidateCallback { public: diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index dead6e8e3ba0..cc3b60633c92 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -981,54 +981,18 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::kw_module: Diag(Tok, diag::err_unexpected_module_decl); SkipUntil(tok::semi); - return nullptr; - - // DEV: BSC Template Function Declaration Structure | TODO, refactor, long long - // "^[]specifier-identifier--(paramlist) {body}" structure - // static inline int int foo(T a, int b) {return b;} - // TODO: parse high-level syntax (structure, inline, ...) - // Type Specifier: see c11 spec 6.7.2 - case tok::kw__Atomic: // not verified - case tok::kw_union: // not verified - case tok::kw_struct: // not supported! - case tok::kw_class: // not verified - case tok::kw_enum: // not verified - // case tok::kw_typedef: // typedef will be parsed in another branch - case tok::kw__Complex: // not verified - case tok::kw_void: // not verified - case tok::kw_bool: // not supported! - case tok::kw__Bool: // not supported! - case tok::kw_char: - case tok::kw_short: - case tok::kw_int: - case tok::kw_long: - case tok::kw_float: - case tok::kw_double: - case tok::kw_signed: - case tok::kw_unsigned: - case tok::identifier: - { - assert(Tok.isAnyTypeSpecifierKind() && "Tok should be Type Specifier!"); - // branch of parsing BSC template function - // DEV: entrance condition: [] type-specifier | TODO: refactor - bool isBSCTemplateDecl = getLangOpts().BSC && - ((NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::less)) || - (NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::identifier) - && PP.LookAhead(2).is(tok::less)) || - // BSC Mark: Temporarily add judgement for "long int foo" situation. - (NextToken().is(tok::kw_int) && PP.LookAhead(1).is(tok::identifier) && PP.LookAhead(2).is(tok::less)) - ); - if (isBSCTemplateDecl) { + return nullptr; + default: + dont_know: + // DEV: parse BSC template declaration + if (isBSCTemplateDecl(Tok)) { // parsing function (enter next level of parsing function) SourceLocation DeclEnd; return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs); - } else { - goto dont_know; + break; } - } - default: - dont_know: + if (Tok.isEditorPlaceholder()) { ConsumeToken(); return nullptr; diff --git a/clang/test/BSC/Generic/return_type_multi.cbs b/clang/test/BSC/Generic/return_type_multi.cbs index e18ffda94f25..848ef6d8a779 100644 --- a/clang/test/BSC/Generic/return_type_multi.cbs +++ b/clang/test/BSC/Generic/return_type_multi.cbs @@ -18,7 +18,7 @@ int main() { unsigned x2 = bar(1.0, 2.0); long long y1 = foo(1, 1.0); - long long y2 = foo(3.0, 99.0); + long long y2 = foo(3.0, 99.0); printf("%uand %uand\n", x1, x2); printf("%lld, %lld\n", y1, y2); diff --git a/clang/test/BSC/Generic/return_type_multi_tok.cbs b/clang/test/BSC/Generic/return_type_multi_tok.cbs new file mode 100644 index 000000000000..fb6a41647e35 --- /dev/null +++ b/clang/test/BSC/Generic/return_type_multi_tok.cbs @@ -0,0 +1,71 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + + +signed char Alice (T a, T b) +{ + return a > b ? a : b; +} + +unsigned char Bob (T a, T b) +{ + return 'c'; +} + +unsigned int Charlie (T a, T b) +{ + return a > b ? a : b; +} + +unsigned short Dave (T a, T b) +{ + return a > b ? a : b; +} + + +unsigned long Eve (T a, T b) +{ + return a > b ? a : b; +} + + +long double Frank (T a, T b) +{ + return 42.0; +} + + +long long Garcia (T a, T b) +{ + return a > b ? a : b; +} + + +unsigned long long Henry (T a, T b) +{ + return 42.0; +} + + +signed long long Issac (T a, T b) +{ + return 42.0; +} + + +int main () +{ + signed char alice = Alice(1, 2); + unsigned char bob = Bob(1, 2); + unsigned int charlie = Charlie(1, 2); + unsigned short dave = Dave(1, 2); + unsigned long eve = Eve(1, 2); + long double frank = Frank(1, 2); + long long garcia = Garcia(1, 2); + + unsigned long long henry = Henry(1, 2); + signed long long issac = Issac(1, 2); + + return 0; +} diff --git a/clang/test/BSC/Generic/return_type_pointer.cbs b/clang/test/BSC/Generic/return_type_pointer.cbs new file mode 100644 index 000000000000..416bf768032e --- /dev/null +++ b/clang/test/BSC/Generic/return_type_pointer.cbs @@ -0,0 +1,29 @@ +#include + + +int * Foo (T a, T b) // pointer +{ + T x = a > b ? a : b; + static int res = 42; + return &res; +} + + +int * Bar (T a, T b) // array +{ + T x = a > b ? a : b; + static int array[] = {0, 1, 2}; + return array; +} + + +int main () +{ + int *res = Foo(1, 2); + printf("%d\n", *res); + + int *array = Bar(1, 2); + printf("%d %d %d\n", array[0], array[1], array[2]); + + return 0; +} -- Gitee From 13631eacd2775a999b3278b8f289206fe6292a30 Mon Sep 17 00:00:00 2001 From: qinziang Date: Tue, 21 Mar 2023 19:29:41 +0800 Subject: [PATCH 14/22] [generic] bug-fix: fix logic flaws fix logic flaws in: 1) skipping template param list ''; 2) isBSCTemplateDecl() method --- clang/lib/Parse/ParseExprCXX.cpp | 6 ++++-- clang/lib/Parse/ParseTemplate.cpp | 7 ------- clang/lib/Parse/ParseTentative.cpp | 12 +++++++----- clang/test/BSC/Generic/return_type_pointer.cbs | 5 +++++ 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 2de5b4644580..f376cc6ac690 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -394,12 +394,14 @@ bool Parser::ParseOptionalCXXScopeSpecifier( bool parsingBSCTemplateFunction = getLangOpts().BSC && Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::less) && - PP.LookAhead(1).is(tok::identifier) && + PP.LookAhead(1).is(tok::identifier) && // this could be missidentified from typo: "intt" (PP.LookAhead(2).is(tok::comma) || PP.LookAhead(2).is(tok::greater)); if (parsingBSCTemplateFunction) { int lParenOffset = 0; - while (!PP.LookAhead(lParenOffset).is(tok::l_paren)) { + Token tmpTok = PP.LookAhead(lParenOffset); + while (!tmpTok.is(tok::l_paren) && !tmpTok.is(tok::eof)) { lParenOffset += 1; + tmpTok = PP.LookAhead(lParenOffset); } Next = PP.LookAhead(lParenOffset); } else { diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 216e2f1501b3..9712c83cfe2a 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -43,13 +43,6 @@ Decl *Parser::ParseDeclarationStartingWithTemplate( return ParseExplicitInstantiation(Context, SourceLocation(), ConsumeToken(), DeclEnd, AccessAttrs, AS); } - // // DEV: at BSC template declaration, parse this in a independent branch - // bool isBSCTemplateDeclOrSpc = getLangOpts().BSC && - // ((NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::less)) || - // (NextToken().is(tok::identifier) && PP.LookAhead(1).is(tok::identifier) - // && PP.LookAhead(2).is(tok::less)) - // ); - // DEV: parse BSC template declaration if (isBSCTemplateDecl(Tok)) { return ParseBSCGenericDeclaration(Context, DeclEnd, AccessAttrs, diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index ac5a069f246c..465c2ef7837b 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1120,15 +1120,17 @@ bool Parser::isBSCTemplateDecl(Token tok) { int MaxLessTokenLookAheadOffset = 6; // tok::less must appear with in 6 more token: "static inline unsigned long long Foo<" int LessOffset = 0; bool FoundLess = false; + Token prevTok = tok; Token tmpTok = PP.LookAhead(LessOffset); - for (; LessOffset < MaxLessTokenLookAheadOffset; LessOffset++) { - tmpTok = PP.LookAhead(LessOffset); + for (LessOffset = 1; LessOffset <= MaxLessTokenLookAheadOffset && !PP.LookAhead(LessOffset).is(tok::eof); LessOffset++) { // fix-me: watch this loop if (tmpTok.is(tok::l_paren) || tmpTok.is(tok::l_brace) || tmpTok.is(tok::equal)) // "<>" must appear neighboring with function/struct identtifier return false; - if (tmpTok.is(tok::less) && PP.LookAhead(LessOffset - 1).is(tok::identifier)) { + if (tmpTok.is(tok::less) && prevTok.is(tok::identifier)) { FoundLess = true; break; // when ">" missing, leave tis diagnose work in deeper api. } + prevTok = tmpTok; + tmpTok = PP.LookAhead(LessOffset); } if (!FoundLess) return false; @@ -1142,7 +1144,7 @@ bool Parser::isBSCTemplateDecl(Token tok) { break; if (tmpTok.is(tok::semi) || tmpTok.is(tok::equal)) // no "{" in current sentence return false; - if (tmpTok.is(tok::l_brace)) { + if (tmpTok.is(tok::l_brace) || tmpTok.is(tok::r_brace)) { // l_brace could missing, pass this for latter diagnose return true; } } @@ -1164,7 +1166,7 @@ bool Parser::isBSCTemplateDecl(Token tok) { tmpTok = PP.LookAhead(LessOffset + LParenOffset + LBraceOffset); if (tmpTok.is(tok::semi) || tmpTok.is(tok::equal)) // no "{" in current sentence return false; - if (tmpTok.is(tok::l_brace)) { + if (tmpTok.is(tok::l_brace) || tmpTok.is(tok::r_brace)) { // l_brace could missing, pass this for latter diagnose return true; } } diff --git a/clang/test/BSC/Generic/return_type_pointer.cbs b/clang/test/BSC/Generic/return_type_pointer.cbs index 416bf768032e..83a644f23d52 100644 --- a/clang/test/BSC/Generic/return_type_pointer.cbs +++ b/clang/test/BSC/Generic/return_type_pointer.cbs @@ -1,3 +1,8 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + + #include -- Gitee From f206ff9b59e941c426f358f9817193efe3473d14 Mon Sep 17 00:00:00 2001 From: Aperzer Date: Wed, 22 Mar 2023 11:06:51 +0800 Subject: [PATCH 15/22] [generic] support C-Style cast check in generic func body. Now we can use C-Style cast check in BSC generic func body. Such as: #include int max (T a, T b) { int x = int(a) + int(b); return x; } int main () { float a = 2.3; float b = 1.1; int res = max(a, b); printf("res = %d\n", res); return 0; } Test cases has been added/repaired. --- clang/lib/Parse/ParseExpr.cpp | 2 +- clang/lib/Sema/SemaCast.cpp | 16 +++++++++++---- clang/test/BSC/Generic/bsc_generic.cbs | 4 ++++ .../test/BSC/Generic/cast_in_generic_body.cbs | 17 ++++++++++++++++ clang/test/BSC/Generic/cast_struct_to_int.cbs | 20 +++++++++++++++++++ 5 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 clang/test/BSC/Generic/cast_in_generic_body.cbs create mode 100644 clang/test/BSC/Generic/cast_struct_to_int.cbs diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 625e8e0453b7..7749ceb4e5f0 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1565,7 +1565,7 @@ Parser::ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand, ParseKind, isAddressOfOperand, NotCastExpr, isTypeCast, isVectorLiteral, NotPrimaryExpression, HasBSCScopeSpec); } - if (!getLangOpts().CPlusPlus) { + if (!(getLangOpts().CPlusPlus || getLangOpts().BSC)) { // BSC Mark: enter the type-cast check in bsc generic situation. Diag(Tok, diag::err_expected_expression); return ExprError(); } diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 671820afd485..0661a258e7f8 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -2690,7 +2690,7 @@ static void DiagnoseBadFunctionCast(Sema &Self, const ExprResult &SrcExpr, /// Check the semantics of a C-style cast operation, in C. void CastOperation::CheckCStyleCast() { - assert(!Self.getLangOpts().CPlusPlus); + assert(!Self.getLangOpts().CPlusPlus); // BSC Mark: BSC C-Style cast check should enter here. // C-style casts can resolve __unknown_any types. if (claimPlaceholder(BuiltinType::UnknownAny)) { @@ -3083,9 +3083,17 @@ ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo, Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange(); Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getEndLoc()); - Op.CheckCXXCStyleCast(/*FunctionalCast=*/true, /*ListInit=*/false); - if (Op.SrcExpr.isInvalid()) - return ExprError(); + // BSC Mark: try to use C-Style cast check for BSC generic. + if (getLangOpts().BSC){ + Op.CheckCStyleCast(); + if (Op.SrcExpr.isInvalid()){ + return ExprError(); + } + } else { + Op.CheckCXXCStyleCast(/*FunctionalCast=*/true, /*ListInit=*/false); + if (Op.SrcExpr.isInvalid()) + return ExprError(); + } auto *SubExpr = Op.SrcExpr.get(); if (auto *BindExpr = dyn_cast(SubExpr)) diff --git a/clang/test/BSC/Generic/bsc_generic.cbs b/clang/test/BSC/Generic/bsc_generic.cbs index dc2ab6889ff3..1d9698d03f38 100644 --- a/clang/test/BSC/Generic/bsc_generic.cbs +++ b/clang/test/BSC/Generic/bsc_generic.cbs @@ -1,3 +1,7 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + #include struct S{ diff --git a/clang/test/BSC/Generic/cast_in_generic_body.cbs b/clang/test/BSC/Generic/cast_in_generic_body.cbs new file mode 100644 index 000000000000..f5a73fb074cd --- /dev/null +++ b/clang/test/BSC/Generic/cast_in_generic_body.cbs @@ -0,0 +1,17 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +int foo (T a, T b) +{ + int x = int(a) + int(b); + return x; +} + +int main () +{ + float a = 2.3; + float b = 1.1; + int res = foo(a, b); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/cast_struct_to_int.cbs b/clang/test/BSC/Generic/cast_struct_to_int.cbs new file mode 100644 index 000000000000..6f503faf71fb --- /dev/null +++ b/clang/test/BSC/Generic/cast_struct_to_int.cbs @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -verify %s + +T1 foo (T1 a, T2 b) +{ + int x = int(b); // expected-error {{operand of type 'struct S' where arithmetic or pointer type is required}} + return x; +} + +struct S +{ + int a; +}; + +int main () +{ + float a = 2.5; + struct S s1 = {.a = 1}; + int res = foo(a, s1); // expected-note {{in instantiation of function template specialization 'foo' requested here}} + return 0; +} \ No newline at end of file -- Gitee From d1211fa68e6e13405d79edefb2c0a07db552c189 Mon Sep 17 00:00:00 2001 From: Aperzer Date: Mon, 27 Mar 2023 17:26:10 +0800 Subject: [PATCH 16/22] [generic] fix failed cases of clang-test Failed cases mainly is two aspects: BSC test cases and the others. For BSC test cases, we rewrite the key API 'ParseOptionalCXXScopeSpecifier'; For the other test cases, we changed some check logic of sema part. Now all the cases has been fixed, except one remaining(not urgent, need reconfiguration, will fix later) --- clang/include/clang/Parse/Parser.h | 10 + clang/lib/Parse/ParseDecl.cpp | 2 +- clang/lib/Parse/ParseDeclCXX.cpp | 23 +- clang/lib/Parse/ParseExprCXX.cpp | 303 +++++++++++++++++++++ clang/lib/Sema/SemaTemplateInstantiate.cpp | 5 + 5 files changed, 341 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 6b6fd2bfc723..267ef496cc58 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1898,6 +1898,16 @@ private: bool OnlyNamespace = false, bool InUsingDeclaration = false); + bool ParseOptionalBSCGenericSpecifier(CXXScopeSpec &SS, + ParsedType ObjectType, + bool ObjectHasErrors, + bool EnteringContext, + bool *MayBePseudoDestructor = nullptr, + bool IsTypename = false, + IdentifierInfo **LastII = nullptr, + bool OnlyNamespace = false, + bool InUsingDeclaration = false); + //===--------------------------------------------------------------------===// // C++11 5.1.2: Lambda expressions diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index ab95877ef78a..a3673bb3d111 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3338,7 +3338,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // In C++, check to see if this is a scope specifier like foo::bar::, if // so handle it as such. This is important for ctor parsing. - if (getLangOpts().CPlusPlus || getLangOpts().BSC) { + if (getLangOpts().CPlusPlus) { if (TryAnnotateCXXScopeToken(EnteringContext)) { DS.SetTypeSpecError(); goto DoneWithDeclSpec; diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 611bdb484060..af33ac4de1c8 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1546,7 +1546,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Parse the (optional) nested-name-specifier. CXXScopeSpec &SS = DS.getTypeSpecScope(); - if (getLangOpts().CPlusPlus || getLangOpts().BSC) { // 'struct S s1' should enter here + if (getLangOpts().CPlusPlus) { // "FOO : BAR" is not a potential typo for "FOO::BAR". In this context it // is a base-specifier-list. ColonProtectionRAIIObject X(*this); @@ -1568,6 +1568,27 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, SS = Spec; } + // BSC Mark: 'struct S s1' should enter here + if (getLangOpts().BSC) { + ColonProtectionRAIIObject X(*this); + + CXXScopeSpec Spec; + bool HasValidSpec = true; + if (ParseOptionalBSCGenericSpecifier(Spec, /*ObjectType=*/nullptr, // After this, TokenKind is tok::annot_template_id! + /*ObjectHadErrors=*/false, + EnteringContext)) { + DS.SetTypeSpecError(); + HasValidSpec = false; + } + if (Spec.isSet()) + if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) { + Diag(Tok, diag::err_expected) << tok::identifier; + HasValidSpec = false; + } + if (HasValidSpec) + SS = Spec; + } + TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; auto RecoverFromUndeclaredTemplateName = [&](IdentifierInfo *Name, diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index f376cc6ac690..d74f84350d36 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -575,6 +575,309 @@ bool Parser::ParseOptionalCXXScopeSpecifier( return false; } +// BSC Mark: parse instation for struct part of generic, +// to avoid affecting the original logic of C++ +bool Parser::ParseOptionalBSCGenericSpecifier( + CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors, + bool EnteringContext, bool *MayBePseudoDestructor, bool IsTypename, + IdentifierInfo **LastII, bool OnlyNamespace, bool InUsingDeclaration) { + assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && + "Call sites of this function should be guarded by checking for C++ or BSC"); + + if (Tok.is(tok::annot_cxxscope)) { + assert(!LastII && "want last identifier but have already annotated scope"); + assert(!MayBePseudoDestructor && "unexpected annot_cxxscope"); + Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), + Tok.getAnnotationRange(), + SS); + ConsumeAnnotationToken(); + return false; + } + + // Has to happen before any "return false"s in this function. + bool CheckForDestructor = false; + if (MayBePseudoDestructor && *MayBePseudoDestructor) { + CheckForDestructor = true; + *MayBePseudoDestructor = false; + } + + if (LastII) + *LastII = nullptr; + + bool HasScopeSpecifier = false; + + if (!HasScopeSpecifier && + Tok.isOneOf(tok::kw_decltype, tok::annot_decltype)) { + DeclSpec DS(AttrFactory); + SourceLocation DeclLoc = Tok.getLocation(); + SourceLocation EndLoc = ParseDecltypeSpecifier(DS); + + SourceLocation CCLoc; + // Work around a standard defect: 'decltype(auto)::' is not a + // nested-name-specifier. + if (DS.getTypeSpecType() == DeclSpec::TST_decltype_auto || + !TryConsumeToken(tok::coloncolon, CCLoc)) { + AnnotateExistingDecltypeSpecifier(DS, DeclLoc, EndLoc); + return false; + } + + if (Actions.ActOnCXXNestedNameSpecifierDecltype(SS, DS, CCLoc)) + SS.SetInvalid(SourceRange(DeclLoc, CCLoc)); + + HasScopeSpecifier = true; + } + + // Preferred type might change when parsing qualifiers, we need the original. + auto SavedType = PreferredType; + while (true) { + if (HasScopeSpecifier) { + if (Tok.is(tok::code_completion)) { + // Code completion for a nested-name-specifier, where the code + // completion token follows the '::'. + Actions.CodeCompleteQualifiedId(getCurScope(), SS, EnteringContext, + InUsingDeclaration, ObjectType.get(), + SavedType.get(SS.getBeginLoc())); + // Include code completion token into the range of the scope otherwise + // when we try to annotate the scope tokens the dangling code completion + // token will cause assertion in + // Preprocessor::AnnotatePreviousCachedTokens. + SS.setEndLoc(Tok.getLocation()); + cutOffParsing(); + return true; + } + + ObjectType = nullptr; + } + + // nested-name-specifier: + // nested-name-specifier 'template'[opt] simple-template-id '::' + + // Parse the optional 'template' keyword, then make sure we have + // 'identifier <' after it. + if (Tok.is(tok::kw_template)) { + // If we don't have a scope specifier or an object type, this isn't a + // nested-name-specifier, since they aren't allowed to start with + // 'template'. + if (!HasScopeSpecifier && !ObjectType) + break; + + TentativeParsingAction TPA(*this); + SourceLocation TemplateKWLoc = ConsumeToken(); + + UnqualifiedId TemplateName; + if (Tok.is(tok::identifier)) { + // Consume the identifier. + TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeToken(); + } else if (Tok.is(tok::kw_operator)) { + // We don't need to actually parse the unqualified-id in this case, + // because a simple-template-id cannot start with 'operator', but + // go ahead and parse it anyway for consistency with the case where + // we already annotated the template-id. + if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, + TemplateName)) { + TPA.Commit(); + break; + } + + if (TemplateName.getKind() != UnqualifiedIdKind::IK_OperatorFunctionId && + TemplateName.getKind() != UnqualifiedIdKind::IK_LiteralOperatorId) { + Diag(TemplateName.getSourceRange().getBegin(), + diag::err_id_after_template_in_nested_name_spec) + << TemplateName.getSourceRange(); + TPA.Commit(); + break; + } + } else { + TPA.Revert(); + break; + } + + // If the next token is not '<', we have a qualified-id that refers + // to a template name, such as T::template apply, but is not a + // template-id. + if (Tok.isNot(tok::less)) { + TPA.Revert(); + break; + } + + // Commit to parsing the template-id. + TPA.Commit(); + TemplateTy Template; + TemplateNameKind TNK = Actions.ActOnTemplateName( + getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType, + EnteringContext, Template, /*AllowInjectedClassName*/ true); + if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateKWLoc, + TemplateName, false)) + return true; + + continue; + } + + if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) { + // We have + // + // template-id '::' + // + // So we need to check whether the template-id is a simple-template-id of + // the right kind (it should name a type or be dependent), and then + // convert it into a type within the nested-name-specifier. + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) { + *MayBePseudoDestructor = true; + return false; + } + + if (LastII) + *LastII = TemplateId->Name; + + // Consume the template-id token. + ConsumeAnnotationToken(); + + assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); + SourceLocation CCLoc = ConsumeToken(); + + HasScopeSpecifier = true; + + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + + if (TemplateId->isInvalid() || + Actions.ActOnCXXNestedNameSpecifier(getCurScope(), + SS, + TemplateId->TemplateKWLoc, + TemplateId->Template, + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc, + CCLoc, + EnteringContext)) { + SourceLocation StartLoc + = SS.getBeginLoc().isValid()? SS.getBeginLoc() + : TemplateId->TemplateNameLoc; + SS.SetInvalid(SourceRange(StartLoc, CCLoc)); + } + + continue; + } + + // 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(); + + Token Next; + bool parsingBSCTemplateFunction = getLangOpts().BSC && + Tok.is(tok::identifier) && + PP.LookAhead(0).is(tok::less) && + PP.LookAhead(1).is(tok::identifier) && + (PP.LookAhead(2).is(tok::comma) || PP.LookAhead(2).is(tok::greater)); + if (parsingBSCTemplateFunction) { + int lParenOffset = 0; + while (!PP.LookAhead(lParenOffset).is(tok::l_paren)) { + lParenOffset += 1; + } + Next = PP.LookAhead(lParenOffset); + } else { + Next = NextToken(); + } + + Sema::NestedNameSpecInfo IdInfo(&II, Tok.getLocation(), Next.getLocation(), + ObjectType); + + CheckForTemplateAndDigraph(Next, ObjectType, EnteringContext, II, SS); + + // nested-name-specifier: + // type-name '<' + if (Next.is(tok::less)) { // yt: 'S', next 'S' is set to tok::annote_template_id? + + TemplateTy Template; + UnqualifiedId TemplateName; + TemplateName.setIdentifier(&II, Tok.getLocation()); + bool MemberOfUnknownSpecialization; + if (TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS, + /*hasTemplateKeyword=*/false, + TemplateName, + ObjectType, + EnteringContext, + Template, + MemberOfUnknownSpecialization)) { + // If lookup didn't find anything, we treat the name as a template-name + // anyway. C++20 requires this, and in prior language modes it improves + // error recovery. But before we commit to this, check that we actually + // have something that looks like a template-argument-list next. + if (!IsTypename && TNK == TNK_Undeclared_template && + isTemplateArgumentList(1) == TPResult::False) + break; + + // We have found a template name, so annotate this token + // with a template-id annotation. We do not permit the + // template-id to be translated into a type annotation, + // because some clients (e.g., the parsing of class template + // specializations) still want to see the original template-id + // token, and it might not be a type at all (e.g. a concept name in a + // type-constraint). + ConsumeToken(); // yt: Cpp template specialization enter here + if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), + TemplateName, false)) + return true; + continue; + } + + if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) && + (IsTypename || isTemplateArgumentList(1) == TPResult::True)) { + // If we had errors before, ObjectType can be dependent even without any + // templates. Do not report missing template keyword in that case. + if (!ObjectHadErrors) { + // We have something like t::getAs, where getAs is a + // member of an unknown specialization. However, this will only + // parse correctly as a template, so suggest the keyword 'template' + // before 'getAs' and treat this as a dependent template name. + unsigned DiagID = diag::err_missing_dependent_template_keyword; + if (getLangOpts().MicrosoftExt) + DiagID = diag::warn_missing_dependent_template_keyword; + + Diag(Tok.getLocation(), DiagID) + << II.getName() + << FixItHint::CreateInsertion(Tok.getLocation(), "template "); + } + + SourceLocation TemplateNameLoc = ConsumeToken(); + + TemplateNameKind TNK = Actions.ActOnTemplateName( + getCurScope(), SS, TemplateNameLoc, TemplateName, ObjectType, + EnteringContext, Template, /*AllowInjectedClassName*/ true); + if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), + TemplateName, false)) + return true; + + continue; + } + } + + // We don't have any tokens that form the beginning of a + // nested-name-specifier, so we're done. + break; + } + + // Even if we didn't see any pieces of a nested-name-specifier, we + // still check whether there is a tilde in this position, which + // indicates a potential pseudo-destructor. + if (CheckForDestructor && !HasScopeSpecifier && Tok.is(tok::tilde)) + *MayBePseudoDestructor = true; + + return false; +} + ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOperand, Token &Replacement) { diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index ea2d31644de6..3ba32fd9ae3c 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2653,6 +2653,11 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, MSInfo->setTemplateSpecializationKind(TSK); MSInfo->setPointOfInstantiation(PointOfInstantiation); } + else if (ClassTemplateSpecializationDecl *Spec + = dyn_cast(Instantiation)) { // yt: should be true for BSC + Spec->setTemplateSpecializationKind(TSK); + Spec->setPointOfInstantiation(PointOfInstantiation); + } } else if (ClassTemplateSpecializationDecl *Spec = dyn_cast(Instantiation)) { // yt: should be true for BSC Spec->setTemplateSpecializationKind(TSK); -- Gitee From da04a14cb1ded7e430da8f41951b0e08229aa871 Mon Sep 17 00:00:00 2001 From: qinziang Date: Tue, 28 Mar 2023 21:41:13 +0800 Subject: [PATCH 17/22] [generic] bug-fix: support struct type as actual-template-parameter in template-struct now we support syntax below: struct Brick { int weight; }; struct Wall { T elem; }; int main() { struct Brick brick = {.weight = 1}; struct Wall wall = {.elem = brick}; } The reason of original issue is: 1) Clang assumes C++ is the only language that supports template structure(or even the Generic feature), most RecordDecl-related vaiable default to CXXRecordDecl; 2) BSC uses RecordDecl in its scope and reuses C++ parsing logic; Therefore, there are logic flaws when Clang tries to manipuate CXXRecordDecl in a BSC context. TODO: support template-struct type as actual-template-parameter in template-struct. --- clang/lib/AST/DeclBase.cpp | 8 ++- clang/lib/AST/RecordLayoutBuilder.cpp | 50 ++++++++++--------- .../Generic/struct_template_type_struct.cbs | 31 ++++++++++++ 3 files changed, 64 insertions(+), 25 deletions(-) create mode 100644 clang/test/BSC/Generic/struct_template_type_struct.cbs diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 3e9d1d032b74..e03bc9ff617e 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -1563,8 +1563,12 @@ void DeclContext::addHiddenDecl(Decl *D) { // Notify a C++ record declaration that we've added a member, so it can // update its class-specific state. - if (auto *Record = dyn_cast(this)) - Record->addedMember(D); + // DEV: Only CXXRecordDecl supports addedMember(), Clang assume only C++ supports template-structure, + // BSC template-structure reuses CXX.. logic, each RecordDecl need to be checked. + if (D->getASTContext().getLangOpts().CPlusPlus) { // LangOpts().CPlusPlus does not work at here + if (auto *Record = dyn_cast(this)) + Record->addedMember(D); + } // If this is a newly-created (not de-serialized) import declaration, wire // it in to the list of local import declarations. diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 95d69fa5b11a..2dc22f99b675 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -189,18 +189,20 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() { for (const CXXBaseSpecifier &Base : Class->bases()) { const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); - CharUnits EmptySize; - const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl); - if (BaseDecl->isEmpty()) { - // If the class decl is empty, get its size. - EmptySize = Layout.getSize(); - } else { - // Otherwise, we get the largest empty subobject for the decl. - EmptySize = Layout.getSizeOfLargestEmptySubobject(); - } + if (BaseDecl->getASTContext().getLangOpts().CPlusPlus) { // DEV: Only C++ supports getSizeOfLargestEmptySubobject() + CharUnits EmptySize; + const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl); + if (BaseDecl->isEmpty()) { + // If the class decl is empty, get its size. + EmptySize = Layout.getSize(); + } else { + // Otherwise, we get the largest empty subobject for the decl. + EmptySize = Layout.getSizeOfLargestEmptySubobject(); + } - if (EmptySize > SizeOfLargestEmptySubobject) - SizeOfLargestEmptySubobject = EmptySize; + if (EmptySize > SizeOfLargestEmptySubobject) + SizeOfLargestEmptySubobject = EmptySize; + } } // Check the fields. @@ -212,19 +214,21 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() { if (!RT) continue; - CharUnits EmptySize; - const CXXRecordDecl *MemberDecl = RT->getAsCXXRecordDecl(); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl); - if (MemberDecl->isEmpty()) { - // If the class decl is empty, get its size. - EmptySize = Layout.getSize(); - } else { - // Otherwise, we get the largest empty subobject for the decl. - EmptySize = Layout.getSizeOfLargestEmptySubobject(); - } + if (FD->getASTContext().getLangOpts().CPlusPlus) { // DEV: Only C++ supports getSizeOfLargestEmptySubobject() + CharUnits EmptySize; + const CXXRecordDecl *MemberDecl = RT->getAsCXXRecordDecl(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl); + if (MemberDecl->isEmpty()) { + // If the class decl is empty, get its size. + EmptySize = Layout.getSize(); + } else { + // Otherwise, we get the largest empty subobject for the decl. + EmptySize = Layout.getSizeOfLargestEmptySubobject(); + } - if (EmptySize > SizeOfLargestEmptySubobject) - SizeOfLargestEmptySubobject = EmptySize; + if (EmptySize > SizeOfLargestEmptySubobject) + SizeOfLargestEmptySubobject = EmptySize; + } } } diff --git a/clang/test/BSC/Generic/struct_template_type_struct.cbs b/clang/test/BSC/Generic/struct_template_type_struct.cbs new file mode 100644 index 000000000000..ebe7b74940ac --- /dev/null +++ b/clang/test/BSC/Generic/struct_template_type_struct.cbs @@ -0,0 +1,31 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include + +struct Shape { + int width; + int hight; +}; + +struct S { + T elem; +}; + + +int main () +{ + struct Shape shape = {.width = 42, .hight = 42}; + printf("%d, %d\n", shape.width, shape.hight); + + struct S aaa = {.elem = 42}; + printf("%d\n", aaa.elem); + + struct S bbb = {.elem = shape}; + printf("%d, %d\n", bbb.elem.width, bbb.elem.hight); + + // struct S> ccc = {.elem = bbb}; + + return 0; +} -- Gitee From 993b2cb3484aed33498a9660fad5c3a5611b58c4 Mon Sep 17 00:00:00 2001 From: qinziang Date: Thu, 30 Mar 2023 10:10:25 +0800 Subject: [PATCH 18/22] [generic] code-reformat: modify comment codecheck commit, mainly modify comment: 1. remove comment personal mark 'DEV' 2. clarify some comment 3. rename argument 'isBSCTemplateStructParsing' as 'isParsingBSCTemplateStruct' --- clang/lib/AST/RecordLayoutBuilder.cpp | 2 +- clang/lib/Lex/Preprocessor.cpp | 2 +- clang/lib/Parse/ParseDecl.cpp | 17 ++++++++--------- clang/lib/Parse/ParseDeclCXX.cpp | 13 ++++++------- clang/lib/Parse/ParseExprCXX.cpp | 10 +++++----- clang/lib/Parse/ParseTemplate.cpp | 22 +++++++++++----------- clang/lib/Parse/ParseTentative.cpp | 3 ++- clang/lib/Parse/Parser.cpp | 7 ++++--- clang/test/BSC/Generic/diagnose.cbs | 1 - 9 files changed, 38 insertions(+), 39 deletions(-) diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 2dc22f99b675..8d2f415ff269 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -189,7 +189,7 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() { for (const CXXBaseSpecifier &Base : Class->bases()) { const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); - if (BaseDecl->getASTContext().getLangOpts().CPlusPlus) { // DEV: Only C++ supports getSizeOfLargestEmptySubobject() + if (BaseDecl->getASTContext().getLangOpts().CPlusPlus) { // Only C++ supports getSizeOfLargestEmptySubobject() CharUnits EmptySize; const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl); if (BaseDecl->isEmpty()) { diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 6a86a7f97a84..9a97a629617d 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -897,7 +897,7 @@ void Preprocessor::Lex(Token &Result) { ReturnedToken = CurTokenLexer->Lex(Result); break; case CLK_CachingLexer: - CachingLex(Result); // DEV: in ConsumeToken(),read Token from global Cache s.t. token consumption is linear + CachingLex(Result); // in ConsumeToken(),read Token from global Cache, therefore, token consumption is linear ReturnedToken = true; break; case CLK_LexAfterModuleImport: diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index a3673bb3d111..901d9474f27f 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1661,7 +1661,7 @@ Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, case tok::kw_template: case tok::kw_export: ProhibitAttributes(attrs); - SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); // DEV: C++ template function parsing branch + SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); // C++ template function parsing branch break; case tok::kw_inline: // Could be the start of an inline namespace. Allowed as an ext in C++03. @@ -1684,7 +1684,8 @@ Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, SingleDecl = ParseStaticAssertDeclaration(DeclEnd); break; default: - // DEV: parse BSC template declaration + // parse BSC template declaration + // TODO: change if statement entrance condition, abandon isBSCTemplateDecl() if (isBSCTemplateDecl(Tok)) { ProhibitAttributes(attrs); SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); // OK: ClassTemplateDecl with RecordDecl. @@ -3390,7 +3391,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (Tok.isNot(tok::identifier)) continue; ParsedAttributesWithRange Attrs(AttrFactory); - if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) { // DEV: template parameter "T" in BSC will be miss-parsed here + if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) { // template parameter "T" in BSC might be miss-parsed here | when? if (!Attrs.empty()) { AttrsLastTime = true; attrs.takeAllFrom(Attrs); @@ -3952,7 +3953,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___interface: case tok::kw_union: { tok::TokenKind Kind = Tok.getKind(); - ConsumeToken(); // consume 'struct keyword' + ConsumeToken(); // consume 'struct' keyword // These are attributes following class specifiers. // To produce better diagnostic, we parse them when @@ -5953,8 +5954,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec()); // BSC Mark: Add language judgement for BSC template situation. - // DEV: adding BSC entrance condition! - // if (getLangOpts().CPlusPlus && D.mayHaveIdentifier()) { + // add BSC entrance condition! if ((getLangOpts().CPlusPlus || getLangOpts().BSC) && D.mayHaveIdentifier()) { // This might be a C++17 structured binding. @@ -6044,7 +6044,6 @@ void Parser::ParseDirectDeclarator(Declarator &D) { D.getContext() == DeclaratorContext::Member); } - // DEV: [to check] | D.getName() returns (clang::UnqualifiedIdKind::IK_Identifier), witch is incorrect. Identifier,StartLocation,EndLocation not instantialized bool HadScope = D.getCXXScopeSpec().isValid(); if (ParseUnqualifiedId(D.getCXXScopeSpec(), /*ObjectType=*/nullptr, @@ -6233,7 +6232,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) { // BSC Mark: Add language judgement for BSC template situation. - // DEV: Change branch entering condition | BSC syntax reusing C++ parsing code + // Change branch entering condition | BSC syntax reusing C++ parsing code if ((getLangOpts().CPlusPlus || getLangOpts().BSC) && D.mayBeFollowedByCXXDirectInit()) { // The name of the declarator, if any, is tentatively declared within @@ -6596,7 +6595,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, LocalEndLoc = RParenLoc; EndLoc = RParenLoc; - // DEV: Change branch entering condition | reusing C++ parse code when parsing BSC syntax + // Change branch entering condition | reusing C++ parse code when parsing BSC syntax // if (getLangOpts().CPlusPlus) { if (getLangOpts().CPlusPlus || getLangOpts().BSC) { // FIXME: Accept these components in any order, and produce fixits to diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index af33ac4de1c8..a87a38527f42 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1625,18 +1625,18 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, IdentifierInfo *Name = nullptr; SourceLocation NameLoc; TemplateIdAnnotation *TemplateId = nullptr; - bool isBSCTemplateStructParsing = getLangOpts().BSC && Tok.is(tok::identifier) && NextToken().is(tok::less); + bool isParsingBSCTemplateStruct = getLangOpts().BSC && Tok.is(tok::identifier) && NextToken().is(tok::less); if (Tok.is(tok::identifier)) { Name = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); - // DEV: BSC Sturct Template Declaration may have "" syntax. + // BSC Sturct Template Declaration may have "" syntax. // This param list must been parsed, skip it. - if (isBSCTemplateStructParsing) { + if (isParsingBSCTemplateStruct) { while (Tok.getKind() != tok::greater) { ConsumeToken(); } - assert(TryConsumeToken(tok::greater) && "comsuming BSC struct template param list fail!"); + assert(TryConsumeToken(tok::greater) && "fail at comsuming BSC struct template param list!"); } if (Tok.is(tok::less) && getLangOpts().CPlusPlus) { @@ -1996,14 +1996,13 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (SkipBody.ShouldSkip) SkipCXXMemberSpecification(StartLoc, AttrFixitLoc, TagType, TagOrTempResult.get()); - // DEV: add BSC entrance condition - // else if (getLangOpts().CPlusPlus) + // add BSC entrance condition else if (getLangOpts().CPlusPlus) ParseCXXMemberSpecification(StartLoc, AttrFixitLoc, attrs, TagType, TagOrTempResult.get()); else { Decl* D = nullptr; - if (isBSCTemplateStructParsing) { + if (isParsingBSCTemplateStruct) { // TODO: add more check D = static_cast(TagOrTempResult.get())->getTemplatedDecl(); } else { diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index d74f84350d36..5ae4ac29ec05 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -388,13 +388,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier( // nested-name-specifier identifier '::' // Token Next = NextToken(); - // DEV: skip template template param list in template function declaration: "T max (T a, T b) {...}" - // ^^^ + // Skip template template param list in template function declaration: "T max (T a, T b) {...}" + // ^^^ Token Next; bool parsingBSCTemplateFunction = getLangOpts().BSC && Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::less) && - PP.LookAhead(1).is(tok::identifier) && // this could be missidentified from typo: "intt" + PP.LookAhead(1).is(tok::identifier) && // TODO: this could be missidentified from typo: "intt" (PP.LookAhead(2).is(tok::comma) || PP.LookAhead(2).is(tok::greater)); if (parsingBSCTemplateFunction) { int lParenOffset = 0; @@ -3118,8 +3118,8 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, SourceLocation IdLoc = ConsumeToken(); if (!getLangOpts().CPlusPlus) { - // DEV: at BSC syntax T max(T a, T b) {...} - // ^ + // at BSC syntax T max(T a, T b) {...} + // ^ if(getLangOpts().BSC && Tok.is(tok::less)) { assert(Tok.is(tok::less) && "expected 'less' token"); while (!Tok.is(tok::greater)) { diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 9712c83cfe2a..c9532a12d023 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -43,17 +43,17 @@ Decl *Parser::ParseDeclarationStartingWithTemplate( return ParseExplicitInstantiation(Context, SourceLocation(), ConsumeToken(), DeclEnd, AccessAttrs, AS); } - // DEV: parse BSC template declaration + // Parse BSC template declaration + // TODO: change if statement entrance condition, abandon isBSCTemplateDecl() if (isBSCTemplateDecl(Tok)) { return ParseBSCGenericDeclaration(Context, DeclEnd, AccessAttrs, AS); } - // DEV: Warning: Debug: use continue, otherwise, using step-into will fail! return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AccessAttrs, AS); } -/// DEV: DIY rewrite ParseTemplateDeclarationOrSpecialization for BSC +// DIY rewrite ParseTemplateDeclarationOrSpecialization for BSC Decl *Parser::ParseBSCGenericDeclaration( DeclaratorContext Context, SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, AccessSpecifier AS) { @@ -560,7 +560,7 @@ bool Parser::ParseTemplateParameters( } -// DEV: ParseBSCTemplateParameters - rewrite ParseTemplateParameters for cross-order BSC syntax, use Peeking +// ParseBSCTemplateParameters - rewrite ParseTemplateParameters for cross-order BSC syntax, use Peeking bool Parser::ParseBSCTemplateParameters( MultiParseScope &TemplateScopes, unsigned Depth, SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, @@ -681,7 +681,7 @@ Parser::ParseBSCTemplateParameterList(const unsigned Depth, // a comma or closing brace. // SkipUntil(tok::comma, tok::greater, tok::greatergreater, // StopAtSemi | StopBeforeMatch); - SkipUntil(tok::comma, tok::greater, // DEV: fix-me: logic error + SkipUntil(tok::comma, tok::greater, // FIXME: logic error StopAtSemi | StopBeforeMatch); } peekTok = PP.LookAhead(lookAheadOffset); @@ -829,7 +829,7 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { Tok.getEndLoc()), "typename"); - Tok.setKind(tok::kw_typename); // DEV: unkown manipulation, rename "typedef" as "typename" + Tok.setKind(tok::kw_typename); // unkown manipulation, rename "typedef" as "typename" } return ParseTypeParameter(Depth, Position); @@ -861,7 +861,7 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { llvm_unreachable("template param classification can't be ambiguous"); } - // DEV: call upper layer method recursively to parse nested template param list + // Call upper layer method recursively to parse nested template param list // template > if (Tok.is(tok::kw_template)) return ParseTemplateTemplateParameter(Depth, Position); @@ -1043,11 +1043,11 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { } -// DEV: ParseBSCTypeParameter - rewrite ParseTypeParameter for cross-order BSC syntax, use Peeking +// ParseBSCTypeParameter - rewrite ParseTypeParameter for cross-order BSC syntax, use Peeking NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, int &lookAheadOffset) { - // DEV: Check Tok location + // Check Tok location Token peekTok = PP.LookAhead(lookAheadOffset); - bool isBSCTemplateTypeParameter = getLangOpts().BSC; // FIXME: fix the cond + bool isBSCTemplateTypeParameter = getLangOpts().BSC; // TODO: fix the cond //bool isBSCTemplateTypeParameter = getLangOpts().BSC && (peekTok.getKind() == tok::identifier); assert(isBSCTemplateTypeParameter && "A type-parameter starts with 'class', 'typename' or a type-constraint"); @@ -1090,7 +1090,7 @@ NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, int SourceLocation NameLoc = peekTok.getLocation(); IdentifierInfo *ParamName = nullptr; if (peekTok.is(tok::identifier)) { - ParamName = peekTok.getIdentifierInfo(); // DEV: unknown manipulation parsing T token + ParamName = peekTok.getIdentifierInfo(); // unknown manipulation, parsing T token lookAheadOffset += 1; peekTok = PP.LookAhead(lookAheadOffset); } else if (peekTok.isOneOf(tok::equal, tok::comma, tok::greater, diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 465c2ef7837b..381cfb2e50f8 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1122,7 +1122,8 @@ bool Parser::isBSCTemplateDecl(Token tok) { bool FoundLess = false; Token prevTok = tok; Token tmpTok = PP.LookAhead(LessOffset); - for (LessOffset = 1; LessOffset <= MaxLessTokenLookAheadOffset && !PP.LookAhead(LessOffset).is(tok::eof); LessOffset++) { // fix-me: watch this loop + // FIXME: below for-loop not verified + for (LessOffset = 1; LessOffset <= MaxLessTokenLookAheadOffset && !PP.LookAhead(LessOffset).is(tok::eof); LessOffset++) { if (tmpTok.is(tok::l_paren) || tmpTok.is(tok::l_brace) || tmpTok.is(tok::equal)) // "<>" must appear neighboring with function/struct identtifier return false; if (tmpTok.is(tok::less) && prevTok.is(tok::identifier)) { diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index cc3b60633c92..3feda7af91d5 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -922,7 +922,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::kw__Static_assert: // A function definition cannot start with any of these keywords. { - // DEV: entrance of parsing template function parameter list “template ” + // entrance of parsing template function parameter list “template ” SourceLocation DeclEnd; return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs); } @@ -984,7 +984,8 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, return nullptr; default: dont_know: - // DEV: parse BSC template declaration + // parse BSC template declaration + // TODO: change if entrance condition, abandon isBSCTemplateDecl() if (isBSCTemplateDecl(Tok)) { // parsing function (enter next level of parsing function) SourceLocation DeclEnd; @@ -998,7 +999,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, return nullptr; } // We can't tell whether this is a function-definition or declaration yet. - // DEV: entrance of parsing template function declaration “T max(T a, T b)” + // Entrance of parsing template function declaration “T max(T a, T b)” // and function declaration “int max(int a, int b)” return ParseDeclarationOrFunctionDefinition(attrs, DS); } diff --git a/clang/test/BSC/Generic/diagnose.cbs b/clang/test/BSC/Generic/diagnose.cbs index 428ae46e7f65..72995729b4e1 100644 --- a/clang/test/BSC/Generic/diagnose.cbs +++ b/clang/test/BSC/Generic/diagnose.cbs @@ -8,4 +8,3 @@ int main() { int res = foo(1, 2); return 0; } // expected-error {{expected ';' at end of declaration}} - -- Gitee From 63d429b48bc15709e1ab74c2e0a06b2fbb541cad Mon Sep 17 00:00:00 2001 From: Aperzer Date: Fri, 31 Mar 2023 15:34:26 +0800 Subject: [PATCH 19/22] [generic] Format all the commits of generic Use clang-format to format all the commits of generic. Verified by clang-test, no new problems were introduced. --- clang/include/clang/Basic/TokenKinds.h | 27 +-- clang/include/clang/Parse/Parser.h | 48 +++--- clang/include/clang/Sema/Sema.h | 10 +- clang/include/clang/Sema/Template.h | 3 +- clang/lib/AST/ASTContext.cpp | 3 +- clang/lib/AST/DeclBase.cpp | 10 +- clang/lib/AST/Mangle.cpp | 3 +- clang/lib/AST/RecordLayoutBuilder.cpp | 9 +- clang/lib/Lex/Preprocessor.cpp | 3 +- clang/lib/Parse/ParseDecl.cpp | 26 +-- clang/lib/Parse/ParseDeclCXX.cpp | 27 +-- clang/lib/Parse/ParseExpr.cpp | 4 +- clang/lib/Parse/ParseExprCXX.cpp | 81 +++++---- clang/lib/Parse/ParseStmt.cpp | 6 +- clang/lib/Parse/ParseTemplate.cpp | 182 ++++++++++++--------- clang/lib/Parse/ParseTentative.cpp | 44 +++-- clang/lib/Parse/Parser.cpp | 13 +- clang/lib/Sema/SemaCast.cpp | 8 +- clang/lib/Sema/SemaDecl.cpp | 75 +++++---- clang/lib/Sema/SemaExpr.cpp | 14 +- clang/lib/Sema/SemaLookup.cpp | 2 +- clang/lib/Sema/SemaOverload.cpp | 11 +- clang/lib/Sema/SemaTemplate.cpp | 34 ++-- clang/lib/Sema/SemaTemplateInstantiate.cpp | 69 ++++---- clang/lib/Sema/SemaType.cpp | 16 +- 25 files changed, 393 insertions(+), 335 deletions(-) diff --git a/clang/include/clang/Basic/TokenKinds.h b/clang/include/clang/Basic/TokenKinds.h index b70360cd7854..e763ee19bca7 100644 --- a/clang/include/clang/Basic/TokenKinds.h +++ b/clang/include/clang/Basic/TokenKinds.h @@ -76,25 +76,14 @@ inline bool isAnyIdentifier(TokenKind K) { /// Return true if this token kind could be type specifier. inline bool isAnyTypeSpecifierKind(TokenKind K) { // Type Specifier: see c11 spec 6.7.2 - return (K == tok::kw__Atomic) || - (K == tok::kw_union) || - (K == tok::kw_struct) || - (K == tok::kw_class) || - (K == tok::kw_enum) || - (K == tok::kw_typedef) || - (K == tok::kw__Complex) || - (K == tok::kw_void) || - (K == tok::kw_bool) || - (K == tok::kw__Bool) || - (K == tok::kw_char) || - (K == tok::kw_short) || - (K == tok::kw_int) || - (K == tok::kw_long) || - (K == tok::kw_float) || - (K == tok::kw_double) || - (K == tok::kw_signed) || - (K == tok::kw_unsigned) || - (K == tok::identifier); + return (K == tok::kw__Atomic) || (K == tok::kw_union) || + (K == tok::kw_struct) || (K == tok::kw_class) || (K == tok::kw_enum) || + (K == tok::kw_typedef) || (K == tok::kw__Complex) || + (K == tok::kw_void) || (K == tok::kw_bool) || (K == tok::kw__Bool) || + (K == tok::kw_char) || (K == tok::kw_short) || (K == tok::kw_int) || + (K == tok::kw_long) || (K == tok::kw_float) || (K == tok::kw_double) || + (K == tok::kw_signed) || (K == tok::kw_unsigned) || + (K == tok::identifier); } /// Return true if this is a C or C++ string-literal (or diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 267ef496cc58..4516ec6e24f5 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1898,15 +1898,11 @@ private: bool OnlyNamespace = false, bool InUsingDeclaration = false); - bool ParseOptionalBSCGenericSpecifier(CXXScopeSpec &SS, - ParsedType ObjectType, - bool ObjectHasErrors, - bool EnteringContext, - bool *MayBePseudoDestructor = nullptr, - bool IsTypename = false, - IdentifierInfo **LastII = nullptr, - bool OnlyNamespace = false, - bool InUsingDeclaration = false); + bool ParseOptionalBSCGenericSpecifier( + CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHasErrors, + bool EnteringContext, bool *MayBePseudoDestructor = nullptr, + bool IsTypename = false, IdentifierInfo **LastII = nullptr, + bool OnlyNamespace = false, bool InUsingDeclaration = false); //===--------------------------------------------------------------------===// // C++11 5.1.2: Lambda expressions @@ -3318,13 +3314,12 @@ private: AccessSpecifier AS); // DEV: ADD BSC-ParseTemplateDeclarationOrSpecialization Decl *ParseBSCGenericDeclaration(DeclaratorContext Context, - SourceLocation &DeclEnd, - ParsedAttributes &AccessAttrs, - AccessSpecifier AS); - Decl *ParseTemplateDeclarationOrSpecializationBSCCompact(DeclaratorContext Context, - SourceLocation &DeclEnd, - ParsedAttributes &AccessAttrs, - AccessSpecifier AS); + SourceLocation &DeclEnd, + ParsedAttributes &AccessAttrs, + AccessSpecifier AS); + Decl *ParseTemplateDeclarationOrSpecializationBSCCompact( + DeclaratorContext Context, SourceLocation &DeclEnd, + ParsedAttributes &AccessAttrs, AccessSpecifier AS); Decl *ParseSingleDeclarationAfterTemplate( DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject &DiagsFromParams, SourceLocation &DeclEnd, @@ -3334,22 +3329,25 @@ private: SourceLocation &LAngleLoc, SourceLocation &RAngleLoc); // DEV: Declare ParseBSCTemplateParameters - bool ParseBSCTemplateParameters(MultiParseScope &TemplateScopes, unsigned Depth, - SmallVectorImpl &TemplateParams, - SourceLocation &LAngleLoc, - SourceLocation &RAngleLoc, - int &lookAheadOffset); + bool ParseBSCTemplateParameters(MultiParseScope &TemplateScopes, + unsigned Depth, + SmallVectorImpl &TemplateParams, + SourceLocation &LAngleLoc, + SourceLocation &RAngleLoc, + int &lookAheadOffset); bool ParseTemplateParameterList(unsigned Depth, SmallVectorImpl &TemplateParams); // DEV: Declare ParseBSCTemplateParameterList - bool ParseBSCTemplateParameterList(unsigned Depth, - SmallVectorImpl &TemplateParams, - int &lookAheadOffset); + bool + ParseBSCTemplateParameterList(unsigned Depth, + SmallVectorImpl &TemplateParams, + int &lookAheadOffset); TPResult isStartOfTemplateTypeParameter(); NamedDecl *ParseTemplateParameter(unsigned Depth, unsigned Position); NamedDecl *ParseTypeParameter(unsigned Depth, unsigned Position); // DEV: Declare ParseBSCTypeParameter - NamedDecl *ParseBSCTypeParameter(unsigned Depth, unsigned Position, int &lookAheadOffset); + NamedDecl *ParseBSCTypeParameter(unsigned Depth, unsigned Position, + int &lookAheadOffset); NamedDecl *ParseTemplateTemplateParameter(unsigned Depth, unsigned Position); NamedDecl *ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position); bool isTypeConstraintAnnotation(); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index c884da9f94b2..41a048207817 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9295,12 +9295,10 @@ public: CXXRecordDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs); - bool - InstantiateClass(SourceLocation PointOfInstantiation, - RecordDecl *Instantiation, RecordDecl *Pattern, - const MultiLevelTemplateArgumentList &TemplateArgs, - TemplateSpecializationKind TSK, - bool Complain = true); + bool InstantiateClass(SourceLocation PointOfInstantiation, + RecordDecl *Instantiation, RecordDecl *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK, bool Complain = true); bool InstantiateEnum(SourceLocation PointOfInstantiation, EnumDecl *Instantiation, EnumDecl *Pattern, diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index 81af1a12a7c3..e908b96fadd5 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -461,8 +461,7 @@ enum class TemplateSubstitutionKind : char { }; class TemplateDeclInstantiator // yt: Key for BSC. - : public DeclVisitor - { + : public DeclVisitor { Sema &SemaRef; Sema::ArgumentPackSubstitutionIndexRAII SubstIndex; DeclContext *Owner; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 86f719831c93..4dd74f9e40e0 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -881,7 +881,8 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( CXXABI *ASTContext::createCXXABI(const TargetInfo &T) { // BSC Mark: add BSC language judgement. - if (!(LangOpts.CPlusPlus || LangOpts.BSC)) return nullptr; + if (!(LangOpts.CPlusPlus || LangOpts.BSC)) + return nullptr; switch (T.getCXXABI().getKind()) { case TargetCXXABI::AppleARM64: diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index e03bc9ff617e..229db10173d0 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -1563,9 +1563,13 @@ void DeclContext::addHiddenDecl(Decl *D) { // Notify a C++ record declaration that we've added a member, so it can // update its class-specific state. - // DEV: Only CXXRecordDecl supports addedMember(), Clang assume only C++ supports template-structure, - // BSC template-structure reuses CXX.. logic, each RecordDecl need to be checked. - if (D->getASTContext().getLangOpts().CPlusPlus) { // LangOpts().CPlusPlus does not work at here + // DEV: Only CXXRecordDecl supports addedMember(), Clang assume only C++ + // supports template-structure, + // BSC template-structure reuses CXX.. logic, each RecordDecl need to be + // checked. + if (D->getASTContext() + .getLangOpts() + .CPlusPlus) { // LangOpts().CPlusPlus does not work at here if (auto *Record = dyn_cast(this)) Record->addedMember(D); } diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp index d3056a3edec3..8a6e30167a08 100644 --- a/clang/lib/AST/Mangle.cpp +++ b/clang/lib/AST/Mangle.cpp @@ -123,7 +123,8 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) { // In BSC, generic function always does mangling. if (getASTContext().getLangOpts().BSC) { if (auto FD = dyn_cast(D)) { - return FD->getTemplatedKind() == FunctionDecl::TemplatedKind::TK_FunctionTemplateSpecialization; + return FD->getTemplatedKind() == + FunctionDecl::TemplatedKind::TK_FunctionTemplateSpecialization; } } diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 8d2f415ff269..90bac15c5b48 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -189,7 +189,9 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() { for (const CXXBaseSpecifier &Base : Class->bases()) { const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); - if (BaseDecl->getASTContext().getLangOpts().CPlusPlus) { // Only C++ supports getSizeOfLargestEmptySubobject() + if (BaseDecl->getASTContext() + .getLangOpts() + .CPlusPlus) { // Only C++ supports getSizeOfLargestEmptySubobject() CharUnits EmptySize; const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl); if (BaseDecl->isEmpty()) { @@ -214,7 +216,10 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() { if (!RT) continue; - if (FD->getASTContext().getLangOpts().CPlusPlus) { // DEV: Only C++ supports getSizeOfLargestEmptySubobject() + if (FD->getASTContext() + .getLangOpts() + .CPlusPlus) { // DEV: Only C++ supports + // getSizeOfLargestEmptySubobject() CharUnits EmptySize; const CXXRecordDecl *MemberDecl = RT->getAsCXXRecordDecl(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl); diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 9a97a629617d..3e6a72f882d0 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -897,7 +897,8 @@ void Preprocessor::Lex(Token &Result) { ReturnedToken = CurTokenLexer->Lex(Result); break; case CLK_CachingLexer: - CachingLex(Result); // in ConsumeToken(),read Token from global Cache, therefore, token consumption is linear + CachingLex(Result); // in ConsumeToken(),read Token from global Cache, + // therefore, token consumption is linear ReturnedToken = true; break; case CLK_LexAfterModuleImport: diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 901d9474f27f..7bcb4c8703ff 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1661,7 +1661,8 @@ Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, case tok::kw_template: case tok::kw_export: ProhibitAttributes(attrs); - SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); // C++ template function parsing branch + SingleDecl = ParseDeclarationStartingWithTemplate( + Context, DeclEnd, attrs); // C++ template function parsing branch break; case tok::kw_inline: // Could be the start of an inline namespace. Allowed as an ext in C++03. @@ -1688,7 +1689,8 @@ Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, // TODO: change if statement entrance condition, abandon isBSCTemplateDecl() if (isBSCTemplateDecl(Tok)) { ProhibitAttributes(attrs); - SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); // OK: ClassTemplateDecl with RecordDecl. + SingleDecl = ParseDeclarationStartingWithTemplate( + Context, DeclEnd, attrs); // OK: ClassTemplateDecl with RecordDecl. break; } @@ -3391,7 +3393,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (Tok.isNot(tok::identifier)) continue; ParsedAttributesWithRange Attrs(AttrFactory); - if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) { // template parameter "T" in BSC might be miss-parsed here | when? + if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, + Attrs)) { // template parameter "T" in BSC might be + // miss-parsed here | when? if (!Attrs.empty()) { AttrsLastTime = true; attrs.takeAllFrom(Attrs); @@ -3953,7 +3957,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___interface: case tok::kw_union: { tok::TokenKind Kind = Tok.getKind(); - ConsumeToken(); // consume 'struct' keyword + ConsumeToken(); // consume 'struct' keyword // These are attributes following class specifiers. // To produce better diagnostic, we parse them when @@ -5955,8 +5959,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // BSC Mark: Add language judgement for BSC template situation. // add BSC entrance condition! - if ((getLangOpts().CPlusPlus || getLangOpts().BSC) - && D.mayHaveIdentifier()) { + if ((getLangOpts().CPlusPlus || getLangOpts().BSC) && D.mayHaveIdentifier()) { // This might be a C++17 structured binding. if (Tok.is(tok::l_square) && !D.mayOmitIdentifier() && D.getCXXScopeSpec().isEmpty()) @@ -5976,7 +5979,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) { D.getContext() == DeclaratorContext::Member; ParseOptionalCXXScopeSpecifier( D.getCXXScopeSpec(), /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, EnteringContext); // BSC compacity problem exists, non-critic + /*ObjectHadErrors=*/false, + EnteringContext); // BSC compacity problem exists, non-critic } if (D.getCXXScopeSpec().isValid()) { @@ -6233,8 +6237,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // BSC Mark: Add language judgement for BSC template situation. // Change branch entering condition | BSC syntax reusing C++ parsing code - if ((getLangOpts().CPlusPlus || getLangOpts().BSC) - && D.mayBeFollowedByCXXDirectInit()) { + if ((getLangOpts().CPlusPlus || getLangOpts().BSC) && + D.mayBeFollowedByCXXDirectInit()) { // The name of the declarator, if any, is tentatively declared within // a possible direct initializer. TentativelyDeclaredIdentifiers.push_back(D.getIdentifier()); @@ -6595,8 +6599,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D, LocalEndLoc = RParenLoc; EndLoc = RParenLoc; - // Change branch entering condition | reusing C++ parse code when parsing BSC syntax - // if (getLangOpts().CPlusPlus) { + // Change branch entering condition | reusing C++ parse code when parsing + // BSC syntax if (getLangOpts().CPlusPlus) { if (getLangOpts().CPlusPlus || getLangOpts().BSC) { // FIXME: Accept these components in any order, and produce fixits to // correct the order if the user gets it wrong. Ideally we should deal diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index a87a38527f42..c0cbf96583af 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1553,9 +1553,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, CXXScopeSpec Spec; bool HasValidSpec = true; - if (ParseOptionalCXXScopeSpecifier(Spec, /*ObjectType=*/nullptr, // After this, TokenKind is tok::annot_template_id! - /*ObjectHadErrors=*/false, - EnteringContext)) { + if (ParseOptionalCXXScopeSpecifier( + Spec, /*ObjectType=*/nullptr, // After this, TokenKind is + // tok::annot_template_id! + /*ObjectHadErrors=*/false, EnteringContext)) { DS.SetTypeSpecError(); HasValidSpec = false; } @@ -1574,9 +1575,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, CXXScopeSpec Spec; bool HasValidSpec = true; - if (ParseOptionalBSCGenericSpecifier(Spec, /*ObjectType=*/nullptr, // After this, TokenKind is tok::annot_template_id! - /*ObjectHadErrors=*/false, - EnteringContext)) { + if (ParseOptionalBSCGenericSpecifier( + Spec, /*ObjectType=*/nullptr, // After this, TokenKind is + // tok::annot_template_id! + /*ObjectHadErrors=*/false, EnteringContext)) { DS.SetTypeSpecError(); HasValidSpec = false; } @@ -1625,18 +1627,20 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, IdentifierInfo *Name = nullptr; SourceLocation NameLoc; TemplateIdAnnotation *TemplateId = nullptr; - bool isParsingBSCTemplateStruct = getLangOpts().BSC && Tok.is(tok::identifier) && NextToken().is(tok::less); + bool isParsingBSCTemplateStruct = + getLangOpts().BSC && Tok.is(tok::identifier) && NextToken().is(tok::less); if (Tok.is(tok::identifier)) { Name = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); // BSC Sturct Template Declaration may have "" syntax. - // This param list must been parsed, skip it. + // This param list must been parsed, skip it. if (isParsingBSCTemplateStruct) { while (Tok.getKind() != tok::greater) { ConsumeToken(); } - assert(TryConsumeToken(tok::greater) && "fail at comsuming BSC struct template param list!"); + assert(TryConsumeToken(tok::greater) && + "fail at comsuming BSC struct template param list!"); } if (Tok.is(tok::less) && getLangOpts().CPlusPlus) { @@ -2001,10 +2005,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, ParseCXXMemberSpecification(StartLoc, AttrFixitLoc, attrs, TagType, TagOrTempResult.get()); else { - Decl* D = nullptr; + Decl *D = nullptr; if (isParsingBSCTemplateStruct) { // TODO: add more check - D = static_cast(TagOrTempResult.get())->getTemplatedDecl(); + D = static_cast(TagOrTempResult.get()) + ->getTemplatedDecl(); } else { D = SkipBody.CheckSameAsPrevious ? SkipBody.New : TagOrTempResult.get(); } diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 7749ceb4e5f0..97a8e4eb000c 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1565,7 +1565,9 @@ Parser::ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand, ParseKind, isAddressOfOperand, NotCastExpr, isTypeCast, isVectorLiteral, NotPrimaryExpression, HasBSCScopeSpec); } - if (!(getLangOpts().CPlusPlus || getLangOpts().BSC)) { // BSC Mark: enter the type-cast check in bsc generic situation. + if (!(getLangOpts().CPlusPlus || + getLangOpts().BSC)) { // BSC Mark: enter the type-cast check in bsc + // generic situation. Diag(Tok, diag::err_expected_expression); return ExprError(); } diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 5ae4ac29ec05..73751152a2d1 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -388,14 +388,17 @@ bool Parser::ParseOptionalCXXScopeSpecifier( // nested-name-specifier identifier '::' // Token Next = NextToken(); - // Skip template template param list in template function declaration: "T max (T a, T b) {...}" + // Skip template template param list in template function declaration: "T + // max (T a, T b) {...}" // ^^^ Token Next; - bool parsingBSCTemplateFunction = getLangOpts().BSC && - Tok.is(tok::identifier) && - PP.LookAhead(0).is(tok::less) && - PP.LookAhead(1).is(tok::identifier) && // TODO: this could be missidentified from typo: "intt" - (PP.LookAhead(2).is(tok::comma) || PP.LookAhead(2).is(tok::greater)); + bool parsingBSCTemplateFunction = + getLangOpts().BSC && Tok.is(tok::identifier) && + PP.LookAhead(0).is(tok::less) && + PP.LookAhead(1).is( + tok::identifier) && // TODO: this could be missidentified from typo: + // "intt" + (PP.LookAhead(2).is(tok::comma) || PP.LookAhead(2).is(tok::greater)); if (parsingBSCTemplateFunction) { int lParenOffset = 0; Token tmpTok = PP.LookAhead(lParenOffset); @@ -407,7 +410,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier( } else { Next = NextToken(); } - + Sema::NestedNameSpecInfo IdInfo(&II, Tok.getLocation(), Next.getLocation(), ObjectType); @@ -495,7 +498,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier( // nested-name-specifier: // type-name '<' - if (Next.is(tok::less)) { // 'S', then 'S' is set to tok::annote_template_id + if (Next.is(tok::less)) { // 'S', then 'S' is set to + // tok::annote_template_id TemplateTy Template; UnqualifiedId TemplateName; @@ -582,14 +586,14 @@ bool Parser::ParseOptionalBSCGenericSpecifier( bool EnteringContext, bool *MayBePseudoDestructor, bool IsTypename, IdentifierInfo **LastII, bool OnlyNamespace, bool InUsingDeclaration) { assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && - "Call sites of this function should be guarded by checking for C++ or BSC"); + "Call sites of this function should be guarded by checking for C++ or " + "BSC"); if (Tok.is(tok::annot_cxxscope)) { assert(!LastII && "want last identifier but have already annotated scope"); assert(!MayBePseudoDestructor && "unexpected annot_cxxscope"); Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), - Tok.getAnnotationRange(), - SS); + Tok.getAnnotationRange(), SS); ConsumeAnnotationToken(); return false; } @@ -610,7 +614,7 @@ bool Parser::ParseOptionalBSCGenericSpecifier( Tok.isOneOf(tok::kw_decltype, tok::annot_decltype)) { DeclSpec DS(AttrFactory); SourceLocation DeclLoc = Tok.getLocation(); - SourceLocation EndLoc = ParseDecltypeSpecifier(DS); + SourceLocation EndLoc = ParseDecltypeSpecifier(DS); SourceLocation CCLoc; // Work around a standard defect: 'decltype(auto)::' is not a @@ -680,11 +684,12 @@ bool Parser::ParseOptionalBSCGenericSpecifier( break; } - if (TemplateName.getKind() != UnqualifiedIdKind::IK_OperatorFunctionId && + if (TemplateName.getKind() != + UnqualifiedIdKind::IK_OperatorFunctionId && TemplateName.getKind() != UnqualifiedIdKind::IK_LiteralOperatorId) { Diag(TemplateName.getSourceRange().getBegin(), diag::err_id_after_template_in_nested_name_spec) - << TemplateName.getSourceRange(); + << TemplateName.getSourceRange(); TPA.Commit(); break; } @@ -743,18 +748,13 @@ bool Parser::ParseOptionalBSCGenericSpecifier( TemplateId->NumArgs); if (TemplateId->isInvalid() || - Actions.ActOnCXXNestedNameSpecifier(getCurScope(), - SS, - TemplateId->TemplateKWLoc, - TemplateId->Template, - TemplateId->TemplateNameLoc, - TemplateId->LAngleLoc, - TemplateArgsPtr, - TemplateId->RAngleLoc, - CCLoc, - EnteringContext)) { - SourceLocation StartLoc - = SS.getBeginLoc().isValid()? SS.getBeginLoc() + Actions.ActOnCXXNestedNameSpecifier( + getCurScope(), SS, TemplateId->TemplateKWLoc, + TemplateId->Template, TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc, + CCLoc, EnteringContext)) { + SourceLocation StartLoc = SS.getBeginLoc().isValid() + ? SS.getBeginLoc() : TemplateId->TemplateNameLoc; SS.SetInvalid(SourceRange(StartLoc, CCLoc)); } @@ -776,11 +776,10 @@ bool Parser::ParseOptionalBSCGenericSpecifier( // Token Next = NextToken(); Token Next; - bool parsingBSCTemplateFunction = getLangOpts().BSC && - Tok.is(tok::identifier) && - PP.LookAhead(0).is(tok::less) && - PP.LookAhead(1).is(tok::identifier) && - (PP.LookAhead(2).is(tok::comma) || PP.LookAhead(2).is(tok::greater)); + bool parsingBSCTemplateFunction = + getLangOpts().BSC && Tok.is(tok::identifier) && + PP.LookAhead(0).is(tok::less) && PP.LookAhead(1).is(tok::identifier) && + (PP.LookAhead(2).is(tok::comma) || PP.LookAhead(2).is(tok::greater)); if (parsingBSCTemplateFunction) { int lParenOffset = 0; while (!PP.LookAhead(lParenOffset).is(tok::l_paren)) { @@ -790,7 +789,7 @@ bool Parser::ParseOptionalBSCGenericSpecifier( } else { Next = NextToken(); } - + Sema::NestedNameSpecInfo IdInfo(&II, Tok.getLocation(), Next.getLocation(), ObjectType); @@ -798,19 +797,17 @@ bool Parser::ParseOptionalBSCGenericSpecifier( // nested-name-specifier: // type-name '<' - if (Next.is(tok::less)) { // yt: 'S', next 'S' is set to tok::annote_template_id? + if (Next.is(tok::less)) { // yt: 'S', next 'S' is set to + // tok::annote_template_id? TemplateTy Template; UnqualifiedId TemplateName; TemplateName.setIdentifier(&II, Tok.getLocation()); bool MemberOfUnknownSpecialization; - if (TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS, - /*hasTemplateKeyword=*/false, - TemplateName, - ObjectType, - EnteringContext, - Template, - MemberOfUnknownSpecialization)) { + if (TemplateNameKind TNK = Actions.isTemplateName( + getCurScope(), SS, + /*hasTemplateKeyword=*/false, TemplateName, ObjectType, + EnteringContext, Template, MemberOfUnknownSpecialization)) { // If lookup didn't find anything, we treat the name as a template-name // anyway. C++20 requires this, and in prior language modes it improves // error recovery. But before we commit to this, check that we actually @@ -3120,7 +3117,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, if (!getLangOpts().CPlusPlus) { // at BSC syntax T max(T a, T b) {...} // ^ - if(getLangOpts().BSC && Tok.is(tok::less)) { + if (getLangOpts().BSC && Tok.is(tok::less)) { assert(Tok.is(tok::less) && "expected 'less' token"); while (!Tok.is(tok::greater)) { ConsumeToken(); @@ -3156,7 +3153,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, } // If the next token is a '<', we may have a template. - TemplateTy Template; + TemplateTy Template; if (Tok.is(tok::less)) return ParseUnqualifiedIdTemplateId( SS, ObjectType, ObjectHadErrors, diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index e3b3a2760045..bd91ac50195a 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -208,7 +208,8 @@ Retry: Default: default: { - if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || getLangOpts().BSC || // let `struct S s1 = {}` enter here. + if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || + getLangOpts().BSC || // let `struct S s1 = {}` enter here. (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) != ParsedStmtContext()) && (GNUAttributeLoc.isValid() || @@ -1126,7 +1127,8 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr, SafeScopeSpecifie StmtResult R; if (Tok.isNot(tok::kw___extension__)) { - R = ParseStatementOrDeclaration(Stmts, SubStmtCtx); // see `struct` in `struct S` + R = ParseStatementOrDeclaration( + Stmts, SubStmtCtx); // see `struct` in `struct S` } else { // __extension__ can start declarations and it can also be a unary // operator for expressions. Consume multiple __extension__ markers here diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index c9532a12d023..f3d598e783f0 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -46,31 +46,39 @@ Decl *Parser::ParseDeclarationStartingWithTemplate( // Parse BSC template declaration // TODO: change if statement entrance condition, abandon isBSCTemplateDecl() if (isBSCTemplateDecl(Tok)) { - return ParseBSCGenericDeclaration(Context, DeclEnd, AccessAttrs, - AS); + return ParseBSCGenericDeclaration(Context, DeclEnd, AccessAttrs, AS); } return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AccessAttrs, AS); } // DIY rewrite ParseTemplateDeclarationOrSpecialization for BSC -Decl *Parser::ParseBSCGenericDeclaration( - DeclaratorContext Context, SourceLocation &DeclEnd, - ParsedAttributes &AccessAttrs, AccessSpecifier AS) { - assert(getLangOpts().BSC && "Error enter BSC template declaration parsing function."); +Decl *Parser::ParseBSCGenericDeclaration(DeclaratorContext Context, + SourceLocation &DeclEnd, + ParsedAttributes &AccessAttrs, + AccessSpecifier AS) { + assert(getLangOpts().BSC && + "Error enter BSC template declaration parsing function."); MultiParseScope TemplateParamScopes(*this); // Tell the action that names should be checked in the context of // the declaration to come. - ParsingDeclRAIIObject - ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent); // not sure - - // Parse multiple levels of template headers within this template // make sure each parameter pass same branch & branch condition is fully considered - bool isSpecialization = true; // changed in (2), shuold be false : Kind(isSpecialization? ExplicitSpecialization : Template) - bool LastParamListWasEmpty = false; // changed in (2), should be false: Whether the last template parameter list was empty. - TemplateParameterLists ParamLists; // changed in (2), only called onece at ParamLists.push_back - TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); // changed in (2), + ParsingDeclRAIIObject ParsingTemplateParams( + *this, ParsingDeclRAIIObject::NoParent); // not sure + + // Parse multiple levels of template headers within this template // make + // sure each parameter pass same branch & branch condition is fully considered + bool isSpecialization = + true; // changed in (2), shuold be false : Kind(isSpecialization? + // ExplicitSpecialization : Template) + bool LastParamListWasEmpty = + false; // changed in (2), should be false: Whether the last template + // parameter list was empty. + TemplateParameterLists + ParamLists; // changed in (2), only called onece at ParamLists.push_back + TemplateParameterDepthRAII CurTemplateDepthTracker( + TemplateParameterDepth); // changed in (2), // Consume the 'export', if any. // no corresponding syntax SourceLocation ExportLoc; @@ -79,22 +87,26 @@ Decl *Parser::ParseBSCGenericDeclaration( // Consume the 'template', which should be here. // no corresponding syntax SourceLocation TemplateLoc; TryConsumeToken(tok::kw_template, TemplateLoc); - - int lookAheadOffset = 0; // lookAheadOffset starts from 0, assume the first token we see must not be '<' - while (!PP.LookAhead(lookAheadOffset).is(tok::less)) { // use while since the template function definition struct is not solid in BSC + + int lookAheadOffset = 0; // lookAheadOffset starts from 0, assume the first + // token we see must not be '<' + while (!PP.LookAhead(lookAheadOffset) + .is(tok::less)) { // use while since the template function + // definition struct is not solid in BSC lookAheadOffset += 1; } - assert(PP.LookAhead(lookAheadOffset).is(tok::less) && "BSC template function parameter list does not begin with tok::less"); + assert(PP.LookAhead(lookAheadOffset).is(tok::less) && + "BSC template function parameter list does not begin with tok::less"); // Parse the '<' template-parameter-list '>' SourceLocation LAngleLoc, RAngleLoc; - SmallVector TemplateParams; + SmallVector TemplateParams; if (ParseBSCTemplateParameters(TemplateParamScopes, - CurTemplateDepthTracker.getDepth(), - TemplateParams, LAngleLoc, RAngleLoc, - lookAheadOffset)) { // open this + CurTemplateDepthTracker.getDepth(), + TemplateParams, LAngleLoc, RAngleLoc, + lookAheadOffset)) { // open this // Skip until the semi-colon or a '}'. - SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); // error handel + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); // error handel TryConsumeToken(tok::semi); return nullptr; } @@ -102,9 +114,9 @@ Decl *Parser::ParseBSCGenericDeclaration( ExprResult OptionalRequiresClauseConstraintER; if (!TemplateParams.empty()) { isSpecialization = false; // keep this - ++CurTemplateDepthTracker; // keep this + ++CurTemplateDepthTracker; // keep this - if (TryConsumeToken(tok::kw_requires)) { // C++ concept-requries clause + if (TryConsumeToken(tok::kw_requires)) { // C++ concept-requries clause OptionalRequiresClauseConstraintER = Actions.ActOnRequiresClause(ParseConstraintLogicalOrExpression( /*IsTrailingRequiresClause=*/false)); @@ -119,24 +131,28 @@ Decl *Parser::ParseBSCGenericDeclaration( LastParamListWasEmpty = true; } - ParamLists.push_back(Actions.ActOnTemplateParameterList( // make sure parameters input is same as C++, for both func and struct - CurTemplateDepthTracker.getDepth(), ExportLoc, TemplateLoc, LAngleLoc, - TemplateParams, RAngleLoc, OptionalRequiresClauseConstraintER.get())); + ParamLists.push_back( + Actions.ActOnTemplateParameterList( // make sure parameters input is same + // as C++, for both func and struct + CurTemplateDepthTracker.getDepth(), ExportLoc, TemplateLoc, LAngleLoc, + TemplateParams, RAngleLoc, OptionalRequiresClauseConstraintER.get())); // Parse the actual template declaration. - if (Tok.is(tok::kw_concept)) // C++ concept-requires clause, no corresponding syntax in BSC - return ParseConceptDefinition( - ParsedTemplateInfo(&ParamLists, isSpecialization, - LastParamListWasEmpty), - DeclEnd); - - return ParseSingleDeclarationAfterTemplate( // make sure parameters input is same as C++, for both func and struct + if (Tok.is(tok::kw_concept)) // C++ concept-requires clause, no corresponding + // syntax in BSC + return ParseConceptDefinition(ParsedTemplateInfo(&ParamLists, + isSpecialization, + LastParamListWasEmpty), + DeclEnd); + + return ParseSingleDeclarationAfterTemplate( // make sure parameters input is + // same as C++, for both func and + // struct Context, ParsedTemplateInfo(&ParamLists, isSpecialization, LastParamListWasEmpty), ParsingTemplateParams, DeclEnd, AccessAttrs, AS); } - /// Parse a template declaration or an explicit specialization. /// /// Template declarations include one or more template parameter lists @@ -559,8 +575,8 @@ bool Parser::ParseTemplateParameters( return false; } - -// ParseBSCTemplateParameters - rewrite ParseTemplateParameters for cross-order BSC syntax, use Peeking +// ParseBSCTemplateParameters - rewrite ParseTemplateParameters for cross-order +// BSC syntax, use Peeking bool Parser::ParseBSCTemplateParameters( MultiParseScope &TemplateScopes, unsigned Depth, SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, @@ -573,8 +589,7 @@ bool Parser::ParseBSCTemplateParameters( if (peekTok.is(tok::less)) { lookAheadOffset += 1; LAngleLoc = peekTok.getLocation(); - } - else { + } else { Diag(peekTok.getLocation(), diag::err_expected_less_after) << "template"; return true; } @@ -589,7 +604,8 @@ bool Parser::ParseBSCTemplateParameters( // } if (!peekTok.is(tok::greater)) { TemplateScopes.Enter(Scope::TemplateParamScope); - Failed = ParseBSCTemplateParameterList(Depth, TemplateParams, lookAheadOffset); + Failed = + ParseBSCTemplateParameterList(Depth, TemplateParams, lookAheadOffset); } peekTok = PP.LookAhead(lookAheadOffset); @@ -620,7 +636,6 @@ bool Parser::ParseBSCTemplateParameters( return false; } - /// ParseTemplateParameterList - Parse a template parameter list. If /// the parsing fails badly (i.e., closing bracket was left out), this /// will try to put the token stream in a reasonable position (closing @@ -663,25 +678,25 @@ Parser::ParseTemplateParameterList(const unsigned Depth, return true; } -// ParseBSCTemplateParameterList - rewrite ParseTemplateParameterList, for cross-order BSC syntax, use Peeking -bool -Parser::ParseBSCTemplateParameterList(const unsigned Depth, - SmallVectorImpl &TemplateParams, - int &lookAheadOffset) { +// ParseBSCTemplateParameterList - rewrite ParseTemplateParameterList, for +// cross-order BSC syntax, use Peeking +bool Parser::ParseBSCTemplateParameterList( + const unsigned Depth, SmallVectorImpl &TemplateParams, + int &lookAheadOffset) { Token peekTok = PP.LookAhead(lookAheadOffset); while (1) { // if (NamedDecl *TmpParam // = ParseTemplateParameter(Depth, TemplateParams.size())) { - if (NamedDecl *TmpParam - = ParseBSCTypeParameter(Depth, TemplateParams.size(), lookAheadOffset)) { + if (NamedDecl *TmpParam = ParseBSCTypeParameter( + Depth, TemplateParams.size(), lookAheadOffset)) { TemplateParams.push_back(TmpParam); } else { // If we failed to parse a template parameter, skip until we find // a comma or closing brace. // SkipUntil(tok::comma, tok::greater, tok::greatergreater, // StopAtSemi | StopBeforeMatch); - SkipUntil(tok::comma, tok::greater, // FIXME: logic error + SkipUntil(tok::comma, tok::greater, // FIXME: logic error StopAtSemi | StopBeforeMatch); } peekTok = PP.LookAhead(lookAheadOffset); @@ -691,7 +706,7 @@ Parser::ParseBSCTemplateParameterList(const unsigned Depth, // ConsumeToken(); lookAheadOffset += 1; peekTok = PP.LookAhead(lookAheadOffset); - // } else if (peekTok.isOneOf(tok::greater, tok::greatergreater)) { + // } else if (peekTok.isOneOf(tok::greater, tok::greatergreater)) { } else if (peekTok.is(tok::greater)) { // Don't consume this... that's done by template parser. break; @@ -703,8 +718,7 @@ Parser::ParseBSCTemplateParameterList(const unsigned Depth, // SkipUntil(tok::comma, tok::greater, tok::greatergreater, // StopAtSemi | StopBeforeMatch); Diag(peekTok.getLocation(), diag::err_expected_comma_greater); - SkipUntil(tok::comma, tok::greater, - StopAtSemi | StopBeforeMatch); + SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch); return false; } } @@ -829,7 +843,8 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { Tok.getEndLoc()), "typename"); - Tok.setKind(tok::kw_typename); // unkown manipulation, rename "typedef" as "typename" + Tok.setKind(tok::kw_typename); // unkown manipulation, rename "typedef" as + // "typename" } return ParseTypeParameter(Depth, Position); @@ -861,7 +876,7 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { llvm_unreachable("template param classification can't be ambiguous"); } - // Call upper layer method recursively to parse nested template param list + // Call upper layer method recursively to parse nested template param list // template > if (Tok.is(tok::kw_template)) return ParseTemplateTemplateParameter(Depth, Position); @@ -1042,14 +1057,18 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { return NewDecl; } - -// ParseBSCTypeParameter - rewrite ParseTypeParameter for cross-order BSC syntax, use Peeking -NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, int &lookAheadOffset) { +// ParseBSCTypeParameter - rewrite ParseTypeParameter for cross-order BSC +// syntax, use Peeking +NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, + int &lookAheadOffset) { // Check Tok location Token peekTok = PP.LookAhead(lookAheadOffset); bool isBSCTemplateTypeParameter = getLangOpts().BSC; // TODO: fix the cond - //bool isBSCTemplateTypeParameter = getLangOpts().BSC && (peekTok.getKind() == tok::identifier); - assert(isBSCTemplateTypeParameter && "A type-parameter starts with 'class', 'typename' or a type-constraint"); + // bool isBSCTemplateTypeParameter = getLangOpts().BSC && (peekTok.getKind() + // == tok::identifier); + assert( + isBSCTemplateTypeParameter && + "A type-parameter starts with 'class', 'typename' or a type-constraint"); CXXScopeSpec TypeConstraintSS; TemplateIdAnnotation *TypeConstraint = nullptr; @@ -1064,14 +1083,16 @@ NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, int static_cast(peekTok.getAnnotationValue()); assert(TypeConstraint->Kind == TNK_Concept_template && "stray non-concept template-id annotation"); - // KeyLoc = ConsumeAnnotationToken(); // no annot_template_id in BSC, KeyLoc remain at init status + // KeyLoc = ConsumeAnnotationToken(); // no annot_template_id in BSC, + // KeyLoc remain at init status } else { assert(TypeConstraintSS.isEmpty() && "expected type constraint after scope specifier"); // Consume the 'class' or 'typename' keyword. TypenameKeyword = false; - // KeyLoc = ConsumeToken(); // no typename in BSC, KeyLoc remain at init status + // KeyLoc = ConsumeToken(); // no typename in BSC, KeyLoc remain at init + // status } // Grab the ellipsis (if given). @@ -1080,21 +1101,21 @@ NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, int EllipsisLoc = peekTok.getLocation(); lookAheadOffset += 1; peekTok = PP.LookAhead(lookAheadOffset); - Diag(EllipsisLoc, - getLangOpts().CPlusPlus11 - ? diag::warn_cxx98_compat_variadic_templates - : diag::ext_variadic_templates); + Diag(EllipsisLoc, getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_variadic_templates + : diag::ext_variadic_templates); } // Grab the template parameter name (if given) SourceLocation NameLoc = peekTok.getLocation(); IdentifierInfo *ParamName = nullptr; if (peekTok.is(tok::identifier)) { - ParamName = peekTok.getIdentifierInfo(); // unknown manipulation, parsing T token + ParamName = + peekTok.getIdentifierInfo(); // unknown manipulation, parsing T token lookAheadOffset += 1; peekTok = PP.LookAhead(lookAheadOffset); } else if (peekTok.isOneOf(tok::equal, tok::comma, tok::greater, - tok::greatergreater)) { + tok::greatergreater)) { // Unnamed template parameter. Don't have to do anything here, just // don't consume this token. } else { @@ -1125,12 +1146,9 @@ NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, int .get(); } - NamedDecl *NewDecl = Actions.ActOnTypeParameter(getCurScope(), - TypenameKeyword, EllipsisLoc, - KeyLoc, ParamName, NameLoc, - Depth, Position, EqualLoc, - DefaultArg, - TypeConstraint != nullptr); + NamedDecl *NewDecl = Actions.ActOnTypeParameter( + getCurScope(), TypenameKeyword, EllipsisLoc, KeyLoc, ParamName, NameLoc, + Depth, Position, EqualLoc, DefaultArg, TypeConstraint != nullptr); if (TypeConstraint) { Actions.ActOnTypeConstraint(TypeConstraintSS, TypeConstraint, @@ -1141,7 +1159,6 @@ NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, int return NewDecl; } - /// ParseTemplateTemplateParameter - Handle the parsing of template /// template parameters. /// @@ -1531,7 +1548,8 @@ Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken, tok::greatergreatergreater, tok::greaterequal, tok::greatergreaterequal)) // BSC Mark: Template arguments will be parsed at here. - // Pay attention to this API if we want to figure out how template arguements being parsed. + // Pay attention to this API if we want to figure out how template + // arguements being parsed. Invalid = ParseTemplateArgumentList(TemplateArgs); if (Invalid) { @@ -1596,8 +1614,8 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, UnqualifiedId &TemplateName, bool AllowTypeAnnotation, bool TypeConstraint) { - assert((getLangOpts().CPlusPlus || getLangOpts().BSC) - && "Can only annotate template-ids in C++"); + assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && + "Can only annotate template-ids in C++"); assert((Tok.is(tok::less) || TypeConstraint) && "Parser isn't at the beginning of a template-id"); assert(!(TypeConstraint && AllowTypeAnnotation) && "type-constraint can't be " @@ -1615,9 +1633,10 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, bool ArgsInvalid = false; if (!TypeConstraint || Tok.is(tok::less)) { // BSC Mark: The template args will be parsed at here. - // Pay attention to this API if we want to figure out how template arguements being parsed. + // Pay attention to this API if we want to figure out how template + // arguements being parsed. // @Code: - // int res = max(a, b); + // int res = max(a, b); // ^^^^^^^^^^^^ <-these are template args ArgsInvalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc, TemplateArgs, RAngleLoc); @@ -1879,7 +1898,8 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { do { // BSC Mark: Template arguments will be parsed at here. - // Pay attention to this API if we want to figure out how template arguements being parsed. + // Pay attention to this API if we want to figure out how template + // arguements being parsed. ParsedTemplateArgument Arg = ParseTemplateArgument(); SourceLocation EllipsisLoc; if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 381cfb2e50f8..d0c52c37f763 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1117,18 +1117,24 @@ bool Parser::isBSCTemplateDecl(Token tok) { return false; // 2. check "Foo<>" structure // ^^^^ - int MaxLessTokenLookAheadOffset = 6; // tok::less must appear with in 6 more token: "static inline unsigned long long Foo<" + int MaxLessTokenLookAheadOffset = + 6; // tok::less must appear with in 6 more token: "static inline unsigned + // long long Foo<" int LessOffset = 0; bool FoundLess = false; Token prevTok = tok; Token tmpTok = PP.LookAhead(LessOffset); // FIXME: below for-loop not verified - for (LessOffset = 1; LessOffset <= MaxLessTokenLookAheadOffset && !PP.LookAhead(LessOffset).is(tok::eof); LessOffset++) { - if (tmpTok.is(tok::l_paren) || tmpTok.is(tok::l_brace) || tmpTok.is(tok::equal)) // "<>" must appear neighboring with function/struct identtifier - return false; + for (LessOffset = 1; LessOffset <= MaxLessTokenLookAheadOffset && + !PP.LookAhead(LessOffset).is(tok::eof); + LessOffset++) { + if (tmpTok.is(tok::l_paren) || tmpTok.is(tok::l_brace) || + tmpTok.is(tok::equal)) // "<>" must appear neighboring with + // function/struct identtifier + return false; if (tmpTok.is(tok::less) && prevTok.is(tok::identifier)) { FoundLess = true; - break; // when ">" missing, leave tis diagnose work in deeper api. + break; // when ">" missing, leave tis diagnose work in deeper api. } prevTok = tmpTok; tmpTok = PP.LookAhead(LessOffset); @@ -1139,13 +1145,17 @@ bool Parser::isBSCTemplateDecl(Token tok) { // ^^^ int LBraceOffset = 1; tmpTok = PP.LookAhead(LessOffset + LBraceOffset); - for (; !tmpTok.is(tok::eof); LBraceOffset++) { // check "Foo<>" structure + for (; !tmpTok.is(tok::eof); LBraceOffset++) { // check "Foo<>" structure tmpTok = PP.LookAhead(LessOffset + LBraceOffset); - if (tmpTok.is(tok::l_paren)) // might be function declaration, skip current check + if (tmpTok.is( + tok::l_paren)) // might be function declaration, skip current check break; - if (tmpTok.is(tok::semi) || tmpTok.is(tok::equal)) // no "{" in current sentence + if (tmpTok.is(tok::semi) || + tmpTok.is(tok::equal)) // no "{" in current sentence return false; - if (tmpTok.is(tok::l_brace) || tmpTok.is(tok::r_brace)) { // l_brace could missing, pass this for latter diagnose + if (tmpTok.is(tok::l_brace) || + tmpTok.is(tok::r_brace)) { // l_brace could missing, pass this for + // latter diagnose return true; } } @@ -1153,21 +1163,25 @@ bool Parser::isBSCTemplateDecl(Token tok) { // ^^ ^^^ int LParenOffset = 1; tmpTok = PP.LookAhead(LessOffset + LParenOffset); - for (; !tmpTok.is(tok::eof); LParenOffset++) { // check "Foo<>" structure + for (; !tmpTok.is(tok::eof); LParenOffset++) { // check "Foo<>" structure tmpTok = PP.LookAhead(LessOffset + LParenOffset); - if (tmpTok.is(tok::semi) || tmpTok.is(tok::equal)) // no "{" in current sentence + if (tmpTok.is(tok::semi) || + tmpTok.is(tok::equal)) // no "{" in current sentence return false; if (tmpTok.is(tok::l_paren)) { - break; // when ")" missing, leave tis diagnose work in deeper api. + break; // when ")" missing, leave tis diagnose work in deeper api. } } LBraceOffset = 1; tmpTok = PP.LookAhead(LessOffset + LParenOffset + LBraceOffset); - for (; !tmpTok.is(tok::eof); LBraceOffset++) { // check "Foo<>" structure + for (; !tmpTok.is(tok::eof); LBraceOffset++) { // check "Foo<>" structure tmpTok = PP.LookAhead(LessOffset + LParenOffset + LBraceOffset); - if (tmpTok.is(tok::semi) || tmpTok.is(tok::equal)) // no "{" in current sentence + if (tmpTok.is(tok::semi) || + tmpTok.is(tok::equal)) // no "{" in current sentence return false; - if (tmpTok.is(tok::l_brace) || tmpTok.is(tok::r_brace)) { // l_brace could missing, pass this for latter diagnose + if (tmpTok.is(tok::l_brace) || + tmpTok.is(tok::r_brace)) { // l_brace could missing, pass this for + // latter diagnose return true; } } diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 3feda7af91d5..d55273eca156 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -922,7 +922,8 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::kw__Static_assert: // A function definition cannot start with any of these keywords. { - // entrance of parsing template function parameter list “template ” + // entrance of parsing template function parameter list “template + // ” SourceLocation DeclEnd; return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs); } @@ -981,7 +982,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::kw_module: Diag(Tok, diag::err_unexpected_module_decl); SkipUntil(tok::semi); - return nullptr; + return nullptr; default: dont_know: // parse BSC template declaration @@ -992,7 +993,6 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs); break; } - if (Tok.isEditorPlaceholder()) { ConsumeToken(); @@ -1662,7 +1662,7 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) { const bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope); CXXScopeSpec SS; - // BSC Mark: Add BSC language judgement, when instantiates BSC template + // BSC Mark: Add BSC language judgement, when instantiates BSC template // function without LHS and "=", we need enter this. // @Code // int main(){ foo(1, 2); } @@ -1976,7 +1976,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() { CXXScopeSpec SS; // BSC Mark: Add BSC language judgement. - // This will help us parse the instantiation + // This will help us parse the instantiation // part of BSC template situation. if (getLangOpts().CPlusPlus || getLangOpts().BSC) if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, @@ -2106,7 +2106,8 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS, /// as the current tokens, so only call it in contexts where these are invalid. bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && - "Call sites of this function should be guarded by checking for C++ and BSC"); + "Call sites of this function should be guarded by checking for C++ " + "and BSC"); assert(MightBeCXXScopeToken() && "Cannot be a type or scope token!"); CXXScopeSpec SS; diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 0661a258e7f8..660cc8a7a360 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -2690,7 +2690,9 @@ static void DiagnoseBadFunctionCast(Sema &Self, const ExprResult &SrcExpr, /// Check the semantics of a C-style cast operation, in C. void CastOperation::CheckCStyleCast() { - assert(!Self.getLangOpts().CPlusPlus); // BSC Mark: BSC C-Style cast check should enter here. + assert( + !Self.getLangOpts() + .CPlusPlus); // BSC Mark: BSC C-Style cast check should enter here. // C-style casts can resolve __unknown_any types. if (claimPlaceholder(BuiltinType::UnknownAny)) { @@ -3084,9 +3086,9 @@ ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo, Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getEndLoc()); // BSC Mark: try to use C-Style cast check for BSC generic. - if (getLangOpts().BSC){ + if (getLangOpts().BSC) { Op.CheckCStyleCast(); - if (Op.SrcExpr.isInvalid()){ + if (Op.SrcExpr.isInvalid()) { return ExprError(); } } else { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 4274e42e308f..9f4119db45ed 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -909,7 +909,8 @@ Corrected: if (SS.isEmpty() && NextToken.is(tok::l_paren)) { // In C++, this is an ADL-only call. // FIXME: Reference? - if (getLangOpts().CPlusPlus || getLangOpts().BSC) // BSC Mark: key of check undefined function name. + if (getLangOpts().CPlusPlus || + getLangOpts().BSC) // BSC Mark: key of check undefined function name. return NameClassification::UndeclaredNonType(); // C90 6.3.2.2: @@ -1201,7 +1202,9 @@ Corrected: ExprResult Sema::ActOnNameClassifiedAsUndeclaredNonType(IdentifierInfo *Name, SourceLocation NameLoc) { - assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && "ADL-only call in C?"); // BSC Mark: key of check undefined function name. + assert( + (getLangOpts().CPlusPlus || getLangOpts().BSC) && + "ADL-only call in C?"); // BSC Mark: key of check undefined function name. CXXScopeSpec SS; LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true); @@ -4631,7 +4634,8 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, return ActOnFriendTypeDecl(S, DS, TemplateParams); } - const CXXScopeSpec &SS = DS.getTypeSpecScope(); // what happens to BSC? We dont have the CXXScopeSpec. + const CXXScopeSpec &SS = DS.getTypeSpecScope(); // what happens to BSC? We + // dont have the CXXScopeSpec. bool IsExplicitSpecialization = !TemplateParams.empty() && TemplateParams.back()->size() == 0; if (Tag && SS.isNotEmpty() && !Tag->isCompleteDefinition() && @@ -9307,7 +9311,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // or an overloaded operator, then set the pure flag (isVirtual will already // return true). if (const CXXRecordDecl *Parent = - dyn_cast(NewFD->getDeclContext())) { + dyn_cast(NewFD->getDeclContext())) { if (Parent->isInterface() && cast(NewFD)->isUserProvided()) NewFD->setPure(true); @@ -9333,8 +9337,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId ? D.getName().TemplateId : nullptr, - TemplateParamLists, isFriend, isMemberSpecialization, - Invalid); + TemplateParamLists, isFriend, isMemberSpecialization, Invalid); if (TemplateParams) { // Check that we can declare a template here. if (CheckTemplateDeclScope(S, TemplateParams)) @@ -9358,18 +9361,16 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, Invalid = true; } - FunctionTemplate = FunctionTemplateDecl::Create(Context, DC, - NewFD->getLocation(), - Name, TemplateParams, - NewFD); + FunctionTemplate = FunctionTemplateDecl::Create( + Context, DC, NewFD->getLocation(), Name, TemplateParams, NewFD); FunctionTemplate->setLexicalDeclContext(CurContext); NewFD->setDescribedFunctionTemplate(FunctionTemplate); // For source fidelity, store the other template param lists. if (TemplateParamLists.size() > 1) { - NewFD->setTemplateParameterListsInfo(Context, - ArrayRef(TemplateParamLists) - .drop_back(1)); + NewFD->setTemplateParameterListsInfo( + Context, ArrayRef(TemplateParamLists) + .drop_back(1)); } } else { // This is a function template specialization. @@ -9395,9 +9396,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } Diag(D.getIdentifierLoc(), diag::err_template_spec_decl_friend) - << Name << RemoveRange - << FixItHint::CreateRemoval(RemoveRange) - << FixItHint::CreateInsertion(InsertLoc, "<>"); + << Name << RemoveRange << FixItHint::CreateRemoval(RemoveRange) + << FixItHint::CreateInsertion(InsertLoc, "<>"); } } } else { @@ -9418,7 +9418,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (FunctionTemplate) FunctionTemplate->setInvalidDecl(); } - + // If a function is defined as defaulted or deleted, mark it as such now. // We'll do the relevant checks on defaulted / deleted functions later. switch (D.getFunctionDefinitionKind()) { @@ -9654,26 +9654,23 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->getReturnType().hasNonTrivialToPrimitiveCopyCUnion()) checkNonTrivialCUnion(NewFD->getReturnType(), NewFD->getReturnTypeSourceRange().getBegin(), - NTCUC_FunctionReturn, NTCUK_Destruct|NTCUK_Copy); - + NTCUC_FunctionReturn, NTCUK_Destruct | NTCUK_Copy); + // BSC Mark: We need this API for BSC template situation. // If we have a function template, check the template parameter // list. This will check and merge default template arguments. if (FunctionTemplate) { - FunctionTemplateDecl *PrevTemplate = - FunctionTemplate->getPreviousDecl(); - CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(), - PrevTemplate ? PrevTemplate->getTemplateParameters() - : nullptr, - D.getDeclSpec().isFriendSpecified() - ? (D.isFunctionDefinition() - ? TPC_FriendFunctionTemplateDefinition - : TPC_FriendFunctionTemplate) - : (D.getCXXScopeSpec().isSet() && - DC && DC->isRecord() && - DC->isDependentContext()) - ? TPC_ClassTemplateMember - : TPC_FunctionTemplate); + FunctionTemplateDecl *PrevTemplate = FunctionTemplate->getPreviousDecl(); + CheckTemplateParameterList( + FunctionTemplate->getTemplateParameters(), + PrevTemplate ? PrevTemplate->getTemplateParameters() : nullptr, + D.getDeclSpec().isFriendSpecified() + ? (D.isFunctionDefinition() ? TPC_FriendFunctionTemplateDefinition + : TPC_FriendFunctionTemplate) + : (D.getCXXScopeSpec().isSet() && DC && DC->isRecord() && + DC->isDependentContext()) + ? TPC_ClassTemplateMember + : TPC_FunctionTemplate); } } else { // C++11 [replacement.functions]p3: @@ -15654,11 +15651,13 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, return nullptr; OwnedDecl = false; - DeclResult Result = CheckClassTemplate( // for 'struct S' it will enter here too. - S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attrs, TemplateParams, - AS, ModulePrivateLoc, - /*FriendLoc*/ SourceLocation(), TemplateParameterLists.size() - 1, - TemplateParameterLists.data(), SkipBody); + DeclResult Result = + CheckClassTemplate( // for 'struct S' it will enter here too. + S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attrs, + TemplateParams, AS, ModulePrivateLoc, + /*FriendLoc*/ SourceLocation(), + TemplateParameterLists.size() - 1, + TemplateParameterLists.data(), SkipBody); return Result.get(); } else { // The "template<>" header is extraneous. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 2fb614de536a..a09c98d1a6c5 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6513,11 +6513,11 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, // Determine whether this is a dependent call inside a C++ template, // in which case we won't do any semantic analysis now. if (Fn->isTypeDependent() || Expr::hasAnyTypeDependentArguments(ArgExprs)) { - tryImplicitlyCaptureThisIfImplicitMemberFunctionAccessWithDependentArgs( - *this, dyn_cast(Fn->IgnoreParens()), - Fn->getBeginLoc()); - return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy, - VK_RValue, RParenLoc, CurFPFeatureOverrides()); + tryImplicitlyCaptureThisIfImplicitMemberFunctionAccessWithDependentArgs( + *this, dyn_cast(Fn->IgnoreParens()), + Fn->getBeginLoc()); + return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy, + VK_RValue, RParenLoc, CurFPFeatureOverrides()); } } @@ -8250,12 +8250,12 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // C++ is sufficiently different to merit its own checker. if (getLangOpts().CPlusPlus) return CXXCheckConditionalOperands(Cond, LHS, RHS, VK, OK, QuestionLoc); - + // BSC Mark: We do this for BSC template situation. // This avoids errors during the comparison phase. if (getLangOpts().BSC && (Cond.get()->isTypeDependent() || LHS.get()->isTypeDependent() || - RHS.get()->isTypeDependent())) + RHS.get()->isTypeDependent())) return CXXCheckConditionalOperands(Cond, LHS, RHS, VK, OK, QuestionLoc); VK = VK_RValue; diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index a1a369674555..7e724bf20a1d 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -2827,7 +2827,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { // namespaces of its associated classes. case Type::Record: { // BSC Mark: try to avoid cast. - if(Result.S.getLangOpts().BSC){ + if (Result.S.getLangOpts().BSC) { break; } CXXRecordDecl *Class = diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index ca41b550e8f9..0428c7620524 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -8060,7 +8060,6 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, } } } - } } /// Helper function for adjusting address spaces for the pointer or reference @@ -8114,7 +8113,7 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { return VRQuals; } - if(Context.getLangOpts().BSC) { + if (Context.getLangOpts().BSC) { // BSC Mark: Don`t do anything here to avoid cast. } else { CXXRecordDecl *ClassDecl = cast(TyRec->getDecl()); @@ -8137,7 +8136,7 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { if (const PointerType *ResTypePtr = CanTy->getAs()) CanTy = ResTypePtr->getPointeeType(); else if (const MemberPointerType *ResTypeMPtr = - CanTy->getAs()) + CanTy->getAs()) CanTy = ResTypeMPtr->getPointeeType(); else done = true; @@ -8149,7 +8148,7 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { } } } - + return VRQuals; } @@ -12981,7 +12980,9 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn, llvm_unreachable("performing ADL for builtin"); // We don't perform ADL in C. - assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && "ADL enabled in C"); // BSC Mark: key of check undefined function name. + assert( + (getLangOpts().CPlusPlus || getLangOpts().BSC) && + "ADL enabled in C"); // BSC Mark: key of check undefined function name. } #endif diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index d73254a048fc..b17e71352bec 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -176,8 +176,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S, TemplateTy &TemplateResult, bool &MemberOfUnknownSpecialization, bool Disambiguation) { - assert((getLangOpts().CPlusPlus || getLangOpts().BSC) - && "No template names in C!"); + assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && + "No template names in C!"); DeclarationName TName; MemberOfUnknownSpecialization = false; @@ -1953,14 +1953,16 @@ DeclResult Sema::CheckClassTemplate( = !(TUK == TUK_Friend && CurContext->isDependentContext()); RecordDecl *NewClass; - if(getLangOpts().CPlusPlus) { - NewClass = - CXXRecordDecl::Create(Context, Kind, SemanticContext, KWLoc, NameLoc, Name, - PrevClassTemplate && ShouldAddRedecl ? - PrevClassTemplate->getTemplatedDecl() : nullptr, - /*DelayTypeCreation=*/true); + if (getLangOpts().CPlusPlus) { + NewClass = CXXRecordDecl::Create(Context, Kind, SemanticContext, KWLoc, + NameLoc, Name, + PrevClassTemplate && ShouldAddRedecl + ? PrevClassTemplate->getTemplatedDecl() + : nullptr, + /*DelayTypeCreation=*/true); } else { - NewClass = RecordDecl::Create(Context, Kind, SemanticContext, KWLoc, NameLoc, Name); + NewClass = RecordDecl::Create(Context, Kind, SemanticContext, KWLoc, + NameLoc, Name); } SetNestedNameSpecifier(*this, NewClass, SS); if (NumOuterTemplateParamLists > 0) @@ -1976,15 +1978,16 @@ DeclResult Sema::CheckClassTemplate( } ClassTemplateDecl *NewTemplate // [2]: ClassTemplateDecl is created - = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, - DeclarationName(Name), TemplateParams, - NewClass); + = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, + DeclarationName(Name), TemplateParams, + NewClass); if (ShouldAddRedecl) NewTemplate->setPreviousDecl(PrevClassTemplate); if (!getLangOpts().BSC) { - static_cast(NewClass)->setDescribedClassTemplate(NewTemplate); + static_cast(NewClass)->setDescribedClassTemplate( + NewTemplate); } if (ModulePrivateLoc.isValid()) @@ -1993,7 +1996,8 @@ DeclResult Sema::CheckClassTemplate( // Build the type for the class template declaration now. if (!getLangOpts().BSC) { QualType T = NewTemplate->getInjectedClassNameSpecialization(); - T = Context.getInjectedClassNameType(static_cast(NewClass), T); + T = Context.getInjectedClassNameType(static_cast(NewClass), + T); assert(T->isDependentType() && "Class template type is not dependent?"); (void)T; } @@ -2022,7 +2026,7 @@ DeclResult Sema::CheckClassTemplate( AddPushedVisibilityAttribute(NewClass); if (!getLangOpts().BSC) { - inferGslOwnerPointerAttribute(static_cast(NewClass)); + inferGslOwnerPointerAttribute(static_cast(NewClass)); } if (TUK != TUK_Friend) { diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 3ba32fd9ae3c..53fabf25abe9 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2621,18 +2621,17 @@ namespace clang { /// to the lack of a definition. /// /// \returns true if an error occurred, false otherwise. -bool -Sema::InstantiateClass(SourceLocation PointOfInstantiation, - RecordDecl *Instantiation, RecordDecl *Pattern, - const MultiLevelTemplateArgumentList &TemplateArgs, - TemplateSpecializationKind TSK, - bool Complain) { - RecordDecl *PatternDef - = cast_or_null(Pattern->getDefinition()); +bool Sema::InstantiateClass(SourceLocation PointOfInstantiation, + RecordDecl *Instantiation, RecordDecl *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK, bool Complain) { + RecordDecl *PatternDef = cast_or_null(Pattern->getDefinition()); if (getLangOpts().CPlusPlus) { - if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Instantiation, - (static_cast(Instantiation))->getInstantiatedFromMemberClass(), - Pattern, PatternDef, TSK, Complain)) + if (DiagnoseUninstantiableTemplate( + PointOfInstantiation, Instantiation, + (static_cast(Instantiation)) + ->getInstantiatedFromMemberClass(), + Pattern, PatternDef, TSK, Complain)) return true; } @@ -2648,18 +2647,20 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Record the point of instantiation. if (getLangOpts().CPlusPlus) { - if(MemberSpecializationInfo *MSInfo - = (static_cast(Instantiation))->getMemberSpecializationInfo()) { + if (MemberSpecializationInfo *MSInfo = + (static_cast(Instantiation)) + ->getMemberSpecializationInfo()) { MSInfo->setTemplateSpecializationKind(TSK); MSInfo->setPointOfInstantiation(PointOfInstantiation); - } - else if (ClassTemplateSpecializationDecl *Spec - = dyn_cast(Instantiation)) { // yt: should be true for BSC + } else if (ClassTemplateSpecializationDecl *Spec = + dyn_cast( + Instantiation)) { // yt: should be true for BSC Spec->setTemplateSpecializationKind(TSK); Spec->setPointOfInstantiation(PointOfInstantiation); } - } else if (ClassTemplateSpecializationDecl *Spec - = dyn_cast(Instantiation)) { // yt: should be true for BSC + } else if (ClassTemplateSpecializationDecl *Spec = + dyn_cast( + Instantiation)) { // yt: should be true for BSC Spec->setTemplateSpecializationKind(TSK); Spec->setPointOfInstantiation(PointOfInstantiation); } @@ -2704,7 +2705,9 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Do substitution on the base class specifiers. if (getLangOpts().CPlusPlus) { - if (SubstBaseSpecifiers(static_cast(Instantiation), static_cast(Pattern), TemplateArgs)) + if (SubstBaseSpecifiers(static_cast(Instantiation), + static_cast(Pattern), + TemplateArgs)) Instantiation->setInvalidDecl(); } @@ -2741,7 +2744,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, continue; } - Decl *NewMember = Instantiator.Visit(Member); // yt: (1)before: Member 'T a;' (2)after: NewMember 'int a;' + Decl *NewMember = Instantiator.Visit( + Member); // yt: (1)before: Member 'T a;' (2)after: NewMember 'int a;' if (NewMember) { if (FieldDecl *Field = dyn_cast(NewMember)) { Fields.push_back(Field); @@ -2765,8 +2769,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, break; } } else if (CXXMethodDecl *MD = dyn_cast(NewMember)) { - if (getLangOpts().CPlusPlus && MD->isConstexpr() && !MD->getFriendObjectKind() && - (MD->isVirtualAsWritten() || (static_cast(Instantiation))->getNumBases())) + if (getLangOpts().CPlusPlus && MD->isConstexpr() && + !MD->getFriendObjectKind() && + (MD->isVirtualAsWritten() || + (static_cast(Instantiation))->getNumBases())) MightHaveConstexprVirtualFunctions = true; } @@ -2783,8 +2789,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Finish checking fields. ActOnFields(nullptr, Instantiation->getLocation(), Instantiation, Fields, SourceLocation(), SourceLocation(), ParsedAttributesView()); - if(getLangOpts().CPlusPlus) { - CheckCompletedCXXClass(nullptr, (static_cast(Instantiation))); // FIXME: make it work for BSC RecordDecl + if (getLangOpts().CPlusPlus) { + CheckCompletedCXXClass( + nullptr, (static_cast( + Instantiation))); // FIXME: make it work for BSC RecordDecl } // Default arguments are parsed, if not instantiated. We can go instantiate @@ -2868,12 +2876,14 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // of a polymorphic class template specialization. Otherwise, eagerly // instantiate only constexpr virtual functions in preparation for their use // in constant evaluation. - if(getLangOpts().CPlusPlus) { + if (getLangOpts().CPlusPlus) { if (TSK == TSK_ExplicitInstantiationDefinition) - MarkVTableUsed(PointOfInstantiation, (static_cast(Instantiation)), true); + MarkVTableUsed(PointOfInstantiation, + (static_cast(Instantiation)), true); else if (MightHaveConstexprVirtualFunctions) - MarkVirtualMembersReferenced(PointOfInstantiation, static_cast(Instantiation), - /*ConstexprOnly*/ true); + MarkVirtualMembersReferenced( + PointOfInstantiation, static_cast(Instantiation), + /*ConstexprOnly*/ true); } } @@ -3057,8 +3067,7 @@ bool Sema::usesPartialOrExplicitSpecialization( /// Get the instantiation pattern to use to instantiate the definition of a /// given ClassTemplateSpecializationDecl (either the pattern of the primary /// template or of a partial specialization). -static ActionResult -getPatternForClassTemplateSpecialization( +static ActionResult getPatternForClassTemplateSpecialization( Sema &S, SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, TemplateSpecializationKind TSK) { diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 5a97a46ddfde..63de3858d779 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8619,7 +8619,7 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, // If we have a class template specialization or a class member of a // class template specialization, or an array with known size of such, // try to instantiate it. - RecordDecl* RD = nullptr; + RecordDecl *RD = nullptr; if (getLangOpts().BSC) { RD = dyn_cast_or_null(Tag); } else { @@ -8643,18 +8643,20 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, Instantiated = true; } } else { - CXXRecordDecl *Pattern = (static_cast(RD))->getInstantiatedFromMemberClass(); + CXXRecordDecl *Pattern = + (static_cast(RD))->getInstantiatedFromMemberClass(); if (!RD->isBeingDefined() && Pattern) { - MemberSpecializationInfo *MSI = (static_cast(RD))->getMemberSpecializationInfo(); + MemberSpecializationInfo *MSI = + (static_cast(RD))->getMemberSpecializationInfo(); assert(MSI && "Missing member specialization information?"); // This record was instantiated from a class within a template. if (MSI->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) { runWithSufficientStackSpace(Loc, [&] { - Diagnosed = InstantiateClass(Loc, (static_cast(RD)), Pattern, - getTemplateInstantiationArgs(RD), - TSK_ImplicitInstantiation, - /*Complain=*/Diagnoser); + Diagnosed = InstantiateClass( + Loc, (static_cast(RD)), Pattern, + getTemplateInstantiationArgs(RD), TSK_ImplicitInstantiation, + /*Complain=*/Diagnoser); }); Instantiated = true; } -- Gitee From 4b6cbf4d3daf8910ab0650a6cf889bc7c348010c Mon Sep 17 00:00:00 2001 From: Aperzer Date: Tue, 11 Apr 2023 19:55:07 +0800 Subject: [PATCH 20/22] [generic] fix comments of PR This commit is to fix the comments of generic`s first PR. Including but not limited to: refactoring API, delete useless remark, etc. Test cases has been run, no new issues introduced. --- clang/include/clang/Sema/Template.h | 2 +- clang/lib/AST/ASTContext.cpp | 2 +- clang/lib/Parse/ParseDecl.cpp | 10 ++++------ clang/lib/Parse/ParseDeclCXX.cpp | 19 +++++++++--------- clang/lib/Parse/ParseExpr.cpp | 5 ++--- clang/lib/Parse/ParseExprCXX.cpp | 12 +++++------ clang/lib/Parse/ParseStmt.cpp | 2 +- clang/lib/Parse/ParseTemplate.cpp | 15 +++----------- clang/lib/Parse/Parser.cpp | 12 ++++++----- clang/lib/Sema/SemaCast.cpp | 14 +++++-------- clang/lib/Sema/SemaDecl.cpp | 21 ++++++++++---------- clang/lib/Sema/SemaExpr.cpp | 23 +++++----------------- clang/lib/Sema/SemaLookup.cpp | 2 +- clang/lib/Sema/SemaOverload.cpp | 14 +++++-------- clang/lib/Sema/SemaTemplate.cpp | 4 ++-- clang/lib/Sema/SemaTemplateInstantiate.cpp | 12 +++++------ 16 files changed, 67 insertions(+), 102 deletions(-) diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index e908b96fadd5..a49881ca45b7 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -460,7 +460,7 @@ enum class TemplateSubstitutionKind : char { bool isLocalPackExpansion(const Decl *D); }; - class TemplateDeclInstantiator // yt: Key for BSC. + class TemplateDeclInstantiator : public DeclVisitor { Sema &SemaRef; Sema::ArgumentPackSubstitutionIndexRAII SubstIndex; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 4dd74f9e40e0..154a9bdb3883 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -880,7 +880,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( } CXXABI *ASTContext::createCXXABI(const TargetInfo &T) { - // BSC Mark: add BSC language judgement. + // Add BSC judgement to pass language check of generic. if (!(LangOpts.CPlusPlus || LangOpts.BSC)) return nullptr; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 7bcb4c8703ff..f324e86557a8 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1689,8 +1689,7 @@ Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, // TODO: change if statement entrance condition, abandon isBSCTemplateDecl() if (isBSCTemplateDecl(Tok)) { ProhibitAttributes(attrs); - SingleDecl = ParseDeclarationStartingWithTemplate( - Context, DeclEnd, attrs); // OK: ClassTemplateDecl with RecordDecl. + SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); break; } @@ -3380,7 +3379,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isConstructorDeclarator(/*Unqualified*/true)) goto DoneWithDeclSpec; - ParsedType TypeRep = Actions.getTypeName( // `T a;` resolve T now + ParsedType TypeRep = Actions.getTypeName( *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), nullptr, false, false, nullptr, false, false, isClassTemplateDeductionContext(DSContext)); @@ -5957,8 +5956,7 @@ static SourceLocation getMissingDeclaratorIdLoc(Declarator &D, void Parser::ParseDirectDeclarator(Declarator &D) { DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec()); - // BSC Mark: Add language judgement for BSC template situation. - // add BSC entrance condition! + // Add language judgement for BSC template entrance. if ((getLangOpts().CPlusPlus || getLangOpts().BSC) && D.mayHaveIdentifier()) { // This might be a C++17 structured binding. if (Tok.is(tok::l_square) && !D.mayOmitIdentifier() && @@ -6235,7 +6233,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { bool IsAmbiguous = false; // if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) { - // BSC Mark: Add language judgement for BSC template situation. + // Add language judgement for BSC template entrance. // Change branch entering condition | BSC syntax reusing C++ parsing code if ((getLangOpts().CPlusPlus || getLangOpts().BSC) && D.mayBeFollowedByCXXDirectInit()) { diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index c0cbf96583af..8f537531a57e 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1553,10 +1553,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, CXXScopeSpec Spec; bool HasValidSpec = true; - if (ParseOptionalCXXScopeSpecifier( - Spec, /*ObjectType=*/nullptr, // After this, TokenKind is - // tok::annot_template_id! - /*ObjectHadErrors=*/false, EnteringContext)) { + if (ParseOptionalCXXScopeSpecifier(Spec, /*ObjectType=*/nullptr, + /*ObjectHadErrors=*/false, + EnteringContext)) { DS.SetTypeSpecError(); HasValidSpec = false; } @@ -1569,16 +1568,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, SS = Spec; } - // BSC Mark: 'struct S s1' should enter here + // Generic struct 'struct S s1' should enter here. if (getLangOpts().BSC) { ColonProtectionRAIIObject X(*this); CXXScopeSpec Spec; bool HasValidSpec = true; - if (ParseOptionalBSCGenericSpecifier( - Spec, /*ObjectType=*/nullptr, // After this, TokenKind is - // tok::annot_template_id! - /*ObjectHadErrors=*/false, EnteringContext)) { + if (ParseOptionalBSCGenericSpecifier(Spec, /*ObjectType=*/nullptr, + /*ObjectHadErrors=*/false, + EnteringContext)) { DS.SetTypeSpecError(); HasValidSpec = false; } @@ -1844,7 +1842,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, bool Owned = false; Sema::SkipBodyInfo SkipBody; - if (TemplateId) { // specialization for BSC generic: `struct S` + if (TemplateId) { + // specialization for BSC generic: `struct S` // Explicit specialization, class template partial specialization, // or explicit instantiation. ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 97a8e4eb000c..66aecbee5f11 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1565,9 +1565,8 @@ Parser::ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand, ParseKind, isAddressOfOperand, NotCastExpr, isTypeCast, isVectorLiteral, NotPrimaryExpression, HasBSCScopeSpec); } - if (!(getLangOpts().CPlusPlus || - getLangOpts().BSC)) { // BSC Mark: enter the type-cast check in bsc - // generic situation. + // Enter the type-cast check in bsc generic. + if (!(getLangOpts().CPlusPlus || getLangOpts().BSC)) { Diag(Tok, diag::err_expected_expression); return ExprError(); } diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 73751152a2d1..5b4e9a77137e 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -498,8 +498,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier( // nested-name-specifier: // type-name '<' - if (Next.is(tok::less)) { // 'S', then 'S' is set to - // tok::annote_template_id + if (Next.is(tok::less)) { TemplateTy Template; UnqualifiedId TemplateName; @@ -579,8 +578,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier( return false; } -// BSC Mark: parse instation for struct part of generic, -// to avoid affecting the original logic of C++ +// Parse instation for bsc struct part of generic, to avoid affecting +// the original logic of C++. bool Parser::ParseOptionalBSCGenericSpecifier( CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors, bool EnteringContext, bool *MayBePseudoDestructor, bool IsTypename, @@ -797,8 +796,7 @@ bool Parser::ParseOptionalBSCGenericSpecifier( // nested-name-specifier: // type-name '<' - if (Next.is(tok::less)) { // yt: 'S', next 'S' is set to - // tok::annote_template_id? + if (Next.is(tok::less)) { TemplateTy Template; UnqualifiedId TemplateName; @@ -823,7 +821,7 @@ bool Parser::ParseOptionalBSCGenericSpecifier( // specializations) still want to see the original template-id // token, and it might not be a type at all (e.g. a concept name in a // type-constraint). - ConsumeToken(); // yt: Cpp template specialization enter here + ConsumeToken(); if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), TemplateName, false)) return true; diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index bd91ac50195a..e582c7ae51ac 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -209,7 +209,7 @@ Retry: Default: default: { if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || - getLangOpts().BSC || // let `struct S s1 = {}` enter here. + getLangOpts().BSC || (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) != ParsedStmtContext()) && (GNUAttributeLoc.isValid() || diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index f3d598e783f0..2977768d38cf 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -1547,9 +1547,7 @@ Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken, if (!Tok.isOneOf(tok::greater, tok::greatergreater, tok::greatergreatergreater, tok::greaterequal, tok::greatergreaterequal)) - // BSC Mark: Template arguments will be parsed at here. - // Pay attention to this API if we want to figure out how template - // arguements being parsed. + // Template arguments will be parsed at here. Invalid = ParseTemplateArgumentList(TemplateArgs); if (Invalid) { @@ -1632,12 +1630,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, TemplateArgList TemplateArgs; bool ArgsInvalid = false; if (!TypeConstraint || Tok.is(tok::less)) { - // BSC Mark: The template args will be parsed at here. - // Pay attention to this API if we want to figure out how template - // arguements being parsed. - // @Code: - // int res = max(a, b); - // ^^^^^^^^^^^^ <-these are template args + // The template args will be parsed at here. ArgsInvalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc, TemplateArgs, RAngleLoc); // If we couldn't recover from invalid arguments, don't form an annotation @@ -1897,9 +1890,7 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { ColonProtectionRAIIObject ColonProtection(*this, false); do { - // BSC Mark: Template arguments will be parsed at here. - // Pay attention to this API if we want to figure out how template - // arguements being parsed. + // Template arguments will be parsed at here. ParsedTemplateArgument Arg = ParseTemplateArgument(); SourceLocation EllipsisLoc; if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index d55273eca156..28f6b6e86a73 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -23,6 +23,7 @@ #include "llvm/Support/Path.h" using namespace clang; + namespace { /// A comment handler that passes comments found by the preprocessor /// to the parser action. @@ -1662,10 +1663,12 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) { const bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope); CXXScopeSpec SS; - // BSC Mark: Add BSC language judgement, when instantiates BSC template + // Add BSC language judgement, when instantiates BSC template // function without LHS and "=", we need enter this. // @Code - // int main(){ foo(1, 2); } + // int main() { + // foo(1, 2); + // } if ((getLangOpts().CPlusPlus || getLangOpts().BSC) && ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, /*ObjectHadErrors=*/false, @@ -1975,9 +1978,8 @@ bool Parser::TryAnnotateTypeOrScopeToken() { bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope); CXXScopeSpec SS; - // BSC Mark: Add BSC language judgement. - // This will help us parse the instantiation - // part of BSC template situation. + // Add BSC language judgement. This will help us parse + // the instantiation part of BSC template situation. if (getLangOpts().CPlusPlus || getLangOpts().BSC) if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, /*ObjectHadErrors=*/false, diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 660cc8a7a360..ff5071e6c63a 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -2690,9 +2690,7 @@ static void DiagnoseBadFunctionCast(Sema &Self, const ExprResult &SrcExpr, /// Check the semantics of a C-style cast operation, in C. void CastOperation::CheckCStyleCast() { - assert( - !Self.getLangOpts() - .CPlusPlus); // BSC Mark: BSC C-Style cast check should enter here. + assert(!Self.getLangOpts().CPlusPlus); // C-style casts can resolve __unknown_any types. if (claimPlaceholder(BuiltinType::UnknownAny)) { @@ -3085,16 +3083,14 @@ ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo, Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange(); Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getEndLoc()); - // BSC Mark: try to use C-Style cast check for BSC generic. + // Try to use C-Style cast check for BSC generic. if (getLangOpts().BSC) { Op.CheckCStyleCast(); - if (Op.SrcExpr.isInvalid()) { - return ExprError(); - } } else { Op.CheckCXXCStyleCast(/*FunctionalCast=*/true, /*ListInit=*/false); - if (Op.SrcExpr.isInvalid()) - return ExprError(); + } + if (Op.SrcExpr.isInvalid()) { + return ExprError(); } auto *SubExpr = Op.SrcExpr.get(); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 9f4119db45ed..72307ccc9160 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -909,8 +909,8 @@ Corrected: if (SS.isEmpty() && NextToken.is(tok::l_paren)) { // In C++, this is an ADL-only call. // FIXME: Reference? - if (getLangOpts().CPlusPlus || - getLangOpts().BSC) // BSC Mark: key of check undefined function name. + // In BSC, this is the key of check undefined function name. + if (getLangOpts().CPlusPlus || getLangOpts().BSC) return NameClassification::UndeclaredNonType(); // C90 6.3.2.2: @@ -1202,9 +1202,10 @@ Corrected: ExprResult Sema::ActOnNameClassifiedAsUndeclaredNonType(IdentifierInfo *Name, SourceLocation NameLoc) { + // In BSC, this is the entrance of checking undefined function name. assert( (getLangOpts().CPlusPlus || getLangOpts().BSC) && - "ADL-only call in C?"); // BSC Mark: key of check undefined function name. + "ADL-only call in C?"); CXXScopeSpec SS; LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true); @@ -4574,7 +4575,7 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, DS.getTypeSpecType() == DeclSpec::TST_interface || DS.getTypeSpecType() == DeclSpec::TST_union || DS.getTypeSpecType() == DeclSpec::TST_enum) { - TagD = DS.getRepAsDecl(); // ClassTemplateDecl: struct S {T a}; + TagD = DS.getRepAsDecl(); if (!TagD) // We probably had an error return nullptr; @@ -4585,7 +4586,7 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, if (isa(TagD)) Tag = cast(TagD); else if (ClassTemplateDecl *CTD = dyn_cast(TagD)) - Tag = CTD->getTemplatedDecl(); // RecordDecl: struct S{T a;}; + Tag = CTD->getTemplatedDecl(); } if (Tag) { @@ -4634,8 +4635,7 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, return ActOnFriendTypeDecl(S, DS, TemplateParams); } - const CXXScopeSpec &SS = DS.getTypeSpecScope(); // what happens to BSC? We - // dont have the CXXScopeSpec. + const CXXScopeSpec &SS = DS.getTypeSpecScope(); bool IsExplicitSpecialization = !TemplateParams.empty() && TemplateParams.back()->size() == 0; if (Tag && SS.isNotEmpty() && !Tag->isCompleteDefinition() && @@ -9294,7 +9294,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, FPT->getExtProtoInfo().withExceptionSpec(EST_BasicNoexcept))); } - // BSC Mark: This is for BSC template case. + // Refactor C++ logic for BSC template. if (getLangOpts().BSC) { bool isInline = D.getDeclSpec().isInlineSpecified(); bool isVirtual = D.getDeclSpec().isVirtualSpecified(); @@ -9656,7 +9656,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->getReturnTypeSourceRange().getBegin(), NTCUC_FunctionReturn, NTCUK_Destruct | NTCUK_Copy); - // BSC Mark: We need this API for BSC template situation. + // We need this API for BSC template situation. // If we have a function template, check the template parameter // list. This will check and merge default template arguments. if (FunctionTemplate) { @@ -10069,7 +10069,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, CompleteMemberSpecialization(NewFD, Previous); } - // BSC Mark: This is for BSC template case. // This can return a 'FunctionTemplateDecl' for the AST Context. if (getLangOpts().BSC) { if (FunctionTemplate) { @@ -15652,7 +15651,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, OwnedDecl = false; DeclResult Result = - CheckClassTemplate( // for 'struct S' it will enter here too. + CheckClassTemplate( S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attrs, TemplateParams, AS, ModulePrivateLoc, /*FriendLoc*/ SourceLocation(), diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index a09c98d1a6c5..c176f13aa954 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6502,7 +6502,7 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, } } - // BSC Mark: This branch is for when attempting to parse a function-call + // This branch is for attempting to parse a function-call // in the body of template function. Such as: // @Code: // T1 Misc(T1 a, T2 b) @@ -8251,7 +8251,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, if (getLangOpts().CPlusPlus) return CXXCheckConditionalOperands(Cond, LHS, RHS, VK, OK, QuestionLoc); - // BSC Mark: We do this for BSC template situation. + // We do this for BSC template situation. // This avoids errors during the comparison phase. if (getLangOpts().BSC && (Cond.get()->isTypeDependent() || LHS.get()->isTypeDependent() || @@ -14583,22 +14583,9 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, RHSExpr = resolvedRHS.get(); } - if (getLangOpts().CPlusPlus) { - // If either expression is type-dependent, always build an - // overloaded op. - if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent()) - return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); - - // Otherwise, build an overloaded op if either expression has an - // overloadable type. - if (LHSExpr->getType()->isOverloadableType() || - RHSExpr->getType()->isOverloadableType()) - return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); - } - - // BSC Mark: This is for BSC template situation. - // API "isTypeDependent()" only deal with template situation. - if (getLangOpts().BSC) { + // Add BSC judgement, this will help we delay the check if + // the expression is type-dependent. + if (getLangOpts().CPlusPlus || getLangOpts().BSC) { // If either expression is type-dependent, always build an // overloaded op. if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent()) diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 7e724bf20a1d..abddcc09c3fb 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -2826,7 +2826,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { // Its associated namespaces are the innermost enclosing // namespaces of its associated classes. case Type::Record: { - // BSC Mark: try to avoid cast. + // Try to avoid cast to avoid segfault. if (Result.S.getLangOpts().BSC) { break; } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 0428c7620524..a0116dcd0c3e 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -8040,9 +8040,8 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, if (!SemaRef.isCompleteType(Loc, Ty)) return; - if (SemaRef.getLangOpts().BSC) { - // BSC Mark: Don`t do anything here to avoid cast. - } else { + // Don`t do anything here to avoid cast if is BSC. + if (!SemaRef.getLangOpts().BSC) { CXXRecordDecl *ClassDecl = cast(TyRec->getDecl()); for (NamedDecl *D : ClassDecl->getVisibleConversionFunctions()) { if (isa(D)) @@ -8113,9 +8112,8 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { return VRQuals; } - if (Context.getLangOpts().BSC) { - // BSC Mark: Don`t do anything here to avoid cast. - } else { + // Don`t do anything here to avoid cast if is BSC. + if (!Context.getLangOpts().BSC) { CXXRecordDecl *ClassDecl = cast(TyRec->getDecl()); if (!ClassDecl->hasDefinition()) return VRQuals; @@ -12980,9 +12978,7 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn, llvm_unreachable("performing ADL for builtin"); // We don't perform ADL in C. - assert( - (getLangOpts().CPlusPlus || getLangOpts().BSC) && - "ADL enabled in C"); // BSC Mark: key of check undefined function name. + assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && "ADL enabled in C"); } #endif diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index b17e71352bec..a6f8866edbdb 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1966,7 +1966,7 @@ DeclResult Sema::CheckClassTemplate( } SetNestedNameSpecifier(*this, NewClass, SS); if (NumOuterTemplateParamLists > 0) - NewClass->setTemplateParameterListsInfo( // [1]: set template parameters + NewClass->setTemplateParameterListsInfo( Context, llvm::makeArrayRef(OuterTemplateParamLists, NumOuterTemplateParamLists)); @@ -1977,7 +1977,7 @@ DeclResult Sema::CheckClassTemplate( AddMsStructLayoutForRecord(NewClass); } - ClassTemplateDecl *NewTemplate // [2]: ClassTemplateDecl is created + ClassTemplateDecl *NewTemplate = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, DeclarationName(Name), TemplateParams, NewClass); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 53fabf25abe9..7c10a152bc99 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2654,13 +2654,13 @@ bool Sema::InstantiateClass(SourceLocation PointOfInstantiation, MSInfo->setPointOfInstantiation(PointOfInstantiation); } else if (ClassTemplateSpecializationDecl *Spec = dyn_cast( - Instantiation)) { // yt: should be true for BSC + Instantiation)) { Spec->setTemplateSpecializationKind(TSK); Spec->setPointOfInstantiation(PointOfInstantiation); } } else if (ClassTemplateSpecializationDecl *Spec = dyn_cast( - Instantiation)) { // yt: should be true for BSC + Instantiation)) { Spec->setTemplateSpecializationKind(TSK); Spec->setPointOfInstantiation(PointOfInstantiation); } @@ -2694,7 +2694,7 @@ bool Sema::InstantiateClass(SourceLocation PointOfInstantiation, InstantiateAttrs(TemplateArgs, Pattern, Instantiation); // Start the definition of this instantiation. - Instantiation->startDefinition(); // yt: start the instantiation! + Instantiation->startDefinition(); // The instantiation is visible here, even if it was first declared in an // unimported module. @@ -2745,7 +2745,7 @@ bool Sema::InstantiateClass(SourceLocation PointOfInstantiation, } Decl *NewMember = Instantiator.Visit( - Member); // yt: (1)before: Member 'T a;' (2)after: NewMember 'int a;' + Member); if (NewMember) { if (FieldDecl *Field = dyn_cast(NewMember)) { Fields.push_back(Field); @@ -3183,7 +3183,7 @@ static ActionResult getPatternForClassTemplateSpecialization( } } - RecordDecl *Pattern = nullptr; // yt: RecordDecl for BSC. + RecordDecl *Pattern = nullptr; Specialized = ClassTemplateSpec->getSpecializedTemplateOrPartial(); if (auto *PartialSpec = Specialized.dyn_cast()) { @@ -3227,7 +3227,7 @@ bool Sema::InstantiateClassTemplateSpecialization( if (ClassTemplateSpec->isInvalidDecl()) return true; - ActionResult Pattern = // yt: here BSC is RecordDecl + ActionResult Pattern = getPatternForClassTemplateSpecialization(*this, PointOfInstantiation, ClassTemplateSpec, TSK); if (!Pattern.isUsable()) -- Gitee From 9e496f59858184f3de7ff3c448021de3d743a359 Mon Sep 17 00:00:00 2001 From: qinziang Date: Wed, 12 Apr 2023 22:10:15 +0800 Subject: [PATCH 21/22] [generic] fix comments for PR, follow-up This commit is a response to the PR review of generic, follow-up the previous commit. This commit modifies comments, refactors API, etc. No new issues introduced. --- clang/include/clang/Basic/TokenKinds.h | 13 -- clang/include/clang/Lex/Token.h | 5 - clang/include/clang/Parse/Parser.h | 6 +- clang/lib/AST/DeclBase.cpp | 2 +- clang/lib/AST/RecordLayoutBuilder.cpp | 57 +++---- clang/lib/Lex/Preprocessor.cpp | 3 +- clang/lib/Parse/ParseDecl.cpp | 7 +- clang/lib/Parse/ParseDeclCXX.cpp | 14 +- clang/lib/Parse/ParseExprCXX.cpp | 17 +- clang/lib/Parse/ParseStmt.cpp | 2 +- clang/lib/Parse/ParseTemplate.cpp | 33 +--- clang/lib/Parse/ParseTentative.cpp | 58 +++---- clang/lib/Parse/Parser.cpp | 9 +- clang/lib/Sema/SemaCast.cpp | 2 +- clang/lib/Sema/SemaDecl.cpp | 172 +------------------- clang/lib/Sema/SemaExpr.cpp | 2 +- clang/lib/Sema/SemaOverload.cpp | 3 +- clang/lib/Sema/SemaTemplate.cpp | 7 +- clang/lib/Sema/SemaTemplateInstantiate.cpp | 14 +- clang/test/BSC/Method/Linkage/queue.hbs.gch | Bin 0 -> 213368 bytes 20 files changed, 98 insertions(+), 328 deletions(-) create mode 100644 clang/test/BSC/Method/Linkage/queue.hbs.gch diff --git a/clang/include/clang/Basic/TokenKinds.h b/clang/include/clang/Basic/TokenKinds.h index e763ee19bca7..4e66aa1c8c2d 100644 --- a/clang/include/clang/Basic/TokenKinds.h +++ b/clang/include/clang/Basic/TokenKinds.h @@ -73,19 +73,6 @@ inline bool isAnyIdentifier(TokenKind K) { return (K == tok::identifier) || (K == tok::raw_identifier); } -/// Return true if this token kind could be type specifier. -inline bool isAnyTypeSpecifierKind(TokenKind K) { - // Type Specifier: see c11 spec 6.7.2 - return (K == tok::kw__Atomic) || (K == tok::kw_union) || - (K == tok::kw_struct) || (K == tok::kw_class) || (K == tok::kw_enum) || - (K == tok::kw_typedef) || (K == tok::kw__Complex) || - (K == tok::kw_void) || (K == tok::kw_bool) || (K == tok::kw__Bool) || - (K == tok::kw_char) || (K == tok::kw_short) || (K == tok::kw_int) || - (K == tok::kw_long) || (K == tok::kw_float) || (K == tok::kw_double) || - (K == tok::kw_signed) || (K == tok::kw_unsigned) || - (K == tok::identifier); -} - /// Return true if this is a C or C++ string-literal (or /// C++11 user-defined-string-literal) token. inline bool isStringLiteral(TokenKind K) { diff --git a/clang/include/clang/Lex/Token.h b/clang/include/clang/Lex/Token.h index 819da8734245..89042a674fec 100644 --- a/clang/include/clang/Lex/Token.h +++ b/clang/include/clang/Lex/Token.h @@ -110,11 +110,6 @@ public: return tok::isAnyIdentifier(getKind()); } - /// Return true if this token kind could be type specifier. - bool isAnyTypeSpecifierKind() const { - return tok::isAnyTypeSpecifierKind(getKind()); - } - /// Return true if this is a "literal", like a numeric /// constant, string, etc. bool isLiteral() const { diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 4516ec6e24f5..577256730ea4 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2566,7 +2566,6 @@ private: /// during a tentative parse, but also should not be annotated as a non-type. bool isTentativelyDeclared(IdentifierInfo *II); - // DEV: Determine whether Tok at BSC template declaration clause. bool isBSCTemplateDecl(Token tok); // "Tentative parsing" functions, used for disambiguation. If a parsing error @@ -3312,7 +3311,7 @@ private: SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, AccessSpecifier AS); - // DEV: ADD BSC-ParseTemplateDeclarationOrSpecialization + // BSC style ParseTemplateDeclarationOrSpecialization Decl *ParseBSCGenericDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, @@ -3328,7 +3327,6 @@ private: SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, SourceLocation &RAngleLoc); - // DEV: Declare ParseBSCTemplateParameters bool ParseBSCTemplateParameters(MultiParseScope &TemplateScopes, unsigned Depth, SmallVectorImpl &TemplateParams, @@ -3337,7 +3335,6 @@ private: int &lookAheadOffset); bool ParseTemplateParameterList(unsigned Depth, SmallVectorImpl &TemplateParams); - // DEV: Declare ParseBSCTemplateParameterList bool ParseBSCTemplateParameterList(unsigned Depth, SmallVectorImpl &TemplateParams, @@ -3345,7 +3342,6 @@ private: TPResult isStartOfTemplateTypeParameter(); NamedDecl *ParseTemplateParameter(unsigned Depth, unsigned Position); NamedDecl *ParseTypeParameter(unsigned Depth, unsigned Position); - // DEV: Declare ParseBSCTypeParameter NamedDecl *ParseBSCTypeParameter(unsigned Depth, unsigned Position, int &lookAheadOffset); NamedDecl *ParseTemplateTemplateParameter(unsigned Depth, unsigned Position); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 229db10173d0..705edd198c02 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -1563,7 +1563,7 @@ void DeclContext::addHiddenDecl(Decl *D) { // Notify a C++ record declaration that we've added a member, so it can // update its class-specific state. - // DEV: Only CXXRecordDecl supports addedMember(), Clang assume only C++ + // Only CXXRecordDecl supports addedMember(), Clang assume only C++ // supports template-structure, // BSC template-structure reuses CXX.. logic, each RecordDecl need to be // checked. diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 90bac15c5b48..9dd426e877f9 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -189,22 +189,21 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() { for (const CXXBaseSpecifier &Base : Class->bases()) { const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); - if (BaseDecl->getASTContext() - .getLangOpts() - .CPlusPlus) { // Only C++ supports getSizeOfLargestEmptySubobject() - CharUnits EmptySize; - const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl); - if (BaseDecl->isEmpty()) { - // If the class decl is empty, get its size. - EmptySize = Layout.getSize(); - } else { - // Otherwise, we get the largest empty subobject for the decl. - EmptySize = Layout.getSizeOfLargestEmptySubobject(); - } + if (!BaseDecl->getASTContext().getLangOpts().CPlusPlus) + continue; - if (EmptySize > SizeOfLargestEmptySubobject) - SizeOfLargestEmptySubobject = EmptySize; + CharUnits EmptySize; + const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl); + if (BaseDecl->isEmpty()) { + // If the class decl is empty, get its size. + EmptySize = Layout.getSize(); + } else { + // Otherwise, we get the largest empty subobject for the decl. + EmptySize = Layout.getSizeOfLargestEmptySubobject(); } + + if (EmptySize > SizeOfLargestEmptySubobject) + SizeOfLargestEmptySubobject = EmptySize; } // Check the fields. @@ -216,24 +215,22 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() { if (!RT) continue; - if (FD->getASTContext() - .getLangOpts() - .CPlusPlus) { // DEV: Only C++ supports - // getSizeOfLargestEmptySubobject() - CharUnits EmptySize; - const CXXRecordDecl *MemberDecl = RT->getAsCXXRecordDecl(); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl); - if (MemberDecl->isEmpty()) { - // If the class decl is empty, get its size. - EmptySize = Layout.getSize(); - } else { - // Otherwise, we get the largest empty subobject for the decl. - EmptySize = Layout.getSizeOfLargestEmptySubobject(); - } + if (!FD->getASTContext().getLangOpts().CPlusPlus) + continue; - if (EmptySize > SizeOfLargestEmptySubobject) - SizeOfLargestEmptySubobject = EmptySize; + CharUnits EmptySize; + const CXXRecordDecl *MemberDecl = RT->getAsCXXRecordDecl(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl); + if (MemberDecl->isEmpty()) { + // If the class decl is empty, get its size. + EmptySize = Layout.getSize(); + } else { + // Otherwise, we get the largest empty subobject for the decl. + EmptySize = Layout.getSizeOfLargestEmptySubobject(); } + + if (EmptySize > SizeOfLargestEmptySubobject) + SizeOfLargestEmptySubobject = EmptySize; } } diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 3e6a72f882d0..177786d90390 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -897,8 +897,7 @@ void Preprocessor::Lex(Token &Result) { ReturnedToken = CurTokenLexer->Lex(Result); break; case CLK_CachingLexer: - CachingLex(Result); // in ConsumeToken(),read Token from global Cache, - // therefore, token consumption is linear + CachingLex(Result); ReturnedToken = true; break; case CLK_LexAfterModuleImport: diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index f324e86557a8..b34a526bef6f 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1689,7 +1689,8 @@ Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, // TODO: change if statement entrance condition, abandon isBSCTemplateDecl() if (isBSCTemplateDecl(Tok)) { ProhibitAttributes(attrs); - SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); + SingleDecl = + ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); break; } @@ -6231,7 +6232,6 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // In such a case, check if we actually have a function declarator; if it // is not, the declarator has been fully parsed. bool IsAmbiguous = false; - // if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) { // Add language judgement for BSC template entrance. // Change branch entering condition | BSC syntax reusing C++ parsing code @@ -6597,8 +6597,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, LocalEndLoc = RParenLoc; EndLoc = RParenLoc; - // Change branch entering condition | reusing C++ parse code when parsing - // BSC syntax if (getLangOpts().CPlusPlus) { + // Change branch entering condition, reusing C++ parse code when parsing if (getLangOpts().CPlusPlus || getLangOpts().BSC) { // FIXME: Accept these components in any order, and produce fixits to // correct the order if the user gets it wrong. Ideally we should deal diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 8f537531a57e..d2a3b13aa165 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1553,9 +1553,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, CXXScopeSpec Spec; bool HasValidSpec = true; - if (ParseOptionalCXXScopeSpecifier(Spec, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, - EnteringContext)) { + if (ParseOptionalCXXScopeSpecifier(Spec, /*ObjectType=*/nullptr, + /*ObjectHadErrors=*/false, + EnteringContext)) { DS.SetTypeSpecError(); HasValidSpec = false; } @@ -1574,9 +1574,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, CXXScopeSpec Spec; bool HasValidSpec = true; - if (ParseOptionalBSCGenericSpecifier(Spec, /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, - EnteringContext)) { + if (ParseOptionalBSCGenericSpecifier(Spec, /*ObjectType=*/nullptr, + /*ObjectHadErrors=*/false, + EnteringContext)) { DS.SetTypeSpecError(); HasValidSpec = false; } @@ -1842,7 +1842,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, bool Owned = false; Sema::SkipBodyInfo SkipBody; - if (TemplateId) { + if (TemplateId) { // specialization for BSC generic: `struct S` // Explicit specialization, class template partial specialization, // or explicit instantiation. diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 5b4e9a77137e..e5146a52b347 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -386,20 +386,18 @@ bool Parser::ParseOptionalCXXScopeSpecifier( // type-name '::' // namespace-name '::' // nested-name-specifier identifier '::' - // Token Next = NextToken(); - // Skip template template param list in template function declaration: "T - // max (T a, T b) {...}" - // ^^^ + // Skip param list "" in template function declaration: + // "T max (T a, T b) {...}" Token Next; - bool parsingBSCTemplateFunction = + bool ParsingBSCTemplateFunction = getLangOpts().BSC && Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::less) && PP.LookAhead(1).is( tok::identifier) && // TODO: this could be missidentified from typo: // "intt" (PP.LookAhead(2).is(tok::comma) || PP.LookAhead(2).is(tok::greater)); - if (parsingBSCTemplateFunction) { + if (ParsingBSCTemplateFunction) { int lParenOffset = 0; Token tmpTok = PP.LookAhead(lParenOffset); while (!tmpTok.is(tok::l_paren) && !tmpTok.is(tok::eof)) { @@ -578,7 +576,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier( return false; } -// Parse instation for bsc struct part of generic, to avoid affecting +// Parse instation for bsc struct part of generic, to avoid affecting // the original logic of C++. bool Parser::ParseOptionalBSCGenericSpecifier( CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors, @@ -772,14 +770,13 @@ bool Parser::ParseOptionalBSCGenericSpecifier( // type-name '::' // namespace-name '::' // nested-name-specifier identifier '::' - // Token Next = NextToken(); Token Next; - bool parsingBSCTemplateFunction = + bool ParsingBSCTemplateFunction = getLangOpts().BSC && Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::less) && PP.LookAhead(1).is(tok::identifier) && (PP.LookAhead(2).is(tok::comma) || PP.LookAhead(2).is(tok::greater)); - if (parsingBSCTemplateFunction) { + if (ParsingBSCTemplateFunction) { int lParenOffset = 0; while (!PP.LookAhead(lParenOffset).is(tok::l_paren)) { lParenOffset += 1; diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index e582c7ae51ac..11aceec602ba 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -209,7 +209,7 @@ Retry: Default: default: { if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || - getLangOpts().BSC || + getLangOpts().BSC || (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) != ParsedStmtContext()) && (GNUAttributeLoc.isValid() || diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 2977768d38cf..7dc6a49495d3 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -581,10 +581,6 @@ bool Parser::ParseBSCTemplateParameters( MultiParseScope &TemplateScopes, unsigned Depth, SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, SourceLocation &RAngleLoc, int &lookAheadOffset) { - // if (!TryConsumeToken(tok::less, LAngleLoc)) { - // Diag(Tok.getLocation(), diag::err_expected_less_after) << "template"; - // return true; - // } Token peekTok = PP.LookAhead(lookAheadOffset); if (peekTok.is(tok::less)) { lookAheadOffset += 1; @@ -597,11 +593,6 @@ bool Parser::ParseBSCTemplateParameters( // Try to parse the template parameter list. bool Failed = false; - // FIXME: Missing greatergreatergreater support. - // if (!Tok.is(tok::greater) && !Tok.is(tok::greatergreater)) { - // TemplateScopes.Enter(Scope::TemplateParamScope); - // Failed = ParseTemplateParameterList(Depth, TemplateParams); - // } if (!peekTok.is(tok::greater)) { TemplateScopes.Enter(Scope::TemplateParamScope); Failed = @@ -609,20 +600,6 @@ bool Parser::ParseBSCTemplateParameters( } peekTok = PP.LookAhead(lookAheadOffset); - // if (Tok.is(tok::greatergreater)) { - // // No diagnostic required here: a template-parameter-list can only be - // // followed by a declaration or, for a template template parameter, the - // // 'class' keyword. Therefore, the second '>' will be diagnosed later. - // // This matters for elegant diagnosis of: - // // template> struct S; - // Tok.setKind(tok::greater); - // RAngleLoc = Tok.getLocation(); - // Tok.setLocation(Tok.getLocation().getLocWithOffset(1)); - // } else if (!TryConsumeToken(tok::greater, RAngleLoc) && Failed) { - // Diag(Tok.getLocation(), diag::err_expected) << tok::greater; - // return true; - // } - if (peekTok.getKind() == tok::greater) { lookAheadOffset += 1; RAngleLoc = peekTok.getLocation(); @@ -694,8 +671,6 @@ bool Parser::ParseBSCTemplateParameterList( } else { // If we failed to parse a template parameter, skip until we find // a comma or closing brace. - // SkipUntil(tok::comma, tok::greater, tok::greatergreater, - // StopAtSemi | StopBeforeMatch); SkipUntil(tok::comma, tok::greater, // FIXME: logic error StopAtSemi | StopBeforeMatch); } @@ -714,9 +689,6 @@ bool Parser::ParseBSCTemplateParameterList( // Somebody probably forgot to close the template. Skip ahead and // try to get out of the expression. This error is currently // subsumed by whatever goes on in ParseTemplateParameter. - // Diag(Tok.getLocation(), diag::err_expected_comma_greater); - // SkipUntil(tok::comma, tok::greater, tok::greatergreater, - // StopAtSemi | StopBeforeMatch); Diag(peekTok.getLocation(), diag::err_expected_comma_greater); SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch); return false; @@ -1064,8 +1036,6 @@ NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, // Check Tok location Token peekTok = PP.LookAhead(lookAheadOffset); bool isBSCTemplateTypeParameter = getLangOpts().BSC; // TODO: fix the cond - // bool isBSCTemplateTypeParameter = getLangOpts().BSC && (peekTok.getKind() - // == tok::identifier); assert( isBSCTemplateTypeParameter && "A type-parameter starts with 'class', 'typename' or a type-constraint"); @@ -1083,7 +1053,6 @@ NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, static_cast(peekTok.getAnnotationValue()); assert(TypeConstraint->Kind == TNK_Concept_template && "stray non-concept template-id annotation"); - // KeyLoc = ConsumeAnnotationToken(); // no annot_template_id in BSC, // KeyLoc remain at init status } else { assert(TypeConstraintSS.isEmpty() && @@ -1630,7 +1599,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, TemplateArgList TemplateArgs; bool ArgsInvalid = false; if (!TypeConstraint || Tok.is(tok::less)) { - // The template args will be parsed at here. + // The template args will be parsed at here. ArgsInvalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc, TemplateArgs, RAngleLoc); // If we couldn't recover from invalid arguments, don't form an annotation diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index d0c52c37f763..5fc1dbea8559 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1106,70 +1106,67 @@ bool Parser::isTentativelyDeclared(IdentifierInfo *II) { != TentativelyDeclaredIdentifiers.end(); } +// Check template declaration syntax in BSC: +// function template declaration: "T Foo(T a) {..}" +// struct template declaration: "struct S {..};" +// The method of checking template declaration is: +// 1. find template parameter list syntax structure "identifier " +// 2. find declaration syntax(different from spcialization syntax) +// " ()" in template function or " {}" in template structure bool Parser::isBSCTemplateDecl(Token tok) { - /* - check structure in BSC syntax: - "T Foo(T a) {..}" or - "struct S {..};" - */ // 1. check language if (!getLangOpts().BSC) return false; - // 2. check "Foo<>" structure - // ^^^^ - int MaxLessTokenLookAheadOffset = - 6; // tok::less must appear with in 6 more token: "static inline unsigned - // long long Foo<" + + // 2. check "identifier" structure int LessOffset = 0; bool FoundLess = false; Token prevTok = tok; Token tmpTok = PP.LookAhead(LessOffset); - // FIXME: below for-loop not verified - for (LessOffset = 1; LessOffset <= MaxLessTokenLookAheadOffset && - !PP.LookAhead(LessOffset).is(tok::eof); - LessOffset++) { + for (LessOffset = 1; !PP.LookAhead(LessOffset).is(tok::eof); LessOffset++) { if (tmpTok.is(tok::l_paren) || tmpTok.is(tok::l_brace) || - tmpTok.is(tok::equal)) // "<>" must appear neighboring with - // function/struct identtifier + tmpTok.is(tok::equal)) { + // "<>" must appear neighboring with identtifier return false; + } if (tmpTok.is(tok::less) && prevTok.is(tok::identifier)) { FoundLess = true; - break; // when ">" missing, leave tis diagnose work in deeper api. + break; // do not check if ">" missing, leave diagnose in outer API } prevTok = tmpTok; tmpTok = PP.LookAhead(LessOffset); } if (!FoundLess) return false; - // 3. check "<> {}" structure in struct declaration - // ^^^ + + // 3. check " {}" structure in struct declaration int LBraceOffset = 1; tmpTok = PP.LookAhead(LessOffset + LBraceOffset); for (; !tmpTok.is(tok::eof); LBraceOffset++) { // check "Foo<>" structure tmpTok = PP.LookAhead(LessOffset + LBraceOffset); - if (tmpTok.is( - tok::l_paren)) // might be function declaration, skip current check + if (tmpTok.is(tok::l_paren)) // could be function declaration, skip break; if (tmpTok.is(tok::semi) || tmpTok.is(tok::equal)) // no "{" in current sentence return false; - if (tmpTok.is(tok::l_brace) || - tmpTok.is(tok::r_brace)) { // l_brace could missing, pass this for - // latter diagnose + if (tmpTok.is(tok::l_brace) || tmpTok.is(tok::r_brace)) { + // do not check if l_brace missing, leave diagnose in outer API return true; } } - // 4. check "<>(..) {}" structure in function declaration - // ^^ ^^^ + + // 4. check "() {}" structure in function declaration int LParenOffset = 1; tmpTok = PP.LookAhead(LessOffset + LParenOffset); - for (; !tmpTok.is(tok::eof); LParenOffset++) { // check "Foo<>" structure + for (; !tmpTok.is(tok::eof); + LParenOffset++) { // check "identifier " syntax tmpTok = PP.LookAhead(LessOffset + LParenOffset); if (tmpTok.is(tok::semi) || tmpTok.is(tok::equal)) // no "{" in current sentence return false; if (tmpTok.is(tok::l_paren)) { - break; // when ")" missing, leave tis diagnose work in deeper api. + // do not check ")" missing, leave diagnose in outer API + break; } } LBraceOffset = 1; @@ -1179,9 +1176,8 @@ bool Parser::isBSCTemplateDecl(Token tok) { if (tmpTok.is(tok::semi) || tmpTok.is(tok::equal)) // no "{" in current sentence return false; - if (tmpTok.is(tok::l_brace) || - tmpTok.is(tok::r_brace)) { // l_brace could missing, pass this for - // latter diagnose + if (tmpTok.is(tok::l_brace) || tmpTok.is(tok::r_brace)) { + // do not check l_brace missing, leave diagnose in outer API return true; } } diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 28f6b6e86a73..bb31c40b9fcf 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -23,7 +23,6 @@ #include "llvm/Support/Path.h" using namespace clang; - namespace { /// A comment handler that passes comments found by the preprocessor /// to the parser action. @@ -923,8 +922,6 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::kw__Static_assert: // A function definition cannot start with any of these keywords. { - // entrance of parsing template function parameter list “template - // ” SourceLocation DeclEnd; return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs); } @@ -1000,8 +997,6 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, return nullptr; } // We can't tell whether this is a function-definition or declaration yet. - // Entrance of parsing template function declaration “T max(T a, T b)” - // and function declaration “int max(int a, int b)” return ParseDeclarationOrFunctionDefinition(attrs, DS); } @@ -1666,8 +1661,8 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) { // Add BSC language judgement, when instantiates BSC template // function without LHS and "=", we need enter this. // @Code - // int main() { - // foo(1, 2); + // int main() { + // foo(1, 2); // } if ((getLangOpts().CPlusPlus || getLangOpts().BSC) && ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index ff5071e6c63a..7667750b757a 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -2690,7 +2690,7 @@ static void DiagnoseBadFunctionCast(Sema &Self, const ExprResult &SrcExpr, /// Check the semantics of a C-style cast operation, in C. void CastOperation::CheckCStyleCast() { - assert(!Self.getLangOpts().CPlusPlus); + assert(!Self.getLangOpts().CPlusPlus); // C-style casts can resolve __unknown_any types. if (claimPlaceholder(BuiltinType::UnknownAny)) { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 72307ccc9160..8f63d8af78a0 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1203,9 +1203,8 @@ ExprResult Sema::ActOnNameClassifiedAsUndeclaredNonType(IdentifierInfo *Name, SourceLocation NameLoc) { // In BSC, this is the entrance of checking undefined function name. - assert( - (getLangOpts().CPlusPlus || getLangOpts().BSC) && - "ADL-only call in C?"); + assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && + "ADL-only call in C?"); CXXScopeSpec SS; LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true); @@ -8971,7 +8970,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (IsLocalExternDecl) NewFD->setLocalExternDecl(); - if (getLangOpts().CPlusPlus) { + if (getLangOpts().CPlusPlus || getLangOpts().BSC) { bool isInline = D.getDeclSpec().isInlineSpecified(); bool isVirtual = D.getDeclSpec().isVirtualSpecified(); bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier(); @@ -9294,159 +9293,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, FPT->getExtProtoInfo().withExceptionSpec(EST_BasicNoexcept))); } - // Refactor C++ logic for BSC template. - if (getLangOpts().BSC) { - bool isInline = D.getDeclSpec().isInlineSpecified(); - bool isVirtual = D.getDeclSpec().isVirtualSpecified(); - bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier(); - isFriend = D.getDeclSpec().isFriendSpecified(); - if (isFriend && !isInline && D.isFunctionDefinition()) { - // C++ [class.friend]p5 - // A function can be defined in a friend declaration of a - // class . . . . Such a function is implicitly inline. - NewFD->setImplicitlyInline(); - } - - // If this is a method defined in an __interface, and is not a constructor - // or an overloaded operator, then set the pure flag (isVirtual will already - // return true). - if (const CXXRecordDecl *Parent = - dyn_cast(NewFD->getDeclContext())) { - if (Parent->isInterface() && cast(NewFD)->isUserProvided()) - NewFD->setPure(true); - - // C++ [class.union]p2 - // A union can have member functions, but not virtual functions. - if (isVirtual && Parent->isUnion()) - Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_in_union); - } - - SetNestedNameSpecifier(*this, NewFD, D); - isMemberSpecialization = false; - isFunctionTemplateSpecialization = false; - if (D.isInvalidType()) - NewFD->setInvalidDecl(); - - // Match up the template parameter lists with the scope specifier, then - // determine whether we have a template or a template specialization. - bool Invalid = false; - TemplateParameterList *TemplateParams = - MatchTemplateParametersToScopeSpecifier( - D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(), - D.getCXXScopeSpec(), - D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId - ? D.getName().TemplateId - : nullptr, - TemplateParamLists, isFriend, isMemberSpecialization, Invalid); - if (TemplateParams) { - // Check that we can declare a template here. - if (CheckTemplateDeclScope(S, TemplateParams)) - NewFD->setInvalidDecl(); - - if (TemplateParams->size() > 0) { - // This is a function template - - // A destructor cannot be a template. - if (Name.getNameKind() == DeclarationName::CXXDestructorName) { - Diag(NewFD->getLocation(), diag::err_destructor_template); - NewFD->setInvalidDecl(); - } - - // If we're adding a template to a dependent context, we may need to - // rebuilding some of the types used within the template parameter list, - // now that we know what the current instantiation is. - if (DC->isDependentContext()) { - ContextRAII SavedContext(*this, DC); - if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams)) - Invalid = true; - } - - FunctionTemplate = FunctionTemplateDecl::Create( - Context, DC, NewFD->getLocation(), Name, TemplateParams, NewFD); - FunctionTemplate->setLexicalDeclContext(CurContext); - NewFD->setDescribedFunctionTemplate(FunctionTemplate); - - // For source fidelity, store the other template param lists. - if (TemplateParamLists.size() > 1) { - NewFD->setTemplateParameterListsInfo( - Context, ArrayRef(TemplateParamLists) - .drop_back(1)); - } - } else { - // This is a function template specialization. - isFunctionTemplateSpecialization = true; - // For source fidelity, store all the template param lists. - if (TemplateParamLists.size() > 0) - NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists); - - // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);". - if (isFriend) { - // We want to remove the "template<>", found here. - SourceRange RemoveRange = TemplateParams->getSourceRange(); - - // If we remove the template<> and the name is not a - // template-id, we're actually silently creating a problem: - // the friend declaration will refer to an untemplated decl, - // and clearly the user wants a template specialization. So - // we need to insert '<>' after the name. - SourceLocation InsertLoc; - if (D.getName().getKind() != UnqualifiedIdKind::IK_TemplateId) { - InsertLoc = D.getName().getSourceRange().getEnd(); - InsertLoc = getLocForEndOfToken(InsertLoc); - } - - Diag(D.getIdentifierLoc(), diag::err_template_spec_decl_friend) - << Name << RemoveRange << FixItHint::CreateRemoval(RemoveRange) - << FixItHint::CreateInsertion(InsertLoc, "<>"); - } - } - } else { - // Check that we can declare a template here. - if (!TemplateParamLists.empty() && isMemberSpecialization && - CheckTemplateDeclScope(S, TemplateParamLists.back())) - NewFD->setInvalidDecl(); - - // All template param lists were matched against the scope specifier: - // this is NOT (an explicit specialization of) a template. - if (TemplateParamLists.size() > 0) - // For source fidelity, store all the template param lists. - NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists); - } - - if (Invalid) { - NewFD->setInvalidDecl(); - if (FunctionTemplate) - FunctionTemplate->setInvalidDecl(); - } - - // If a function is defined as defaulted or deleted, mark it as such now. - // We'll do the relevant checks on defaulted / deleted functions later. - switch (D.getFunctionDefinitionKind()) { - case FunctionDefinitionKind::Declaration: - case FunctionDefinitionKind::Definition: - break; - - case FunctionDefinitionKind::Defaulted: - NewFD->setDefaulted(); - break; - - case FunctionDefinitionKind::Deleted: - NewFD->setDeletedAsWritten(); - break; - } - - // C++11 [except.spec]p15: - // A deallocation function with no exception-specification is treated - // as if it were specified with noexcept(true). - const FunctionProtoType *FPT = R->getAs(); - if ((Name.getCXXOverloadedOperator() == OO_Delete || - Name.getCXXOverloadedOperator() == OO_Array_Delete) && - getLangOpts().CPlusPlus11 && FPT && !FPT->hasExceptionSpec()) - NewFD->setType(Context.getFunctionType( - FPT->getReturnType(), FPT->getParamTypes(), - FPT->getExtProtoInfo().withExceptionSpec(EST_BasicNoexcept))); - } - // Filter out previous declarations that don't match the scope. FilterLookupForScope(Previous, OriginalDC, S, shouldConsiderLinkage(NewFD), D.getCXXScopeSpec().isNotEmpty() || @@ -15650,13 +15496,11 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, return nullptr; OwnedDecl = false; - DeclResult Result = - CheckClassTemplate( - S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attrs, - TemplateParams, AS, ModulePrivateLoc, - /*FriendLoc*/ SourceLocation(), - TemplateParameterLists.size() - 1, - TemplateParameterLists.data(), SkipBody); + DeclResult Result = CheckClassTemplate( + S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attrs, TemplateParams, + AS, ModulePrivateLoc, + /*FriendLoc*/ SourceLocation(), TemplateParameterLists.size() - 1, + TemplateParameterLists.data(), SkipBody); return Result.get(); } else { // The "template<>" header is extraneous. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index c176f13aa954..40d0b4010165 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -14583,7 +14583,7 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, RHSExpr = resolvedRHS.get(); } - // Add BSC judgement, this will help we delay the check if + // Add BSC judgement, this will help we delay the check if // the expression is type-dependent. if (getLangOpts().CPlusPlus || getLangOpts().BSC) { // If either expression is type-dependent, always build an diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index a0116dcd0c3e..d7e98809bd16 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -12978,7 +12978,8 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn, llvm_unreachable("performing ADL for builtin"); // We don't perform ADL in C. - assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && "ADL enabled in C"); + assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && + "ADL enabled in C"); } #endif diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index a6f8866edbdb..ea3c621807b7 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1977,10 +1977,9 @@ DeclResult Sema::CheckClassTemplate( AddMsStructLayoutForRecord(NewClass); } - ClassTemplateDecl *NewTemplate - = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, - DeclarationName(Name), TemplateParams, - NewClass); + ClassTemplateDecl *NewTemplate = ClassTemplateDecl::Create( + Context, SemanticContext, NameLoc, DeclarationName(Name), TemplateParams, + NewClass); if (ShouldAddRedecl) NewTemplate->setPreviousDecl(PrevClassTemplate); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 7c10a152bc99..23bcb4795ec0 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2653,14 +2653,12 @@ bool Sema::InstantiateClass(SourceLocation PointOfInstantiation, MSInfo->setTemplateSpecializationKind(TSK); MSInfo->setPointOfInstantiation(PointOfInstantiation); } else if (ClassTemplateSpecializationDecl *Spec = - dyn_cast( - Instantiation)) { + dyn_cast(Instantiation)) { Spec->setTemplateSpecializationKind(TSK); Spec->setPointOfInstantiation(PointOfInstantiation); } } else if (ClassTemplateSpecializationDecl *Spec = - dyn_cast( - Instantiation)) { + dyn_cast(Instantiation)) { Spec->setTemplateSpecializationKind(TSK); Spec->setPointOfInstantiation(PointOfInstantiation); } @@ -2744,8 +2742,7 @@ bool Sema::InstantiateClass(SourceLocation PointOfInstantiation, continue; } - Decl *NewMember = Instantiator.Visit( - Member); + Decl *NewMember = Instantiator.Visit(Member); if (NewMember) { if (FieldDecl *Field = dyn_cast(NewMember)) { Fields.push_back(Field); @@ -3227,9 +3224,8 @@ bool Sema::InstantiateClassTemplateSpecialization( if (ClassTemplateSpec->isInvalidDecl()) return true; - ActionResult Pattern = - getPatternForClassTemplateSpecialization(*this, PointOfInstantiation, - ClassTemplateSpec, TSK); + ActionResult Pattern = getPatternForClassTemplateSpecialization( + *this, PointOfInstantiation, ClassTemplateSpec, TSK); if (!Pattern.isUsable()) return Pattern.isInvalid(); diff --git a/clang/test/BSC/Method/Linkage/queue.hbs.gch b/clang/test/BSC/Method/Linkage/queue.hbs.gch new file mode 100644 index 0000000000000000000000000000000000000000..deb68030f754e42249b57c9de685452216bc495a GIT binary patch literal 213368 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

=|9-fK#$)h7!&f8$(~oz{EpSJ993R-hNo|B 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ð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

{z~FVE6i9Y&TWy6ko--H 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 Date: Tue, 18 Apr 2023 17:55:42 +0800 Subject: [PATCH 22/22] [generic] fix new comments Mainly deleted useless remarks, plus did some rollbacks of code. --- clang/include/clang/Sema/Template.h | 3 ++- clang/lib/Parse/ParseDecl.cpp | 12 ++++-------- clang/lib/Parse/ParseDeclCXX.cpp | 2 +- clang/lib/Parse/ParseStmt.cpp | 3 +-- clang/lib/Parse/ParseTemplate.cpp | 10 ++-------- clang/lib/Parse/Parser.cpp | 2 ++ clang/lib/Sema/SemaCast.cpp | 3 +-- clang/lib/Sema/SemaOverload.cpp | 1 - clang/test/BSC/Method/Linkage/queue.hbs.gch | Bin 213368 -> 0 bytes 9 files changed, 13 insertions(+), 23 deletions(-) delete mode 100644 clang/test/BSC/Method/Linkage/queue.hbs.gch diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index a49881ca45b7..8c3fc70d26be 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -461,7 +461,8 @@ enum class TemplateSubstitutionKind : char { }; class TemplateDeclInstantiator - : public DeclVisitor { + : public DeclVisitor + { Sema &SemaRef; Sema::ArgumentPackSubstitutionIndexRAII SubstIndex; DeclContext *Owner; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index b34a526bef6f..e2ae24609a7e 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1661,8 +1661,7 @@ Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, case tok::kw_template: case tok::kw_export: ProhibitAttributes(attrs); - SingleDecl = ParseDeclarationStartingWithTemplate( - Context, DeclEnd, attrs); // C++ template function parsing branch + SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); break; case tok::kw_inline: // Could be the start of an inline namespace. Allowed as an ext in C++03. @@ -3393,9 +3392,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (Tok.isNot(tok::identifier)) continue; ParsedAttributesWithRange Attrs(AttrFactory); - if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, - Attrs)) { // template parameter "T" in BSC might be - // miss-parsed here | when? + if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) { if (!Attrs.empty()) { AttrsLastTime = true; attrs.takeAllFrom(Attrs); @@ -3957,7 +3954,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___interface: case tok::kw_union: { tok::TokenKind Kind = Tok.getKind(); - ConsumeToken(); // consume 'struct' keyword + ConsumeToken(); // These are attributes following class specifiers. // To produce better diagnostic, we parse them when @@ -5978,8 +5975,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { D.getContext() == DeclaratorContext::Member; ParseOptionalCXXScopeSpecifier( D.getCXXScopeSpec(), /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, - EnteringContext); // BSC compacity problem exists, non-critic + /*ObjectHadErrors=*/false, EnteringContext); } if (D.getCXXScopeSpec().isValid()) { diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index d2a3b13aa165..ba70ce1ddb05 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1999,7 +1999,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (SkipBody.ShouldSkip) SkipCXXMemberSpecification(StartLoc, AttrFixitLoc, TagType, TagOrTempResult.get()); - // add BSC entrance condition else if (getLangOpts().CPlusPlus) ParseCXXMemberSpecification(StartLoc, AttrFixitLoc, attrs, TagType, TagOrTempResult.get()); @@ -3138,6 +3137,7 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas( AccessSpecifier &AS, ParsedAttributesWithRange &AccessAttrs, DeclSpec::TST TagType, Decl *TagDecl) { ParenBraceBracketBalancer BalancerRAIIObj(*this); + switch (Tok.getKind()) { case tok::kw___if_exists: case tok::kw___if_not_exists: diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 11aceec602ba..33d35af1fe83 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1127,8 +1127,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr, SafeScopeSpecifie StmtResult R; if (Tok.isNot(tok::kw___extension__)) { - R = ParseStatementOrDeclaration( - Stmts, SubStmtCtx); // see `struct` in `struct S` + R = ParseStatementOrDeclaration(Stmts, SubStmtCtx); } else { // __extension__ can start declarations and it can also be a unary // operator for expressions. Consume multiple __extension__ markers here diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 7dc6a49495d3..b9c089bf4c31 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -815,8 +815,7 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { Tok.getEndLoc()), "typename"); - Tok.setKind(tok::kw_typename); // unkown manipulation, rename "typedef" as - // "typename" + Tok.setKind(tok::kw_typename); } return ParseTypeParameter(Depth, Position); @@ -848,8 +847,6 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { llvm_unreachable("template param classification can't be ambiguous"); } - // Call upper layer method recursively to parse nested template param list - // template > if (Tok.is(tok::kw_template)) return ParseTemplateTemplateParameter(Depth, Position); @@ -1516,7 +1513,6 @@ Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken, if (!Tok.isOneOf(tok::greater, tok::greatergreater, tok::greatergreatergreater, tok::greaterequal, tok::greatergreaterequal)) - // Template arguments will be parsed at here. Invalid = ParseTemplateArgumentList(TemplateArgs); if (Invalid) { @@ -1599,7 +1595,6 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, TemplateArgList TemplateArgs; bool ArgsInvalid = false; if (!TypeConstraint || Tok.is(tok::less)) { - // The template args will be parsed at here. ArgsInvalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc, TemplateArgs, RAngleLoc); // If we couldn't recover from invalid arguments, don't form an annotation @@ -1859,7 +1854,6 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { ColonProtectionRAIIObject ColonProtection(*this, false); do { - // Template arguments will be parsed at here. ParsedTemplateArgument Arg = ParseTemplateArgument(); SourceLocation EllipsisLoc; if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) @@ -1869,7 +1863,7 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { return true; // Save this template argument. - TemplateArgs.push_back(Arg); // ex: Arg is 'int' in S + TemplateArgs.push_back(Arg); // If the next token is a comma, consume it and keep reading // arguments. diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index bb31c40b9fcf..7c0d192ead2b 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -23,6 +23,7 @@ #include "llvm/Support/Path.h" using namespace clang; + namespace { /// A comment handler that passes comments found by the preprocessor /// to the parser action. @@ -981,6 +982,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, Diag(Tok, diag::err_unexpected_module_decl); SkipUntil(tok::semi); return nullptr; + default: dont_know: // parse BSC template declaration diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 7667750b757a..a2ae49926f14 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -3089,9 +3089,8 @@ ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo, } else { Op.CheckCXXCStyleCast(/*FunctionalCast=*/true, /*ListInit=*/false); } - if (Op.SrcExpr.isInvalid()) { + if (Op.SrcExpr.isInvalid()) return ExprError(); - } auto *SubExpr = Op.SrcExpr.get(); if (auto *BindExpr = dyn_cast(SubExpr)) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index d7e98809bd16..c363c26039f0 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -8146,7 +8146,6 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { } } } - return VRQuals; } diff --git a/clang/test/BSC/Method/Linkage/queue.hbs.gch b/clang/test/BSC/Method/Linkage/queue.hbs.gch deleted file mode 100644 index deb68030f754e42249b57c9de685452216bc495a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 213368 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

=|9-fK#$)h7!&f8$(~oz{EpSJ993R-hNo|B zpvS67#-RG3o?(*Layr>TUyXOLcYCTaI!N6#)vK|iuIAHlt6!SmI6FvPXY;&*U6xI=D$@Ke&yqB$@^XF~HM6(y=6Di7~7`C{w-^-`_3S zr^*XhG^hyQFO?in@@&^U>ox_}jtetJ)CYB~l`PNg)ckjlMh;ak zGTsc?cT0P)McQ!dh%~=F$5}hJnCsOAQe(r7)9ZsYOC;6c>bT5|CALE2Z9!_|KIs)p zUB{P0ts~R?W#u0H5Y8+$*uv+00`8B2~t7^|^lrKJ5tT}{G7>p1Kp zli0}gzIFEn)<)`#NpQUJ(yzeS{{l3MVDH8E8Se~Iw# z-W_jDuMaAEN0OG;ne&LhW=OF2&`RUOVC-&>#?HEqx5rs0!&@$}5Otn)l~4NpfgYJN zjW^T>r9UNEoY!gm+|P_9k1RJn20N-f+B@rNc6nK+r1_nHkg3#pnq1F1EV(V%m{}jx zJyxk z#*%}B%vjPr&-gTUd7fPXW2d~V)6)E&i)10?=uI#2%&OUII1y^S~52jwhe??e2}QZtr(G|c!C zG`2?CezH!x&BGd*=67`gD^us0Pe|(?2=u7;H!ef4Jk7q!>(o5tr5PFQ{lT-wqwxF} zSPypD9%`MQ=C>nLvQC}XS}5tlE{f5{+v)Ia${c zH^>?V#%8f5bzaj2iSL7f9#1QbMR3czSXzE(&IJ$6=wR=kCm7!iQk#Egjjz?!_zkkg zB3GodJ=i5fn*Ly5?c9;Z+adlDwm832`I?s*OO{PHz8|DM|2b>Nk`;1mT$*3Yt*lj@ zm-D);4ohY%HkQ-}nGZ{s=XaVPAFde_>^-{8_)(C0Pm5R2Yjqt_k=A%POp&A=O1>uR z0%LFb7+1r`swCB5>{+=POSUdE{s-cJCB1@Ot{-VlNb|e>6=qfEb)WF^eJHSYZa^!ZT9eZJl8&+S>O9pV@AQWPJsyZQ-U*Fu zk-VSZX?(=bj3ply7%x+Zd9-7R*C^{OEIG(*>b!upUUgVid}}r9``U~$?sE)e?XQ! zk}Id`I<^kBUZ3U{y^<-T;bR`YTLNokV~ln6K`ColT0y7zS#QmxVDByQ#v!BBP4S+M zU3E40Othw?`8D}TLZb7O#lGoV0zLktGj4{Ghf5b1bSe)8nz7{7dgF*u>MJWe+fi|{ zgRQA)e%}X4RMC0n4&OTLl754+zCP&t+0x|&olVyQHNnB&*KakB9;G(l>Dkj&r+qcp zng+&vC5h2_s$YD%u;h*FjsJj>uSu#45S0oumK?p?I3By)<#7d!?H^;Elje8vQEv1OhrPjGDeS5HyrS2e7#PxX`D4P&2RO$tO!fy`J_J* z=+Qpg_#}3@D0#o2Q}dLr1>qMD`|rG3S~B8M_TtrT}`&}#!+gkToV@T{fgv< z!cOCXVLAA|@t`qll)7%FSJNAHl5?TTMQMIHw@IFZfqs!KeKgRci0#AHrLv+&5ky(W z=TX<5mfnWt9}j2YaESxPrK8kcQC?kGeqU(L;t|6(ek{8)oSE;{m2P5*Mz7Sfcj1@5 z&G$+@Yw5>L&6_1Ny;*B>&M77H&(W@F+WxHs;9sOxHey)av3JI@l8~b5G_|EWC+9v1 ze*9kLYxG#E4^fV)E5u*slD*)^!Scju5!*r8v}>pYl)Y+qnzqY8xi#zT?Xn#0**!Zu z9`VNV>~}R!SF!kENyWpu6Mf~IeWM2d63cRuYo7AHxX+`tS-&8^;ZE&RedeX`_Ew@l zas;P8?8h5oBfy*K-d$XfO>Yk|%msbx%1~l2x8tRhFNP4e%VfmfvZ9DBhdr^p{4u^f z==-^0i6olWvwZni{}_79d=mU$e0lS4)|Ll`VtM5nzPzMq#{K7MdEj=weB1H4>!WD* z3&QUAef98B+FievFF(7bNqL_X%g^b#a@L34-SwLU%V%8gNt(=Ab)dQXyuac00 z5rd3s{22Q{fLT%!vTnp6CSR&=m3%U3&jaLXRa@lbcw?HTZhCqcRMh>*j!&AfU8(uU z;m4O?JL|7u#E-;ha@fmzN#_ZVa*5Wk|33O70lI(ZfQdd=RvZ6GI%!SdfC}>m_pTcQ zKtSmi5>U|k>|5RN3IWOmK$YfK?;i-zwBZB+a(#}aZ<*``z{4$^!dm4Q-cJ+2T*0+k z<1=Yp>sg`@pTq%ou+2U*#{-aaiUXQ`ly}s9Nq`rUxZ&w3lN233m+t63 zPk_<0xY{?Ecl+!mfbu=gztfbFxSO;QBHU7qG3{P@f)5R4y|cbBKpDe4Ig$n7^u=P#_x zAV;0Pmj`%=F>lHP!vQFGfjf4+sc~W34Fp)s0bZd!=g&Pyp1-V$1Gbtzp8w-a04y7L zq-+YUvrT@304aBHz&2C+{ObsyTfqTdVLiWgeno(u^&HS5{nvus*AsYwr zfNcW@>@)qiATb>PsgJ-zc+)SF|3iSzyEvdt+I2%qH~^+f9&Ve$doHH@n*c?3a=|#{hK|pM$vSFfl324zH}ZRZbE+3?+O{V^;}H>3U9)~q! zQ7C=>43Z&}Z@x{l$ZOGXwp4#bS{nA>y_C1Fe^gRr^g0>UwMY7_3_Mt~M;X1B>Wv=X zMx8rO`S$8aFN&|k#$CE636P#Os^vDs*XQii=E!jH*;+Uy=sxLEeS^pOuveeQ63g1* zQqWADVLh04f|islok%nrJ+4Gw{TI=^XOs*yPtGvzGrdHB^@}HVpB-r&?DbJt?HRen zG-=$j*=v6D#4g`jzqtSDY1pOv=N2|PNBe^ROHX&*MOo#J1+pf|h+*FwO%DW32O!`? zA*uQu|D)R*))C-;^ZnK;eUN89AM}&|L1jdUwWD;<&r`_fUrkZ@d$l&z`7D}p=22!G zyy@r=&u%7{-J!h6R5FP5=o=!nY;bE+qfg*ia~S|$LH@(a0Ju|gqi#L{nnJZrC!(;+ zj49rGM{e{=on=g#c-a%ObUqzGkcj_PIzD@~J=HcrmkQ{4QV7XaBWDoGpG+N1s< zGYL@WL)u84-CkJp6akhURtnl!J%VdPH=*lA)rV5paq2C;W=TZIWt@_RY=R)#9RcJC zrU~nZMKAINV7DxgJmJ6EX%o9Qk|#W=Cr_|UC<(kchX8;04(Fb5kNFPYOA{f8ads?8 z$_9OMpGGBxq`qk$P{rnkoT~Ky5TI*j3-f7h3K%rvzVl-Vuss=EAyH5MWX7Ryh-Uma zzG=GjK=3F3z@{}H2NG91CNE3e@dW`Y$KFV6XPPR5|MwsO9j^w~_#cO)-zSW2xh-JC zuxXN04@F*2zVzj@WaXM67q40`c|g6}?&ekw)gD*)6Tp0S1zEXy$nyW4|B(RiZxF29 z{E9-b@?ulLm?NvO%h{I(bLC9YAKCJmH`uuNF%OfQrP*UD2~cxj9#_tkONS@^n*aqL z31RYhQ|hS+;~@K$oiU^w!avD|IQ-cZ6-n^5P(=h1W(oc>9u<3sZ zf^w!_{Y1Og2Q<(B$Tuz0og4SkT9W;;KUdDwbstY$Lx9OY>Pa~z(%s|Utp=d^1Ajp| z=^rD|pqvElM}Bw3K=z!{-CQ|CL*6paAlVaFaOKR%eb?_64p_OID`#l+>DCwm7?uml z>3GXeP)@aJm)D^Y*hTxkNlK0}xO>c&HIyQv|G`~rope)RVj2LFQ|Uec?3iX7y=4^v z4n4>L>!oi7E}BDpe%s{@z~|GhjGDNT00j?vk|1W?SAoX~aQ4@9loHdVh=K`{4gx3} zIiS>II7eL0<%O{LXxs|fS9{F$r zyr^GQbBq8DM>G-ua^xQjH!qGVhqAc42 z36%UtD7S*mQa^Ojd;pr?;AWZ>)j6Z}8wNo9IBv&FrfY*HL;!HM){9&^FUr>1eUj4D z(WTtyuSnB;62}1`dDg>=>=QZ8Rg4~1H?$)fh;h9jFR})l&$d z8N6)#B?4@kEdb7x&C|`MD$q5JQ_v57e04;z83&J%4F$q zUWq1gK*QkMCZ{}1fb=0;iVs^ebWsF2KZOID20uRi%uxc|JkqlpdiW^kGwCKd08M4Q z*tHH;PruqufC&QNWAm4$rwPzq!2#yMw~jr(1^};F{v$|}pIARMRTIFv%3clMiELOg zZsTCDAMBMYA^nwr3uN)nZ{^vex^_x<+djBN&0~uw_Du<=U$C5#0dQrh7lrnn9!cT9 z6QKDS4zMI#Ih6M%0ruU*0e9DWM_$(kfcCz{L_wOA{qDlKasX~G<^aoysL0OWPw*y?(Qv zJ^3gBY(JTjzC$Klc85@6F6BN~|4KBtDqE7a=OOfRJw6Xam%Kr(+PqP`d)aVh(iac; zVae4kyqB~3%#U98I(08m9FTf<*VN!=2ypHZ4mj`gdUPH&d%BWQbU-_K_a0^bW&)gP zus3_-qPq_JTkf?Cdx9r{jtNNzZO5eG^AB8Pof{55jmH*}q&CIT#Ra#Jq$S~AdwY3wG}ph*@F3TJVDO|>jW3d1 zhvRt?jy8SNus)dtFRdfN)xlTgPpIhx9dj=iJXZQf!*vAEui$_igC`GuIgS8F1VFs$ zNWc{x0L-w5I+HcQR@qMx1bB245(T9@omZ^C#U!1R5})@m^@=5922%%HzA-BJ=X!)g z?$hruI_%838l(F+0g6U*K(%Lfa1}L^%?CKZG^ae=A=M<6s~zJ3xv``rJ>oPrPn_;EmLS_*pRb?Z&RP8^0zB>yjq%)_v0xbGUA$Z|~%~)lQA}{bnKwK5HZI z*$VT%edrZxXv==(9dGW`uxnkvQ_uGDJshy&^Z!2dJ8y}v2`%x|kU!dgBS6AE{NP`# z`{1Fw2w?rehi8)ZUz3lW2=|rC;(q!y4c8Jq`aK(xDSVa=eQ9;sE9CsE6Dae`;>uKb>J%JmKEeP6Q{L&XFf=PD^(m&VY2v-n+ZTuJ_l&0t^U^f z908V9ji6wuGClQ=2Z@66MnSHgJu&J3M27s{bJ>K)Ho%}AhZNLrd_I5K#drQiE%cqg z@qWX$F@8b-0VF#(VA6uhOX~Lsu=~FpaH-R8!qW8wc;F#wNb(kBezvBA02eRV8XtEOEOQsDPIzWC1=0g zL}l^wY>lCN1GRHUqar9A^qW4BKS2P=MK2x>4Zr2_aA?`QblPsZS+%r1!mo6m+q0qO zzjO}O9~W}b=I<81Iv3tj+)7U3!dPU$kw$<2>CFUE)_*XTzp{J{9IG z6Y`2PVO_W zKY5uhMtWZ58+C7P&-#8o1?Hz5khD|mBE|VWl3@*V`LY1gYt-B|D1Gr>wnPwHh15} zZ-mZY~e!-}i&)82GRSWPs#s)p`H!`*fW6(mz z9>fUDV(d|jQQ&L-BG6on&x>5b*cOc8OBs6tW86*P3uDU7jP1pUyoIqBFyfXm_AZ9@L78~kSUk3nR$#I$4G{_r!eLgF!nY^Rv}{_VBE5tvClA&irCi} zD~lMrfKgG**smCO-OkuGjM|lu31dYGW8Y!ix(akKMz3b=}&UO2(eWsICIf7^&6Z8DrjB&{)UVJ`B|zjJ07T-ih^hLGKuf^^84& zF>(WAUt!#SH)B6yl;6YHWelScpL$xuSRIC+iLu8pM%RKjj7b||2aKvsumi@1dl_4J zA7k%h++4@le=v&fXY6~7vdxTL!npeZJg!sE*u5CC2O0Yi4 z-4@1P!?@vL#@@nM_z37?+`JWZG4dV-zZkba2KgUn>`WtLOP^ru6O5cE89Rqj^c42S zDBFg;G1hHo>?(%wX~^^pWWw-k!e=95_&4J-4>3mUVC+eZ@jLOH5ysRO*azc|U5s^N zr0-_zG=~0J?1`~-5B9{!*^50fik`!s7-i36PmFc@uqTFbKlVI;Ju&ZZV5~a@IWYd!#n__PVKK_yV7PjgfJVu{SYp{1Sfr75o@u z($|PFjIi^J9l$vD4L-&5Ti6>T{X5tjL;pQv6MlfdVO+vk_aprH0{j?5W@GH%7)yR) z>|+eWMLdUwvFK;y28F^8Ybb{5xYmV66EA zeur_#HTdB$%CR-Nk(0m|!`BpydGrl^rs-n!paLAhbi&Up=ckwg`u6|&gL|>F_(k8* z@WjZA2ng9)Gt8GY6)zR%rA(T$eZ4R9V&(V+3)T??l>;kP{xQ!NA3$s{@Xrn{UTrAO z#S?)Qm8Io{1#7A*it%i$VO4I$N_JBKK896Bn|QEUWxi~*>zcAvc&c`70Uobp&&v@| z-h}mHOCR#Z$G4W0msYJVC}HPBIUzpXQb_=-n?cxN zn&G?MaFJVBQMfuEqO2@2R3)48?SH5hx1A;SExURB%4V&i6ST-1%ne)NRf{`6RB8=hijIRLpL_zMq z3Z#Tx-(-8(mrZottGr@Od8InGtN>ms*drHC{;>}&NoLlce4*h!0qpFR!R95Uxdj#E z>%yv^u_B8*<(!-pXu4kz<6+)1ddj`1xOYt{q)XvzGOUlEc4M82qN?SbGd2pYoWbM$ z2IX0QKYZXf|Ex~_p~j>I4L9;Ugh#(a%1{a6ZH4Uncio7NzxS}JfHEr!#||UGZlUJ- zm;9I#(z*M*+uqOSWh?DF`tTiBS>rbPvT?3DsmRCgIuw={6j#T>_n(4u4dGE!_Sf)Y zwjJ=HfR||=<<%m;6f`!BL;>bzDDQi@h~0yi-@?mMR$-hhcViv$*xa&;-Wu{02-`3! z*eBolað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

{z~FVE6i9Y&TWy6ko--H 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