diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index d71822ebaa94..cac0ea46a0e9 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1549,8 +1549,8 @@ def err_unbalanced_parentheses_in_where_clause : Error< def err_expected_list_of_types_expr_for_generic_function : Error< "expected a list of type arguments for a generic function">; -def err_type_function_comma_or_greater_expected : Error< - "expected , or >">; +def err_type_function_comma_or_closing_expected : Error< + "expected , or %0">; def err_num_type_args_params_mistmatch : Error< "generic struct takes %0 type arguments, but instantiation provided %1">; @@ -1558,6 +1558,9 @@ def err_num_type_args_params_mistmatch : Error< def err_expected_type_argument_list_for_generic_instance : Error< "expected a type argument list for a generic struct type">; +def err_mismatched_brackets : Error< + "found '<' after _TyArgs, use '(' instead">; + def err_expected_type_argument_list_for_itype_generic_instance : Error< "expected a type argument list for a struct with a bounds-safe interface in a checked scope">; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 51ca15f350d0..7c079c3042e3 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2085,7 +2085,7 @@ class Parser : public CodeCompletionHandler { ExprResult ParseGenericFunctionApplication(ExprResult TypeFunc, SourceLocation Loc); using TypeArgVector = SmallVector; - std::pair ParseGenericTypeArgumentList(SourceLocation Loc); + std::pair ParseGenericTypeArgumentList(SourceLocation Loc, bool IsTyArgs=false); QualType SubstituteTypeVariable(QualType QT, SmallVector &typeNames); diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 0ebddd13f17f..baa013d2ee4a 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -2120,12 +2120,12 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } /// Checked C: parse an application of the 'Base' 'RecordDecl' to a number of type -/// arguments that are yet to be parsed. +/// arguments that are yet to be parsed. This function can handle both old and new syntax. /// 'IsItypeGeneric' is true if we're parsing a type application where the base type /// is an "itype generic" (as opposed to a regular generic). This is used when generatingq /// error messages. /// -/// generic-struct-instantiation +/// generic-struct-typeargs-instantiation /// '<' type-name-list '>' /// /// type-name-list @@ -2135,14 +2135,35 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, /// ',' type-name type-name-list-suffix [opt] DeclResult Parser::ParseRecordTypeApplication(RecordDecl *Base, bool IsItypeGeneric) { assert(Base->isGenericOrItypeGeneric() && "Instantiated record must be generic"); - if (Tok.isNot(tok::less)) { + bool IsTyArgs = Tok.is(tok::kw__TyArgs); + if (Tok.isNot(tok::less) && !IsTyArgs) { if (IsItypeGeneric) Diag(Tok.getLocation(), diag::err_expected_type_argument_list_for_itype_generic_instance); else Diag(Tok.getLocation(), diag::err_expected_type_argument_list_for_generic_instance); - SkipUntil(tok::greater, StopAtSemi); + if (IsTyArgs) + SkipUntil(tok::r_paren, StopAtSemi); + else + SkipUntil(tok::greater, StopAtSemi); return true; } - ConsumeToken(); // eat '<' - auto ArgsRes = ParseGenericTypeArgumentList(SourceLocation()); + if (IsTyArgs) { + // Skip the _TyArgs keyword. + ConsumeToken(); + if (Tok.is(tok::greater)) { + Diag(Tok.getLocation(), diag::err_mismatched_brackets); + SkipUntil(tok::greater, StopAtSemi); + return true; + } + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after) << "_TyArgs"; + SkipUntil(tok::r_paren, StopAtSemi); + return true; + } + } + if (IsTyArgs) + ConsumeParen(); // eat '(' + else + ConsumeToken(); // eat '<' + auto ArgsRes = ParseGenericTypeArgumentList(SourceLocation(), IsTyArgs); if (ArgsRes.first) { // Problem while parsing the type arguments (error is produced by 'ParseGenericTypeArgumentList') return true; diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 629fd354c1c8..12f5f37cca8b 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -3816,18 +3816,24 @@ ExprResult Parser::ParseBoundsExpression() { // This is re-used for both generic functions and generic structs. // Return false if parsing succeeds, in which case the 'typeArgs' is also populated. // Return true if parsing fails. -std::pair Parser::ParseGenericTypeArgumentList(SourceLocation Loc) { +std::pair Parser::ParseGenericTypeArgumentList(SourceLocation Loc, bool IsTyArgs) { Parser::TypeArgVector typeArgumentInfos; auto err = std::make_pair<>(true, Parser::TypeArgVector()); auto firstTypeArgument = true; // Expect to see a list of type names, followed by a '>'. - while (Tok.getKind() != tok::greater) { + tok::TokenKind ExpectedEndToken = IsTyArgs ? tok::r_paren : tok::greater; + StringRef ExpectedEndTokenStr = IsTyArgs ? ")" : ">"; + while (Tok.getKind() != ExpectedEndToken) { if (!firstTypeArgument) { if (ExpectAndConsume(tok::comma, - diag::err_type_function_comma_or_greater_expected)) { - // We want to consume greater, but not consume semi - SkipUntil(tok::greater, StopAtSemi | StopBeforeMatch); + diag::err_type_function_comma_or_closing_expected, ExpectedEndTokenStr)) { + // We want to consume greater or r_paren, but not consume semi + if (IsTyArgs) + SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch); + else + SkipUntil(tok::greater, StopAtSemi | StopBeforeMatch); if (Tok.getKind() == tok::greater) ConsumeToken(); + if (Tok.getKind() == tok::r_paren) ConsumeParen(); return err; } } else @@ -3838,8 +3844,12 @@ std::pair Parser::ParseGenericTypeArgumentList(Sour if (Ty.isInvalid()) { // We do not need to write an error message since ParseTypeName does. // We want to consume greater, but not consume semi - SkipUntil(tok::greater, StopAtSemi | StopBeforeMatch); + if (IsTyArgs) + SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch); + else + SkipUntil(tok::greater, StopAtSemi | StopBeforeMatch); if (Tok.getKind() == tok::greater) ConsumeToken(); + if (Tok.getKind() == tok::r_paren) ConsumeParen(); return err; } @@ -3847,7 +3857,10 @@ std::pair Parser::ParseGenericTypeArgumentList(Sour QualType realType = Actions.GetTypeFromParser(Ty.get(), &TInfo); typeArgumentInfos.push_back({ realType, TInfo }); } - ConsumeToken(); // consume '>' token + if (IsTyArgs) + ConsumeParen(); // consume ')' token + else + ConsumeToken(); // consume '>' token return std::make_pair(false, typeArgumentInfos); } @@ -3876,7 +3889,7 @@ Parser::ParseGenericMacroTypeArgumentList(SourceLocation Loc) { if (Tok.getKind() == tok::comma) { // consume comma ConsumeToken(); } else if (Tok.getKind() != tok::r_paren && !typeArgumentInfos.empty()) { - Diag(Tok, diag::err_type_function_comma_or_greater_expected); + Diag(Tok, diag::err_type_function_comma_or_closing_expected); return handleError(); } } else {