diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index e5465893b393fb0f02ab67324f9ca18b13c32932..fe05378f4a9d9267ba1cef8c823b3eadec23f5b0 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1889,6 +1889,23 @@ private: bool EnteringContext, IdentifierInfo &II, CXXScopeSpec &SS); + static bool IsBSCTemplateBlackList(tok::TokenKind TmpKind) { + switch (TmpKind) + { + case tok::eof: + case tok::equal: + case tok::l_brace: + case tok::semi: + case tok::numeric_constant: + return true; + + default: + break; + } + + return false; + } + bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHasErrors, @@ -2388,6 +2405,9 @@ private: AccessSpecifier AS = AS_none, DeclSpecContext DSC = DeclSpecContext::DSC_normal, LateParsedAttrList *LateAttrs = nullptr, bool BSCScopeSpecFlag = false); + // Record BSC Generic Look-Ahead when parsing '<>' + int BSCGenericLookAhead; + bool IsParsingBSCGenericParameters = false; void ParseBSCScopeSpecifiers(DeclSpec &DS); bool IsBSCMethodAmbiguous(); bool DiagnoseMissingSemiAfterTagDefinition( @@ -3424,19 +3444,16 @@ private: unsigned Depth, SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, - SourceLocation &RAngleLoc, - int &LookAheadOffset); + SourceLocation &RAngleLoc); bool ParseTemplateParameterList(unsigned Depth, SmallVectorImpl &TemplateParams); bool ParseBSCTemplateParameterList(unsigned Depth, - SmallVectorImpl &TemplateParams, - int &LookAheadOffset); + SmallVectorImpl &TemplateParams); TPResult isStartOfTemplateTypeParameter(); NamedDecl *ParseTemplateParameter(unsigned Depth, unsigned Position); NamedDecl *ParseTypeParameter(unsigned Depth, unsigned Position); - NamedDecl *ParseBSCTypeParameter(unsigned Depth, unsigned Position, - int &LookAheadOffset); + NamedDecl *ParseBSCTypeParameter(unsigned Depth, unsigned Position); 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 bb2dfa61f5fff2a546cd3c2a2583997378fc334d..2e5f70c9f592067a3e03631aae36491358275bce 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3177,7 +3177,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // Start the range at the current token but make the end of the range // invalid. This will make the entire range invalid unless we successfully // consume a token. - DS.SetRangeStart(Tok.getLocation()); + if (getLangOpts().BSC && IsParsingBSCGenericParameters) { + DS.SetRangeStart(PP.LookAhead(BSCGenericLookAhead).getLocation()); + } else { + DS.SetRangeStart(Tok.getLocation()); + } DS.SetRangeEnd(SourceLocation()); } @@ -3188,6 +3192,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // We use Sema's policy to get bool macros right. PrintingPolicy Policy = Actions.getPrintingPolicy(); while (true) { + // Get Switch Tok for BSC constant generic. + Token SwitchTok; + if (getLangOpts().BSC && IsParsingBSCGenericParameters){ + SwitchTok = PP.LookAhead(BSCGenericLookAhead); + } else { + SwitchTok = Tok; + } + bool isInvalid = false; bool isStorageClass = false; const char *PrevSpec = nullptr; @@ -3209,7 +3221,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, !DS.hasTypeSpecifier() && GetLookAheadToken(1).is(tok::less)) Tok.setKind(tok::identifier); - SourceLocation Loc = Tok.getLocation(); + SourceLocation Loc = SwitchTok.getLocation(); // Helper for image types in OpenCL. auto handleOpenCLImageKW = [&] (StringRef Ext, TypeSpecifierType ImageTypeSpec) { @@ -3240,7 +3252,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, Diag(Loc, diag::ambiguous_bscmethod_define); } - switch (Tok.getKind()) { + switch (SwitchTok.getKind()) { default: DoneWithDeclSpec: if (!AttrsLastTime) @@ -3610,7 +3622,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, goto DoneWithDeclSpec; ParsedType TypeRep = Actions.getTypeName( - *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), nullptr, + *SwitchTok.getIdentifierInfo(), SwitchTok.getLocation(), getCurScope(), nullptr, false, false, nullptr, false, false, isClassTemplateDeductionContext(DSContext)); @@ -3619,7 +3631,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (!TypeRep) { if (TryAnnotateTypeConstraint()) goto DoneWithDeclSpec; - if (Tok.isNot(tok::identifier)) + if (SwitchTok.isNot(tok::identifier)) continue; ParsedAttributes Attrs(AttrFactory); if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) { @@ -3648,8 +3660,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (isInvalid) break; - DS.SetRangeEnd(Tok.getLocation()); - ConsumeToken(); // The identifier + DS.SetRangeEnd(SwitchTok.getLocation()); + if (IsParsingBSCGenericParameters) { + BSCGenericLookAhead++; + } else { + ConsumeToken(); // The identifier + } // Objective-C supports type arguments and protocol references // following an Objective-C object or object pointer @@ -4358,7 +4374,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, continue; } - DS.SetRangeEnd(ConsumedEnd.isValid() ? ConsumedEnd : Tok.getLocation()); + DS.SetRangeEnd(ConsumedEnd.isValid() ? ConsumedEnd : SwitchTok.getLocation()); // If the specifier wasn't legal, issue a diagnostic. if (isInvalid) { @@ -4378,9 +4394,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, Diag(Loc, DiagID) << PrevSpec; } - if (DiagID != diag::err_bool_redeclaration && ConsumedEnd.isInvalid()) - // After an error the next token can be an annotation token. - ConsumeAnyToken(); + if (DiagID != diag::err_bool_redeclaration && ConsumedEnd.isInvalid()) { + if (getLangOpts().BSC && IsParsingBSCGenericParameters){ + // Assuming that clang consumed this token + BSCGenericLookAhead++; + } else { + // After an error the next token can be an annotation token. + ConsumeAnyToken(); + } + } AttrsLastTime = false; } @@ -5995,7 +6017,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D, D.setExtension(); // BSC - if (getLangOpts().BSC && FindUntil(tok::coloncolon)) { + if (getLangOpts().BSC && FindUntil(tok::coloncolon) + && !IsParsingBSCGenericParameters) { DeclSpec DS(AttrFactory); ParseBSCScopeSpecifiers(DS); TryConsumeToken(tok::coloncolon); @@ -6305,6 +6328,19 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // the l_paren token. } + if (IsParsingBSCGenericParameters) { + Token SwitchTok = PP.LookAhead(BSCGenericLookAhead); + UnqualifiedId &Result = D.getName(); + if (SwitchTok.is(tok::identifier)) { + IdentifierInfo *Id = SwitchTok.getIdentifierInfo(); + SourceLocation IdLoc = SwitchTok.getLocation(); + Result.setIdentifier(Id, IdLoc); + BSCGenericLookAhead++; + } + D.SetRangeEnd(D.getName().getSourceRange().getEnd()); + goto PastIdentifier; + } + if (Tok.isOneOf(tok::identifier, tok::kw_operator, tok::annot_template_id, tok::tilde)) { // We found something that indicates the start of an unqualified-id. diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 7c86e9ce79b05758840e3be19c695a1e9703ecfd..2093cf6fbff5e81219a9dbd338e3142d41f5bd58 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -102,6 +102,46 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType, /*AtDigraph*/false); } +// To judge if the syntax is a BSC template declaration. +static bool IsBSCTemplateDeclaration(bool IsBSC, + bool IsIdentifier, + Preprocessor &PP) { + + bool IsCase_1 = (PP.LookAhead(1).is(tok::kw_int) && + PP.LookAhead(2).is(tok::identifier)); + + bool IsCase_2 = (PP.LookAhead(1).is(tok::identifier) && + PP.LookAhead(2).isOneOf(tok::comma, + tok::greater)); + + bool IsCase_3 = (PP.LookAhead(1).is(tok::identifier) && + PP.LookAhead(2).is(tok::identifier) && + PP.LookAhead(3).isOneOf(tok::comma, + tok::greater)); + + bool IsCase_4 = (PP.LookAhead(1).isOneOf(tok::kw_unsigned, + tok::kw_signed, + tok::kw_long, + tok::kw_short) && + PP.LookAhead(2).isOneOf(tok::kw_int, + tok::identifier, + tok::kw_short, + tok::kw_long) && + PP.LookAhead(3).isOneOf(tok::kw_int, + tok::identifier, + tok::comma, + tok::greater, + tok::kw_long)); + + bool IsBSCTemplateDecl = IsBSC && + IsIdentifier && + PP.LookAhead(0).is(tok::less) && + (IsCase_1 || IsCase_2 || + IsCase_3 || IsCase_4); + + return IsBSCTemplateDecl; +} + /// Parse global scope or nested-name-specifier if present. /// /// Parses a C++ global scope specifier ('::') or nested-name-specifier (which @@ -391,19 +431,22 @@ bool Parser::ParseOptionalCXXScopeSpecifier( // Skip param list "" in template function declaration: // "T max (T a, T b) {...}" Token Next; - bool ParsingBSCTemplateFunction = - getLangOpts().BSC && Tok.is(tok::identifier) && - PP.LookAhead(0).is(tok::less) && - PP.LookAhead(1).is( - tok::identifier) && // TODO: this could be missidentified from typo: - // "intt" - (PP.LookAhead(2).is(tok::comma) || PP.LookAhead(2).is(tok::greater)); + // TODO: this could be missidentified from typo:// "intt" + bool ParsingBSCTemplateFunction = + IsBSCTemplateDeclaration(getLangOpts().BSC, + Tok.is(tok::identifier), + PP); if (ParsingBSCTemplateFunction) { // Determine if '>' is followed by '{' or '(' int LGreaterOffset = 2; Token TmpTok = PP.LookAhead(LGreaterOffset); - while (!TmpTok.is(tok::greater) && !TmpTok.is(tok::eof)) { + // Attention to case like: int a = foo<(1>>2)>(3); + // The case above is not parsing BSC template function. + while ((TmpTok.isNot(tok::greater) || + (PP.LookAhead(LGreaterOffset + 1).is(tok::greater) || + PP.LookAhead(LGreaterOffset - 1).is(tok::greater) + )) && !IsBSCTemplateBlackList(TmpTok.getKind())) { LGreaterOffset += 1; TmpTok = PP.LookAhead(LGreaterOffset); } @@ -777,30 +820,29 @@ bool Parser::ParseOptionalBSCGenericSpecifier( // nested-name-specifier identifier '::' Token Next; - bool ParsingBSCTemplateFunction = - getLangOpts().BSC && Tok.is(tok::identifier) && - PP.LookAhead(0).is(tok::less) && PP.LookAhead(1).is(tok::identifier) && - (PP.LookAhead(2).is(tok::comma) || PP.LookAhead(2).is(tok::greater)); + bool ParsingBSCTemplateStruct = + IsBSCTemplateDeclaration(getLangOpts().BSC, + Tok.is(tok::identifier), + PP); - if (ParsingBSCTemplateFunction) { - // Determine if 'tok::greater' is followed by 'l_ paren' and 'l_brace' - int LGreaterOffset = 2; + int LGreaterOffset = 2; + if (ParsingBSCTemplateStruct) { + // Determine if '>' is followed by '{' or '(' Token TmpTok = PP.LookAhead(LGreaterOffset); - while (!TmpTok.is(tok::greater) && !TmpTok.is(tok::eof)) { + while ((TmpTok.isNot(tok::greater) || + (PP.LookAhead(LGreaterOffset + 1).is(tok::greater) || + PP.LookAhead(LGreaterOffset - 1).is(tok::greater)) + ) && !IsBSCTemplateBlackList(TmpTok.getKind())) { LGreaterOffset += 1; TmpTok = PP.LookAhead(LGreaterOffset); } - ParsingBSCTemplateFunction = + ParsingBSCTemplateStruct = TmpTok.is(tok::greater) && (PP.LookAhead(LGreaterOffset + 1) .isOneOf(tok::l_paren, tok::l_brace)); } - if (ParsingBSCTemplateFunction) { - int LParenOffset = 0; - while (!PP.LookAhead(LParenOffset).isOneOf(tok::l_paren, tok::eof)) { - LParenOffset += 1; - } - Next = PP.LookAhead(LParenOffset); + if (ParsingBSCTemplateStruct) { + Next = PP.LookAhead(LGreaterOffset + 1); } else { Next = NextToken(); } diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 7dc0d626a3f788506ed7eb13b4ded03334f6d711..63ca582b009f679e183900d2525aa36eadebf05a 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -94,29 +94,29 @@ Decl *Parser::ParseBSCGenericDeclaration(DeclaratorContext Context, if (TemplateLoc.isInvalid()) TemplateLoc = Tok.getLocation(); - int LookAheadOffset = 0; // LookAheadOffset starts from 0, assume the first + BSCGenericLookAhead = 0; // BSCGenericLookAhead starts from 0, assume the first // token we see must not be '<' - while (!PP.LookAhead(LookAheadOffset) + while (!PP.LookAhead(BSCGenericLookAhead) .is(tok::less)) { // use while since the template function // definition struct is not solid in BSC - LookAheadOffset += 1; + BSCGenericLookAhead++; } - assert(PP.LookAhead(LookAheadOffset).is(tok::less) && + assert(PP.LookAhead(BSCGenericLookAhead).is(tok::less) && "BSC template function parameter list does not begin with tok::less"); int LookGreaterOffset = 1; - Token TmpTok = PP.LookAhead(LookGreaterOffset + LookAheadOffset); - Token PostTok = PP.LookAhead(LookGreaterOffset + LookAheadOffset + 1); + Token TmpTok = PP.LookAhead(LookGreaterOffset + BSCGenericLookAhead); + Token PostTok = PP.LookAhead(LookGreaterOffset + BSCGenericLookAhead + 1); while (!(TmpTok.is(tok::greater) && PostTok.isOneOf(tok::l_brace, tok::l_paren, tok::coloncolon)) && !TmpTok.is(tok::eof)) { if (TmpTok.is(tok::less)) { - LookAheadOffset = LookGreaterOffset + LookAheadOffset; + BSCGenericLookAhead = LookGreaterOffset + BSCGenericLookAhead; LookGreaterOffset = 0; } LookGreaterOffset++; - TmpTok = PP.LookAhead(LookGreaterOffset + LookAheadOffset); - PostTok = PP.LookAhead(LookGreaterOffset + LookAheadOffset + 1); + TmpTok = PP.LookAhead(LookGreaterOffset + BSCGenericLookAhead); + PostTok = PP.LookAhead(LookGreaterOffset + BSCGenericLookAhead + 1); } assert(TmpTok.is(tok::greater) && @@ -128,8 +128,8 @@ Decl *Parser::ParseBSCGenericDeclaration(DeclaratorContext Context, SmallVector TemplateParams; if (ParseBSCTemplateParameters(TemplateParamScopes, CurTemplateDepthTracker.getDepth(), - TemplateParams, LAngleLoc, RAngleLoc, - LookAheadOffset)) { // open this + TemplateParams, LAngleLoc, RAngleLoc)) { + // open this // Skip until the semi-colon or a '}'. SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); // error handel TryConsumeToken(tok::semi); @@ -627,28 +627,30 @@ bool Parser::ParseTemplateParameters( bool Parser::ParseBSCTemplateParameters( MultiParseScope &TemplateScopes, unsigned Depth, SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, - SourceLocation &RAngleLoc, int &LookAheadOffset) { - Token PeekTok = PP.LookAhead(LookAheadOffset); + SourceLocation &RAngleLoc) { + Token PeekTok = PP.LookAhead(BSCGenericLookAhead); if (PeekTok.is(tok::less)) { - LookAheadOffset += 1; + BSCGenericLookAhead++; + IsParsingBSCGenericParameters = true; LAngleLoc = PeekTok.getLocation(); } else { Diag(PeekTok.getLocation(), diag::err_expected_less_after) << "template"; return true; } - PeekTok = PP.LookAhead(LookAheadOffset); + PeekTok = PP.LookAhead(BSCGenericLookAhead); // Try to parse the template parameter list. bool Failed = false; if (!PeekTok.is(tok::greater)) { TemplateScopes.Enter(Scope::TemplateParamScope); Failed = - ParseBSCTemplateParameterList(Depth, TemplateParams, LookAheadOffset); + ParseBSCTemplateParameterList(Depth, TemplateParams); } - PeekTok = PP.LookAhead(LookAheadOffset); + PeekTok = PP.LookAhead(BSCGenericLookAhead); if (PeekTok.getKind() == tok::greater) { - LookAheadOffset += 1; + BSCGenericLookAhead++; + IsParsingBSCGenericParameters = false; RAngleLoc = PeekTok.getLocation(); } else { if (Failed) { @@ -705,29 +707,33 @@ Parser::ParseTemplateParameterList(const unsigned Depth, // 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); + const unsigned Depth, SmallVectorImpl &TemplateParams) { + Token PeekTok = PP.LookAhead(BSCGenericLookAhead); while (1) { // if (NamedDecl *TmpParam // = ParseTemplateParameter(Depth, TemplateParams.size())) { if (NamedDecl *TmpParam = ParseBSCTypeParameter( - Depth, TemplateParams.size(), LookAheadOffset)) { + Depth, TemplateParams.size())) { 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, // FIXME: logic error - StopAtSemi | StopBeforeMatch); + for (; PeekTok.isNot(tok::semi); BSCGenericLookAhead++) { + PeekTok = PP.LookAhead(BSCGenericLookAhead); + if (PeekTok.isOneOf(tok::comma, + tok::greater, + tok::semi)) + break; + } } - PeekTok = PP.LookAhead(LookAheadOffset); + PeekTok = PP.LookAhead(BSCGenericLookAhead); // 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); + BSCGenericLookAhead++; + PeekTok = PP.LookAhead(BSCGenericLookAhead); // } else if (PeekTok.isOneOf(tok::greater, tok::greatergreater)) { } else if (PeekTok.is(tok::greater)) { // Don't consume this... that's done by template parser. @@ -1076,15 +1082,37 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { // ParseBSCTypeParameter - rewrite ParseTypeParameter for cross-order BSC // syntax, use Peeking -NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, - int &LookAheadOffset) { +NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position) { // Check Tok location - Token PeekTok = PP.LookAhead(LookAheadOffset); + Token PeekTok = PP.LookAhead(BSCGenericLookAhead); bool isBSCTemplateTypeParameter = getLangOpts().BSC; // TODO: fix the cond assert( isBSCTemplateTypeParameter && "A type-parameter starts with 'class', 'typename' or a type-constraint"); + if (PeekTok.is(tok::kw_struct)) { + Diag(PeekTok.getLocation(), diag::err_template_nontype_parm_bad_type) << PeekTok.getName(); + return nullptr; + } + + bool IsNextCommaOrGreater = + PP.LookAhead(BSCGenericLookAhead + 1).isOneOf(tok::comma, + tok::greater); + + // if ((PeekTok.isNot(tok::identifier) && (!IsNextCommaOrGreater)) || + // !IsNextCommaOrGreater) { + // return ParseNonTypeTemplateParameter(Depth, Position); + // } + + if (PeekTok.isNot(tok::identifier) && IsNextCommaOrGreater) { + Diag(PeekTok.getLocation(), diag::err_expected_template_parameter) << PeekTok.getName(); + return nullptr; + } + + if (PeekTok.isNot(tok::identifier) || !IsNextCommaOrGreater) { + return ParseNonTypeTemplateParameter(Depth, Position); + } + CXXScopeSpec TypeConstraintSS; TemplateIdAnnotation *TypeConstraint = nullptr; bool TypenameKeyword = false; @@ -1113,8 +1141,8 @@ NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, SourceLocation EllipsisLoc; if (PeekTok.is(tok::ellipsis)) { EllipsisLoc = PeekTok.getLocation(); - LookAheadOffset += 1; - PeekTok = PP.LookAhead(LookAheadOffset); + BSCGenericLookAhead++; + PeekTok = PP.LookAhead(BSCGenericLookAhead); Diag(EllipsisLoc, getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_variadic_templates : diag::ext_variadic_templates); @@ -1126,8 +1154,8 @@ NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, if (PeekTok.is(tok::identifier)) { ParamName = PeekTok.getIdentifierInfo(); // unknown manipulation, parsing T token - LookAheadOffset += 1; - PeekTok = PP.LookAhead(LookAheadOffset); + BSCGenericLookAhead++; + PeekTok = PP.LookAhead(BSCGenericLookAhead); } else if (PeekTok.isOneOf(tok::equal, tok::comma, tok::greater, tok::greatergreater)) { // Unnamed template parameter. Don't have to do anything here, just @@ -1139,10 +1167,10 @@ NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, // Recover from misplaced ellipsis. bool AlreadyHasEllipsis = EllipsisLoc.isValid(); - if (PP.LookAhead(LookAheadOffset).is(tok::ellipsis)) { + if (PP.LookAhead(BSCGenericLookAhead).is(tok::ellipsis)) { EllipsisLoc = PeekTok.getLocation(); - LookAheadOffset += 1; - PeekTok = PP.LookAhead(LookAheadOffset); + BSCGenericLookAhead++; + PeekTok = PP.LookAhead(BSCGenericLookAhead); DiagnoseMisplacedEllipsis(EllipsisLoc, NameLoc, AlreadyHasEllipsis, true); } @@ -1153,8 +1181,8 @@ NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, ParsedType DefaultArg; if (PeekTok.is(tok::equal)) { EqualLoc = PeekTok.getLocation(); - LookAheadOffset += 1; - PeekTok = PP.LookAhead(LookAheadOffset); + BSCGenericLookAhead++; + PeekTok = PP.LookAhead(BSCGenericLookAhead); DefaultArg = ParseTypeName(/*Range=*/nullptr, DeclaratorContext::TemplateTypeArg) .get(); diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 418663de690ea9a38f89e4209c3b8f8656d05f35..0ee055fe819c9a1e7c4a6136afa904a5823ed1f8 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1121,49 +1121,88 @@ bool Parser::isBSCTemplateDecl(Token tok) { if (!getLangOpts().BSC) return false; - // 2. check "identifier" structure - int LessOffset = 0; + int LookAheadOffset = 0; bool FoundLess = false; bool FoundGreater = false; - bool FoundIdentifier = false; - Token prevTok = tok; - Token TmpTok = PP.LookAhead(LessOffset); - for (LessOffset = 1; !PP.LookAhead(LessOffset).is(tok::eof); LessOffset++) { - if (TmpTok.is(tok::l_paren) || TmpTok.is(tok::l_brace) || - TmpTok.is(tok::equal)) { - return false; - } - // "<>" must appear neighboring with identtifier - if (TmpTok.is(tok::less) && prevTok.is(tok::identifier)) { - FoundLess = true; - break; // do not check if ">" missing, leave diagnose in outer API + bool HasValidParameter = false; + tok::TokenKind LookAheadKind = + PP.LookAhead(LookAheadOffset).getKind(); + + Token PreTok; + Token NextTok; + Token LookAheadTok; + + for(; !IsBSCTemplateBlackList(LookAheadKind); LookAheadOffset++) { + LookAheadTok = PP.LookAhead(LookAheadOffset); + LookAheadKind = PP.LookAhead(LookAheadOffset).getKind(); + + NextTok = PP.LookAhead(LookAheadOffset + 1); + if(LookAheadOffset != 0) { + PreTok = PP.LookAhead(LookAheadOffset - 1); + } else { + PreTok = Tok; } - prevTok = TmpTok; - TmpTok = PP.LookAhead(LessOffset); - } - if (!FoundLess) - return false; + + switch (LookAheadTok.getKind()) { + case tok::less: + // Not BSC template declaration syntax. + if (LookAheadTok.isAtStartOfLine() || + PreTok.isAtStartOfLine()) + return false; - // 3. check " {}", "()" or " ::" structure in struct - // declaration - int LBraceOffset = 0; - TmpTok = PP.LookAhead(LessOffset + LBraceOffset); - for (; !TmpTok.is(tok::eof); LBraceOffset++) { // check "Foo<>" structure - TmpTok = PP.LookAhead(LessOffset + LBraceOffset); - if (TmpTok.is(tok::greater)) { - Token PostTok = PP.LookAhead(LessOffset + LBraceOffset + 1); - if (PostTok.isOneOf(tok::l_brace, tok::l_paren, tok::coloncolon) && - FoundIdentifier) - return true; + if (PreTok.is(tok::identifier)) { + // If already found less, or it`s a bit operation + // case, like 'foo<(a<;', skip it. + if (FoundLess || (PreTok.is(tok::less) || + NextTok.is(tok::less))) + break; + + // To avoid the misjudgement of a none-return + // BSC template function, like this: + // @Code + // void foo(T a){}; + // void test() { + // foo(1); // At here + // } + // @EndCode + // Template struct will be distinguished at '>'. + if (!(getCurScope()->getDepth() == 0) && + getCurScope()->getParent()->isClassScope()) + break; + + FoundLess = true; + } + break; + case tok::l_paren: + if (FoundLess) + { + return false; + } + break; + case tok::greater: + // invalid syntax for BSC template + if (LookAheadTok.isAtStartOfLine()) + return false; + if (!FoundLess || (PreTok.is(tok::greater) || + NextTok.is(tok::greater))) + break; + // valid syntax for BSC template + if (HasValidParameter && NextTok.isOneOf(tok::l_brace, + tok::l_paren, + tok::coloncolon)) { + FoundGreater = true; + return true; + } + break; + case tok::identifier: + if (FoundLess && !FoundGreater) // check if there is an identifier in "<>"" + HasValidParameter = true; + break; + default: + break; } - if (TmpTok.is(tok::identifier) && - !FoundGreater) // check if there is an identifier in "<>"" - FoundIdentifier = true; - if (TmpTok.is(tok::semi) || - TmpTok.is(tok::equal)) // no "{" in current sentence - return false; } - + return false; } diff --git a/clang/test/BSC/Driver/rewrite-bsc/Generic/rewrite_bsc_generic_4.cbs b/clang/test/BSC/Driver/rewrite-bsc/Generic/rewrite_bsc_generic_4.cbs index b30c6f476d4c2c17645f594803ea96c26362bd03..9f9c0463893f4a725709de59f47562f487dd935f 100644 --- a/clang/test/BSC/Driver/rewrite-bsc/Generic/rewrite_bsc_generic_4.cbs +++ b/clang/test/BSC/Driver/rewrite-bsc/Generic/rewrite_bsc_generic_4.cbs @@ -20,8 +20,7 @@ int main() { } -// CHECK:struct Block -// CHECK-NEXT:{ +// CHECK:struct Block { // CHECK-NEXT: int a; // CHECK-NEXT:}; diff --git a/clang/test/BSC/Generic/Constant/Constant_func_1.cbs b/clang/test/BSC/Generic/Constant/Constant_func_1.cbs new file mode 100644 index 0000000000000000000000000000000000000000..1eeb5b24c94ba1672d1990bb877f10b26e08d0d4 --- /dev/null +++ b/clang/test/BSC/Generic/Constant/Constant_func_1.cbs @@ -0,0 +1,50 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +T constant_1(T a) +{ + T data[B]; + return a; +} + +T constant_2(T a) +{ + T data[B]; + return a; +} + +T constant_3(T a) +{ + T data[B]; + return a; +} + +T constant_4(T a) +{ + T data[B]; + return a; +} + +T constant_5(T a) +{ + T data[B]; + return a; +} + +T constant_6(T a) +{ + T data[B]; + return a; +} + +int main() { + int a1 = constant_1(1); + int a2 = constant_2(1); + int a3 = constant_3(1); + int a4 = constant_4(1); + int a5 = constant_5(1); + int a6 = constant_6(1); + + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/Constant/Constant_func_2.cbs b/clang/test/BSC/Generic/Constant/Constant_func_2.cbs new file mode 100644 index 0000000000000000000000000000000000000000..9c1ec1fe57126a8356f8027364c6ee52030ccb33 --- /dev/null +++ b/clang/test/BSC/Generic/Constant/Constant_func_2.cbs @@ -0,0 +1,33 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +typedef long long int LLint; +typedef unsigned long long int ULLint; + +T foo_1(T a) { + T data[B]; + return a; +} + +ULLint foo_2(T a) { + T data[B]; + ULLint c = C; + return a; +} + +LLint foo_3(int a) { + LLint b = 1; + return a > B ? a : B; +} + + +int main() { + int a1 = foo_1<5, 6, int>(1); + + int a2 = foo_2<5, int, 6>(1); + + LLint a3 = foo_3<5>(1); + + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/Constant/Constant_struct_1.cbs b/clang/test/BSC/Generic/Constant/Constant_struct_1.cbs new file mode 100644 index 0000000000000000000000000000000000000000..dbd5d21ac01b015707e98786d36a3a225e31f3cc --- /dev/null +++ b/clang/test/BSC/Generic/Constant/Constant_struct_1.cbs @@ -0,0 +1,45 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +struct Array_1 +{ + T data[N]; +}; + +struct Array_2 +{ + T data[N]; +}; + +struct Array_3 +{ + T data[N]; +}; + +struct Array_4 +{ + T data[N]; +}; + +struct Array_5 +{ + T data[N]; +}; + +struct Array_6 +{ + T data[N]; +}; + + +int main() { + struct Array_1 arr1; + struct Array_2 arr2; + struct Array_3 arr3; + struct Array_4 arr4; + struct Array_5 arr5; + struct Array_6 arr6; + + return 0; +} diff --git a/clang/test/BSC/Generic/Constant/Constant_struct_2.cbs b/clang/test/BSC/Generic/Constant/Constant_struct_2.cbs new file mode 100644 index 0000000000000000000000000000000000000000..439acc66ada5d79742fdd7106f727df271e0e767 --- /dev/null +++ b/clang/test/BSC/Generic/Constant/Constant_struct_2.cbs @@ -0,0 +1,32 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +typedef long long int LLint; +typedef unsigned short US; + +struct Array_1 +{ + LLint data[B]; + T a; +}; + +struct Array_2 +{ + int data[B]; + US a; +}; + +struct Array_3 +{ + US data[B]; + int data_2[C]; +}; + +int main() { + struct Array_1<5, 6, int> arr1 = {.a = 1}; + struct Array_2<5, 6> arr2 = {.a = 1}; + struct Array_3<5, int, 6> arr3; + + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/Constant/Invalid_constant.cbs b/clang/test/BSC/Generic/Constant/Invalid_constant.cbs new file mode 100644 index 0000000000000000000000000000000000000000..19cdd81b99fed270dc8b7471cc75af8e506ce129 --- /dev/null +++ b/clang/test/BSC/Generic/Constant/Invalid_constant.cbs @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -verify %s + +int foo_1(int a) { + int x = N; + int y = L.f1; // expected-error {{no member named 'f1' in type 'int'}} + return x; +} + +int foo_2(int a) { // expected-note {{candidate template ignored: invalid explicitly-specified argument for template parameter 'B'}} + int x = B; + return x; +} + +int foo_3(int a) { // expected-note {{possible target for call}} + int x = C; + return x; +} + +float foo_4(int a) { /* expected-error {{a non-type template parameter cannot have type 'float' before C++20}} + expected-error {{type-id cannot have a name}} */ + float x = F; + return x; +} + +int main() { + int a = foo_2<3.15>(2); // expected-error {{no matching function for call to 'foo_2'}} + + float x = 1.5; + int b = foo_3(2); // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/StructAndFunction/invalid_paramete_1.cbs b/clang/test/BSC/Generic/StructAndFunction/invalid_paramete_1.cbs new file mode 100644 index 0000000000000000000000000000000000000000..35a3946174aa03af8a102e8fc6a54d19c4afb79c --- /dev/null +++ b/clang/test/BSC/Generic/StructAndFunction/invalid_paramete_1.cbs @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -verify %s + +struct S // expected-error {{a non-type template parameter cannot have type struct}} +{ + T a; +}; + +T test(T a) // expected-error {{a non-type template parameter cannot have type struct}} +{ + return a; +} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/StructAndFunction/invalid_paramete_2.cbs b/clang/test/BSC/Generic/StructAndFunction/invalid_paramete_2.cbs new file mode 100644 index 0000000000000000000000000000000000000000..f2fab3a1168858c97dae27b41af00bf4ff95f5d7 --- /dev/null +++ b/clang/test/BSC/Generic/StructAndFunction/invalid_paramete_2.cbs @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -verify %s + +void test2(T a) // expected-error {{expected template parameter}} +{ + int c = 1; +} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/StructAndFunction/invalid_paramete_3.cbs b/clang/test/BSC/Generic/StructAndFunction/invalid_paramete_3.cbs new file mode 100644 index 0000000000000000000000000000000000000000..3163adaba20fb095e7f150d20ec6c0539ea4f913 --- /dev/null +++ b/clang/test/BSC/Generic/StructAndFunction/invalid_paramete_3.cbs @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -verify %s + +T foo(T a) /* expected-error {{unknown type name 'T'}} + expected-error {{expected ';' after top level declarator}} */ +{ + return a; +} + +int main() { + return 0; +} \ No newline at end of file