From 9c181d309f07513d80631ef580eb34ae0cabf6fc Mon Sep 17 00:00:00 2001 From: qinziang Date: Tue, 21 Feb 2023 12:14:47 +0800 Subject: [PATCH 01/18] [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 d9c892251ce7..a24e1890f5cd 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); } @@ -3394,7 +3433,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); @@ -5956,7 +5995,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()) @@ -5976,7 +6017,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()) { @@ -6044,6 +6085,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, @@ -6229,7 +6271,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()); @@ -6590,7 +6635,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 8362125c6fb418f1515a37590a0979590498e89b Mon Sep 17 00:00:00 2001 From: Aperzer Date: Thu, 23 Feb 2023 19:35:25 +0800 Subject: [PATCH 02/18] [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 a24e1890f5cd..66c61f76fd7d 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -5995,9 +5995,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()) @@ -6273,8 +6275,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 22b280decae4..146f2d19fd74 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 dc80bde5f638..0bac9b0b42a5 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9288,6 +9288,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() || @@ -9491,11 +9648,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. @@ -9893,6 +10070,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 4dce16017717..7d307d92f181 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -8219,6 +8219,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; @@ -14558,6 +14565,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 7f76e9999bc8aedd0501cfc898ace686ba449011 Mon Sep 17 00:00:00 2001 From: EdwardWang Date: Thu, 23 Feb 2023 01:00:07 +0800 Subject: [PATCH 03/18] [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 09803be0c6a31be18d0190abffa6b09eff9c90f2 Mon Sep 17 00:00:00 2001 From: qinziang Date: Fri, 24 Feb 2023 15:47:59 +0800 Subject: [PATCH 04/18] [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 785bdaeff516be45a2c8abb22e6cd5b2502d0e17 Mon Sep 17 00:00:00 2001 From: qinziang Date: Sat, 25 Feb 2023 18:02:00 +0800 Subject: [PATCH 05/18] [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 ee0a1c8f7c7508bd37112aa07098ca0d1818ebc7 Mon Sep 17 00:00:00 2001 From: Aperzer Date: Tue, 28 Feb 2023 10:09:20 +0800 Subject: [PATCH 06/18] [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 7d307d92f181..7bb93de8556a 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6490,6 +6490,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 657dadb3c8a3607684c69ab9fe31021d4763a2a2 Mon Sep 17 00:00:00 2001 From: Aperzer Date: Thu, 2 Mar 2023 15:38:56 +0800 Subject: [PATCH 07/18] [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 03108ee7cdab7e642d6d74afcf4dc83227c36740 Mon Sep 17 00:00:00 2001 From: qinziang Date: Thu, 2 Mar 2023 19:29:14 +0800 Subject: [PATCH 08/18] [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 66c61f76fd7d..3121ce8b6d59 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) @@ -3381,7 +3381,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; @@ -3433,7 +3433,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); @@ -3995,7 +3995,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 9d96713233e5c34c9b9b71f92caacedafd51148c Mon Sep 17 00:00:00 2001 From: EdwardWang Date: Thu, 9 Mar 2023 22:05:09 +0800 Subject: [PATCH 09/18] [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 3121ce8b6d59..770365fc8fa8 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; } @@ -3420,7 +3420,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 0bac9b0b42a5..90f5cc7d179e 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() && @@ -17670,9 +17670,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 ea776b674480774e84edbf75c8074f5cfe2f1310 Mon Sep 17 00:00:00 2001 From: EdwardWang Date: Sat, 11 Mar 2023 14:26:54 +0800 Subject: [PATCH 10/18] [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 15d760391b3465f344c26fbef79fe410dc0d0723 Mon Sep 17 00:00:00 2001 From: EdwardWang Date: Sat, 11 Mar 2023 15:37:13 +0800 Subject: [PATCH 11/18] [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 b0c085d98044..509a943829ff 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9299,7 +9299,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 770365fc8fa8..5af62a99515f 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 90f5cc7d179e..ccf8da13bd02 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -15652,7 +15652,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, @@ -16016,7 +16016,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 5eaf2967d70e70dea05171d916b5700d67e3a323 Mon Sep 17 00:00:00 2001 From: Aperzer Date: Sun, 19 Mar 2023 18:50:49 +0800 Subject: [PATCH 12/18] [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 5af62a99515f..ec78e221d0d2 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 ccf8da13bd02..44c1f80f16af 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 f9b5e7dc2a6c..9bf8318d2f70 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 1de6c9b2c2bd07c7e0843cba8ef64cb1e9141f87 Mon Sep 17 00:00:00 2001 From: qinziang Date: Mon, 20 Mar 2023 10:53:05 +0800 Subject: [PATCH 13/18] [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 ec78e221d0d2..caed4a077f18 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 f2ac3e1bea24a83fd17bd102534df8361e7cc155 Mon Sep 17 00:00:00 2001 From: qinziang Date: Tue, 21 Mar 2023 19:29:41 +0800 Subject: [PATCH 14/18] [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 1d4eef7e0f1f40e9d81db71c4321030290b6da23 Mon Sep 17 00:00:00 2001 From: Aperzer Date: Wed, 22 Mar 2023 11:06:51 +0800 Subject: [PATCH 15/18] [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 146f2d19fd74..fb41168f6e82 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1563,7 +1563,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 faf9e5e308d7c8c407c6c9d2859c922ec61bd3bc Mon Sep 17 00:00:00 2001 From: Aperzer Date: Mon, 27 Mar 2023 17:26:10 +0800 Subject: [PATCH 16/18] [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 caed4a077f18..77d186d9a70f 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3349,7 +3349,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 1b45e30916e8d0ff6360b64cc813b46d4611e9ee Mon Sep 17 00:00:00 2001 From: qinziang Date: Tue, 28 Mar 2023 21:41:13 +0800 Subject: [PATCH 17/18] [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 04ad1ec864ebca754aa86780bba6ca91f809c3cd Mon Sep 17 00:00:00 2001 From: qinziang Date: Thu, 30 Mar 2023 10:10:25 +0800 Subject: [PATCH 18/18] [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 77d186d9a70f..2a3a54a77c51 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. @@ -3401,7 +3402,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); @@ -3963,7 +3964,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 @@ -5964,8 +5965,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. @@ -6055,7 +6055,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, @@ -6244,7 +6243,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 @@ -6607,7 +6606,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