From e67a7ca8be8fb6bc57d12bfc33b427fe4b1d2521 Mon Sep 17 00:00:00 2001 From: Healing Date: Wed, 26 Apr 2023 09:05:30 +0000 Subject: [PATCH 1/5] !53 [BSC] bugfix for method ambiguous * [BSC] bugfix method ambiguous --- clang/lib/Parse/ParseDecl.cpp | 1 - .../BSC/Method/Struct/struct_error_function_definition.cbs | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 clang/test/BSC/Method/Struct/struct_error_function_definition.cbs diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 41e3a4bb78f5..a51f5add7dfd 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -5671,7 +5671,6 @@ static bool isPipeDeclerator(const Declarator &D) { } bool Parser::IsBSCMethodAmbiguous() { - assert(NextToken().isNot(tok::eof)); if (GetLookAheadToken(2).isNot(tok::coloncolon)) { bool FlagUnsigned = (Tok.is(tok::kw_unsigned) && NextToken().isOneOf(tok::kw_int, tok::kw_short, diff --git a/clang/test/BSC/Method/Struct/struct_error_function_definition.cbs b/clang/test/BSC/Method/Struct/struct_error_function_definition.cbs new file mode 100644 index 000000000000..a02ac305ffaf --- /dev/null +++ b/clang/test/BSC/Method/Struct/struct_error_function_definition.cbs @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -verify %s + +struct PollResult_int {}; + +struct struct PollResult_int PollResult_int::completed(struct PollResult_int *this, int result) { // expected-error {{declaration of anonymous struct must be a definition}} +} // expected-error {{expected identifier or '('}} -- Gitee From 7029fc14bc66438ed3d955dfa2938ef723640b30 Mon Sep 17 00:00:00 2001 From: yangdiangzb Date: Wed, 26 Apr 2023 09:13:13 +0000 Subject: [PATCH 2/5] [BSC] bugfix for BSC LangStandards bugfix for BSC LangStandards --- clang/include/clang/Basic/LangStandards.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/LangStandards.def b/clang/include/clang/Basic/LangStandards.def index 8870a735f5ce..a4cb38c1ed84 100644 --- a/clang/include/clang/Basic/LangStandards.def +++ b/clang/include/clang/Basic/LangStandards.def @@ -202,7 +202,7 @@ LANGSTANDARD(hip, "hip", HIP, "HIP", // LANGSTANDARD(bsc, "bsc", BSC, "BiSheng C Language", - LineComment | BSC | C99 | C11 | C17 | C2x | Digraphs) + LineComment | BSC | C99 | C11 | C17 | C2x | Digraphs | GNUMode | HexFloat) #undef LANGSTANDARD #undef LANGSTANDARD_ALIAS -- Gitee From 3516b07f873916120d4e23706f8b06c6e3259241 Mon Sep 17 00:00:00 2001 From: Aperzer Date: Mon, 15 May 2023 06:53:31 +0000 Subject: [PATCH 3/5] !56 [generic]fix bugs of 4 issues [generic]fix bugs of issues --- clang/lib/Parse/ParseDecl.cpp | 12 ++++++++---- clang/lib/Parse/ParseExprCXX.cpp | 12 ++++++++---- clang/lib/Sema/SemaExpr.cpp | 2 ++ clang/test/BSC/Generic/normal_c_logic_1.cbs | 20 ++++++++++++++++++++ clang/test/BSC/Generic/normal_c_logic_2.cbs | 19 +++++++++++++++++++ clang/test/BSC/Generic/normal_c_logic_3.cbs | 14 ++++++++++++++ clang/test/BSC/Generic/normal_c_logic_4.cbs | 15 +++++++++++++++ 7 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 clang/test/BSC/Generic/normal_c_logic_1.cbs create mode 100644 clang/test/BSC/Generic/normal_c_logic_2.cbs create mode 100644 clang/test/BSC/Generic/normal_c_logic_3.cbs create mode 100644 clang/test/BSC/Generic/normal_c_logic_4.cbs diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index a51f5add7dfd..0191354e84b9 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -5956,7 +5956,9 @@ void Parser::ParseDirectDeclarator(Declarator &D) { DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec()); // Add language judgement for BSC template entrance. - if ((getLangOpts().CPlusPlus || getLangOpts().BSC) && D.mayHaveIdentifier()) { + if ((getLangOpts().CPlusPlus || + (getLangOpts().BSC && Actions.getCurScope()->isTemplateParamScope())) && + D.mayHaveIdentifier()) { // This might be a C++17 structured binding. if (Tok.is(tok::l_square) && !D.mayOmitIdentifier() && D.getCXXScopeSpec().isEmpty()) @@ -6230,9 +6232,11 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // is not, the declarator has been fully parsed. bool IsAmbiguous = false; - // Add language judgement for BSC template entrance. - // Change branch entering condition | BSC syntax reusing C++ parsing code - if ((getLangOpts().CPlusPlus || getLangOpts().BSC) && + // Add language judgement for BSC template entrance. Change branch + // entering condition | BSC syntax reusing C++ parsing code + if ((getLangOpts().CPlusPlus || + (getLangOpts().BSC) && + Actions.getCurScope()->getParent()->isTemplateParamScope()) && D.mayBeFollowedByCXXDirectInit()) { // The name of the declarator, if any, is tentatively declared within // a possible direct initializer. diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 1ef83f6e6f9f..25dade7c2687 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -3110,15 +3110,19 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, SourceLocation IdLoc = ConsumeToken(); if (!getLangOpts().CPlusPlus) { - // at BSC syntax T max(T a, T b) {...} - // ^ - if (getLangOpts().BSC && Tok.is(tok::less)) { + // We add this judge to parse BSC syntax, without + // affecting the original logic of C. + // @Code:k + // T max(T a, T b) {...} + // @EndCode + if (Actions.getCurScope()->isTemplateParamScope() && + (getLangOpts().BSC && Tok.is(tok::less))) { // TODO: we should refactoring check logic, abandon assert. assert(Tok.is(tok::less) && "expected 'less' token"); while (!Tok.is(tok::greater)) { ConsumeToken(); } - if(Tok.is(tok::greater)) { + if (Tok.is(tok::greater)) { ConsumeToken(); } else { Diag(Tok.getLocation(), diag::err_expected_comma_greater); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 5bb97ef3d6c9..b132228b41bb 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -14605,7 +14605,9 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, // overloaded op. if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent()) return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); + } + if (getLangOpts().CPlusPlus) { // Otherwise, build an overloaded op if either expression has an // overloadable type. if (LHSExpr->getType()->isOverloadableType() || diff --git a/clang/test/BSC/Generic/normal_c_logic_1.cbs b/clang/test/BSC/Generic/normal_c_logic_1.cbs new file mode 100644 index 000000000000..d16e29160479 --- /dev/null +++ b/clang/test/BSC/Generic/normal_c_logic_1.cbs @@ -0,0 +1,20 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include + +struct f { + int len; +}; + +int f(struct f* m) { + if (m->len + +int m(bool i) { + return 0; +} + +int main() { + return 0; +} + diff --git a/clang/test/BSC/Generic/normal_c_logic_4.cbs b/clang/test/BSC/Generic/normal_c_logic_4.cbs new file mode 100644 index 000000000000..20b1f495a62b --- /dev/null +++ b/clang/test/BSC/Generic/normal_c_logic_4.cbs @@ -0,0 +1,15 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +struct Runtime { + int a; +}; +struct Runtime runtime; + +int main() { + struct Runtime a; + runtime = a; + return 0; +} + -- Gitee From 6dafe42d7c20e9b0c71b21a059972b8a226c725e Mon Sep 17 00:00:00 2001 From: yangdiangzb Date: Thu, 18 May 2023 03:11:41 +0000 Subject: [PATCH 4/5] [BSC][Driver] bugfix for save-temps options [bsc][Driver] bugfix for -save-temps options --- clang/include/clang/Driver/Types.def | 7 +++-- clang/lib/Driver/ToolChains/Clang.cpp | 2 +- clang/lib/Driver/Types.cpp | 31 ++++++++++++++----- clang/test/BSC/Driver/options/save_temp.cbs | 16 ++++++++++ .../{std-option => options}/std_option.cbs | 0 5 files changed, 45 insertions(+), 11 deletions(-) create mode 100644 clang/test/BSC/Driver/options/save_temp.cbs rename clang/test/BSC/Driver/{std-option => options}/std_option.cbs (100%) diff --git a/clang/include/clang/Driver/Types.def b/clang/include/clang/Driver/Types.def index 1e0fc9788064..b6402db4e042 100644 --- a/clang/include/clang/Driver/Types.def +++ b/clang/include/clang/Driver/Types.def @@ -44,10 +44,10 @@ TYPE("cuda", CUDA_DEVICE, PP_CUDA, "cu", phases TYPE("hip-cpp-output", PP_HIP, INVALID, "cui", phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("hip", HIP, PP_HIP, "cu", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("hip", HIP_DEVICE, PP_HIP, "cu", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link) -TYPE("bsc", BSC, PP_C, "cbs", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link) +TYPE("bsc-cpp-output", PP_BSC, INVALID, "i", phases::Compile, phases::Backend, phases::Assemble, phases::Link) +TYPE("bsc", BSC, PP_BSC, "cbs", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("objective-c-cpp-output", PP_ObjC, INVALID, "mi", phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("objc-cpp-output", PP_ObjC_Alias, INVALID, "mi", phases::Compile, phases::Backend, phases::Assemble, phases::Link) -TYPE("bsc-cpp-output", PP_BSCXX, INVALID, "ii", phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("objective-c", ObjC, PP_ObjC, "m", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("c++-cpp-output", PP_CXX, INVALID, "ii", phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("c++", CXX, PP_CXX, "cpp", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link) @@ -60,7 +60,8 @@ TYPE("renderscript", RenderScript, PP_C, "rs", phases TYPE("c-header-cpp-output", PP_CHeader, INVALID, "i", phases::Precompile) TYPE("c-header", CHeader, PP_CHeader, "h", phases::Preprocess, phases::Precompile) TYPE("cl-header", CLHeader, PP_CHeader, "h", phases::Preprocess, phases::Precompile) -TYPE("bsc-header", BSCHeader, PP_CHeader, "hbs", phases::Preprocess, phases::Precompile) +TYPE("bsc-header-cpp-output", PP_BSCHeader, INVALID, "i", phases::Precompile) +TYPE("bsc-header", BSCHeader, PP_BSCHeader, "hbs", phases::Preprocess, phases::Precompile) TYPE("objective-c-header-cpp-output", PP_ObjCHeader, INVALID, "mi", phases::Precompile) TYPE("objective-c-header", ObjCHeader, PP_ObjCHeader, "h", phases::Preprocess, phases::Precompile) TYPE("c++-header-cpp-output", PP_CXXHeader, INVALID, "ii", phases::Precompile) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index f5d4c656fd09..4baf9dc4e623 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -716,7 +716,7 @@ static void addDashXForInput(const ArgList &Args, const InputInfo &Input, if (Args.hasArg(options::OPT_rewrite_objc)) CmdArgs.push_back(types::getTypeName(types::TY_PP_ObjCXX)); else if (Args.hasArg(options::OPT_rewrite_bsc)) - CmdArgs.push_back(types::getTypeName(types::TY_PP_BSCXX)); + CmdArgs.push_back(types::getTypeName(types::TY_PP_BSC)); else { // Map the driver type to the frontend type. This is mostly an identity // mapping, except that the distinction between module interface units diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp index bd08e05526d0..ed2b4bb89737 100644 --- a/clang/lib/Driver/Types.cpp +++ b/clang/lib/Driver/Types.cpp @@ -97,13 +97,28 @@ bool types::onlyPrecompileType(ID Id) { bool types::canTypeBeUserSpecified(ID Id) { static const clang::driver::types::ID kStaticLangageTypes[] = { - TY_CUDA_DEVICE, TY_HIP_DEVICE, TY_PP_CHeader, - TY_PP_ObjCHeader, TY_PP_CXXHeader, TY_PP_ObjCXXHeader, - TY_PP_CXXModule, TY_LTO_IR, TY_LTO_BC, - TY_Plist, TY_RewrittenObjC, TY_RewrittenLegacyObjC, - TY_RewrittenBSC, TY_Remap, TY_PCH, - TY_Object, TY_Image, TY_dSYM, - TY_Dependencies, TY_CUDA_FATBIN, TY_HIP_FATBIN}; + TY_CUDA_DEVICE, + TY_HIP_DEVICE, + TY_PP_CHeader, + TY_PP_BSCHeader, + TY_PP_ObjCHeader, + TY_PP_CXXHeader, + TY_PP_ObjCXXHeader, + TY_PP_CXXModule, + TY_LTO_IR, + TY_LTO_BC, + TY_Plist, + TY_RewrittenObjC, + TY_RewrittenLegacyObjC, + TY_RewrittenBSC, + TY_Remap, + TY_PCH, + TY_Object, + TY_Image, + TY_dSYM, + TY_Dependencies, + TY_CUDA_FATBIN, + TY_HIP_FATBIN}; return !llvm::is_contained(kStaticLangageTypes, Id); } @@ -129,6 +144,7 @@ bool types::isAcceptedByClang(ID Id) { case TY_CL: case TY_CUDA: case TY_PP_CUDA: case TY_BSC: + case TY_PP_BSC: case TY_CUDA_DEVICE: case TY_HIP: case TY_PP_HIP: @@ -139,6 +155,7 @@ bool types::isAcceptedByClang(ID Id) { case TY_CHeader: case TY_PP_CHeader: case TY_CLHeader: case TY_BSCHeader: + case TY_PP_BSCHeader: case TY_ObjCHeader: case TY_PP_ObjCHeader: case TY_CXXHeader: case TY_PP_CXXHeader: case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: diff --git a/clang/test/BSC/Driver/options/save_temp.cbs b/clang/test/BSC/Driver/options/save_temp.cbs new file mode 100644 index 000000000000..0c7205dbb64f --- /dev/null +++ b/clang/test/BSC/Driver/options/save_temp.cbs @@ -0,0 +1,16 @@ +// RUN: %clang -save-temps %s + +struct Foo { + int a; +}; + +int struct Foo::getA(struct Foo* this) { + return this->a; +} + + +int main() { + struct Foo foo = {.a = 1}; + foo.getA(); + return 0; +} diff --git a/clang/test/BSC/Driver/std-option/std_option.cbs b/clang/test/BSC/Driver/options/std_option.cbs similarity index 100% rename from clang/test/BSC/Driver/std-option/std_option.cbs rename to clang/test/BSC/Driver/options/std_option.cbs -- Gitee From 5ff69bfb5d1a76ef1d3c00ad0fedf04c1559ee3f Mon Sep 17 00:00:00 2001 From: Healing Date: Tue, 13 Jun 2023 06:18:56 +0000 Subject: [PATCH 5/5] [generic] combine generics with member functions * fix shield assert bug * support instantiation before defining member functions * extending member functions for generic struct * support return types of generic struct or instantiated struct --- clang/include/clang/AST/ASTContext.h | 2 +- clang/include/clang/AST/Decl.h | 80 +++- clang/include/clang/AST/DeclCXX.h | 76 ---- clang/include/clang/AST/Type.h | 6 +- clang/include/clang/AST/TypeLoc.h | 4 +- clang/include/clang/Parse/Parser.h | 13 +- clang/include/clang/Sema/Sema.h | 18 +- clang/include/clang/Sema/Template.h | 1 + clang/lib/AST/ASTContext.cpp | 8 +- clang/lib/AST/ASTImporter.cpp | 6 +- clang/lib/AST/Decl.cpp | 106 +++++- clang/lib/AST/DeclBase.cpp | 21 +- clang/lib/AST/DeclCXX.cpp | 99 ----- clang/lib/AST/Type.cpp | 4 +- clang/lib/Index/IndexingContext.cpp | 4 +- clang/lib/Parse/ParseDecl.cpp | 8 +- clang/lib/Parse/ParseExpr.cpp | 2 +- clang/lib/Parse/ParseExprCXX.cpp | 97 ++--- clang/lib/Parse/ParseTemplate.cpp | 125 ++++--- clang/lib/Parse/ParseTentative.cpp | 78 ++-- clang/lib/Parse/Parser.cpp | 16 +- clang/lib/Sema/SemaAccess.cpp | 4 +- clang/lib/Sema/SemaCXXScopeSpec.cpp | 5 +- clang/lib/Sema/SemaCodeComplete.cpp | 2 +- clang/lib/Sema/SemaDecl.cpp | 25 +- clang/lib/Sema/SemaDeclCXX.cpp | 2 +- clang/lib/Sema/SemaExpr.cpp | 2 + clang/lib/Sema/SemaInit.cpp | 3 + clang/lib/Sema/SemaLookup.cpp | 7 +- clang/lib/Sema/SemaTemplate.cpp | 55 +-- clang/lib/Sema/SemaTemplateInstantiate.cpp | 37 +- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 346 +++++++++++++++++- clang/lib/Sema/SemaType.cpp | 20 +- .../test/BSC/Generic/DataStructure/Array.cbs | 156 ++++++++ .../BSC/Generic/DataStructure/LinkedList.cbs | 74 ++++ clang/test/BSC/Generic/DataStructure/Map.cbs | 100 +++++ .../test/BSC/Generic/DataStructure/Queue.cbs | 76 ++++ .../test/BSC/Generic/DataStructure/Stack.cbs | 67 ++++ .../test/BSC/Generic/conflict_member_func.cbs | 13 + .../member_func_call_builtIn_member_func.cbs | 22 ++ .../Generic/member_func_call_generic_func.cbs | 20 + .../member_func_call_generic_member_func.cbs | 24 ++ .../member_func_call_generic_member_func2.cbs | 25 ++ .../BSC/Generic/member_func_declaration.cbs | 13 + .../BSC/Generic/member_func_error_call.cbs | 16 + .../BSC/Generic/member_func_instance_call.cbs | 29 ++ .../member_func_multi_generic_params.cbs | 27 ++ .../BSC/Generic/member_func_static_call.cbs | 25 ++ clang/test/BSC/Generic/multi_instantiated.cbs | 35 ++ .../Generic/multi_instantiated_diff_types.cbs | 16 + .../BSC/Generic/redefinition_member_func.cbs | 13 + .../return_type_Instantiated_struct.cbs | 18 + .../Generic/return_type_generic_struct.cbs | 18 + .../Generic/return_type_generic_struct1.cbs | 17 + .../BSC/Generic/return_type_generic_union.cbs | 18 + ..._instantiate_before_define_member_func.cbs | 23 ++ .../Struct/struct_incomplete_type_call.cbs | 7 + 57 files changed, 1697 insertions(+), 437 deletions(-) create mode 100644 clang/test/BSC/Generic/DataStructure/Array.cbs create mode 100644 clang/test/BSC/Generic/DataStructure/LinkedList.cbs create mode 100644 clang/test/BSC/Generic/DataStructure/Map.cbs create mode 100644 clang/test/BSC/Generic/DataStructure/Queue.cbs create mode 100644 clang/test/BSC/Generic/DataStructure/Stack.cbs create mode 100644 clang/test/BSC/Generic/conflict_member_func.cbs create mode 100644 clang/test/BSC/Generic/member_func_call_builtIn_member_func.cbs create mode 100644 clang/test/BSC/Generic/member_func_call_generic_func.cbs create mode 100644 clang/test/BSC/Generic/member_func_call_generic_member_func.cbs create mode 100644 clang/test/BSC/Generic/member_func_call_generic_member_func2.cbs create mode 100644 clang/test/BSC/Generic/member_func_declaration.cbs create mode 100644 clang/test/BSC/Generic/member_func_error_call.cbs create mode 100644 clang/test/BSC/Generic/member_func_instance_call.cbs create mode 100644 clang/test/BSC/Generic/member_func_multi_generic_params.cbs create mode 100644 clang/test/BSC/Generic/member_func_static_call.cbs create mode 100644 clang/test/BSC/Generic/multi_instantiated.cbs create mode 100644 clang/test/BSC/Generic/multi_instantiated_diff_types.cbs create mode 100644 clang/test/BSC/Generic/redefinition_member_func.cbs create mode 100644 clang/test/BSC/Generic/return_type_Instantiated_struct.cbs create mode 100644 clang/test/BSC/Generic/return_type_generic_struct.cbs create mode 100644 clang/test/BSC/Generic/return_type_generic_struct1.cbs create mode 100644 clang/test/BSC/Generic/return_type_generic_union.cbs create mode 100644 clang/test/BSC/Generic/struct_instantiate_before_define_member_func.cbs create mode 100644 clang/test/BSC/Method/Struct/struct_incomplete_type_call.cbs diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 359f666c7f49..e01805f7ee0c 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1449,7 +1449,7 @@ public: QualType getEnumType(const EnumDecl *Decl) const; - QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const; + QualType getInjectedClassNameType(RecordDecl *Decl, QualType TST) const; QualType getAttributedType(attr::Kind attrKind, QualType modifiedType, diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index a23159fcec00..a641bc96221b 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -54,6 +54,7 @@ namespace clang { class ASTContext; struct ASTTemplateArgumentListInfo; class Attr; +class ClassTemplateDecl; class CompoundStmt; class DependentFunctionTemplateSpecializationInfo; class EnumDecl; @@ -3842,6 +3843,18 @@ public: APK_CanNeverPassInRegs }; + /// The template or declaration that this declaration + /// describes or was instantiated from, respectively. + /// + /// For non-templates, this value will be null. For record + /// declarations that describe a class template, this will be a + /// pointer to a ClassTemplateDecl. For member + /// classes of class template specializations, this will be the + /// MemberSpecializationInfo referring to the member class that was + /// instantiated or specialized. + llvm::PointerUnion + TemplateOrInstantiation; + protected: RecordDecl(Kind DK, TagKind TK, const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, @@ -3850,7 +3863,8 @@ protected: public: static RecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, - IdentifierInfo *Id, RecordDecl* PrevDecl = nullptr); + IdentifierInfo *Id, RecordDecl *PrevDecl = nullptr, + bool DelayTypeCreation = false); static RecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID); RecordDecl *getPreviousDecl() { @@ -3961,6 +3975,70 @@ public: RecordDeclBits.HasNonTrivialToPrimitiveCopyCUnion = V; } + /// The declaration for X::A is a (non-templated) CXXRecordDecl + /// whose parent is the class template specialization X. For + /// this declaration, getInstantiatedFromMemberClass() will return + /// the CXXRecordDecl X::A. When a complete definition of + /// X::A is required, it will be instantiated from the + /// declaration returned by getInstantiatedFromMemberClass(). + RecordDecl *getInstantiatedFromMemberClass() const; + + /// If this class is an instantiation of a member class of a + /// class template specialization, retrieves the member specialization + /// information. + MemberSpecializationInfo *getMemberSpecializationInfo() const; + + /// Specify that this record is an instantiation of the + /// member class \p RD. + void setInstantiationOfMemberClass(RecordDecl *RD, + TemplateSpecializationKind TSK); + + /// Retrieves the class template that is described by this + /// class declaration. + /// + /// Every class template is represented as a ClassTemplateDecl and a + /// CXXRecordDecl. The former contains template properties (such as + /// the template parameter lists) while the latter contains the + /// actual description of the template's + /// contents. ClassTemplateDecl::getTemplatedDecl() retrieves the + /// CXXRecordDecl that from a ClassTemplateDecl, while + /// getDescribedClassTemplate() retrieves the ClassTemplateDecl from + /// a CXXRecordDecl. + ClassTemplateDecl *getDescribedClassTemplate() const; + + void setDescribedClassTemplate(ClassTemplateDecl *Template); + + /// Determine whether this particular class is a specialization or + /// instantiation of a class template or member class of a class template, + /// and how it was instantiated or specialized. + TemplateSpecializationKind getTemplateSpecializationKind() const; + + /// Set the kind of specialization or template instantiation this is. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK); + + /// Retrieve the record declaration from which this record could be + /// instantiated. Returns null if this class is not a template instantiation. + const RecordDecl *getTemplateInstantiationPattern() const; + + RecordDecl *getTemplateInstantiationPattern() { + return const_cast(const_cast(this) + ->getTemplateInstantiationPattern()); + } + + /// If the class is a local class [class.local], returns + /// the enclosing function declaration. + const FunctionDecl *isLocalClass() const { + if (const auto *RD = dyn_cast(getDeclContext())) + return RD->isLocalClass(); + + return dyn_cast(getDeclContext()); + } + + FunctionDecl *isLocalClass() { + return const_cast( + const_cast(this)->isLocalClass()); + } + /// Determine whether this class can be passed in registers. In C++ mode, /// it must have at least one trivial, non-deleted copy or move constructor. /// FIXME: This should be set as part of completeDefinition. diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 5d627c5fb8f1..4a5165fa6676 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -443,18 +443,6 @@ class CXXRecordDecl : public RecordDecl { return static_cast(*DD); } - /// The template or declaration that this declaration - /// describes or was instantiated from, respectively. - /// - /// For non-templates, this value will be null. For record - /// declarations that describe a class template, this will be a - /// pointer to a ClassTemplateDecl. For member - /// classes of class template specializations, this will be the - /// MemberSpecializationInfo referring to the member class that was - /// instantiated or specialized. - llvm::PointerUnion - TemplateOrInstantiation; - /// Called from setBases and addedMember to notify the class that a /// direct or virtual base class or a member of class type has been added. void addedClassSubobject(CXXRecordDecl *Base); @@ -1423,56 +1411,6 @@ public: /// struct A { }; /// }; /// \endcode - /// - /// The declaration for X::A is a (non-templated) CXXRecordDecl - /// whose parent is the class template specialization X. For - /// this declaration, getInstantiatedFromMemberClass() will return - /// the CXXRecordDecl X::A. When a complete definition of - /// X::A is required, it will be instantiated from the - /// declaration returned by getInstantiatedFromMemberClass(). - CXXRecordDecl *getInstantiatedFromMemberClass() const; - - /// If this class is an instantiation of a member class of a - /// class template specialization, retrieves the member specialization - /// information. - MemberSpecializationInfo *getMemberSpecializationInfo() const; - - /// Specify that this record is an instantiation of the - /// member class \p RD. - void setInstantiationOfMemberClass(CXXRecordDecl *RD, - TemplateSpecializationKind TSK); - - /// Retrieves the class template that is described by this - /// class declaration. - /// - /// Every class template is represented as a ClassTemplateDecl and a - /// CXXRecordDecl. The former contains template properties (such as - /// the template parameter lists) while the latter contains the - /// actual description of the template's - /// contents. ClassTemplateDecl::getTemplatedDecl() retrieves the - /// CXXRecordDecl that from a ClassTemplateDecl, while - /// getDescribedClassTemplate() retrieves the ClassTemplateDecl from - /// a CXXRecordDecl. - ClassTemplateDecl *getDescribedClassTemplate() const; - - void setDescribedClassTemplate(ClassTemplateDecl *Template); - - /// Determine whether this particular class is a specialization or - /// instantiation of a class template or member class of a class template, - /// and how it was instantiated or specialized. - TemplateSpecializationKind getTemplateSpecializationKind() const; - - /// Set the kind of specialization or template instantiation this is. - void setTemplateSpecializationKind(TemplateSpecializationKind TSK); - - /// Retrieve the record declaration from which this record could be - /// instantiated. Returns null if this class is not a template instantiation. - const CXXRecordDecl *getTemplateInstantiationPattern() const; - - CXXRecordDecl *getTemplateInstantiationPattern() { - return const_cast(const_cast(this) - ->getTemplateInstantiationPattern()); - } /// Returns the destructor decl for this class. CXXDestructorDecl *getDestructor() const; @@ -1481,20 +1419,6 @@ public: /// destructors are marked noreturn. bool isAnyDestructorNoReturn() const; - /// If the class is a local class [class.local], returns - /// the enclosing function declaration. - const FunctionDecl *isLocalClass() const { - if (const auto *RD = dyn_cast(getDeclContext())) - return RD->isLocalClass(); - - return dyn_cast(getDeclContext()); - } - - FunctionDecl *isLocalClass() { - return const_cast( - const_cast(this)->isLocalClass()); - } - /// Determine whether this dependent class is a current instantiation, /// when viewed from within the given context. bool isCurrentInstantiation(const DeclContext *CurContext) const; diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 319d3850346b..81ce0df4342a 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -5253,7 +5253,7 @@ class InjectedClassNameType : public Type { // interdependencies. template friend class serialization::AbstractTypeReader; - CXXRecordDecl *Decl; + RecordDecl *Decl; /// The template specialization which this type represents. /// For example, in @@ -5266,7 +5266,7 @@ class InjectedClassNameType : public Type { /// and always dependent. QualType InjectedType; - InjectedClassNameType(CXXRecordDecl *D, QualType TST) + InjectedClassNameType(RecordDecl *D, QualType TST) : Type(InjectedClassName, QualType(), TypeDependence::DependentInstantiation), Decl(D), InjectedType(TST) { @@ -5286,7 +5286,7 @@ public: return getInjectedTST()->getTemplateName(); } - CXXRecordDecl *getDecl() const; + RecordDecl *getDecl() const; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h index 65e95d52c303..6d511f522d6a 100644 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -683,9 +683,7 @@ class InjectedClassNameTypeLoc : InjectedClassNameTypeLoc, InjectedClassNameType> { public: - CXXRecordDecl *getDecl() const { - return getTypePtr()->getDecl(); - } + RecordDecl *getDecl() const { return getTypePtr()->getDecl(); } }; /// Wrapper for source info for unresolved typename using decls. diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 5a42e5634e81..f0877618932b 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -838,9 +838,10 @@ private: public: // If NeedType is true, then TryAnnotateTypeOrScopeToken will try harder to // find a type name by attempting typo correction. - bool TryAnnotateTypeOrScopeToken(); - bool TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS, - bool IsNewScope); + bool TryAnnotateTypeOrScopeToken(QualType ExtendedTy = QualType()); + bool + TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS, bool IsNewScope, + QualType ExtendedTy = QualType()); bool TryAnnotateCXXScopeToken(bool EnteringContext = false); bool MightBeCXXScopeToken() { @@ -3330,18 +3331,18 @@ private: SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, SourceLocation &RAngleLoc, - int &lookAheadOffset); + int &LookAheadOffset); bool ParseTemplateParameterList(unsigned Depth, SmallVectorImpl &TemplateParams); bool ParseBSCTemplateParameterList(unsigned Depth, SmallVectorImpl &TemplateParams, - int &lookAheadOffset); + int &LookAheadOffset); TPResult isStartOfTemplateTypeParameter(); NamedDecl *ParseTemplateParameter(unsigned Depth, unsigned Position); NamedDecl *ParseTypeParameter(unsigned Depth, unsigned Position); NamedDecl *ParseBSCTypeParameter(unsigned Depth, unsigned Position, - int &lookAheadOffset); + int &LookAheadOffset); NamedDecl *ParseTemplateTemplateParameter(unsigned Depth, unsigned Position); NamedDecl *ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position); bool isTypeConstraintAnnotation(); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 987bf010fe1d..bbdf5c4c2cc8 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2317,7 +2317,8 @@ public: bool IsCtorOrDtorName = false, bool WantNontrivialTypeSourceInfo = false, bool IsClassTemplateDeductionContext = true, - IdentifierInfo **CorrectedII = nullptr); + IdentifierInfo **CorrectedII = nullptr, + QualType ExtendedTy = QualType()); TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S); bool isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S); void DiagnoseUnknownTypeName(IdentifierInfo *&II, @@ -7510,9 +7511,9 @@ public: TemplateParameterList *MatchTemplateParametersToScopeSpecifier( SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId, - ArrayRef ParamLists, - bool IsFriend, bool &IsMemberSpecialization, bool &Invalid, - bool SuppressDiagnostic = false); + ArrayRef ParamLists, bool IsFriend, + bool &IsMemberSpecialization, bool &Invalid, + bool SuppressDiagnostic = false, QualType ExtendedTy = QualType()); DeclResult CheckClassTemplate( Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, @@ -9344,10 +9345,11 @@ public: TemplateSpecializationKind TSK, bool Complain = true); - void InstantiateClassMembers(SourceLocation PointOfInstantiation, - CXXRecordDecl *Instantiation, - const MultiLevelTemplateArgumentList &TemplateArgs, - TemplateSpecializationKind TSK); + void + InstantiateClassMembers(SourceLocation PointOfInstantiation, + RecordDecl *Instantiation, + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK); void InstantiateClassTemplateSpecializationMembers( SourceLocation PointOfInstantiation, diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index 8c3fc70d26be..0b741c532f90 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -593,6 +593,7 @@ enum class TemplateSubstitutionKind : char { SmallVectorImpl &Params); bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl); bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl); + bool InitMethodInstantiation(BSCMethodDecl *New, BSCMethodDecl *Tmpl); bool SubstDefaultedFunction(FunctionDecl *New, FunctionDecl *Tmpl); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 154a9bdb3883..433eb2dce693 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -4395,9 +4395,7 @@ QualType ASTContext::getDependentExtIntType(bool IsUnsigned, } #ifndef NDEBUG -static bool NeedsInjectedClassNameType(const RecordDecl *D) { - if (!isa(D)) return false; - const auto *RD = cast(D); +static bool NeedsInjectedClassNameType(const RecordDecl *RD) { if (isa(RD)) return true; if (RD->getDescribedClassTemplate() && @@ -4409,12 +4407,12 @@ static bool NeedsInjectedClassNameType(const RecordDecl *D) { /// getInjectedClassNameType - Return the unique reference to the /// injected class name type for the specified templated declaration. -QualType ASTContext::getInjectedClassNameType(CXXRecordDecl *Decl, +QualType ASTContext::getInjectedClassNameType(RecordDecl *Decl, QualType TST) const { assert(NeedsInjectedClassNameType(Decl)); if (Decl->TypeForDecl) { assert(isa(Decl->TypeForDecl)); - } else if (CXXRecordDecl *PrevDecl = Decl->getPreviousDecl()) { + } else if (RecordDecl *PrevDecl = Decl->getPreviousDecl()) { assert(PrevDecl->TypeForDecl && "previous declaration has no type"); Decl->TypeForDecl = PrevDecl->TypeForDecl; assert(isa(Decl->TypeForDecl)); diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 943a8419cbc0..89e6de99f237 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1374,7 +1374,7 @@ ExpectedType ASTNodeImporter::VisitAutoType(const AutoType *T) { ExpectedType ASTNodeImporter::VisitInjectedClassNameType( const InjectedClassNameType *T) { - Expected ToDeclOrErr = import(T->getDecl()); + Expected ToDeclOrErr = import(T->getDecl()); if (!ToDeclOrErr) return ToDeclOrErr.takeError(); @@ -2918,9 +2918,9 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { DCXX->getMemberSpecializationInfo()) { TemplateSpecializationKind SK = MemberInfo->getTemplateSpecializationKind(); - CXXRecordDecl *FromInst = DCXX->getInstantiatedFromMemberClass(); + RecordDecl *FromInst = DCXX->getInstantiatedFromMemberClass(); - if (Expected ToInstOrErr = import(FromInst)) + if (Expected ToInstOrErr = import(FromInst)) D2CXX->setInstantiationOfMemberClass(*ToInstOrErr, SK); else return ToInstOrErr.takeError(); diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 5069c6ea574b..476fb7bc1a50 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1116,8 +1116,8 @@ getExplicitVisibilityAux(const NamedDecl *ND, // If this is a member class of a specialization of a class template // and the corresponding decl has explicit visibility, use that. - if (const auto *RD = dyn_cast(ND)) { - CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass(); + if (const auto *RD = dyn_cast(ND)) { + RecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass(); if (InstantiatedFrom) return getVisibilityOf(InstantiatedFrom, kind); } @@ -4502,12 +4502,14 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, const ASTContext &C, RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, - IdentifierInfo *Id, RecordDecl* PrevDecl) { + IdentifierInfo *Id, RecordDecl *PrevDecl, + bool DelayTypeCreation) { RecordDecl *R = new (C, DC) RecordDecl(Record, TK, C, DC, StartLoc, IdLoc, Id, PrevDecl); R->setMayHaveOutOfDateDef(C.getLangOpts().Modules); - C.getTypeDeclType(R, PrevDecl); + if (!DelayTypeCreation) + C.getTypeDeclType(R, PrevDecl); return R; } @@ -4519,6 +4521,102 @@ RecordDecl *RecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) { return R; } +RecordDecl *RecordDecl::getInstantiatedFromMemberClass() const { + if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) + return cast(MSInfo->getInstantiatedFrom()); + + return nullptr; +} + +MemberSpecializationInfo *RecordDecl::getMemberSpecializationInfo() const { + return TemplateOrInstantiation.dyn_cast(); +} + +ClassTemplateDecl *RecordDecl::getDescribedClassTemplate() const { + return TemplateOrInstantiation.dyn_cast(); +} + +void RecordDecl::setDescribedClassTemplate(ClassTemplateDecl *Template) { + TemplateOrInstantiation = Template; +} + +TemplateSpecializationKind RecordDecl::getTemplateSpecializationKind() const { + if (const auto *Spec = dyn_cast(this)) + return Spec->getSpecializationKind(); + + if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) + return MSInfo->getTemplateSpecializationKind(); + + return TSK_Undeclared; +} + +void RecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { + if (auto *Spec = dyn_cast(this)) { + Spec->setSpecializationKind(TSK); + return; + } + + if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) { + MSInfo->setTemplateSpecializationKind(TSK); + return; + } + + llvm_unreachable("Not a class template or member class specialization"); +} + +const RecordDecl *RecordDecl::getTemplateInstantiationPattern() const { + auto GetDefinitionOrSelf = [](const RecordDecl *D) -> const RecordDecl * { + if (auto *Def = D->getDefinition()) + return Def; + return D; + }; + + // If it's a class template specialization, find the template or partial + // specialization from which it was instantiated. + if (auto *TD = dyn_cast(this)) { + auto From = TD->getInstantiatedFrom(); + if (auto *CTD = From.dyn_cast()) { + while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) { + if (NewCTD->isMemberSpecialization()) + break; + CTD = NewCTD; + } + return GetDefinitionOrSelf(CTD->getTemplatedDecl()); + } + if (auto *CTPSD = + From.dyn_cast()) { + while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) { + if (NewCTPSD->isMemberSpecialization()) + break; + CTPSD = NewCTPSD; + } + return GetDefinitionOrSelf(CTPSD); + } + } + + if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) { + if (isTemplateInstantiation(MSInfo->getTemplateSpecializationKind())) { + const RecordDecl *RD = this; + while (auto *NewRD = RD->getInstantiatedFromMemberClass()) + RD = NewRD; + return GetDefinitionOrSelf(RD); + } + } + + assert(!isTemplateInstantiation(this->getTemplateSpecializationKind()) && + "couldn't find pattern for class template instantiation"); + return nullptr; +} + +void RecordDecl::setInstantiationOfMemberClass(RecordDecl *RD, + TemplateSpecializationKind TSK) { + assert(TemplateOrInstantiation.isNull() && + "Previous template or instantiation?"); + assert(!isa(this)); + TemplateOrInstantiation = + new (getASTContext()) MemberSpecializationInfo(RD, TSK); +} + bool RecordDecl::isInjectedClassName() const { return isImplicit() && getDeclName() && getDeclContext()->isRecord() && cast(getDeclContext())->getDeclName() == getDeclName(); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 705edd198c02..ca6b4b5c4970 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -983,7 +983,8 @@ bool Decl::AccessDeclContextSanity() const { // AS_none as access specifier. isa(this) || isa(this) || - isa(this)) + isa(this) || + isa(getDeclContext())) return true; assert(Access != AS_none && @@ -1151,6 +1152,11 @@ bool DeclContext::isDependentContext() const { return true; } + if (const auto *Record = dyn_cast(this)) { + if (Record->getDescribedClassTemplate()) + return true; + } + if (const auto *Function = dyn_cast(this)) { if (Function->getDescribedFunctionTemplate()) return true; @@ -1900,6 +1906,19 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, // this decl. buildLookup(); makeDeclVisibleInContextImpl(D, Internal); + // There may be instances before extending member functions for + // structs in BSC. Therefore, we need to add member functions + // to the already instantiated map when defining them. + if (getParentASTContext().getLangOpts().BSC && dyn_cast(D)) { + if (RecordDecl *RD = dyn_cast(this)) { + if (ClassTemplateDecl *DCT = RD->getDescribedClassTemplate()) { + for (auto it = DCT->spec_begin(); it != DCT->spec_end(); ++it) { + (*it)->setCompleteDefinition(false); + (*it)->setSpecializationKind(TSK_Undeclared); + } + } + } + } } else { setHasLazyLocalLexicalLookups(true); } diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index ec71d0fabe90..132990229751 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -1776,105 +1776,6 @@ void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) { llvm_unreachable("conversion not found in set!"); } -CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const { - if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) - return cast(MSInfo->getInstantiatedFrom()); - - return nullptr; -} - -MemberSpecializationInfo *CXXRecordDecl::getMemberSpecializationInfo() const { - return TemplateOrInstantiation.dyn_cast(); -} - -void -CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD, - TemplateSpecializationKind TSK) { - assert(TemplateOrInstantiation.isNull() && - "Previous template or instantiation?"); - assert(!isa(this)); - TemplateOrInstantiation - = new (getASTContext()) MemberSpecializationInfo(RD, TSK); -} - -ClassTemplateDecl *CXXRecordDecl::getDescribedClassTemplate() const { - return TemplateOrInstantiation.dyn_cast(); -} - -void CXXRecordDecl::setDescribedClassTemplate(ClassTemplateDecl *Template) { - TemplateOrInstantiation = Template; -} - -TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() const{ - if (const auto *Spec = dyn_cast(this)) - return Spec->getSpecializationKind(); - - if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) - return MSInfo->getTemplateSpecializationKind(); - - return TSK_Undeclared; -} - -void -CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { - if (auto *Spec = dyn_cast(this)) { - Spec->setSpecializationKind(TSK); - return; - } - - if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) { - MSInfo->setTemplateSpecializationKind(TSK); - return; - } - - llvm_unreachable("Not a class template or member class specialization"); -} - -const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const { - auto GetDefinitionOrSelf = - [](const CXXRecordDecl *D) -> const CXXRecordDecl * { - if (auto *Def = D->getDefinition()) - return Def; - return D; - }; - - // If it's a class template specialization, find the template or partial - // specialization from which it was instantiated. - if (auto *TD = dyn_cast(this)) { - auto From = TD->getInstantiatedFrom(); - if (auto *CTD = From.dyn_cast()) { - while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) { - if (NewCTD->isMemberSpecialization()) - break; - CTD = NewCTD; - } - return GetDefinitionOrSelf(CTD->getTemplatedDecl()); - } - if (auto *CTPSD = - From.dyn_cast()) { - while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) { - if (NewCTPSD->isMemberSpecialization()) - break; - CTPSD = NewCTPSD; - } - return GetDefinitionOrSelf(CTPSD); - } - } - - if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) { - if (isTemplateInstantiation(MSInfo->getTemplateSpecializationKind())) { - const CXXRecordDecl *RD = this; - while (auto *NewRD = RD->getInstantiatedFromMemberClass()) - RD = NewRD; - return GetDefinitionOrSelf(RD); - } - } - - assert(!isTemplateInstantiation(this->getTemplateSpecializationKind()) && - "couldn't find pattern for class template instantiation"); - return nullptr; -} - CXXDestructorDecl *CXXRecordDecl::getDestructor() const { ASTContext &Context = getASTContext(); QualType ClassType = Context.getTypeDeclType(this); diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 034e175f1352..26c5d5a21fb0 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3563,8 +3563,8 @@ bool AttributedType::isCallingConv() const { llvm_unreachable("invalid attr kind"); } -CXXRecordDecl *InjectedClassNameType::getDecl() const { - return cast(getInterestingTagDecl(Decl)); +RecordDecl *InjectedClassNameType::getDecl() const { + return cast(getInterestingTagDecl(Decl)); } IdentifierInfo *TemplateTypeParmType::getIdentifier() const { diff --git a/clang/lib/Index/IndexingContext.cpp b/clang/lib/Index/IndexingContext.cpp index 784a6008575b..56f69df58991 100644 --- a/clang/lib/Index/IndexingContext.cpp +++ b/clang/lib/Index/IndexingContext.cpp @@ -197,7 +197,7 @@ bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) { return true; } -static const CXXRecordDecl * +static const RecordDecl * getDeclContextForTemplateInstationPattern(const Decl *D) { if (const auto *CTSD = dyn_cast(D->getDeclContext())) @@ -226,7 +226,7 @@ static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) { return ED->getInstantiatedFromMemberEnum(); } else if (isa(D) || isa(D)) { const auto *ND = cast(D); - if (const CXXRecordDecl *Pattern = + if (const RecordDecl *Pattern = getDeclContextForTemplateInstationPattern(ND)) { for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) { if (BaseND->isImplicit()) diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 0191354e84b9..a4d701ad6484 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -5721,7 +5721,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, D.setExtension(); // BSC - if (getLangOpts().BSC && FindUntil(tok::coloncolon) && Tok.isNot(tok::star)) { + if (getLangOpts().BSC && FindUntil(tok::coloncolon)) { DeclSpec DS(AttrFactory); ParseBSCScopeSpecifiers(DS); TryConsumeToken(tok::coloncolon); @@ -6590,8 +6590,10 @@ void Parser::ParseFunctionDeclarator(Declarator &D, if (PD && !D.getBSCScopeSpec().getExtendedType().isNull()) D.getBSCScopeSpec().HasThisParam = PD->IsThisParam; } - HasProto = ParamInfo.size() || getLangOpts().CPlusPlus - || getLangOpts().OpenCL; + HasProto = ParamInfo.size() || getLangOpts().CPlusPlus || + getLangOpts().OpenCL || + (getLangOpts().BSC && + Actions.getCurScope()->getParent()->isTemplateParamScope()); // If we have the closing ')', eat it. Tracker.consumeClose(); diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 08c0c7e0415b..a1141a61db2b 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1169,7 +1169,7 @@ ExprResult Parser::ParseCastExpression( Next.isOneOf(tok::coloncolon, tok::less, tok::l_paren, tok::l_brace)) { // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse. - if (TryAnnotateTypeOrScopeToken()) + if (TryAnnotateTypeOrScopeToken(T)) return ExprError(); if (!Tok.is(tok::identifier)) return ParseCastExpression(ParseKind, isAddressOfOperand, diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 25dade7c2687..2a55cf08b3bf 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -156,7 +156,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier( 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++"); + "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"); @@ -397,14 +398,26 @@ bool Parser::ParseOptionalCXXScopeSpecifier( tok::identifier) && // TODO: this could be missidentified from typo: // "intt" (PP.LookAhead(2).is(tok::comma) || PP.LookAhead(2).is(tok::greater)); + + 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)) { + LGreaterOffset += 1; + TmpTok = PP.LookAhead(LGreaterOffset); + } + ParsingBSCTemplateFunction = + TmpTok.is(tok::greater) && (PP.LookAhead(LGreaterOffset + 1) + .isOneOf(tok::l_paren, tok::l_brace)); + } + if (ParsingBSCTemplateFunction) { - int lParenOffset = 0; - Token tmpTok = PP.LookAhead(lParenOffset); - while (!tmpTok.is(tok::l_paren) && !tmpTok.is(tok::eof)) { - lParenOffset += 1; - tmpTok = PP.LookAhead(lParenOffset); + int LParenOffset = 0; + while (!PP.LookAhead(LParenOffset).isOneOf(tok::l_paren, tok::eof)) { + LParenOffset += 1; } - Next = PP.LookAhead(lParenOffset); + Next = PP.LookAhead(LParenOffset); } else { Next = NextToken(); } @@ -582,9 +595,8 @@ 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"); + assert(getLangOpts().BSC && + "Call sites of this function should be guarded by checking for BSC"); if (Tok.is(tok::annot_cxxscope)) { assert(!LastII && "want last identifier but have already annotated scope"); @@ -716,49 +728,6 @@ bool Parser::ParseOptionalBSCGenericSpecifier( 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)) @@ -776,12 +745,26 @@ bool Parser::ParseOptionalBSCGenericSpecifier( 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) { + // Determine if 'tok::greater' is followed by 'l_ paren' and 'l_brace' + int LGreaterOffset = 2; + Token TmpTok = PP.LookAhead(LGreaterOffset); + while (!TmpTok.is(tok::greater) && !TmpTok.is(tok::eof)) { + LGreaterOffset += 1; + TmpTok = PP.LookAhead(LGreaterOffset); + } + ParsingBSCTemplateFunction = + TmpTok.is(tok::greater) && (PP.LookAhead(LGreaterOffset + 1) + .isOneOf(tok::l_paren, tok::l_brace)); + } + if (ParsingBSCTemplateFunction) { - int lParenOffset = 0; - while (!PP.LookAhead(lParenOffset).is(tok::l_paren)) { - lParenOffset += 1; + int LParenOffset = 0; + while (!PP.LookAhead(LParenOffset).isOneOf(tok::l_paren, tok::eof)) { + LParenOffset += 1; } - Next = PP.LookAhead(lParenOffset); + Next = PP.LookAhead(LParenOffset); } else { Next = NextToken(); } diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index b9c089bf4c31..7be1b4b4778a 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -88,23 +88,42 @@ Decl *Parser::ParseBSCGenericDeclaration(DeclaratorContext Context, SourceLocation TemplateLoc; TryConsumeToken(tok::kw_template, TemplateLoc); - int lookAheadOffset = 0; // lookAheadOffset starts from 0, assume the first + int LookAheadOffset = 0; // LookAheadOffset starts from 0, assume the first // token we see must not be '<' - while (!PP.LookAhead(lookAheadOffset) + while (!PP.LookAhead(LookAheadOffset) .is(tok::less)) { // use while since the template function // definition struct is not solid in BSC - lookAheadOffset += 1; + LookAheadOffset += 1; } - assert(PP.LookAhead(lookAheadOffset).is(tok::less) && + assert(PP.LookAhead(LookAheadOffset).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); + 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; + LookGreaterOffset = 0; + } + LookGreaterOffset++; + TmpTok = PP.LookAhead(LookGreaterOffset + LookAheadOffset); + PostTok = PP.LookAhead(LookGreaterOffset + LookAheadOffset + 1); + } + + assert(TmpTok.is(tok::greater) && + (PostTok.isOneOf(tok::l_brace, tok::l_paren, tok::coloncolon)) && + "BSC template function parameter list is not standardized."); + // Parse the '<' template-parameter-list '>' SourceLocation LAngleLoc, RAngleLoc; SmallVector TemplateParams; if (ParseBSCTemplateParameters(TemplateParamScopes, CurTemplateDepthTracker.getDepth(), TemplateParams, LAngleLoc, RAngleLoc, - lookAheadOffset)) { // open this + LookAheadOffset)) { // open this // Skip until the semi-colon or a '}'. SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); // error handel TryConsumeToken(tok::semi); @@ -580,32 +599,32 @@ bool Parser::ParseTemplateParameters( bool Parser::ParseBSCTemplateParameters( MultiParseScope &TemplateScopes, unsigned Depth, SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, - SourceLocation &RAngleLoc, int &lookAheadOffset) { - Token peekTok = PP.LookAhead(lookAheadOffset); - if (peekTok.is(tok::less)) { - lookAheadOffset += 1; - LAngleLoc = peekTok.getLocation(); + SourceLocation &RAngleLoc, int &LookAheadOffset) { + 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"; + Diag(PeekTok.getLocation(), diag::err_expected_less_after) << "template"; return true; } - peekTok = PP.LookAhead(lookAheadOffset); + PeekTok = PP.LookAhead(LookAheadOffset); // Try to parse the template parameter list. bool Failed = false; - if (!peekTok.is(tok::greater)) { + if (!PeekTok.is(tok::greater)) { TemplateScopes.Enter(Scope::TemplateParamScope); Failed = - ParseBSCTemplateParameterList(Depth, TemplateParams, lookAheadOffset); + ParseBSCTemplateParameterList(Depth, TemplateParams, LookAheadOffset); } - peekTok = PP.LookAhead(lookAheadOffset); + PeekTok = PP.LookAhead(LookAheadOffset); - if (peekTok.getKind() == tok::greater) { - lookAheadOffset += 1; - RAngleLoc = peekTok.getLocation(); + if (PeekTok.getKind() == tok::greater) { + LookAheadOffset += 1; + RAngleLoc = PeekTok.getLocation(); } else { if (Failed) { - Diag(peekTok.getLocation(), diag::err_expected) << tok::greater; + Diag(PeekTok.getLocation(), diag::err_expected) << tok::greater; return true; } } @@ -659,14 +678,14 @@ Parser::ParseTemplateParameterList(const unsigned Depth, // cross-order BSC syntax, use Peeking bool Parser::ParseBSCTemplateParameterList( const unsigned Depth, SmallVectorImpl &TemplateParams, - int &lookAheadOffset) { - Token peekTok = PP.LookAhead(lookAheadOffset); + int &LookAheadOffset) { + Token PeekTok = PP.LookAhead(LookAheadOffset); while (1) { // if (NamedDecl *TmpParam // = ParseTemplateParameter(Depth, TemplateParams.size())) { if (NamedDecl *TmpParam = ParseBSCTypeParameter( - Depth, TemplateParams.size(), lookAheadOffset)) { + Depth, TemplateParams.size(), LookAheadOffset)) { TemplateParams.push_back(TmpParam); } else { // If we failed to parse a template parameter, skip until we find @@ -674,22 +693,22 @@ bool Parser::ParseBSCTemplateParameterList( SkipUntil(tok::comma, tok::greater, // FIXME: logic error StopAtSemi | StopBeforeMatch); } - peekTok = PP.LookAhead(lookAheadOffset); + PeekTok = PP.LookAhead(LookAheadOffset); // Did we find a comma or the end of the template parameter list? - if (peekTok.is(tok::comma)) { + 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)) { + 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(peekTok.getLocation(), diag::err_expected_comma_greater); + Diag(PeekTok.getLocation(), diag::err_expected_comma_greater); SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch); return false; } @@ -1029,9 +1048,9 @@ 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) { + int &LookAheadOffset) { // Check Tok location - Token peekTok = PP.LookAhead(lookAheadOffset); + Token PeekTok = PP.LookAhead(LookAheadOffset); bool isBSCTemplateTypeParameter = getLangOpts().BSC; // TODO: fix the cond assert( isBSCTemplateTypeParameter && @@ -1044,10 +1063,10 @@ NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, ParseOptionalCXXScopeSpecifier(TypeConstraintSS, /*ObjectType=*/nullptr, /*ObjectHadErrors=*/false, /*EnteringContext*/ false); - if (peekTok.is(tok::annot_template_id)) { + if (PeekTok.is(tok::annot_template_id)) { // Consume the 'type-constraint'. TypeConstraint = - static_cast(peekTok.getAnnotationValue()); + static_cast(PeekTok.getAnnotationValue()); assert(TypeConstraint->Kind == TNK_Concept_template && "stray non-concept template-id annotation"); // KeyLoc remain at init status @@ -1063,38 +1082,38 @@ NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, // Grab the ellipsis (if given). SourceLocation EllipsisLoc; - if (peekTok.is(tok::ellipsis)) { - EllipsisLoc = peekTok.getLocation(); - lookAheadOffset += 1; - peekTok = PP.LookAhead(lookAheadOffset); + 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(); + SourceLocation NameLoc = PeekTok.getLocation(); IdentifierInfo *ParamName = nullptr; - if (peekTok.is(tok::identifier)) { + if (PeekTok.is(tok::identifier)) { ParamName = - peekTok.getIdentifierInfo(); // unknown manipulation, parsing T token - lookAheadOffset += 1; - peekTok = PP.LookAhead(lookAheadOffset); - } else if (peekTok.isOneOf(tok::equal, tok::comma, tok::greater, + PeekTok.getIdentifierInfo(); // unknown manipulation, parsing T token + LookAheadOffset += 1; + PeekTok = PP.LookAhead(LookAheadOffset); + } else if (PeekTok.isOneOf(tok::equal, tok::comma, tok::greater, tok::greatergreater)) { // 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; + 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); + if (PP.LookAhead(LookAheadOffset).is(tok::ellipsis)) { + EllipsisLoc = PeekTok.getLocation(); + LookAheadOffset += 1; + PeekTok = PP.LookAhead(LookAheadOffset); DiagnoseMisplacedEllipsis(EllipsisLoc, NameLoc, AlreadyHasEllipsis, true); } @@ -1103,10 +1122,10 @@ NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, // 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); + if (PeekTok.is(tok::equal)) { + EqualLoc = PeekTok.getLocation(); + LookAheadOffset += 1; + PeekTok = PP.LookAhead(LookAheadOffset); DefaultArg = ParseTypeName(/*Range=*/nullptr, DeclaratorContext::TemplateTypeArg) .get(); @@ -1578,7 +1597,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, bool AllowTypeAnnotation, bool TypeConstraint) { assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && - "Can only annotate template-ids in C++"); + "Can only annotate template-ids in C++ and BSC"); 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/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 5fc1dbea8559..859f2512ef8d 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1107,8 +1107,11 @@ bool Parser::isTentativelyDeclared(IdentifierInfo *II) { } // Check template declaration syntax in BSC: -// function template declaration: "T Foo(T a) {..}" -// struct template declaration: "struct S {..};" +// function template declaration : "T Foo(T a);" +// function template definition : "T Foo(T a) {..}" +// struct template definition: "struct S {..};" +// struct template function declaration : "void struct S::Foo();" +// struct template function definition : "void struct S::Foo(){..};" // The method of checking template declaration is: // 1. find template parameter list syntax structure "identifier " // 2. find declaration syntax(different from spcialization syntax) @@ -1121,65 +1124,44 @@ bool Parser::isBSCTemplateDecl(Token tok) { // 2. check "identifier" structure int LessOffset = 0; bool FoundLess = false; + bool FoundGreater = false; + bool FoundIdentifier = false; Token prevTok = tok; - Token tmpTok = PP.LookAhead(LessOffset); + 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)) { - // "<>" must appear neighboring with identtifier + if (TmpTok.is(tok::l_paren) || TmpTok.is(tok::l_brace) || + TmpTok.is(tok::equal)) { return false; } - if (tmpTok.is(tok::less) && prevTok.is(tok::identifier)) { + // "<>" 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 } - prevTok = tmpTok; - tmpTok = PP.LookAhead(LessOffset); + prevTok = TmpTok; + TmpTok = PP.LookAhead(LessOffset); } 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)) // could be function declaration, skip - break; - if (tmpTok.is(tok::semi) || - tmpTok.is(tok::equal)) // no "{" in current sentence - return false; - if (tmpTok.is(tok::l_brace) || tmpTok.is(tok::r_brace)) { - // do not check if l_brace missing, leave diagnose in outer API - return true; + // 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; } - } - - // 4. check "() {}" structure in function declaration - int LParenOffset = 1; - tmpTok = PP.LookAhead(LessOffset + LParenOffset); - for (; !tmpTok.is(tok::eof); - LParenOffset++) { // check "identifier " syntax - tmpTok = PP.LookAhead(LessOffset + LParenOffset); - if (tmpTok.is(tok::semi) || - tmpTok.is(tok::equal)) // no "{" in current sentence + 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; - if (tmpTok.is(tok::l_paren)) { - // do not check ")" missing, leave diagnose in outer API - break; - } - } - 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) || tmpTok.is(tok::r_brace)) { - // do not check l_brace missing, leave diagnose in outer API - return true; - } } return false; diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 7c0d192ead2b..c525aaef6c93 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -108,6 +108,8 @@ static bool IsCommonTypo(tok::TokenKind ExpectedTok, const Token &Tok) { } bool Parser::FindUntil(tok::TokenKind FindToken) { + if (Tok.isOneOf(tok::star, tok::greater, tok::r_paren, tok::comma)) + return false; std::vector StopTokens {tok::l_brace, tok::semi, tok::eof, tok::equal}; int LookStep = 0; @@ -1872,7 +1874,7 @@ bool Parser::TryKeywordIdentFallback(bool DisableKeyword) { /// /// 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::TryAnnotateTypeOrScopeToken() { +bool Parser::TryAnnotateTypeOrScopeToken(QualType ExtendedTy) { assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope) || Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id) || @@ -1983,22 +1985,26 @@ bool Parser::TryAnnotateTypeOrScopeToken() { /*EnteringContext*/ false)) return true; - return TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation); + return TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation, + ExtendedTy); } /// Try to annotate a type or scope token, having already parsed an /// optional scope specifier. \p IsNewScope should be \c true unless the scope /// specifier was extracted from an existing tok::annot_cxxscope annotation. bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS, - bool IsNewScope) { + bool IsNewScope, + QualType ExtendedTy) { if (Tok.is(tok::identifier)) { // Determine whether the identifier is a type name. if (ParsedType Ty = Actions.getTypeName( *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), &SS, false, NextToken().is(tok::period), nullptr, /*IsCtorOrDtorName=*/false, - /*NonTrivialTypeSourceInfo*/true, - /*IsClassTemplateDeductionContext*/true)) { + /*NonTrivialTypeSourceInfo*/ true, + /*IsClassTemplateDeductionContext*/ true, + /*CorrectedII*/ nullptr, + /*ExtendedTy*/ ExtendedTy)) { SourceLocation BeginLoc = Tok.getLocation(); if (SS.isNotEmpty()) // it was a C++ qualified type name. BeginLoc = SS.getBeginLoc(); diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp index be30445d143c..dcf59b0088df 100644 --- a/clang/lib/Sema/SemaAccess.cpp +++ b/clang/lib/Sema/SemaAccess.cpp @@ -302,7 +302,7 @@ static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived, RD = cast(RT->getDecl()); } else if (const InjectedClassNameType *IT = T->getAs()) { - RD = IT->getDecl(); + RD = cast(IT->getDecl()); } else { assert(T->isDependentType() && "non-dependent base wasn't a record?"); OnFailure = AR_dependent; @@ -655,7 +655,7 @@ struct ProtectedFriendContext { RD = cast(RT->getDecl()); } else if (const InjectedClassNameType *IT = T->getAs()) { - RD = IT->getDecl(); + RD = cast(IT->getDecl()); } else { assert(T->isDependentType() && "non-dependent base wasn't a record?"); EverDependent = true; diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index a4421d2b68af..325d1b3ed90a 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -38,7 +38,8 @@ static CXXRecordDecl *getCurrentInstantiationOf(QualType T, return nullptr; } else if (isa(Ty)) - return cast(Ty)->getDecl(); + return dyn_cast_or_null( + cast(Ty)->getDecl()); else return nullptr; } @@ -219,6 +220,8 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS, SourceLocation loc = SS.getLastQualifierNameLoc(); if (loc.isInvalid()) loc = SS.getRange().getBegin(); + if (LangOpts.BSC && loc.isInvalid()) + loc = tag->getBeginLoc(); // The type must be complete. if (RequireCompleteType(loc, type, diag::err_incomplete_nested_name_spec, diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index be04970979b3..48960737fdf8 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -3228,7 +3228,7 @@ static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy, if (const auto *RecordTy = Ty->getAs()) Record = cast(RecordTy->getDecl()); else if (const auto *InjectedTy = Ty->getAs()) - Record = InjectedTy->getDecl(); + Record = cast(InjectedTy->getDecl()); else { Result.AddTypedTextChunk( Result.getAllocator().CopyString(ND->getNameAsString())); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 2cd64f654d6b..4da550f96c68 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -282,13 +282,13 @@ static ParsedType recoverFromTypeInKnownDependentBase(Sema &S, /// opaque pointer (actually a QualType) corresponding to that /// type. Otherwise, returns NULL. ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, CXXScopeSpec *SS, - bool isClassName, bool HasTrailingDot, - ParsedType ObjectTypePtr, + Scope *S, CXXScopeSpec *SS, bool isClassName, + bool HasTrailingDot, ParsedType ObjectTypePtr, bool IsCtorOrDtorName, bool WantNontrivialTypeSourceInfo, bool IsClassTemplateDeductionContext, - IdentifierInfo **CorrectedII) { + IdentifierInfo **CorrectedII, + QualType ExtendedTy) { // FIXME: Consider allowing this outside C++1z mode as an extension. bool AllowDeducedTemplate = IsClassTemplateDeductionContext && getLangOpts().CPlusPlus17 && !IsCtorOrDtorName && @@ -334,6 +334,14 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS, LookupCtx)) return nullptr; + } else if (getLangOpts().BSC && !ExtendedTy.isNull()) { + const Type *BasedType = ExtendedTy.getCanonicalType().getTypePtr(); + if (dyn_cast_or_null( + BasedType->getAsTagDecl())) { + LookupCtx = BasedType->getAsTagDecl(); + if (LookupCtx) + RequireCompleteDeclContext(*SS, LookupCtx); + } } // FIXME: LookupNestedNameSpecifierName isn't the right kind of @@ -9017,8 +9025,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId ? D.getName().TemplateId : nullptr, - TemplateParamLists, isFriend, isMemberSpecialization, - Invalid); + TemplateParamLists, isFriend, isMemberSpecialization, Invalid, + false, D.getBSCScopeSpec().getExtendedType()); if (TemplateParams) { // Check that we can declare a template here. if (CheckTemplateDeclScope(S, TemplateParams)) @@ -9523,6 +9531,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, ? TPC_ClassTemplateMember : TPC_FunctionTemplate); } + if (getLangOpts().BSC) { + // Fake up an access specifier if it's supposed to be a class member. + if (isa(NewFD->getDeclContext())) + NewFD->setAccess(AS_public); + } } else { // C++11 [replacement.functions]p3: // The program's definitions shall not be specified as inline. diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 8bfaa46162bc..c44a257d491e 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -15091,7 +15091,7 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { CXXRecordDecl *ParentRD = cast(Field->getParent()); if (isTemplateInstantiation(ParentRD->getTemplateSpecializationKind())) { - CXXRecordDecl *ClassPattern = ParentRD->getTemplateInstantiationPattern(); + RecordDecl *ClassPattern = ParentRD->getTemplateInstantiationPattern(); DeclContext::lookup_result Lookup = ClassPattern->lookup(Field->getDeclName()); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index b132228b41bb..bf15f6102041 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -714,6 +714,8 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { // C++ [conv.lval]p3: // If T is cv std::nullptr_t, the result is a null pointer constant. CastKind CK = T->isNullPtrType() ? CK_NullToPointer : CK_LValueToRValue; + if (getLangOpts().BSC && !T->isNullPtrType() && T->getAsCXXRecordDecl()) + CK = CK_NoOp; Res = ImplicitCastExpr::Create(Context, T, CK, E, nullptr, VK_RValue, CurFPFeatureOverrides()); diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index f4493d84238d..d5cb142ef15f 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -5851,6 +5851,9 @@ void InitializationSequence::InitializeFrom(Sema &S, // We're at the end of the line for C: it's either a write-back conversion // or it's a C assignment. There's no need to check anything else. if (!S.getLangOpts().CPlusPlus) { + if (S.getLangOpts().BSC && DestType->getAsCXXRecordDecl()) + return; + // If allowed, check whether this is an Objective-C writeback conversion. if (allowObjCWritebackConversion && tryObjCWritebackConversion(S, *this, Entity, Initializer)) { diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index abddcc09c3fb..78db78385449 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1482,8 +1482,8 @@ static Module *getDefiningModule(Sema &S, Decl *Entity) { // the module containing the pattern. if (FunctionDecl *Pattern = FD->getTemplateInstantiationPattern()) Entity = Pattern; - } else if (CXXRecordDecl *RD = dyn_cast(Entity)) { - if (CXXRecordDecl *Pattern = RD->getTemplateInstantiationPattern()) + } else if (RecordDecl *RD = dyn_cast(Entity)) { + if (RecordDecl *Pattern = RD->getTemplateInstantiationPattern()) Entity = Pattern; } else if (EnumDecl *ED = dyn_cast(Entity)) { if (auto *Pattern = ED->getTemplateInstantiationPattern()) @@ -2437,7 +2437,8 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, } if (!T.isNull() && getLangOpts().BSC) { - DeclContext *DC = getASTContext().BSCDeclContextMap[T.getCanonicalType().getTypePtr()]; + DeclContext *DC = + getASTContext().BSCDeclContextMap[T.getCanonicalType().getTypePtr()]; if (DC) return LookupQualifiedName(R, DC); else diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index ea3c621807b7..71d9efbc7a91 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1961,8 +1961,12 @@ DeclResult Sema::CheckClassTemplate( : nullptr, /*DelayTypeCreation=*/true); } else { - NewClass = RecordDecl::Create(Context, Kind, SemanticContext, KWLoc, - NameLoc, Name); + NewClass = + RecordDecl::Create(Context, Kind, SemanticContext, KWLoc, NameLoc, Name, + PrevClassTemplate && ShouldAddRedecl + ? PrevClassTemplate->getBSCTemplatedDecl() + : nullptr, + /*DelayTypeCreation=*/true); } SetNestedNameSpecifier(*this, NewClass, SS); if (NumOuterTemplateParamLists > 0) @@ -1984,22 +1988,16 @@ DeclResult Sema::CheckClassTemplate( if (ShouldAddRedecl) NewTemplate->setPreviousDecl(PrevClassTemplate); - if (!getLangOpts().BSC) { - static_cast(NewClass)->setDescribedClassTemplate( - NewTemplate); - } + NewClass->setDescribedClassTemplate(NewTemplate); if (ModulePrivateLoc.isValid()) NewTemplate->setModulePrivate(); // Build the type for the class template declaration now. - 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; - } + 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. @@ -3034,6 +3032,9 @@ static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context, /// denotes a fully-specialized type, and therefore this is a declaration of /// a member specialization. /// +/// \param ExtendedTy used to infer scope specifier that will be matched to +/// the given template parameter lists for BSC. +/// /// \returns the template parameter list, if any, that corresponds to the /// name that is preceded by the scope specifier @p SS. This template /// parameter list may have template parameters (if we're declaring a @@ -3044,7 +3045,8 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId, ArrayRef ParamLists, bool IsFriend, - bool &IsMemberSpecialization, bool &Invalid, bool SuppressDiagnostic) { + bool &IsMemberSpecialization, bool &Invalid, bool SuppressDiagnostic, + QualType ExtendedTy) { IsMemberSpecialization = false; Invalid = false; @@ -3059,6 +3061,16 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( T = Context.getTypeDeclType(Record); else T = QualType(SS.getScopeRep()->getAsType(), 0); + } else if (!ExtendedTy.isNull()) { + DeclContext *DC = + getASTContext() + .BSCDeclContextMap[ExtendedTy.getCanonicalType().getTypePtr()]; + if (DC) { + if (RecordDecl *Record = dyn_cast_or_null(DC)) + T = Context.getTypeDeclType(Record); + } else { + T = QualType(ExtendedTy.getTypePtr(), 0); + } } // If we found an explicit specialization that prevents us from needing @@ -3070,7 +3082,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( NestedTypes.push_back(T); // Retrieve the parent of a record type. - if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) { + if (RecordDecl *Record = T->getAsRecordDecl()) { // If this type is an explicit specialization, we're done. if (ClassTemplateSpecializationDecl *Spec = dyn_cast(Record)) { @@ -3202,7 +3214,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( // class templates. In an explicit specialization for such a member, the // member declaration shall be preceded by a template<> for each // enclosing class template that is explicitly specialized. - if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) { + if (RecordDecl *Record = T->getAsRecordDecl()) { if (ClassTemplatePartialSpecializationDecl *Partial = dyn_cast(Record)) { ExpectedTemplateParams = Partial->getTemplateParameters(); @@ -3231,8 +3243,8 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( continue; } - } else if (const TemplateSpecializationType *TST - = T->getAs()) { + } else if (const TemplateSpecializationType *TST = + T->getAs()) { if (TemplateDecl *Template = TST->getTemplateName().getAsTemplateDecl()) { ExpectedTemplateParams = Template->getTemplateParameters(); NeedNonemptyTemplateHeader = true; @@ -9825,8 +9837,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, if (Tag->isInvalidDecl()) return true; - CXXRecordDecl *Record = cast(Tag); - CXXRecordDecl *Pattern = Record->getInstantiatedFromMemberClass(); + RecordDecl *Record = cast(Tag); + RecordDecl *Pattern = Record->getInstantiatedFromMemberClass(); if (!Pattern) { Diag(TemplateLoc, diag::err_explicit_instantiation_nontemplate_type) << Context.getTypeDeclType(Record); @@ -9855,8 +9867,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, CheckExplicitInstantiation(*this, Record, NameLoc, true, TSK); // Verify that it is okay to explicitly instantiate here. - CXXRecordDecl *PrevDecl - = cast_or_null(Record->getPreviousDecl()); + RecordDecl *PrevDecl = cast_or_null(Record->getPreviousDecl()); if (!PrevDecl && Record->getDefinition()) PrevDecl = Record; if (PrevDecl) { diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 23bcb4795ec0..713ffd4d9816 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -14,6 +14,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/ASTMutationListener.h" +#include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/PrettyDeclStackTrace.h" @@ -2646,9 +2647,9 @@ bool Sema::InstantiateClass(SourceLocation PointOfInstantiation, Pattern = PatternDef; // Record the point of instantiation. - if (getLangOpts().CPlusPlus) { + if (getLangOpts().CPlusPlus || getLangOpts().BSC) { if (MemberSpecializationInfo *MSInfo = - (static_cast(Instantiation)) + (static_cast(Instantiation)) ->getMemberSpecializationInfo()) { MSInfo->setTemplateSpecializationKind(TSK); MSInfo->setPointOfInstantiation(PointOfInstantiation); @@ -2715,6 +2716,25 @@ bool Sema::InstantiateClass(SourceLocation PointOfInstantiation, LateInstantiatedAttrVec LateAttrs; Instantiator.enableLateAttributeInstantiation(&LateAttrs); + if (getLangOpts().BSC) { + StoredDeclsMap *Map = Instantiation->getLookupPtr(); + for (auto *Member : getASTContext().getTranslationUnitDecl()->decls()) { + if (BSCMethodDecl *Method = dyn_cast(Member)) { + if (Method->getDeclContext() == cast(Pattern) && + (Map == nullptr || !Map->count(Method->getDeclName()))) { + Instantiator.Visit(Method); + getASTContext().BSCDeclContextMap[Instantiation->getTypeForDecl()] = + Instantiation; + } + } + } + + if (Map) { + Instantiation->setCompleteDefinition(true); + return Instantiation->isInvalidDecl(); + } + } + bool MightHaveConstexprVirtualFunctions = false; for (auto *Member : Pattern->decls()) { // Don't instantiate members not belonging in this semantic context. @@ -3237,11 +3257,10 @@ bool Sema::InstantiateClassTemplateSpecialization( /// Instantiates the definitions of all of the member /// of the given class, which is an instantiation of a class template /// or a member class of a template. -void -Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, - CXXRecordDecl *Instantiation, - const MultiLevelTemplateArgumentList &TemplateArgs, - TemplateSpecializationKind TSK) { +void Sema::InstantiateClassMembers( + SourceLocation PointOfInstantiation, RecordDecl *Instantiation, + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK) { // FIXME: We need to notify the ASTMutationListener that we did all of these // things, in case we have an explicit instantiation definition in a PCM, a // module, or preamble, and the declaration is in an imported AST. @@ -3373,7 +3392,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, SuppressNew) continue; - CXXRecordDecl *Pattern = Record->getInstantiatedFromMemberClass(); + RecordDecl *Pattern = Record->getInstantiatedFromMemberClass(); assert(Pattern && "Missing instantiated-from-template information"); if (!Record->getDefinition()) { @@ -3442,7 +3461,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, // No need to instantiate in-class initializers during explicit // instantiation. if (Field->hasInClassInitializer() && TSK == TSK_ImplicitInstantiation) { - CXXRecordDecl *ClassPattern = + RecordDecl *ClassPattern = Instantiation->getTemplateInstantiationPattern(); DeclContext::lookup_result Lookup = ClassPattern->lookup(Field->getDeclName()); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 5cbb2039bf00..c42f27861a6a 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1753,6 +1753,10 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { if (CXXMethodDecl *DMethod = dyn_cast(D->getTemplatedDecl())) Instantiated = cast_or_null(VisitCXXMethodDecl(DMethod, InstParams)); + else if (BSCMethodDecl *DMethod = + dyn_cast(D->getTemplatedDecl())) + Instantiated = + cast_or_null(VisitBSCMethodDecl(DMethod, InstParams)); else Instantiated = cast_or_null(VisitFunctionDecl( D->getTemplatedDecl(), @@ -2234,7 +2238,327 @@ Decl *TemplateDeclInstantiator::VisitBSCMethodDecl( BSCMethodDecl *D, TemplateParameterList *TemplateParams, Optional ClassScopeSpecializationArgs, RewriteKind FunctionRewriteKind) { - return VisitFunctionDecl(D, TemplateParams, FunctionRewriteKind); + FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); + if (FunctionTemplate && !TemplateParams) { + // We are creating a function template specialization from a function + // template. Check whether there is already a function template + // specialization for this particular set of template arguments. + ArrayRef Innermost = TemplateArgs.getInnermost(); + + void *InsertPos = nullptr; + FunctionDecl *SpecFunc = + FunctionTemplate->findSpecialization(Innermost, InsertPos); + + // If we already have a function template specialization, return it. + if (SpecFunc) + return SpecFunc; + } + + bool isFriend; + if (FunctionTemplate) + isFriend = (FunctionTemplate->getFriendObjectKind() != Decl::FOK_None); + else + isFriend = (D->getFriendObjectKind() != Decl::FOK_None); + + bool MergeWithParentScope = + (TemplateParams != nullptr) || + !(isa(Owner) && + cast(Owner)->isDefinedOutsideFunctionOrMethod()); + LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); + + // Instantiate enclosing template arguments for friends. + SmallVector TempParamLists; + unsigned NumTempParamLists = 0; + if (isFriend && (NumTempParamLists = D->getNumTemplateParameterLists())) { + TempParamLists.resize(NumTempParamLists); + for (unsigned I = 0; I != NumTempParamLists; ++I) { + TemplateParameterList *TempParams = D->getTemplateParameterList(I); + TemplateParameterList *InstParams = SubstTemplateParams(TempParams); + if (!InstParams) + return nullptr; + TempParamLists[I] = InstParams; + } + } + + ExplicitSpecifier InstantiatedExplicitSpecifier = + instantiateExplicitSpecifier(SemaRef, TemplateArgs, + ExplicitSpecifier::getFromDecl(D), D); + if (InstantiatedExplicitSpecifier.isInvalid()) + return nullptr; + + SmallVector Params; + TypeSourceInfo *TInfo = SubstFunctionType(D, Params); + if (!TInfo) + return nullptr; + QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo); + + if (TemplateParams && TemplateParams->size()) { + auto *LastParam = + dyn_cast(TemplateParams->asArray().back()); + if (LastParam && LastParam->isImplicit() && + LastParam->hasTypeConstraint()) { + // In abbreviated templates, the type-constraints of invented template + // type parameters are instantiated with the function type, invalidating + // the TemplateParameterList which relied on the template type parameter + // not having a type constraint. Recreate the TemplateParameterList with + // the updated parameter list. + TemplateParams = TemplateParameterList::Create( + SemaRef.Context, TemplateParams->getTemplateLoc(), + TemplateParams->getLAngleLoc(), TemplateParams->asArray(), + TemplateParams->getRAngleLoc(), TemplateParams->getRequiresClause()); + } + } + + NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc(); + if (QualifierLoc) { + QualifierLoc = + SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, TemplateArgs); + if (!QualifierLoc) + return nullptr; + } + + // FIXME: Concepts: Do not substitute into constraint expressions + Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); + + DeclContext *DC = Owner; + if (isFriend) { + if (QualifierLoc) { + CXXScopeSpec SS; + SS.Adopt(QualifierLoc); + DC = SemaRef.computeDeclContext(SS); + + if (DC && SemaRef.RequireCompleteDeclContext(SS, DC)) + return nullptr; + } else { + DC = SemaRef.FindInstantiatedContext(D->getLocation(), + D->getDeclContext(), TemplateArgs); + } + if (!DC) + return nullptr; + } + + DeclarationNameInfo NameInfo = + SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs); + + if (FunctionRewriteKind != RewriteKind::None) + adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo); + + // Build the instantiated method declaration. + RecordDecl *Record = cast(DC); + BSCMethodDecl *Method = nullptr; + + SourceLocation StartLoc = D->getInnerLocStart(); + StorageClass SC = D->isStatic() ? SC_Static : SC_None; + Method = BSCMethodDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, + TInfo, SC, D->isInlineSpecified(), + D->getConstexprKind(), D->getEndLoc(), + TrailingRequiresClause); + Method->setHasThisParam(D->getHasThisParam()); + QualType ExtendedTy(Record->getTypeForDecl(), 0); + Method->setExtendedType(ExtendedTy); + Method->setExtentedTypeBeginLoc(D->getBeginLoc()); + + if (D->isInlined()) + Method->setImplicitlyInline(); + + if (QualifierLoc) + Method->setQualifierInfo(QualifierLoc); + + if (TemplateParams) { + // Our resulting instantiation is actually a function template, since we + // are substituting only the outer template parameters. For example, given + // + // template + // struct X { + // template void f(T, U); + // }; + // + // X x; + // + // We are instantiating the member template "f" within X, which means + // substituting int for T, but leaving "f" as a member function template. + // Build the function template itself. + FunctionTemplate = FunctionTemplateDecl::Create( + SemaRef.Context, Record, Method->getLocation(), Method->getDeclName(), + TemplateParams, Method); + if (isFriend) { + FunctionTemplate->setLexicalDeclContext(Owner); + FunctionTemplate->setObjectOfFriendDecl(); + } else if (D->isOutOfLine()) + FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); + Method->setDescribedFunctionTemplate(FunctionTemplate); + } else if (FunctionTemplate) { + // Record this function template specialization. + ArrayRef Innermost = TemplateArgs.getInnermost(); + Method->setFunctionTemplateSpecialization( + FunctionTemplate, + TemplateArgumentList::CreateCopy(SemaRef.Context, Innermost), + /*InsertPos=*/nullptr); + } else if (!isFriend) { + // Record that this is an instantiation of a member function. + Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); + } + + // If we are instantiating a member function defined + // out-of-line, the instantiation will have the same lexical + // context (which will be a namespace scope) as the template. + if (isFriend) { + if (NumTempParamLists) + Method->setTemplateParameterListsInfo( + SemaRef.Context, + llvm::makeArrayRef(TempParamLists.data(), NumTempParamLists)); + + Method->setObjectOfFriendDecl(); + } + Method->setLexicalDeclContext(Owner); + + // Attach the parameters + for (unsigned P = 0; P < Params.size(); ++P) + Params[P]->setOwningFunction(Method); + Method->setParams(Params); + + if (InitMethodInstantiation(Method, D)) + Method->setInvalidDecl(); + + LookupResult Previous(SemaRef, NameInfo, Sema::LookupOrdinaryName, + Sema::ForExternalRedeclaration); + + bool IsExplicitSpecialization = false; + + // If the name of this function was written as a template-id, instantiate + // the explicit template arguments. + if (DependentFunctionTemplateSpecializationInfo *Info = + D->getDependentSpecializationInfo()) { + assert(isFriend && "non-friend has dependent specialization info?"); + + // Instantiate the explicit template arguments. + TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), + Info->getRAngleLoc()); + if (SemaRef.Subst(Info->getTemplateArgs(), Info->getNumTemplateArgs(), + ExplicitArgs, TemplateArgs)) + return nullptr; + + // Map the candidate templates to their instantiations. + for (unsigned I = 0, E = Info->getNumTemplates(); I != E; ++I) { + Decl *Temp = SemaRef.FindInstantiatedDecl( + D->getLocation(), Info->getTemplate(I), TemplateArgs); + if (!Temp) + return nullptr; + + Previous.addDecl(cast(Temp)); + } + + if (SemaRef.CheckFunctionTemplateSpecialization(Method, &ExplicitArgs, + Previous)) + Method->setInvalidDecl(); + + IsExplicitSpecialization = true; + } else if (const ASTTemplateArgumentListInfo *Info = + ClassScopeSpecializationArgs.getValueOr( + D->getTemplateSpecializationArgsAsWritten())) { + SemaRef.LookupQualifiedName(Previous, DC); + + TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), + Info->getRAngleLoc()); + if (SemaRef.Subst(Info->getTemplateArgs(), Info->getNumTemplateArgs(), + ExplicitArgs, TemplateArgs)) + return nullptr; + + if (SemaRef.CheckFunctionTemplateSpecialization(Method, &ExplicitArgs, + Previous)) + Method->setInvalidDecl(); + + IsExplicitSpecialization = true; + } else if (ClassScopeSpecializationArgs) { + // Class-scope explicit specialization written without explicit template + // arguments. + SemaRef.LookupQualifiedName(Previous, DC); + if (SemaRef.CheckFunctionTemplateSpecialization(Method, nullptr, Previous)) + Method->setInvalidDecl(); + + IsExplicitSpecialization = true; + } else if (!FunctionTemplate || TemplateParams || isFriend) { + SemaRef.LookupQualifiedName(Previous, Record); + + // In BSC, the previous declaration we find might be a tag type + // (class or enum). In this case, the new declaration will hide the + // tag type. Note that this does does not apply if we're declaring a + // typedef. + if (Previous.isSingleTagDecl()) + Previous.clear(); + } + + SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous, + IsExplicitSpecialization); + + // if (D->isPure()) + // SemaRef.CheckPureMethod(Method, SourceRange()); + + // Propagate access. For a non-friend declaration, the access is + // whatever we're propagating from. For a friend, it should be the + // previous declaration we just found. + if (isFriend && Method->getPreviousDecl()) + Method->setAccess(Method->getPreviousDecl()->getAccess()); + else + Method->setAccess(D->getAccess()); + if (FunctionTemplate) + FunctionTemplate->setAccess(Method->getAccess()); + + SemaRef.CheckOverrideControl(Method); + + // If a function is defined as defaulted or deleted, mark it as such now. + if (D->isExplicitlyDefaulted()) { + if (SubstDefaultedFunction(Method, D)) + return nullptr; + } + if (D->isDeletedAsWritten()) + SemaRef.SetDeclDeleted(Method, Method->getLocation()); + + // If this is an explicit specialization, mark the implicitly-instantiated + // template specialization as being an explicit specialization too. + // FIXME: Is this necessary? + if (IsExplicitSpecialization && !isFriend) + SemaRef.CompleteMemberSpecialization(Method, Previous); + + // If there's a function template, let our caller handle it. + if (FunctionTemplate) { + // do nothing + + // Don't hide a (potentially) valid declaration with an invalid one. + } else if (Method->isInvalidDecl() && !Previous.empty()) { + // do nothing + + // Otherwise, check access to friends and make them visible. + } else if (isFriend) { + // We only need to re-check access for methods which we didn't + // manage to match during parsing. + if (!D->getPreviousDecl()) + SemaRef.CheckFriendAccess(Method); + + Record->makeDeclVisibleInContext(Method); + + // Otherwise, add the declaration. We don't need to do this for + // class-scope specializations because we'll have matched them with + // the appropriate template. + } else { + Owner->addDecl(Method); + } + + // PR17480: Honor the used attribute to instantiate member function + // definitions + if (Method->hasAttr()) { + if (const auto *A = dyn_cast(Owner)) { + SourceLocation Loc; + if (const MemberSpecializationInfo *MSInfo = + A->getMemberSpecializationInfo()) + Loc = MSInfo->getPointOfInstantiation(); + else if (const auto *Spec = dyn_cast(A)) + Loc = Spec->getPointOfInstantiation(); + SemaRef.MarkFunctionReferenced(Loc, Method); + } + } + + return Method; } Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( @@ -4625,6 +4949,19 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, return false; } +bool TemplateDeclInstantiator::InitMethodInstantiation(BSCMethodDecl *New, + BSCMethodDecl *Tmpl) { + if (InitFunctionInstantiation(New, Tmpl)) + return true; + + New->setAccess(Tmpl->getAccess()); + if (Tmpl->isVirtualAsWritten()) + New->setVirtualAsWritten(true); + + // FIXME: New needs a pointer to Tmpl + return false; +} + bool TemplateDeclInstantiator::SubstDefaultedFunction(FunctionDecl *New, FunctionDecl *Tmpl) { // Transfer across any unqualified lookups. @@ -5619,12 +5956,11 @@ isInstantiationOf(ClassTemplatePartialSpecializationDecl *Pattern, return false; } -static bool isInstantiationOf(CXXRecordDecl *Pattern, - CXXRecordDecl *Instance) { - Pattern = Pattern->getCanonicalDecl(); +static bool isInstantiationOf(RecordDecl *Pattern, RecordDecl *Instance) { + Pattern = dyn_cast(Pattern->getCanonicalDecl()); do { - Instance = Instance->getCanonicalDecl(); + Instance = dyn_cast(Instance->getCanonicalDecl()); if (Pattern == Instance) return true; Instance = Instance->getInstantiatedFromMemberClass(); } while (Instance); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index e4af0a8c1af0..96856246644a 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1842,10 +1842,12 @@ QualType Sema::ConvertBSCScopeSpecToType(Declarator &D, SourceLocation Loc, TypeProcessingState state(*this, D); QualType T = ConvertDeclSpecToType(state, DS); NamedDecl *Def = nullptr; + if (!AddToContextMap && T.getTypePtr()->getAs()) + return T; if (T->isIncompleteType(&Def)) { BoundTypeDiagnoser<> Diagnoser(diag::err_typecheck_decl_incomplete_type); Diagnoser.diagnose(*this, Loc, T); - } else if (AddToContextMap) { + } else { BSS.setExtendedType(T); const Type *BasedType = T.getCanonicalType().getTypePtr(); // build declcontext map @@ -1867,6 +1869,12 @@ QualType Sema::ConvertBSCScopeSpecToType(Declarator &D, SourceLocation Loc, TmpRecord->startDefinition(); TmpRecord->completeDefinition(); getASTContext().BSCDeclContextMap[BasedType] = TmpRecord; + } else if (const TemplateSpecializationType *TemplateTy = + dyn_cast(BasedType)) { + auto DC = dyn_cast(TemplateTy->getTemplateName() + .getAsTemplateDecl() + ->getTemplatedDecl()); + getASTContext().BSCDeclContextMap[BasedType] = DC; } } } @@ -5175,8 +5183,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, FunctionType::ExtInfo EI( getCCForDeclaratorChunk(S, D, DeclType.getAttrs(), FTI, chunkIndex)); - if (!FTI.NumParams && !FTI.isVariadic && !LangOpts.CPlusPlus - && !LangOpts.OpenCL) { + if (!FTI.NumParams && !FTI.isVariadic && !LangOpts.CPlusPlus && + !LangOpts.BSC && !LangOpts.OpenCL) { // Simple void foo(), where the incoming T is the result type. T = Context.getFunctionNoProtoType(T, EI); } else { @@ -8423,7 +8431,7 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, // We're in the middle of defining it; this definition should be treated // as visible. return true; - } else if (auto *RD = dyn_cast(D)) { + } else if (auto *RD = dyn_cast(D)) { if (auto *Pattern = RD->getTemplateInstantiationPattern()) RD = Pattern; D = RD->getDefinition(); @@ -8642,8 +8650,8 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, Instantiated = true; } } else { - CXXRecordDecl *Pattern = - (static_cast(RD))->getInstantiatedFromMemberClass(); + RecordDecl *Pattern = + (static_cast(RD))->getInstantiatedFromMemberClass(); if (!RD->isBeingDefined() && Pattern) { MemberSpecializationInfo *MSI = (static_cast(RD))->getMemberSpecializationInfo(); diff --git a/clang/test/BSC/Generic/DataStructure/Array.cbs b/clang/test/BSC/Generic/DataStructure/Array.cbs new file mode 100644 index 000000000000..67754c057121 --- /dev/null +++ b/clang/test/BSC/Generic/DataStructure/Array.cbs @@ -0,0 +1,156 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include +#include + +struct Student { + char *name; + int age; +}; + +struct Array { + T *data; + int size; + int capacity; +}; + +void struct Array::init(struct Array *this, int capacity) { // warning: template argument uses local type 'struct Strudent' + this->data = malloc(sizeof(T) * capacity); + this->size = 0; + this->capacity = capacity; +} + +void struct Array::destroy(struct Array *this) { + if (this) + free(this->data); +} + +int struct Array::isEmpty(struct Array *this) { + return this->size == 0; +} + +int struct Array::isFull(struct Array *this) { + return this->size == this->capacity; +} + +void struct Array::append(struct Array *this, T value) { + if (this->isFull()) { + printf("the array is full!\n"); + exit(1); + } + this->data[this->size++] = value; +} + + +void struct Array::set(struct Array *this, int index, T value) { + if (index < 0 || index >= this->size) { + printf("index out of range!\n"); + exit(1); + } + this->data[index] = value; +} + +T struct Array::get(struct Array *this, int index) { + if (index < 0 || index >= this->size) { + printf("index out of range!\n"); + exit(1); + } + return this->data[index]; +} + +void struct Array::quickSort(struct Array *this, int left, int right, _Bool (*compare)(T, T)) { + if (left >= right) + return; + int i = left, j = right; + T pivot = this->data[left]; + while (i < j) { + while(i < j && compare(this->data[j], pivot)) { + j--; + } + this->data[i] = this->data[j]; + while (i < j && compare(pivot, this->data[i])) { + i++; + } + this->data[j] = this->data[i]; + } + this->data[i] = pivot; + this->quickSort(left, i-1, compare); + this->quickSort(i + 1, right, compare); +} + +int struct Array::binarySearch(struct Array *this, T target, _Bool (*compare)(T, T), _Bool (*equal)(T, T)) { + int left = 0, right = this->size - 1; + while (left <= right) { + int mid = left + (right - left) / 2; + if (equal(this->data[mid], target)) { + return mid; + } else if (compare(target, this->data[mid])) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return -1; +} + +_Bool compareStudent(struct Student s1, struct Student s2) { + return s1.age >= s2.age; +} + +_Bool compareInt(int a, int b) { + return a >= b; +} + +_Bool equalInt(int a, int b) { + return a == b; +} + +int main() { + struct Array arr; + arr.init(10); + for (int i = 0; i < 10; i++) { + arr.append(i); + } + arr.set(5, 0); + for (int i = 0; i < arr.size; i++) { + printf("%d ", arr.get(i)); + } + printf("\n"); + + arr.quickSort(0, arr.size - 1, compareInt); + for (int i = 0; i < arr.size; i++) { + printf("%d ", arr.get(i)); + } + printf("\n"); + + int target = 8; + int index = arr.binarySearch(target, compareInt, equalInt); + if (index == -1) { + printf("Target not found"); + } else { + printf("Target found at index %d", index); + } + arr.destroy(); + + struct Array arr1; + arr1.init(3); + struct Student a = {.name = "Jonh", .age = 20}; + struct Student b = {.name = "Mary", .age = 18}; + struct Student c = {.name = "Lily", .age = 26}; + arr1.append(a); + arr1.append(b); + arr1.append(c); + for (int i = 0; i < arr1.size; i++) { + printf("name: %s, age: %d\n", arr1.get(i).name, arr1.get(i).age); + } + printf("\n"); + + arr1.quickSort(0, arr1.size - 1, compareStudent); + for (int i = 0; i < arr1.size; i++) { + printf("name: %s, age: %d\n", arr1.get(i).name, arr1.get(i).age); + } + arr1.destroy(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/DataStructure/LinkedList.cbs b/clang/test/BSC/Generic/DataStructure/LinkedList.cbs new file mode 100644 index 000000000000..4323038626d9 --- /dev/null +++ b/clang/test/BSC/Generic/DataStructure/LinkedList.cbs @@ -0,0 +1,74 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include +#include + +struct ListNode { + T data; + struct ListNode *next; +}; + +struct LinkedList { + struct ListNode *head; +}; + +void struct LinkedList::init(struct LinkedList *this) { + this->head = malloc(sizeof(struct ListNode)); + this->head->next = NULL; +} + +void struct LinkedList::insert(struct LinkedList *this, T data) { + struct ListNode *newNode = malloc(sizeof(struct ListNode)); + newNode->data = data; + newNode->next = this->head->next; + this->head->next = newNode; +} + +void struct LinkedList::delete(struct LinkedList *this, T data) { + struct ListNode *p = this->head->next; + struct ListNode *pre = this->head; + while(p != NULL) { + if (p->data == data) { + pre->next = p->next; + free(p); + return; + } + pre = p; + p = p->next; + } +} + +void struct LinkedList::destroy(struct LinkedList *this) { + struct ListNode *p = this->head; + while(p != NULL) { + struct ListNode *q = p->next; + free(p); + p = q; + } +} + +int main() { + struct LinkedList L; + L.init(); + for(int i = 0; i < 10; i++) { + L.insert(i); + } + struct ListNode *p = L.head->next; + while(p != NULL) { + printf("%d ", p->data); + p = p->next; + } + printf("\n"); + + L.delete(2); + L.delete(5); + p = L.head->next; + while(p != NULL) { + printf("%d ", p->data); + p = p->next; + } + L.destroy(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/DataStructure/Map.cbs b/clang/test/BSC/Generic/DataStructure/Map.cbs new file mode 100644 index 000000000000..b0806bf1a412 --- /dev/null +++ b/clang/test/BSC/Generic/DataStructure/Map.cbs @@ -0,0 +1,100 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include +#include + +#define MAP_SIZE 100 + +struct MapEntry { + K key; + V value; +}; + +struct Map { + struct MapEntry table[MAP_SIZE]; + int size; +}; + +void struct Map::init(struct Map *this) { + this->size = 0; +} + +int struct Map::isEmpty(struct Map *this) { + return this->size == 0; +} + +int struct Map::contain(struct Map *this, K key) { + int index = -1; + for (int i = 0; i < this->size; i++) { + if (this->table[i].key == key) { + index = i; + break; + } + } + if (index == -1) + return 0; + else + return index + 1; +} + +void struct Map::put(struct Map *this, K key, V value) { + int index = this->contain(key); + if (index) { + this->table[index - 1].key = key; + this->table[index - 1].value = value; + } else { + struct MapEntry entry; + entry.key = key; + entry.value = value; + this->table[this->size++] = entry; + } +} + +V struct Map::find(struct Map *this, K key) { + int index = this->contain(key); + if (!index) { + printf("the key not found in map!\n"); + exit(-1); + } + return this->table[index - 1].value; +} + +int struct Map::count(struct Map *this, K key) { + int index = this->contain(key); + if (index) + return 1; + else + return 0; +} + +void struct Map::earse(struct Map *this, K key) { + int index = this->contain(key); + if (!index) { + printf("Key not found"); + exit(-1); + } + for (int i = index - 1; i < this->size -1; i++) + this->table[i] = this->table[i + 1]; + this->size--; +} + +int main() { + struct Map m; + m.init(); + m.put("Jonh", 30); + m.put("Mary", 18); + m.put("Lily", 26); + m.put("Jonh", 20); + for (int i = 0; i < m.size; i++) { + printf("name: %s, age: %d\n", m.table[i].key, m.table[i].value); + } + m.find("Lily"); + m.earse("Lily"); + for (int i = 0; i < m.size; i++) { + printf("name: %s, age: %d\n", m.table[i].key, m.table[i].value); + } + return 0; +} + diff --git a/clang/test/BSC/Generic/DataStructure/Queue.cbs b/clang/test/BSC/Generic/DataStructure/Queue.cbs new file mode 100644 index 000000000000..a0da4213e586 --- /dev/null +++ b/clang/test/BSC/Generic/DataStructure/Queue.cbs @@ -0,0 +1,76 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include +#include + +#define MAX_SIZE 100 +struct Queue { + T data[MAX_SIZE]; + int head; + int rear; +}; + +void struct Queue::init(struct Queue *this) { + this->head = this->rear = 0; +} + +int struct Queue::isEmpty(struct Queue *this) { + return this->head == this->rear; +} + +int struct Queue::isFull(struct Queue *this) { + return (this->rear + 1) % MAX_SIZE == this->head; +} + +void struct Queue::push(struct Queue *this, T value) { + if (this->isFull()) { + printf("this queue is full!\n"); + exit(-1); + } + this->data[this->rear] = value; + this->rear = (this->rear + 1) % MAX_SIZE; +} + +T struct Queue::pop(struct Queue *this) { + if (this->isEmpty()) { + printf("this queue is empty!\n"); + exit(-1); + } + T value = this->data[this->head]; + this->head = (this->head + 1) % MAX_SIZE; + return value; +} + +T struct Queue::front(struct Queue *this) { + if (this->isEmpty()) { + printf("this queue is empty!\n"); + exit(-1); + } + return this->data[this->head]; +} + +T struct Queue::back(struct Queue *this) { + if (this->isEmpty()) { + printf("this queue is empty!\n"); + exit(-1); + } + return this->data[this->rear - 1]; +} + +int main() { + Queue q; + q.init(); + for (int i = 0; i < 10; i++) { + q.push(i); + } + printf("q.front: %d\n", q.front()); + printf("q.back: %d\n", q.back()); + while(!q.isEmpty()) { + int value = q.pop(); + printf("%d ", value); + } + return 0; +} + diff --git a/clang/test/BSC/Generic/DataStructure/Stack.cbs b/clang/test/BSC/Generic/DataStructure/Stack.cbs new file mode 100644 index 000000000000..c1a14b732c47 --- /dev/null +++ b/clang/test/BSC/Generic/DataStructure/Stack.cbs @@ -0,0 +1,67 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include + +#define MAX_SIZE 100 +struct Stack { + T data[MAX_SIZE]; + int num; +}; + +void struct Stack::init(struct Stack *this) { + this->num = -1; +} + +int struct Stack::isEmpty(struct Stack *this) { + return this->num == -1; +} + +int struct Stack::isFull(struct Stack *this) { + return this->num == MAX_SIZE - 1; +} + +void struct Stack::push(struct Stack *this, T value) { + if (this->isFull()) { + printf("this stack is full!\n"); + return; + } + this->data[++this->num] = value; +} + +T struct Stack::pop(struct Stack *this) { + if (this->isEmpty()) { + printf("this stack is empty!\n"); + return -1; + } + return this->data[this->num--]; +} + +T struct Stack::top(struct Stack *this) { + if (this->isEmpty()) { + printf("this stack is empty!\n"); + return -1; + } + return this->data[this->num]; +} + +T struct Stack::size(struct Stack *this) { + return this->num + 1; +} + + +int main() { + struct Stack s; + s.init(); + for (int i = 0; i < 10; i++) { + s.push(i); + } + printf("s.top: %d\n", s.top()); + printf("s.size: %d\n", s.size()); + while(!s.isEmpty()) { + int value = s.pop(); + printf("%d ", value); + } + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/conflict_member_func.cbs b/clang/test/BSC/Generic/conflict_member_func.cbs new file mode 100644 index 000000000000..e20f64faeb6b --- /dev/null +++ b/clang/test/BSC/Generic/conflict_member_func.cbs @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -verify %s + +struct MyStruct { + T res; +}; + +int struct MyStruct::foo(struct MyStruct *this, int a) { // expected-note {{previous definition is here}} + return a; +} + +int struct MyStruct::foo(struct MyStruct *this) { // expected-error {{conflicting types for 'foo'}} + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/member_func_call_builtIn_member_func.cbs b/clang/test/BSC/Generic/member_func_call_builtIn_member_func.cbs new file mode 100644 index 000000000000..ced1b537f06f --- /dev/null +++ b/clang/test/BSC/Generic/member_func_call_builtIn_member_func.cbs @@ -0,0 +1,22 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +struct MyStruct { + T res; +}; + +void int::increase(int* this) { + *this = *this +1; +} + +int struct MyStruct::foo() { + int x = 1; + x.increase(); + return x; +} + +int main() { + int res = struct MyStruct::foo(); + return res - 2; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/member_func_call_generic_func.cbs b/clang/test/BSC/Generic/member_func_call_generic_func.cbs new file mode 100644 index 000000000000..041ce80a8ea4 --- /dev/null +++ b/clang/test/BSC/Generic/member_func_call_generic_func.cbs @@ -0,0 +1,20 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +struct MyStruct { + T res; +}; + +int foo(T1 a, T2 b) { + return 42; +} + +int struct MyStruct::foo() { + return foo(1, 2); +} + +int main() { + int res = struct MyStruct::foo(); + return res - 42; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/member_func_call_generic_member_func.cbs b/clang/test/BSC/Generic/member_func_call_generic_member_func.cbs new file mode 100644 index 000000000000..92b6957afc15 --- /dev/null +++ b/clang/test/BSC/Generic/member_func_call_generic_member_func.cbs @@ -0,0 +1,24 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +struct MyStruct1 { + T res; +}; + +struct MyStruct2 { + T res; +}; + +int struct MyStruct1::foo() { + return 42; +} + +int struct MyStruct2::foo() { + return struct MyStruct1::foo(); +} + +int main() { + int res = struct MyStruct2::foo(); + return res - 42; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/member_func_call_generic_member_func2.cbs b/clang/test/BSC/Generic/member_func_call_generic_member_func2.cbs new file mode 100644 index 000000000000..dc8fa976167c --- /dev/null +++ b/clang/test/BSC/Generic/member_func_call_generic_member_func2.cbs @@ -0,0 +1,25 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +struct MyStruct1 { + T res; +}; + +struct MyStruct2 { + T res; +}; + +int struct MyStruct1::foo(struct MyStruct1 *this) { + return 42; +} + +int struct MyStruct2::foo() { + struct MyStruct1 s = {.res = 1}; + return s.foo(); +} + +int main() { + int res = struct MyStruct2::foo(); + return res - 42; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/member_func_declaration.cbs b/clang/test/BSC/Generic/member_func_declaration.cbs new file mode 100644 index 000000000000..4fb7ba198606 --- /dev/null +++ b/clang/test/BSC/Generic/member_func_declaration.cbs @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -verify %s +// expected-no-diagnostics + +struct MyStruct { + T res; +}; + +union MyUnion { + T res; +}; + +int struct MyStruct::completed(struct MyStruct *this, int a); +int union MyUnion::completed(union MyUnion *this, int a); \ No newline at end of file diff --git a/clang/test/BSC/Generic/member_func_error_call.cbs b/clang/test/BSC/Generic/member_func_error_call.cbs new file mode 100644 index 000000000000..b6b879517790 --- /dev/null +++ b/clang/test/BSC/Generic/member_func_error_call.cbs @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -verify %s + +struct MyStruct { + T res; +}; + +T struct MyStruct::foo(struct MyStruct *this, T a) { + this->res = this->res + a; + return this->res; +} + +int main() { + struct MyStruct s; + int res = s->foo(10); // expected-error {{member reference type 'struct MyStruct' is not a pointer; did you mean to use '.'?}} + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/member_func_instance_call.cbs b/clang/test/BSC/Generic/member_func_instance_call.cbs new file mode 100644 index 000000000000..c108ae553ab5 --- /dev/null +++ b/clang/test/BSC/Generic/member_func_instance_call.cbs @@ -0,0 +1,29 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +struct MyStruct { + T res; +}; + +union MyUnion { + T res; +}; + +T struct MyStruct::foo(struct MyStruct *this, T a) { + this->res = this->res + a; + return this->res; +} + +T union MyUnion::foo(union MyUnion *this, T a) { + this->res = this->res + a; + return this->res; +} + +int main() { + struct MyStruct s = {.res = 1}; + union MyUnion u = {.res = 5}; + int res1 = s.foo(10); + int res2 = u.foo(6); + return res1 - res2; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/member_func_multi_generic_params.cbs b/clang/test/BSC/Generic/member_func_multi_generic_params.cbs new file mode 100644 index 000000000000..fc58b4938bc4 --- /dev/null +++ b/clang/test/BSC/Generic/member_func_multi_generic_params.cbs @@ -0,0 +1,27 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +struct MyStruct { + T1 res; +}; + +union MyUnion { + T1 res; +}; + +struct MyStruct struct MyStruct::foo(struct MyStruct *this) { + return *this; +} + +union MyUnion union MyUnion::foo(union MyUnion *this) { + return *this; +} + +int main() { + struct MyStruct s = {.res = 1}; + union MyUnion u = {.res = 5.0}; + s.foo(); + u.foo(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/member_func_static_call.cbs b/clang/test/BSC/Generic/member_func_static_call.cbs new file mode 100644 index 000000000000..4f9b61f46383 --- /dev/null +++ b/clang/test/BSC/Generic/member_func_static_call.cbs @@ -0,0 +1,25 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +struct MyStruct { + T res; +}; + +union MyUnion { + T res; +}; + +T struct MyStruct::foo(T a) { + return a; +} + +T union MyUnion::foo(T a) { + return a; +} + +int main() { + int res1 = struct MyStruct::foo(12); + int res2 = union MyUnion::foo(10); + return res1 - res2 - 2; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/multi_instantiated.cbs b/clang/test/BSC/Generic/multi_instantiated.cbs new file mode 100644 index 000000000000..2bca2620ab40 --- /dev/null +++ b/clang/test/BSC/Generic/multi_instantiated.cbs @@ -0,0 +1,35 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +struct MyStruct { + int isPending; + T res; +}; + +struct MyStruct foo(struct MyStruct *a) { + return *a; +} + +int struct MyStruct::bar(struct MyStruct *this, int a) { + return a; +} + +int f() { + struct MyStruct p; + int res1 = p.bar(10); + int res2 = struct MyStruct::bar(&p, 12); + return res1 + res2; +} + +int struct MyStruct::poll(struct MyStruct *this, int a) { + return a; +} + +int main() { + struct MyStruct p; + int res1 = p.poll(10); + int res2 = struct MyStruct::poll(&p, 12); + int res3 = f(); + return res1 + res2 - res3; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/multi_instantiated_diff_types.cbs b/clang/test/BSC/Generic/multi_instantiated_diff_types.cbs new file mode 100644 index 000000000000..36691ec694df --- /dev/null +++ b/clang/test/BSC/Generic/multi_instantiated_diff_types.cbs @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -verify %s +// expected-no-diagnostics + +struct S { + T t; +}; +void struct S::f(struct S* this) {} + +int main() { + struct S s1; + s1.f(); + struct S s2; + s2.f(); + + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/redefinition_member_func.cbs b/clang/test/BSC/Generic/redefinition_member_func.cbs new file mode 100644 index 000000000000..33d4d2085edc --- /dev/null +++ b/clang/test/BSC/Generic/redefinition_member_func.cbs @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -verify %s + +struct MyStruct { + T res; +}; + +int struct MyStruct::foo(struct MyStruct *this, int a) { // expected-note {{previous definition is here}} + return a; +} + +int struct MyStruct::foo(struct MyStruct *this, int a) { // expected-error {{redefinition of 'foo'}} + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/return_type_Instantiated_struct.cbs b/clang/test/BSC/Generic/return_type_Instantiated_struct.cbs new file mode 100644 index 000000000000..72b25ea1419a --- /dev/null +++ b/clang/test/BSC/Generic/return_type_Instantiated_struct.cbs @@ -0,0 +1,18 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +struct MyStruct { + T1 res1; + T2 res2; +}; + +struct MyStruct foo(struct MyStruct *this) { + return *this; +} + +int main() { + struct MyStruct p = {.res1 = 1, .res2 = 1.0}; + foo(&p); + return p.res1 - 1; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/return_type_generic_struct.cbs b/clang/test/BSC/Generic/return_type_generic_struct.cbs new file mode 100644 index 000000000000..bdad0cf41717 --- /dev/null +++ b/clang/test/BSC/Generic/return_type_generic_struct.cbs @@ -0,0 +1,18 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +struct MyStruct { + T1 res1; + T2 res2; +}; + +struct MyStruct foo(struct MyStruct *this) { + return *this; +} + +int main() { + struct MyStruct p; + foo(&p); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/return_type_generic_struct1.cbs b/clang/test/BSC/Generic/return_type_generic_struct1.cbs new file mode 100644 index 000000000000..0ffa6a59754c --- /dev/null +++ b/clang/test/BSC/Generic/return_type_generic_struct1.cbs @@ -0,0 +1,17 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +struct MyStruct { + T res; +}; + +struct MyStruct foo(struct MyStruct *this, T2 a) { + return *this; +} + +int main() { + struct MyStruct p; + foo(&p, 12); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/return_type_generic_union.cbs b/clang/test/BSC/Generic/return_type_generic_union.cbs new file mode 100644 index 000000000000..ef1005f8db49 --- /dev/null +++ b/clang/test/BSC/Generic/return_type_generic_union.cbs @@ -0,0 +1,18 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +union MyUnion { + T1 res1; + T2 res2; +}; + +union MyUnion foo(union MyUnion *this) { + return *this; +} + +int main() { + union MyUnion p; + foo(&p); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/struct_instantiate_before_define_member_func.cbs b/clang/test/BSC/Generic/struct_instantiate_before_define_member_func.cbs new file mode 100644 index 000000000000..fe61298a3404 --- /dev/null +++ b/clang/test/BSC/Generic/struct_instantiate_before_define_member_func.cbs @@ -0,0 +1,23 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +struct MyStruct { + T res; +}; + +struct MyStruct foo(struct MyStruct *a) { + return *a; +} + +int struct MyStruct::foo(struct MyStruct *this, int a) { + return a; +} + +int main() { + struct MyStruct p; + p.res = 22; + int res1 = p.foo(10); + int res2 = struct MyStruct::foo(&p, 12); + return res1 + res2 - p.res; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/Struct/struct_incomplete_type_call.cbs b/clang/test/BSC/Method/Struct/struct_incomplete_type_call.cbs new file mode 100644 index 000000000000..41de170533c1 --- /dev/null +++ b/clang/test/BSC/Method/Struct/struct_incomplete_type_call.cbs @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -verify %s + +int main() { + struct Foo::getA(); // expected-error {{variable has incomplete type 'struct Foo'}} + // expected-error@-1 {{use of undeclared identifier 'getA'}} + return 0; +} -- Gitee