diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 7fbf6294970eb722b5b24f74198f8fcbb34bd708..018e47dadcd9b4e64bb0bd19bb1a44a1439254c8 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -2291,6 +2291,10 @@ public: return static_cast(TemplatedDecl); } + RecordDecl *getBSCTemplatedDecl() const { + return static_cast(TemplatedDecl); + } + /// Returns whether this template declaration defines the primary /// class pattern. bool isThisDeclarationADefinition() const { diff --git a/clang/include/clang/Basic/TokenKinds.h b/clang/include/clang/Basic/TokenKinds.h index 4e66aa1c8c2d80f342c023445bdadf770303d96f..b70360cd78541303e06a115ce37918cd80c0c8ac 100644 --- a/clang/include/clang/Basic/TokenKinds.h +++ b/clang/include/clang/Basic/TokenKinds.h @@ -73,6 +73,30 @@ inline bool isAnyIdentifier(TokenKind K) { return (K == tok::identifier) || (K == tok::raw_identifier); } +/// Return true if this token kind could be type specifier. +inline bool isAnyTypeSpecifierKind(TokenKind K) { + // Type Specifier: see c11 spec 6.7.2 + return (K == tok::kw__Atomic) || + (K == tok::kw_union) || + (K == tok::kw_struct) || + (K == tok::kw_class) || + (K == tok::kw_enum) || + (K == tok::kw_typedef) || + (K == tok::kw__Complex) || + (K == tok::kw_void) || + (K == tok::kw_bool) || + (K == tok::kw__Bool) || + (K == tok::kw_char) || + (K == tok::kw_short) || + (K == tok::kw_int) || + (K == tok::kw_long) || + (K == tok::kw_float) || + (K == tok::kw_double) || + (K == tok::kw_signed) || + (K == tok::kw_unsigned) || + (K == tok::identifier); +} + /// Return true if this is a C or C++ string-literal (or /// C++11 user-defined-string-literal) token. inline bool isStringLiteral(TokenKind K) { diff --git a/clang/include/clang/Lex/Token.h b/clang/include/clang/Lex/Token.h index 89042a674fec392c0e36419fbc33a6205c6af7e9..819da87342451e96b2724b8f2a7edfd6d53e540e 100644 --- a/clang/include/clang/Lex/Token.h +++ b/clang/include/clang/Lex/Token.h @@ -110,6 +110,11 @@ public: return tok::isAnyIdentifier(getKind()); } + /// Return true if this token kind could be type specifier. + bool isAnyTypeSpecifierKind() const { + return tok::isAnyTypeSpecifierKind(getKind()); + } + /// Return true if this is a "literal", like a numeric /// constant, string, etc. bool isLiteral() const { diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 9e800892644710a8c1359772ca46d596bcbb3dfc..267ef496cc58468803d9bd08ac4b9d56ec9a085b 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1898,6 +1898,16 @@ private: bool OnlyNamespace = false, bool InUsingDeclaration = false); + bool ParseOptionalBSCGenericSpecifier(CXXScopeSpec &SS, + ParsedType ObjectType, + bool ObjectHasErrors, + bool EnteringContext, + bool *MayBePseudoDestructor = nullptr, + bool IsTypename = false, + IdentifierInfo **LastII = nullptr, + bool OnlyNamespace = false, + bool InUsingDeclaration = false); + //===--------------------------------------------------------------------===// // C++11 5.1.2: Lambda expressions @@ -2560,6 +2570,9 @@ private: /// during a tentative parse, but also should not be annotated as a non-type. bool isTentativelyDeclared(IdentifierInfo *II); + // DEV: Determine whether Tok at BSC template declaration clause. + bool isBSCTemplateDecl(Token tok); + // "Tentative parsing" functions, used for disambiguation. If a parsing error // is encountered they will return TPResult::Error. // Returning TPResult::True/False indicates that the ambiguity was @@ -3303,6 +3316,15 @@ private: SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, AccessSpecifier AS); + // DEV: ADD BSC-ParseTemplateDeclarationOrSpecialization + Decl *ParseBSCGenericDeclaration(DeclaratorContext Context, + SourceLocation &DeclEnd, + ParsedAttributes &AccessAttrs, + AccessSpecifier AS); + Decl *ParseTemplateDeclarationOrSpecializationBSCCompact(DeclaratorContext Context, + SourceLocation &DeclEnd, + ParsedAttributes &AccessAttrs, + AccessSpecifier AS); Decl *ParseSingleDeclarationAfterTemplate( DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject &DiagsFromParams, SourceLocation &DeclEnd, @@ -3311,11 +3333,23 @@ private: SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, SourceLocation &RAngleLoc); + // DEV: Declare ParseBSCTemplateParameters + bool ParseBSCTemplateParameters(MultiParseScope &TemplateScopes, unsigned Depth, + SmallVectorImpl &TemplateParams, + SourceLocation &LAngleLoc, + SourceLocation &RAngleLoc, + int &lookAheadOffset); bool ParseTemplateParameterList(unsigned Depth, SmallVectorImpl &TemplateParams); + // DEV: Declare ParseBSCTemplateParameterList + bool ParseBSCTemplateParameterList(unsigned Depth, + SmallVectorImpl &TemplateParams, + int &lookAheadOffset); TPResult isStartOfTemplateTypeParameter(); NamedDecl *ParseTemplateParameter(unsigned Depth, unsigned Position); NamedDecl *ParseTypeParameter(unsigned Depth, unsigned Position); + // DEV: Declare ParseBSCTypeParameter + NamedDecl *ParseBSCTypeParameter(unsigned Depth, unsigned Position, int &lookAheadOffset); NamedDecl *ParseTemplateTemplateParameter(unsigned Depth, unsigned Position); NamedDecl *ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position); bool isTypeConstraintAnnotation(); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index b0c085d98044b77808356f310b5929507566a163..509a943829ff47d86c4557504e4a8dce29715619 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9299,7 +9299,7 @@ public: bool InstantiateClass(SourceLocation PointOfInstantiation, - CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, + RecordDecl *Instantiation, RecordDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK, bool Complain = true); diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index 8c3fc70d26be46a62b11ef21f262d3ae76839982..81af1a12a7c333fe3fcdf6e46f8beae3fdaa4d34 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -460,7 +460,7 @@ enum class TemplateSubstitutionKind : char { bool isLocalPackExpansion(const Decl *D); }; - class TemplateDeclInstantiator + class TemplateDeclInstantiator // yt: Key for BSC. : public DeclVisitor { Sema &SemaRef; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index cb7f00abf9e91842d6227f283f2f73b83463dee7..86f719831c931b3b15310ffc10e7165ba9a0c8c7 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -880,7 +880,8 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( } CXXABI *ASTContext::createCXXABI(const TargetInfo &T) { - if (!LangOpts.CPlusPlus) return nullptr; + // BSC Mark: add BSC language judgement. + if (!(LangOpts.CPlusPlus || LangOpts.BSC)) return nullptr; switch (T.getCXXABI().getKind()) { case TargetCXXABI::AppleARM64: diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 3e9d1d032b743257753bbe5b6ab289a0c7787e73..e03bc9ff617e7793602441c3890a1292745af1e8 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -1563,8 +1563,12 @@ void DeclContext::addHiddenDecl(Decl *D) { // Notify a C++ record declaration that we've added a member, so it can // update its class-specific state. - if (auto *Record = dyn_cast(this)) - Record->addedMember(D); + // DEV: Only CXXRecordDecl supports addedMember(), Clang assume only C++ supports template-structure, + // BSC template-structure reuses CXX.. logic, each RecordDecl need to be checked. + if (D->getASTContext().getLangOpts().CPlusPlus) { // LangOpts().CPlusPlus does not work at here + if (auto *Record = dyn_cast(this)) + Record->addedMember(D); + } // If this is a newly-created (not de-serialized) import declaration, wire // it in to the list of local import declarations. diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp index 3e4a497aef988727f8f87e140d27b52f0a984a8b..d3056a3edec3e69e4fcbeb46f18ffe0fcef75b45 100644 --- a/clang/lib/AST/Mangle.cpp +++ b/clang/lib/AST/Mangle.cpp @@ -120,6 +120,13 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) { if (!D->hasExternalFormalLinkage() && D->getOwningModuleForLinkage()) return true; + // In BSC, generic function always does mangling. + if (getASTContext().getLangOpts().BSC) { + if (auto FD = dyn_cast(D)) { + return FD->getTemplatedKind() == FunctionDecl::TemplatedKind::TK_FunctionTemplateSpecialization; + } + } + // In C, functions with no attributes never need to be mangled. Fastpath them. if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs()) return false; diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 95d69fa5b11ad0f41a82b4d05c1f4943a9a5216c..8d2f415ff269a906f36472cad8ab02e53de15eb4 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -189,18 +189,20 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() { for (const CXXBaseSpecifier &Base : Class->bases()) { const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); - CharUnits EmptySize; - const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl); - if (BaseDecl->isEmpty()) { - // If the class decl is empty, get its size. - EmptySize = Layout.getSize(); - } else { - // Otherwise, we get the largest empty subobject for the decl. - EmptySize = Layout.getSizeOfLargestEmptySubobject(); - } + if (BaseDecl->getASTContext().getLangOpts().CPlusPlus) { // Only C++ supports getSizeOfLargestEmptySubobject() + CharUnits EmptySize; + const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl); + if (BaseDecl->isEmpty()) { + // If the class decl is empty, get its size. + EmptySize = Layout.getSize(); + } else { + // Otherwise, we get the largest empty subobject for the decl. + EmptySize = Layout.getSizeOfLargestEmptySubobject(); + } - if (EmptySize > SizeOfLargestEmptySubobject) - SizeOfLargestEmptySubobject = EmptySize; + if (EmptySize > SizeOfLargestEmptySubobject) + SizeOfLargestEmptySubobject = EmptySize; + } } // Check the fields. @@ -212,19 +214,21 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() { if (!RT) continue; - CharUnits EmptySize; - const CXXRecordDecl *MemberDecl = RT->getAsCXXRecordDecl(); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl); - if (MemberDecl->isEmpty()) { - // If the class decl is empty, get its size. - EmptySize = Layout.getSize(); - } else { - // Otherwise, we get the largest empty subobject for the decl. - EmptySize = Layout.getSizeOfLargestEmptySubobject(); - } + if (FD->getASTContext().getLangOpts().CPlusPlus) { // DEV: Only C++ supports getSizeOfLargestEmptySubobject() + CharUnits EmptySize; + const CXXRecordDecl *MemberDecl = RT->getAsCXXRecordDecl(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl); + if (MemberDecl->isEmpty()) { + // If the class decl is empty, get its size. + EmptySize = Layout.getSize(); + } else { + // Otherwise, we get the largest empty subobject for the decl. + EmptySize = Layout.getSizeOfLargestEmptySubobject(); + } - if (EmptySize > SizeOfLargestEmptySubobject) - SizeOfLargestEmptySubobject = EmptySize; + if (EmptySize > SizeOfLargestEmptySubobject) + SizeOfLargestEmptySubobject = EmptySize; + } } } diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 177786d903907aabca30d2994f83fc806af65eb7..9a97a629617d2013414db1bc3d60fd9080695d11 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -897,7 +897,7 @@ void Preprocessor::Lex(Token &Result) { ReturnedToken = CurTokenLexer->Lex(Result); break; case CLK_CachingLexer: - CachingLex(Result); + CachingLex(Result); // in ConsumeToken(),read Token from global Cache, therefore, token consumption is linear ReturnedToken = true; break; case CLK_LexAfterModuleImport: diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index d9c892251ce7035fd665fb8f76efcdf47fe3202d..2a3a54a77c51a8cb3d332b99e715d63917fc4f43 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1661,7 +1661,7 @@ Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, case tok::kw_template: case tok::kw_export: ProhibitAttributes(attrs); - SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); + SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); // C++ template function parsing branch break; case tok::kw_inline: // Could be the start of an inline namespace. Allowed as an ext in C++03. @@ -1684,6 +1684,14 @@ Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, SingleDecl = ParseStaticAssertDeclaration(DeclEnd); break; default: + // parse BSC template declaration + // TODO: change if statement entrance condition, abandon isBSCTemplateDecl() + if (isBSCTemplateDecl(Tok)) { + ProhibitAttributes(attrs); + SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, attrs); // OK: ClassTemplateDecl with RecordDecl. + break; + } + return ParseSimpleDeclaration(Context, DeclEnd, attrs, true, nullptr, DeclSpecStart); } @@ -3381,7 +3389,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isConstructorDeclarator(/*Unqualified*/true)) goto DoneWithDeclSpec; - ParsedType TypeRep = Actions.getTypeName( + ParsedType TypeRep = Actions.getTypeName( // `T a;` resolve T now *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), nullptr, false, false, nullptr, false, false, isClassTemplateDeductionContext(DSContext)); @@ -3394,7 +3402,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (Tok.isNot(tok::identifier)) continue; ParsedAttributesWithRange Attrs(AttrFactory); - if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) { + if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) { // template parameter "T" in BSC might be miss-parsed here | when? if (!Attrs.empty()) { AttrsLastTime = true; attrs.takeAllFrom(Attrs); @@ -3956,7 +3964,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___interface: case tok::kw_union: { tok::TokenKind Kind = Tok.getKind(); - ConsumeToken(); + ConsumeToken(); // consume 'struct' keyword // These are attributes following class specifiers. // To produce better diagnostic, we parse them when @@ -5956,7 +5964,10 @@ static SourceLocation getMissingDeclaratorIdLoc(Declarator &D, void Parser::ParseDirectDeclarator(Declarator &D) { DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec()); - if (getLangOpts().CPlusPlus && D.mayHaveIdentifier()) { + // BSC Mark: Add language judgement for BSC template situation. + // add BSC entrance condition! + if ((getLangOpts().CPlusPlus || getLangOpts().BSC) + && D.mayHaveIdentifier()) { // This might be a C++17 structured binding. if (Tok.is(tok::l_square) && !D.mayOmitIdentifier() && D.getCXXScopeSpec().isEmpty()) @@ -5976,7 +5987,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { D.getContext() == DeclaratorContext::Member; ParseOptionalCXXScopeSpecifier( D.getCXXScopeSpec(), /*ObjectType=*/nullptr, - /*ObjectHadErrors=*/false, EnteringContext); + /*ObjectHadErrors=*/false, EnteringContext); // BSC compacity problem exists, non-critic } if (D.getCXXScopeSpec().isValid()) { @@ -6229,7 +6240,12 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // In such a case, check if we actually have a function declarator; if it // is not, the declarator has been fully parsed. bool IsAmbiguous = false; - if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) { + // if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) { + + // BSC Mark: Add language judgement for BSC template situation. + // Change branch entering condition | BSC syntax reusing C++ parsing code + if ((getLangOpts().CPlusPlus || getLangOpts().BSC) + && D.mayBeFollowedByCXXDirectInit()) { // The name of the declarator, if any, is tentatively declared within // a possible direct initializer. TentativelyDeclaredIdentifiers.push_back(D.getIdentifier()); @@ -6590,7 +6606,9 @@ void Parser::ParseFunctionDeclarator(Declarator &D, LocalEndLoc = RParenLoc; EndLoc = RParenLoc; - if (getLangOpts().CPlusPlus) { + // Change branch entering condition | reusing C++ parse code when parsing BSC syntax + // if (getLangOpts().CPlusPlus) { + if (getLangOpts().CPlusPlus || getLangOpts().BSC) { // FIXME: Accept these components in any order, and produce fixits to // correct the order if the user gets it wrong. Ideally we should deal // with the pure-specifier in the same way. diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 88ebb59f9a607b6ce65cf5d2ede9710d987e2246..a87a38527f42f0dd387b40bd6db181d153634939 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1553,7 +1553,28 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, CXXScopeSpec Spec; bool HasValidSpec = true; - if (ParseOptionalCXXScopeSpecifier(Spec, /*ObjectType=*/nullptr, + if (ParseOptionalCXXScopeSpecifier(Spec, /*ObjectType=*/nullptr, // After this, TokenKind is tok::annot_template_id! + /*ObjectHadErrors=*/false, + EnteringContext)) { + DS.SetTypeSpecError(); + HasValidSpec = false; + } + if (Spec.isSet()) + if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) { + Diag(Tok, diag::err_expected) << tok::identifier; + HasValidSpec = false; + } + if (HasValidSpec) + SS = Spec; + } + + // BSC Mark: 'struct S s1' should enter here + if (getLangOpts().BSC) { + ColonProtectionRAIIObject X(*this); + + CXXScopeSpec Spec; + bool HasValidSpec = true; + if (ParseOptionalBSCGenericSpecifier(Spec, /*ObjectType=*/nullptr, // After this, TokenKind is tok::annot_template_id! /*ObjectHadErrors=*/false, EnteringContext)) { DS.SetTypeSpecError(); @@ -1604,10 +1625,20 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, IdentifierInfo *Name = nullptr; SourceLocation NameLoc; TemplateIdAnnotation *TemplateId = nullptr; + bool isParsingBSCTemplateStruct = getLangOpts().BSC && Tok.is(tok::identifier) && NextToken().is(tok::less); if (Tok.is(tok::identifier)) { Name = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); + // BSC Sturct Template Declaration may have "" syntax. + // This param list must been parsed, skip it. + if (isParsingBSCTemplateStruct) { + while (Tok.getKind() != tok::greater) { + ConsumeToken(); + } + assert(TryConsumeToken(tok::greater) && "fail at comsuming BSC struct template param list!"); + } + if (Tok.is(tok::less) && getLangOpts().CPlusPlus) { // The name was supposed to refer to a template, but didn't. // Eat the template argument list and try to continue parsing this as @@ -1809,7 +1840,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, bool Owned = false; Sema::SkipBodyInfo SkipBody; - if (TemplateId) { + if (TemplateId) { // specialization for BSC generic: `struct S` // Explicit specialization, class template partial specialization, // or explicit instantiation. ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), @@ -1965,12 +1996,18 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (SkipBody.ShouldSkip) SkipCXXMemberSpecification(StartLoc, AttrFixitLoc, TagType, TagOrTempResult.get()); + // add BSC entrance condition else if (getLangOpts().CPlusPlus) ParseCXXMemberSpecification(StartLoc, AttrFixitLoc, attrs, TagType, TagOrTempResult.get()); else { - Decl *D = - SkipBody.CheckSameAsPrevious ? SkipBody.New : TagOrTempResult.get(); + Decl* D = nullptr; + if (isParsingBSCTemplateStruct) { + // TODO: add more check + D = static_cast(TagOrTempResult.get())->getTemplatedDecl(); + } else { + D = SkipBody.CheckSameAsPrevious ? SkipBody.New : TagOrTempResult.get(); + } // Parse the definition body. ParseStructUnionBody(StartLoc, TagType, cast(D)); if (SkipBody.CheckSameAsPrevious && @@ -3097,7 +3134,6 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas( AccessSpecifier &AS, ParsedAttributesWithRange &AccessAttrs, DeclSpec::TST TagType, Decl *TagDecl) { ParenBraceBracketBalancer BalancerRAIIObj(*this); - switch (Tok.getKind()) { case tok::kw___if_exists: case tok::kw___if_not_exists: diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 22b280decae4718b41f9019c0d83a4d4b33f9149..fb41168f6e823be2bd55c51ed99e2b86407721a7 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1075,7 +1075,7 @@ Parser::ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand, } // Turn a potentially qualified name into a annot_typename or // annot_cxxscope if it would be valid. This handles things like x::y, etc. - if (getLangOpts().CPlusPlus) { + if (getLangOpts().CPlusPlus || getLangOpts().BSC) { // Avoid the unnecessary parse-time lookup in the common case // where the syntax forbids a type. const Token &Next = NextToken(); @@ -1563,7 +1563,7 @@ Parser::ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand, ParseKind, isAddressOfOperand, NotCastExpr, isTypeCast, isVectorLiteral, NotPrimaryExpression, HasBSCScopeSpec); } - if (!getLangOpts().CPlusPlus) { + if (!(getLangOpts().CPlusPlus || getLangOpts().BSC)) { // BSC Mark: enter the type-cast check in bsc generic situation. Diag(Tok, diag::err_expected_expression); return ExprError(); } diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 4b5703d79f28e49f4a9add23e46d1f237139e01c..5ae4ac29ec05c32ca42543cd385e0e9bb6441e92 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -155,7 +155,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier( CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors, bool EnteringContext, bool *MayBePseudoDestructor, bool IsTypename, IdentifierInfo **LastII, bool OnlyNamespace, bool InUsingDeclaration) { - assert(getLangOpts().CPlusPlus && + assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && "Call sites of this function should be guarded by checking for C++"); if (Tok.is(tok::annot_cxxscope)) { @@ -386,7 +386,28 @@ bool Parser::ParseOptionalCXXScopeSpecifier( // type-name '::' // namespace-name '::' // nested-name-specifier identifier '::' - Token Next = NextToken(); + // Token Next = NextToken(); + + // Skip template template param list in template function declaration: "T max (T a, T b) {...}" + // ^^^ + Token Next; + bool parsingBSCTemplateFunction = getLangOpts().BSC && + Tok.is(tok::identifier) && + PP.LookAhead(0).is(tok::less) && + PP.LookAhead(1).is(tok::identifier) && // TODO: this could be missidentified from typo: "intt" + (PP.LookAhead(2).is(tok::comma) || PP.LookAhead(2).is(tok::greater)); + 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); + } + Next = PP.LookAhead(lParenOffset); + } else { + Next = NextToken(); + } + Sema::NestedNameSpecInfo IdInfo(&II, Tok.getLocation(), Next.getLocation(), ObjectType); @@ -474,7 +495,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier( // nested-name-specifier: // type-name '<' - if (Next.is(tok::less)) { + if (Next.is(tok::less)) { // 'S', then 'S' is set to tok::annote_template_id TemplateTy Template; UnqualifiedId TemplateName; @@ -554,6 +575,309 @@ bool Parser::ParseOptionalCXXScopeSpecifier( return false; } +// BSC Mark: parse instation for struct part of generic, +// to avoid affecting the original logic of C++ +bool Parser::ParseOptionalBSCGenericSpecifier( + CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors, + bool EnteringContext, bool *MayBePseudoDestructor, bool IsTypename, + IdentifierInfo **LastII, bool OnlyNamespace, bool InUsingDeclaration) { + assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && + "Call sites of this function should be guarded by checking for C++ or BSC"); + + if (Tok.is(tok::annot_cxxscope)) { + assert(!LastII && "want last identifier but have already annotated scope"); + assert(!MayBePseudoDestructor && "unexpected annot_cxxscope"); + Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), + Tok.getAnnotationRange(), + SS); + ConsumeAnnotationToken(); + return false; + } + + // Has to happen before any "return false"s in this function. + bool CheckForDestructor = false; + if (MayBePseudoDestructor && *MayBePseudoDestructor) { + CheckForDestructor = true; + *MayBePseudoDestructor = false; + } + + if (LastII) + *LastII = nullptr; + + bool HasScopeSpecifier = false; + + if (!HasScopeSpecifier && + Tok.isOneOf(tok::kw_decltype, tok::annot_decltype)) { + DeclSpec DS(AttrFactory); + SourceLocation DeclLoc = Tok.getLocation(); + SourceLocation EndLoc = ParseDecltypeSpecifier(DS); + + SourceLocation CCLoc; + // Work around a standard defect: 'decltype(auto)::' is not a + // nested-name-specifier. + if (DS.getTypeSpecType() == DeclSpec::TST_decltype_auto || + !TryConsumeToken(tok::coloncolon, CCLoc)) { + AnnotateExistingDecltypeSpecifier(DS, DeclLoc, EndLoc); + return false; + } + + if (Actions.ActOnCXXNestedNameSpecifierDecltype(SS, DS, CCLoc)) + SS.SetInvalid(SourceRange(DeclLoc, CCLoc)); + + HasScopeSpecifier = true; + } + + // Preferred type might change when parsing qualifiers, we need the original. + auto SavedType = PreferredType; + while (true) { + if (HasScopeSpecifier) { + if (Tok.is(tok::code_completion)) { + // Code completion for a nested-name-specifier, where the code + // completion token follows the '::'. + Actions.CodeCompleteQualifiedId(getCurScope(), SS, EnteringContext, + InUsingDeclaration, ObjectType.get(), + SavedType.get(SS.getBeginLoc())); + // Include code completion token into the range of the scope otherwise + // when we try to annotate the scope tokens the dangling code completion + // token will cause assertion in + // Preprocessor::AnnotatePreviousCachedTokens. + SS.setEndLoc(Tok.getLocation()); + cutOffParsing(); + return true; + } + + ObjectType = nullptr; + } + + // nested-name-specifier: + // nested-name-specifier 'template'[opt] simple-template-id '::' + + // Parse the optional 'template' keyword, then make sure we have + // 'identifier <' after it. + if (Tok.is(tok::kw_template)) { + // If we don't have a scope specifier or an object type, this isn't a + // nested-name-specifier, since they aren't allowed to start with + // 'template'. + if (!HasScopeSpecifier && !ObjectType) + break; + + TentativeParsingAction TPA(*this); + SourceLocation TemplateKWLoc = ConsumeToken(); + + UnqualifiedId TemplateName; + if (Tok.is(tok::identifier)) { + // Consume the identifier. + TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeToken(); + } else if (Tok.is(tok::kw_operator)) { + // We don't need to actually parse the unqualified-id in this case, + // because a simple-template-id cannot start with 'operator', but + // go ahead and parse it anyway for consistency with the case where + // we already annotated the template-id. + if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, + TemplateName)) { + TPA.Commit(); + break; + } + + if (TemplateName.getKind() != UnqualifiedIdKind::IK_OperatorFunctionId && + TemplateName.getKind() != UnqualifiedIdKind::IK_LiteralOperatorId) { + Diag(TemplateName.getSourceRange().getBegin(), + diag::err_id_after_template_in_nested_name_spec) + << TemplateName.getSourceRange(); + TPA.Commit(); + break; + } + } else { + TPA.Revert(); + break; + } + + // If the next token is not '<', we have a qualified-id that refers + // to a template name, such as T::template apply, but is not a + // template-id. + if (Tok.isNot(tok::less)) { + TPA.Revert(); + break; + } + + // Commit to parsing the template-id. + TPA.Commit(); + TemplateTy Template; + TemplateNameKind TNK = Actions.ActOnTemplateName( + getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType, + EnteringContext, Template, /*AllowInjectedClassName*/ true); + if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateKWLoc, + TemplateName, false)) + return true; + + continue; + } + + if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) { + // We have + // + // template-id '::' + // + // So we need to check whether the template-id is a simple-template-id of + // the right kind (it should name a type or be dependent), and then + // convert it into a type within the nested-name-specifier. + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) { + *MayBePseudoDestructor = true; + return false; + } + + if (LastII) + *LastII = TemplateId->Name; + + // Consume the template-id token. + ConsumeAnnotationToken(); + + assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); + SourceLocation CCLoc = ConsumeToken(); + + HasScopeSpecifier = true; + + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + + if (TemplateId->isInvalid() || + Actions.ActOnCXXNestedNameSpecifier(getCurScope(), + SS, + TemplateId->TemplateKWLoc, + TemplateId->Template, + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc, + CCLoc, + EnteringContext)) { + SourceLocation StartLoc + = SS.getBeginLoc().isValid()? SS.getBeginLoc() + : TemplateId->TemplateNameLoc; + SS.SetInvalid(SourceRange(StartLoc, CCLoc)); + } + + continue; + } + + // The rest of the nested-name-specifier possibilities start with + // tok::identifier. + if (Tok.isNot(tok::identifier)) + break; + + IdentifierInfo &II = *Tok.getIdentifierInfo(); + + // nested-name-specifier: + // type-name '::' + // namespace-name '::' + // nested-name-specifier identifier '::' + // Token Next = NextToken(); + + Token Next; + bool parsingBSCTemplateFunction = getLangOpts().BSC && + Tok.is(tok::identifier) && + PP.LookAhead(0).is(tok::less) && + PP.LookAhead(1).is(tok::identifier) && + (PP.LookAhead(2).is(tok::comma) || PP.LookAhead(2).is(tok::greater)); + if (parsingBSCTemplateFunction) { + int lParenOffset = 0; + while (!PP.LookAhead(lParenOffset).is(tok::l_paren)) { + lParenOffset += 1; + } + Next = PP.LookAhead(lParenOffset); + } else { + Next = NextToken(); + } + + Sema::NestedNameSpecInfo IdInfo(&II, Tok.getLocation(), Next.getLocation(), + ObjectType); + + CheckForTemplateAndDigraph(Next, ObjectType, EnteringContext, II, SS); + + // nested-name-specifier: + // type-name '<' + if (Next.is(tok::less)) { // yt: 'S', next 'S' is set to tok::annote_template_id? + + TemplateTy Template; + UnqualifiedId TemplateName; + TemplateName.setIdentifier(&II, Tok.getLocation()); + bool MemberOfUnknownSpecialization; + if (TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS, + /*hasTemplateKeyword=*/false, + TemplateName, + ObjectType, + EnteringContext, + Template, + MemberOfUnknownSpecialization)) { + // If lookup didn't find anything, we treat the name as a template-name + // anyway. C++20 requires this, and in prior language modes it improves + // error recovery. But before we commit to this, check that we actually + // have something that looks like a template-argument-list next. + if (!IsTypename && TNK == TNK_Undeclared_template && + isTemplateArgumentList(1) == TPResult::False) + break; + + // We have found a template name, so annotate this token + // with a template-id annotation. We do not permit the + // template-id to be translated into a type annotation, + // because some clients (e.g., the parsing of class template + // specializations) still want to see the original template-id + // token, and it might not be a type at all (e.g. a concept name in a + // type-constraint). + ConsumeToken(); // yt: Cpp template specialization enter here + if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), + TemplateName, false)) + return true; + continue; + } + + if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) && + (IsTypename || isTemplateArgumentList(1) == TPResult::True)) { + // If we had errors before, ObjectType can be dependent even without any + // templates. Do not report missing template keyword in that case. + if (!ObjectHadErrors) { + // We have something like t::getAs, where getAs is a + // member of an unknown specialization. However, this will only + // parse correctly as a template, so suggest the keyword 'template' + // before 'getAs' and treat this as a dependent template name. + unsigned DiagID = diag::err_missing_dependent_template_keyword; + if (getLangOpts().MicrosoftExt) + DiagID = diag::warn_missing_dependent_template_keyword; + + Diag(Tok.getLocation(), DiagID) + << II.getName() + << FixItHint::CreateInsertion(Tok.getLocation(), "template "); + } + + SourceLocation TemplateNameLoc = ConsumeToken(); + + TemplateNameKind TNK = Actions.ActOnTemplateName( + getCurScope(), SS, TemplateNameLoc, TemplateName, ObjectType, + EnteringContext, Template, /*AllowInjectedClassName*/ true); + if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), + TemplateName, false)) + return true; + + continue; + } + } + + // We don't have any tokens that form the beginning of a + // nested-name-specifier, so we're done. + break; + } + + // Even if we didn't see any pieces of a nested-name-specifier, we + // still check whether there is a tilde in this position, which + // indicates a potential pseudo-destructor. + if (CheckForDestructor && !HasScopeSpecifier && Tok.is(tok::tilde)) + *MayBePseudoDestructor = true; + + return false; +} + ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOperand, Token &Replacement) { @@ -2794,6 +3118,17 @@ 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)) { + assert(Tok.is(tok::less) && "expected 'less' token"); + while (!Tok.is(tok::greater)) { + ConsumeToken(); + } + assert(TryConsumeToken(tok::greater) && "expected 'greater' token"); + assert(Tok.is(tok::l_paren) && "expected 'l_paren' token"); + } + // If we're not in C++, only identifiers matter. Record the // identifier and return. Result.setIdentifier(Id, IdLoc); @@ -2821,7 +3156,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, } // If the next token is a '<', we may have a template. - TemplateTy Template; + TemplateTy Template; if (Tok.is(tok::less)) return ParseUnqualifiedIdTemplateId( SS, ObjectType, ObjectHadErrors, diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 0170003db76ece0f85ebd768bb2f861b364f98a1..e3b3a2760045edb60bd7dc8424881804c417d0a4 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -208,7 +208,7 @@ Retry: Default: default: { - if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || + if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || getLangOpts().BSC || // let `struct S s1 = {}` enter here. (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) != ParsedStmtContext()) && (GNUAttributeLoc.isValid() || @@ -1126,7 +1126,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr, SafeScopeSpecifie StmtResult R; if (Tok.isNot(tok::kw___extension__)) { - R = ParseStatementOrDeclaration(Stmts, SubStmtCtx); + R = ParseStatementOrDeclaration(Stmts, SubStmtCtx); // see `struct` in `struct S` } else { // __extension__ can start declarations and it can also be a unary // operator for expressions. Consume multiple __extension__ markers here diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 828b9b2277ff34797f37fd8a056e6a4e93c3bc0f..c9532a12d023cead3e084c92b8a1fc531cab965e 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -43,10 +43,100 @@ Decl *Parser::ParseDeclarationStartingWithTemplate( return ParseExplicitInstantiation(Context, SourceLocation(), ConsumeToken(), DeclEnd, AccessAttrs, AS); } + // Parse BSC template declaration + // TODO: change if statement entrance condition, abandon isBSCTemplateDecl() + if (isBSCTemplateDecl(Tok)) { + return ParseBSCGenericDeclaration(Context, DeclEnd, AccessAttrs, + AS); + } return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AccessAttrs, AS); } +// DIY rewrite ParseTemplateDeclarationOrSpecialization for BSC +Decl *Parser::ParseBSCGenericDeclaration( + DeclaratorContext Context, SourceLocation &DeclEnd, + ParsedAttributes &AccessAttrs, AccessSpecifier AS) { + assert(getLangOpts().BSC && "Error enter BSC template declaration parsing function."); + + MultiParseScope TemplateParamScopes(*this); + + // Tell the action that names should be checked in the context of + // the declaration to come. + ParsingDeclRAIIObject + ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent); // not sure + + // Parse multiple levels of template headers within this template // make sure each parameter pass same branch & branch condition is fully considered + bool isSpecialization = true; // changed in (2), shuold be false : Kind(isSpecialization? ExplicitSpecialization : Template) + bool LastParamListWasEmpty = false; // changed in (2), should be false: Whether the last template parameter list was empty. + TemplateParameterLists ParamLists; // changed in (2), only called onece at ParamLists.push_back + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); // changed in (2), + + // Consume the 'export', if any. // no corresponding syntax + SourceLocation ExportLoc; + TryConsumeToken(tok::kw_export, ExportLoc); + + // Consume the 'template', which should be here. // no corresponding syntax + SourceLocation TemplateLoc; + TryConsumeToken(tok::kw_template, TemplateLoc); + + int lookAheadOffset = 0; // lookAheadOffset starts from 0, assume the first token we see must not be '<' + while (!PP.LookAhead(lookAheadOffset).is(tok::less)) { // use while since the template function definition struct is not solid in BSC + lookAheadOffset += 1; + } + assert(PP.LookAhead(lookAheadOffset).is(tok::less) && "BSC template function parameter list does not begin with tok::less"); + + // Parse the '<' template-parameter-list '>' + SourceLocation LAngleLoc, RAngleLoc; + SmallVector TemplateParams; + if (ParseBSCTemplateParameters(TemplateParamScopes, + CurTemplateDepthTracker.getDepth(), + TemplateParams, LAngleLoc, RAngleLoc, + lookAheadOffset)) { // open this + // Skip until the semi-colon or a '}'. + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); // error handel + TryConsumeToken(tok::semi); + return nullptr; + } + + ExprResult OptionalRequiresClauseConstraintER; + if (!TemplateParams.empty()) { + isSpecialization = false; // keep this + ++CurTemplateDepthTracker; // keep this + + if (TryConsumeToken(tok::kw_requires)) { // C++ concept-requries clause + OptionalRequiresClauseConstraintER = + Actions.ActOnRequiresClause(ParseConstraintLogicalOrExpression( + /*IsTrailingRequiresClause=*/false)); + if (!OptionalRequiresClauseConstraintER.isUsable()) { + // Skip until the semi-colon or a '}'. + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); + TryConsumeToken(tok::semi); + return nullptr; + } + } + } else { + LastParamListWasEmpty = true; + } + + ParamLists.push_back(Actions.ActOnTemplateParameterList( // make sure parameters input is same as C++, for both func and struct + CurTemplateDepthTracker.getDepth(), ExportLoc, TemplateLoc, LAngleLoc, + TemplateParams, RAngleLoc, OptionalRequiresClauseConstraintER.get())); + + // Parse the actual template declaration. + if (Tok.is(tok::kw_concept)) // C++ concept-requires clause, no corresponding syntax in BSC + return ParseConceptDefinition( + ParsedTemplateInfo(&ParamLists, isSpecialization, + LastParamListWasEmpty), + DeclEnd); + + return ParseSingleDeclarationAfterTemplate( // make sure parameters input is same as C++, for both func and struct + Context, + ParsedTemplateInfo(&ParamLists, isSpecialization, LastParamListWasEmpty), + ParsingTemplateParams, DeclEnd, AccessAttrs, AS); +} + + /// Parse a template declaration or an explicit specialization. /// /// Template declarations include one or more template parameter lists @@ -469,6 +559,68 @@ bool Parser::ParseTemplateParameters( return false; } + +// ParseBSCTemplateParameters - rewrite ParseTemplateParameters for cross-order BSC syntax, use Peeking +bool Parser::ParseBSCTemplateParameters( + MultiParseScope &TemplateScopes, unsigned Depth, + SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, + SourceLocation &RAngleLoc, int &lookAheadOffset) { + // if (!TryConsumeToken(tok::less, LAngleLoc)) { + // Diag(Tok.getLocation(), diag::err_expected_less_after) << "template"; + // return true; + // } + Token peekTok = PP.LookAhead(lookAheadOffset); + if (peekTok.is(tok::less)) { + lookAheadOffset += 1; + LAngleLoc = peekTok.getLocation(); + } + else { + Diag(peekTok.getLocation(), diag::err_expected_less_after) << "template"; + return true; + } + peekTok = PP.LookAhead(lookAheadOffset); + + // Try to parse the template parameter list. + bool Failed = false; + // FIXME: Missing greatergreatergreater support. + // if (!Tok.is(tok::greater) && !Tok.is(tok::greatergreater)) { + // TemplateScopes.Enter(Scope::TemplateParamScope); + // Failed = ParseTemplateParameterList(Depth, TemplateParams); + // } + if (!peekTok.is(tok::greater)) { + TemplateScopes.Enter(Scope::TemplateParamScope); + Failed = ParseBSCTemplateParameterList(Depth, TemplateParams, lookAheadOffset); + } + peekTok = PP.LookAhead(lookAheadOffset); + + // if (Tok.is(tok::greatergreater)) { + // // No diagnostic required here: a template-parameter-list can only be + // // followed by a declaration or, for a template template parameter, the + // // 'class' keyword. Therefore, the second '>' will be diagnosed later. + // // This matters for elegant diagnosis of: + // // template> struct S; + // Tok.setKind(tok::greater); + // RAngleLoc = Tok.getLocation(); + // Tok.setLocation(Tok.getLocation().getLocWithOffset(1)); + // } else if (!TryConsumeToken(tok::greater, RAngleLoc) && Failed) { + // Diag(Tok.getLocation(), diag::err_expected) << tok::greater; + // return true; + // } + + if (peekTok.getKind() == tok::greater) { + lookAheadOffset += 1; + RAngleLoc = peekTok.getLocation(); + } else { + if (Failed) { + Diag(peekTok.getLocation(), diag::err_expected) << tok::greater; + return true; + } + } + + return false; +} + + /// ParseTemplateParameterList - Parse a template parameter list. If /// the parsing fails badly (i.e., closing bracket was left out), this /// will try to put the token stream in a reasonable position (closing @@ -511,6 +663,54 @@ Parser::ParseTemplateParameterList(const unsigned Depth, return true; } +// ParseBSCTemplateParameterList - rewrite ParseTemplateParameterList, for cross-order BSC syntax, use Peeking +bool +Parser::ParseBSCTemplateParameterList(const unsigned Depth, + SmallVectorImpl &TemplateParams, + int &lookAheadOffset) { + Token peekTok = PP.LookAhead(lookAheadOffset); + while (1) { + + // if (NamedDecl *TmpParam + // = ParseTemplateParameter(Depth, TemplateParams.size())) { + if (NamedDecl *TmpParam + = ParseBSCTypeParameter(Depth, TemplateParams.size(), lookAheadOffset)) { + TemplateParams.push_back(TmpParam); + } else { + // If we failed to parse a template parameter, skip until we find + // a comma or closing brace. + // SkipUntil(tok::comma, tok::greater, tok::greatergreater, + // StopAtSemi | StopBeforeMatch); + SkipUntil(tok::comma, tok::greater, // FIXME: logic error + StopAtSemi | StopBeforeMatch); + } + peekTok = PP.LookAhead(lookAheadOffset); + + // Did we find a comma or the end of the template parameter list? + if (peekTok.is(tok::comma)) { + // ConsumeToken(); + lookAheadOffset += 1; + peekTok = PP.LookAhead(lookAheadOffset); + // } else if (peekTok.isOneOf(tok::greater, tok::greatergreater)) { + } else if (peekTok.is(tok::greater)) { + // Don't consume this... that's done by template parser. + break; + } else { + // Somebody probably forgot to close the template. Skip ahead and + // try to get out of the expression. This error is currently + // subsumed by whatever goes on in ParseTemplateParameter. + // Diag(Tok.getLocation(), diag::err_expected_comma_greater); + // SkipUntil(tok::comma, tok::greater, tok::greatergreater, + // StopAtSemi | StopBeforeMatch); + Diag(peekTok.getLocation(), diag::err_expected_comma_greater); + SkipUntil(tok::comma, tok::greater, + StopAtSemi | StopBeforeMatch); + return false; + } + } + return true; +} + /// Determine whether the parser is at the start of a template /// type parameter. Parser::TPResult Parser::isStartOfTemplateTypeParameter() { @@ -629,7 +829,7 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { Tok.getEndLoc()), "typename"); - Tok.setKind(tok::kw_typename); + Tok.setKind(tok::kw_typename); // unkown manipulation, rename "typedef" as "typename" } return ParseTypeParameter(Depth, Position); @@ -661,6 +861,8 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { llvm_unreachable("template param classification can't be ambiguous"); } + // Call upper layer method recursively to parse nested template param list + // template > if (Tok.is(tok::kw_template)) return ParseTemplateTemplateParameter(Depth, Position); @@ -840,6 +1042,106 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { return NewDecl; } + +// ParseBSCTypeParameter - rewrite ParseTypeParameter for cross-order BSC syntax, use Peeking +NamedDecl *Parser::ParseBSCTypeParameter(unsigned Depth, unsigned Position, int &lookAheadOffset) { + // Check Tok location + Token peekTok = PP.LookAhead(lookAheadOffset); + bool isBSCTemplateTypeParameter = getLangOpts().BSC; // TODO: fix the cond + //bool isBSCTemplateTypeParameter = getLangOpts().BSC && (peekTok.getKind() == tok::identifier); + assert(isBSCTemplateTypeParameter && "A type-parameter starts with 'class', 'typename' or a type-constraint"); + + CXXScopeSpec TypeConstraintSS; + TemplateIdAnnotation *TypeConstraint = nullptr; + bool TypenameKeyword = false; + SourceLocation KeyLoc; + ParseOptionalCXXScopeSpecifier(TypeConstraintSS, /*ObjectType=*/nullptr, + /*ObjectHadErrors=*/false, + /*EnteringContext*/ false); + if (peekTok.is(tok::annot_template_id)) { + // Consume the 'type-constraint'. + TypeConstraint = + static_cast(peekTok.getAnnotationValue()); + assert(TypeConstraint->Kind == TNK_Concept_template && + "stray non-concept template-id annotation"); + // KeyLoc = ConsumeAnnotationToken(); // no annot_template_id in BSC, KeyLoc remain at init status + } else { + assert(TypeConstraintSS.isEmpty() && + "expected type constraint after scope specifier"); + + // Consume the 'class' or 'typename' keyword. + TypenameKeyword = false; + // KeyLoc = ConsumeToken(); // no typename in BSC, KeyLoc remain at init status + } + + // Grab the ellipsis (if given). + SourceLocation EllipsisLoc; + if (peekTok.is(tok::ellipsis)) { + EllipsisLoc = peekTok.getLocation(); + lookAheadOffset += 1; + peekTok = PP.LookAhead(lookAheadOffset); + Diag(EllipsisLoc, + getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_variadic_templates + : diag::ext_variadic_templates); + } + + // Grab the template parameter name (if given) + SourceLocation NameLoc = peekTok.getLocation(); + IdentifierInfo *ParamName = nullptr; + if (peekTok.is(tok::identifier)) { + ParamName = peekTok.getIdentifierInfo(); // unknown manipulation, parsing T token + lookAheadOffset += 1; + peekTok = PP.LookAhead(lookAheadOffset); + } else if (peekTok.isOneOf(tok::equal, tok::comma, tok::greater, + tok::greatergreater)) { + // Unnamed template parameter. Don't have to do anything here, just + // don't consume this token. + } else { + Diag(peekTok.getLocation(), diag::err_expected) << tok::identifier; + return nullptr; + } + + // Recover from misplaced ellipsis. + bool AlreadyHasEllipsis = EllipsisLoc.isValid(); + if (PP.LookAhead(lookAheadOffset).is(tok::ellipsis)) { + EllipsisLoc = peekTok.getLocation(); + lookAheadOffset += 1; + peekTok = PP.LookAhead(lookAheadOffset); + DiagnoseMisplacedEllipsis(EllipsisLoc, NameLoc, AlreadyHasEllipsis, true); + } + + // Grab a default argument (if available). + // Per C++0x [basic.scope.pdecl]p9, we parse the default argument before + // we introduce the type parameter into the local scope. + SourceLocation EqualLoc; + ParsedType DefaultArg; + if (peekTok.is(tok::equal)) { + EqualLoc = peekTok.getLocation(); + lookAheadOffset += 1; + peekTok = PP.LookAhead(lookAheadOffset); + DefaultArg = + ParseTypeName(/*Range=*/nullptr, DeclaratorContext::TemplateTypeArg) + .get(); + } + + NamedDecl *NewDecl = Actions.ActOnTypeParameter(getCurScope(), + TypenameKeyword, EllipsisLoc, + KeyLoc, ParamName, NameLoc, + Depth, Position, EqualLoc, + DefaultArg, + TypeConstraint != nullptr); + + if (TypeConstraint) { + Actions.ActOnTypeConstraint(TypeConstraintSS, TypeConstraint, + cast(NewDecl), + EllipsisLoc); + } + + return NewDecl; +} + + /// ParseTemplateTemplateParameter - Handle the parsing of template /// template parameters. /// @@ -1228,6 +1530,8 @@ Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken, if (!Tok.isOneOf(tok::greater, tok::greatergreater, tok::greatergreatergreater, tok::greaterequal, tok::greatergreaterequal)) + // BSC Mark: Template arguments will be parsed at here. + // Pay attention to this API if we want to figure out how template arguements being parsed. Invalid = ParseTemplateArgumentList(TemplateArgs); if (Invalid) { @@ -1292,7 +1596,8 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, UnqualifiedId &TemplateName, bool AllowTypeAnnotation, bool TypeConstraint) { - assert(getLangOpts().CPlusPlus && "Can only annotate template-ids in C++"); + assert((getLangOpts().CPlusPlus || getLangOpts().BSC) + && "Can only annotate template-ids in C++"); assert((Tok.is(tok::less) || TypeConstraint) && "Parser isn't at the beginning of a template-id"); assert(!(TypeConstraint && AllowTypeAnnotation) && "type-constraint can't be " @@ -1309,6 +1614,11 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, TemplateArgList TemplateArgs; bool ArgsInvalid = false; if (!TypeConstraint || Tok.is(tok::less)) { + // BSC Mark: The template args will be parsed at here. + // Pay attention to this API if we want to figure out how template arguements being parsed. + // @Code: + // int res = max(a, b); + // ^^^^^^^^^^^^ <-these are template args ArgsInvalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc, TemplateArgs, RAngleLoc); // If we couldn't recover from invalid arguments, don't form an annotation @@ -1568,6 +1878,8 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { ColonProtectionRAIIObject ColonProtection(*this, false); do { + // BSC Mark: Template arguments will be parsed at here. + // Pay attention to this API if we want to figure out how template arguements being parsed. ParsedTemplateArgument Arg = ParseTemplateArgument(); SourceLocation EllipsisLoc; if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) @@ -1577,7 +1889,7 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { return true; // Save this template argument. - TemplateArgs.push_back(Arg); + TemplateArgs.push_back(Arg); // ex: Arg is 'int' in S // If the next token is a comma, consume it and keep reading // arguments. diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 3bf2bc455bfe84f956a189027219c9f741668d46..381cfb2e50f8829be757ed0c7d22cc4667756a34 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1106,6 +1106,75 @@ bool Parser::isTentativelyDeclared(IdentifierInfo *II) { != TentativelyDeclaredIdentifiers.end(); } +bool Parser::isBSCTemplateDecl(Token tok) { + /* + check structure in BSC syntax: + "T Foo(T a) {..}" or + "struct S {..};" + */ + // 1. check language + if (!getLangOpts().BSC) + return false; + // 2. check "Foo<>" structure + // ^^^^ + int MaxLessTokenLookAheadOffset = 6; // tok::less must appear with in 6 more token: "static inline unsigned long long Foo<" + int LessOffset = 0; + bool FoundLess = false; + Token prevTok = tok; + Token tmpTok = PP.LookAhead(LessOffset); + // FIXME: below for-loop not verified + for (LessOffset = 1; LessOffset <= MaxLessTokenLookAheadOffset && !PP.LookAhead(LessOffset).is(tok::eof); LessOffset++) { + if (tmpTok.is(tok::l_paren) || tmpTok.is(tok::l_brace) || tmpTok.is(tok::equal)) // "<>" must appear neighboring with function/struct identtifier + return false; + if (tmpTok.is(tok::less) && prevTok.is(tok::identifier)) { + FoundLess = true; + break; // when ">" missing, leave tis diagnose work in deeper api. + } + prevTok = tmpTok; + tmpTok = PP.LookAhead(LessOffset); + } + if (!FoundLess) + return false; + // 3. check "<> {}" structure in struct declaration + // ^^^ + int LBraceOffset = 1; + tmpTok = PP.LookAhead(LessOffset + LBraceOffset); + for (; !tmpTok.is(tok::eof); LBraceOffset++) { // check "Foo<>" structure + tmpTok = PP.LookAhead(LessOffset + LBraceOffset); + if (tmpTok.is(tok::l_paren)) // might be function declaration, skip current check + break; + if (tmpTok.is(tok::semi) || tmpTok.is(tok::equal)) // no "{" in current sentence + return false; + if (tmpTok.is(tok::l_brace) || tmpTok.is(tok::r_brace)) { // l_brace could missing, pass this for latter diagnose + return true; + } + } + // 4. check "<>(..) {}" structure in function declaration + // ^^ ^^^ + int LParenOffset = 1; + tmpTok = PP.LookAhead(LessOffset + LParenOffset); + for (; !tmpTok.is(tok::eof); LParenOffset++) { // check "Foo<>" structure + tmpTok = PP.LookAhead(LessOffset + LParenOffset); + if (tmpTok.is(tok::semi) || tmpTok.is(tok::equal)) // no "{" in current sentence + return false; + if (tmpTok.is(tok::l_paren)) { + break; // when ")" missing, leave tis diagnose work in deeper api. + } + } + LBraceOffset = 1; + tmpTok = PP.LookAhead(LessOffset + LParenOffset + LBraceOffset); + for (; !tmpTok.is(tok::eof); LBraceOffset++) { // check "Foo<>" structure + tmpTok = PP.LookAhead(LessOffset + LParenOffset + LBraceOffset); + if (tmpTok.is(tok::semi) || tmpTok.is(tok::equal)) // no "{" in current sentence + return false; + if (tmpTok.is(tok::l_brace) || tmpTok.is(tok::r_brace)) { // l_brace could missing, pass this for latter diagnose + return true; + } + } + + return false; +} + namespace { class TentativeParseCCC final : public CorrectionCandidateCallback { public: diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 815d078f0c79371e84e7f8e41c261036912f386c..3feda7af91d5c039349babb01f5e07c086ba0058 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -23,7 +23,6 @@ #include "llvm/Support/Path.h" using namespace clang; - namespace { /// A comment handler that passes comments found by the preprocessor /// to the parser action. @@ -923,6 +922,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::kw__Static_assert: // A function definition cannot start with any of these keywords. { + // entrance of parsing template function parameter list “template ” SourceLocation DeclEnd; return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs); } @@ -981,15 +981,26 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::kw_module: Diag(Tok, diag::err_unexpected_module_decl); SkipUntil(tok::semi); - return nullptr; - + return nullptr; default: dont_know: + // parse BSC template declaration + // TODO: change if entrance condition, abandon isBSCTemplateDecl() + if (isBSCTemplateDecl(Tok)) { + // parsing function (enter next level of parsing function) + SourceLocation DeclEnd; + return ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs); + break; + } + + if (Tok.isEditorPlaceholder()) { ConsumeToken(); return nullptr; } // We can't tell whether this is a function-definition or declaration yet. + // Entrance of parsing template function declaration “T max(T a, T b)” + // and function declaration “int max(int a, int b)” return ParseDeclarationOrFunctionDefinition(attrs, DS); } @@ -1651,7 +1662,11 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) { const bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope); CXXScopeSpec SS; - if (getLangOpts().CPlusPlus && + // BSC Mark: Add BSC language judgement, when instantiates BSC template + // function without LHS and "=", we need enter this. + // @Code + // int main(){ foo(1, 2); } + if ((getLangOpts().CPlusPlus || getLangOpts().BSC) && ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, /*ObjectHadErrors=*/false, EnteringContext)) @@ -1960,7 +1975,10 @@ bool Parser::TryAnnotateTypeOrScopeToken() { bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope); CXXScopeSpec SS; - if (getLangOpts().CPlusPlus) + // BSC Mark: Add BSC language judgement. + // This will help us parse the instantiation + // part of BSC template situation. + if (getLangOpts().CPlusPlus || getLangOpts().BSC) if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, /*ObjectHadErrors=*/false, /*EnteringContext*/ false)) @@ -2087,8 +2105,8 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS, /// Note that this routine emits an error if you call it with ::new or ::delete /// as the current tokens, so only call it in contexts where these are invalid. bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { - assert(getLangOpts().CPlusPlus && - "Call sites of this function should be guarded by checking for C++"); + assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && + "Call sites of this function should be guarded by checking for C++ and BSC"); assert(MightBeCXXScopeToken() && "Cannot be a type or scope token!"); CXXScopeSpec SS; diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 671820afd48559e84ca822cea11d5327e5ba1b9f..0661a258e7f8057cd9ca90142c96aafcf05cb79e 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -2690,7 +2690,7 @@ static void DiagnoseBadFunctionCast(Sema &Self, const ExprResult &SrcExpr, /// Check the semantics of a C-style cast operation, in C. void CastOperation::CheckCStyleCast() { - assert(!Self.getLangOpts().CPlusPlus); + assert(!Self.getLangOpts().CPlusPlus); // BSC Mark: BSC C-Style cast check should enter here. // C-style casts can resolve __unknown_any types. if (claimPlaceholder(BuiltinType::UnknownAny)) { @@ -3083,9 +3083,17 @@ ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo, Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange(); Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getEndLoc()); - Op.CheckCXXCStyleCast(/*FunctionalCast=*/true, /*ListInit=*/false); - if (Op.SrcExpr.isInvalid()) - return ExprError(); + // BSC Mark: try to use C-Style cast check for BSC generic. + if (getLangOpts().BSC){ + Op.CheckCStyleCast(); + if (Op.SrcExpr.isInvalid()){ + return ExprError(); + } + } else { + Op.CheckCXXCStyleCast(/*FunctionalCast=*/true, /*ListInit=*/false); + if (Op.SrcExpr.isInvalid()) + return ExprError(); + } auto *SubExpr = Op.SrcExpr.get(); if (auto *BindExpr = dyn_cast(SubExpr)) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index dc80bde5f6381434af97a8b508dce9f566a139a3..44c1f80f16af8b66ee5188bc7984fb5316396fe8 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -909,7 +909,7 @@ Corrected: if (SS.isEmpty() && NextToken.is(tok::l_paren)) { // In C++, this is an ADL-only call. // FIXME: Reference? - if (getLangOpts().CPlusPlus) + if (getLangOpts().CPlusPlus || getLangOpts().BSC) // BSC Mark: key of check undefined function name. return NameClassification::UndeclaredNonType(); // C90 6.3.2.2: @@ -1201,7 +1201,7 @@ Corrected: ExprResult Sema::ActOnNameClassifiedAsUndeclaredNonType(IdentifierInfo *Name, SourceLocation NameLoc) { - assert(getLangOpts().CPlusPlus && "ADL-only call in C?"); + assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && "ADL-only call in C?"); // BSC Mark: key of check undefined function name. CXXScopeSpec SS; LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true); @@ -4571,7 +4571,7 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, DS.getTypeSpecType() == DeclSpec::TST_interface || DS.getTypeSpecType() == DeclSpec::TST_union || DS.getTypeSpecType() == DeclSpec::TST_enum) { - TagD = DS.getRepAsDecl(); + TagD = DS.getRepAsDecl(); // ClassTemplateDecl: struct S {T a}; if (!TagD) // We probably had an error return nullptr; @@ -4582,7 +4582,7 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, if (isa(TagD)) Tag = cast(TagD); else if (ClassTemplateDecl *CTD = dyn_cast(TagD)) - Tag = CTD->getTemplatedDecl(); + Tag = CTD->getTemplatedDecl(); // RecordDecl: struct S{T a;}; } if (Tag) { @@ -4631,7 +4631,7 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, return ActOnFriendTypeDecl(S, DS, TemplateParams); } - const CXXScopeSpec &SS = DS.getTypeSpecScope(); + const CXXScopeSpec &SS = DS.getTypeSpecScope(); // what happens to BSC? We dont have the CXXScopeSpec. bool IsExplicitSpecialization = !TemplateParams.empty() && TemplateParams.back()->size() == 0; if (Tag && SS.isNotEmpty() && !Tag->isCompleteDefinition() && @@ -9288,6 +9288,163 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, FPT->getExtProtoInfo().withExceptionSpec(EST_BasicNoexcept))); } + // BSC Mark: This is for BSC template case. + if (getLangOpts().BSC) { + bool isInline = D.getDeclSpec().isInlineSpecified(); + bool isVirtual = D.getDeclSpec().isVirtualSpecified(); + bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier(); + isFriend = D.getDeclSpec().isFriendSpecified(); + if (isFriend && !isInline && D.isFunctionDefinition()) { + // C++ [class.friend]p5 + // A function can be defined in a friend declaration of a + // class . . . . Such a function is implicitly inline. + NewFD->setImplicitlyInline(); + } + + // If this is a method defined in an __interface, and is not a constructor + // or an overloaded operator, then set the pure flag (isVirtual will already + // return true). + if (const CXXRecordDecl *Parent = + dyn_cast(NewFD->getDeclContext())) { + if (Parent->isInterface() && cast(NewFD)->isUserProvided()) + NewFD->setPure(true); + + // C++ [class.union]p2 + // A union can have member functions, but not virtual functions. + if (isVirtual && Parent->isUnion()) + Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_in_union); + } + + SetNestedNameSpecifier(*this, NewFD, D); + isMemberSpecialization = false; + isFunctionTemplateSpecialization = false; + if (D.isInvalidType()) + NewFD->setInvalidDecl(); + + // Match up the template parameter lists with the scope specifier, then + // determine whether we have a template or a template specialization. + bool Invalid = false; + TemplateParameterList *TemplateParams = + MatchTemplateParametersToScopeSpecifier( + D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(), + D.getCXXScopeSpec(), + D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId + ? D.getName().TemplateId + : nullptr, + TemplateParamLists, isFriend, isMemberSpecialization, + Invalid); + if (TemplateParams) { + // Check that we can declare a template here. + if (CheckTemplateDeclScope(S, TemplateParams)) + NewFD->setInvalidDecl(); + + if (TemplateParams->size() > 0) { + // This is a function template + + // A destructor cannot be a template. + if (Name.getNameKind() == DeclarationName::CXXDestructorName) { + Diag(NewFD->getLocation(), diag::err_destructor_template); + NewFD->setInvalidDecl(); + } + + // If we're adding a template to a dependent context, we may need to + // rebuilding some of the types used within the template parameter list, + // now that we know what the current instantiation is. + if (DC->isDependentContext()) { + ContextRAII SavedContext(*this, DC); + if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams)) + Invalid = true; + } + + FunctionTemplate = FunctionTemplateDecl::Create(Context, DC, + NewFD->getLocation(), + Name, TemplateParams, + NewFD); + FunctionTemplate->setLexicalDeclContext(CurContext); + NewFD->setDescribedFunctionTemplate(FunctionTemplate); + + // For source fidelity, store the other template param lists. + if (TemplateParamLists.size() > 1) { + NewFD->setTemplateParameterListsInfo(Context, + ArrayRef(TemplateParamLists) + .drop_back(1)); + } + } else { + // This is a function template specialization. + isFunctionTemplateSpecialization = true; + // For source fidelity, store all the template param lists. + if (TemplateParamLists.size() > 0) + NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists); + + // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);". + if (isFriend) { + // We want to remove the "template<>", found here. + SourceRange RemoveRange = TemplateParams->getSourceRange(); + + // If we remove the template<> and the name is not a + // template-id, we're actually silently creating a problem: + // the friend declaration will refer to an untemplated decl, + // and clearly the user wants a template specialization. So + // we need to insert '<>' after the name. + SourceLocation InsertLoc; + if (D.getName().getKind() != UnqualifiedIdKind::IK_TemplateId) { + InsertLoc = D.getName().getSourceRange().getEnd(); + InsertLoc = getLocForEndOfToken(InsertLoc); + } + + Diag(D.getIdentifierLoc(), diag::err_template_spec_decl_friend) + << Name << RemoveRange + << FixItHint::CreateRemoval(RemoveRange) + << FixItHint::CreateInsertion(InsertLoc, "<>"); + } + } + } else { + // Check that we can declare a template here. + if (!TemplateParamLists.empty() && isMemberSpecialization && + CheckTemplateDeclScope(S, TemplateParamLists.back())) + NewFD->setInvalidDecl(); + + // All template param lists were matched against the scope specifier: + // this is NOT (an explicit specialization of) a template. + if (TemplateParamLists.size() > 0) + // For source fidelity, store all the template param lists. + NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists); + } + + if (Invalid) { + NewFD->setInvalidDecl(); + if (FunctionTemplate) + FunctionTemplate->setInvalidDecl(); + } + + // If a function is defined as defaulted or deleted, mark it as such now. + // We'll do the relevant checks on defaulted / deleted functions later. + switch (D.getFunctionDefinitionKind()) { + case FunctionDefinitionKind::Declaration: + case FunctionDefinitionKind::Definition: + break; + + case FunctionDefinitionKind::Defaulted: + NewFD->setDefaulted(); + break; + + case FunctionDefinitionKind::Deleted: + NewFD->setDeletedAsWritten(); + break; + } + + // C++11 [except.spec]p15: + // A deallocation function with no exception-specification is treated + // as if it were specified with noexcept(true). + const FunctionProtoType *FPT = R->getAs(); + if ((Name.getCXXOverloadedOperator() == OO_Delete || + Name.getCXXOverloadedOperator() == OO_Array_Delete) && + getLangOpts().CPlusPlus11 && FPT && !FPT->hasExceptionSpec()) + NewFD->setType(Context.getFunctionType( + FPT->getReturnType(), FPT->getParamTypes(), + FPT->getExtProtoInfo().withExceptionSpec(EST_BasicNoexcept))); + } + // Filter out previous declarations that don't match the scope. FilterLookupForScope(Previous, OriginalDC, S, shouldConsiderLinkage(NewFD), D.getCXXScopeSpec().isNotEmpty() || @@ -9491,11 +9648,31 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } - if (NewFD->getReturnType().hasNonTrivialToPrimitiveDestructCUnion() || - NewFD->getReturnType().hasNonTrivialToPrimitiveCopyCUnion()) - checkNonTrivialCUnion(NewFD->getReturnType(), - NewFD->getReturnTypeSourceRange().getBegin(), - NTCUC_FunctionReturn, NTCUK_Destruct|NTCUK_Copy); + if (NewFD->getReturnType().hasNonTrivialToPrimitiveDestructCUnion() || + NewFD->getReturnType().hasNonTrivialToPrimitiveCopyCUnion()) + checkNonTrivialCUnion(NewFD->getReturnType(), + NewFD->getReturnTypeSourceRange().getBegin(), + NTCUC_FunctionReturn, NTCUK_Destruct|NTCUK_Copy); + + // BSC Mark: We need this API for BSC template situation. + // If we have a function template, check the template parameter + // list. This will check and merge default template arguments. + if (FunctionTemplate) { + FunctionTemplateDecl *PrevTemplate = + FunctionTemplate->getPreviousDecl(); + CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(), + PrevTemplate ? PrevTemplate->getTemplateParameters() + : nullptr, + D.getDeclSpec().isFriendSpecified() + ? (D.isFunctionDefinition() + ? TPC_FriendFunctionTemplateDefinition + : TPC_FriendFunctionTemplate) + : (D.getCXXScopeSpec().isSet() && + DC && DC->isRecord() && + DC->isDependentContext()) + ? TPC_ClassTemplateMember + : TPC_FunctionTemplate); + } } else { // C++11 [replacement.functions]p3: // The program's definitions shall not be specified as inline. @@ -9893,6 +10070,16 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, CompleteMemberSpecialization(NewFD, Previous); } + // BSC Mark: This is for BSC template case. + // This can return a 'FunctionTemplateDecl' for the AST Context. + if (getLangOpts().BSC) { + if (FunctionTemplate) { + if (NewFD->isInvalidDecl()) + FunctionTemplate->setInvalidDecl(); + return FunctionTemplate; + } + } + for (const ParmVarDecl *Param : NewFD->parameters()) { QualType PT = Param->getType(); @@ -15465,7 +15652,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, return nullptr; OwnedDecl = false; - DeclResult Result = CheckClassTemplate( + DeclResult Result = CheckClassTemplate( // for 'struct S' it will enter here too. S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attrs, TemplateParams, AS, ModulePrivateLoc, /*FriendLoc*/ SourceLocation(), TemplateParameterLists.size() - 1, @@ -15829,7 +16016,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // technically forbidden by the current standard but which is // okay according to the likely resolution of an open issue; // see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#407 - if (getLangOpts().CPlusPlus) { + if (getLangOpts().CPlusPlus || getLangOpts().BSC) { if (TypedefNameDecl *TD = dyn_cast(PrevDecl)) { if (const TagType *TT = TD->getUnderlyingType()->getAs()) { TagDecl *Tag = TT->getDecl(); @@ -17483,9 +17670,13 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, } else { ++NonBitFields; QualType FieldType = I->getType(); - if (FieldType->isIncompleteType() || - !Context.getTypeSizeInChars(FieldType).isZero()) + if (getLangOpts().BSC) { ZeroSize = false; + } else { + if (FieldType->isIncompleteType() || + !Context.getTypeSizeInChars(FieldType).isZero()) + ZeroSize = false; + } } } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 4dce16017717a0a306be0212782ec078480b3a64..7bb93de8556affb11e03c7c959583e8f0c0bfa59 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6490,6 +6490,25 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, } } + // BSC Mark: This branch is for when attempting to parse a function-call + // in the body of template function. Such as: + // @Code: + // T1 Misc(T1 a, T2 b) + // { + // a.foo(); + // } + if (getLangOpts().BSC) { + // Determine whether this is a dependent call inside a C++ template, + // in which case we won't do any semantic analysis now. + if (Fn->isTypeDependent() || Expr::hasAnyTypeDependentArguments(ArgExprs)) { + tryImplicitlyCaptureThisIfImplicitMemberFunctionAccessWithDependentArgs( + *this, dyn_cast(Fn->IgnoreParens()), + Fn->getBeginLoc()); + return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy, + VK_RValue, RParenLoc, CurFPFeatureOverrides()); + } + } + // Check for overloaded calls. This can happen even in C due to extensions. if (Fn->getType() == Context.OverloadTy) { OverloadExpr::FindResult find = OverloadExpr::find(Fn); @@ -8219,6 +8238,13 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // C++ is sufficiently different to merit its own checker. if (getLangOpts().CPlusPlus) return CXXCheckConditionalOperands(Cond, LHS, RHS, VK, OK, QuestionLoc); + + // BSC Mark: We do this for BSC template situation. + // This avoids errors during the comparison phase. + if (getLangOpts().BSC && + (Cond.get()->isTypeDependent() || LHS.get()->isTypeDependent() || + RHS.get()->isTypeDependent())) + return CXXCheckConditionalOperands(Cond, LHS, RHS, VK, OK, QuestionLoc); VK = VK_RValue; OK = OK_Ordinary; @@ -14558,6 +14584,21 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); } + // BSC Mark: This is for BSC template situation. + // API "isTypeDependent()" only deal with template situation. + if (getLangOpts().BSC) { + // If either expression is type-dependent, always build an + // overloaded op. + if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent()) + return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); + + // Otherwise, build an overloaded op if either expression has an + // overloadable type. + if (LHSExpr->getType()->isOverloadableType() || + RHSExpr->getType()->isOverloadableType()) + return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); + } + if (getLangOpts().RecoveryAST && (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent())) { assert(!getLangOpts().CPlusPlus); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index f9b5e7dc2a6c899594a3803824a9340ded35b8b8..9bf8318d2f70d51f976d6aedd12eea3d6b663fbb 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -2826,6 +2826,10 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { // Its associated namespaces are the innermost enclosing // namespaces of its associated classes. case Type::Record: { + // BSC Mark: try to avoid cast. + if(Result.S.getLangOpts().BSC){ + break; + } CXXRecordDecl *Class = cast(cast(T)->getDecl()); addAssociatedClassesAndNamespaces(Result, Class); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 7fe7466725fa14ae254ceac69adef4366a8f302a..ca41b550e8f9673aa98d86f70944a513d6255aae 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -8040,22 +8040,27 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, if (!SemaRef.isCompleteType(Loc, Ty)) return; - CXXRecordDecl *ClassDecl = cast(TyRec->getDecl()); - for (NamedDecl *D : ClassDecl->getVisibleConversionFunctions()) { - if (isa(D)) - D = cast(D)->getTargetDecl(); - - // Skip conversion function templates; they don't tell us anything - // about which builtin types we can convert to. - if (isa(D)) - continue; + if (SemaRef.getLangOpts().BSC) { + // BSC Mark: Don`t do anything here to avoid cast. + } else { + CXXRecordDecl *ClassDecl = cast(TyRec->getDecl()); + for (NamedDecl *D : ClassDecl->getVisibleConversionFunctions()) { + if (isa(D)) + D = cast(D)->getTargetDecl(); - CXXConversionDecl *Conv = cast(D); - if (AllowExplicitConversions || !Conv->isExplicit()) { - AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false, - VisibleQuals); + // Skip conversion function templates; they don't tell us anything + // about which builtin types we can convert to. + if (isa(D)) + continue; + + CXXConversionDecl *Conv = cast(D); + if (AllowExplicitConversions || !Conv->isExplicit()) { + AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false, + VisibleQuals); + } } } + } } /// Helper function for adjusting address spaces for the pointer or reference @@ -8109,37 +8114,42 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { return VRQuals; } - CXXRecordDecl *ClassDecl = cast(TyRec->getDecl()); - if (!ClassDecl->hasDefinition()) - return VRQuals; + if(Context.getLangOpts().BSC) { + // BSC Mark: Don`t do anything here to avoid cast. + } else { + CXXRecordDecl *ClassDecl = cast(TyRec->getDecl()); + if (!ClassDecl->hasDefinition()) + return VRQuals; - for (NamedDecl *D : ClassDecl->getVisibleConversionFunctions()) { - if (isa(D)) - D = cast(D)->getTargetDecl(); - if (CXXConversionDecl *Conv = dyn_cast(D)) { - QualType CanTy = Context.getCanonicalType(Conv->getConversionType()); - if (const ReferenceType *ResTypeRef = CanTy->getAs()) - CanTy = ResTypeRef->getPointeeType(); - // Need to go down the pointer/mempointer chain and add qualifiers - // as see them. - bool done = false; - while (!done) { - if (CanTy.isRestrictQualified()) - VRQuals.addRestrict(); - if (const PointerType *ResTypePtr = CanTy->getAs()) - CanTy = ResTypePtr->getPointeeType(); - else if (const MemberPointerType *ResTypeMPtr = - CanTy->getAs()) - CanTy = ResTypeMPtr->getPointeeType(); - else - done = true; - if (CanTy.isVolatileQualified()) - VRQuals.addVolatile(); - if (VRQuals.hasRestrict() && VRQuals.hasVolatile()) - return VRQuals; + for (NamedDecl *D : ClassDecl->getVisibleConversionFunctions()) { + if (isa(D)) + D = cast(D)->getTargetDecl(); + if (CXXConversionDecl *Conv = dyn_cast(D)) { + QualType CanTy = Context.getCanonicalType(Conv->getConversionType()); + if (const ReferenceType *ResTypeRef = CanTy->getAs()) + CanTy = ResTypeRef->getPointeeType(); + // Need to go down the pointer/mempointer chain and add qualifiers + // as see them. + bool done = false; + while (!done) { + if (CanTy.isRestrictQualified()) + VRQuals.addRestrict(); + if (const PointerType *ResTypePtr = CanTy->getAs()) + CanTy = ResTypePtr->getPointeeType(); + else if (const MemberPointerType *ResTypeMPtr = + CanTy->getAs()) + CanTy = ResTypeMPtr->getPointeeType(); + else + done = true; + if (CanTy.isVolatileQualified()) + VRQuals.addVolatile(); + if (VRQuals.hasRestrict() && VRQuals.hasVolatile()) + return VRQuals; + } } } } + return VRQuals; } @@ -12971,7 +12981,7 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn, llvm_unreachable("performing ADL for builtin"); // We don't perform ADL in C. - assert(getLangOpts().CPlusPlus && "ADL enabled in C"); + assert((getLangOpts().CPlusPlus || getLangOpts().BSC) && "ADL enabled in C"); // BSC Mark: key of check undefined function name. } #endif diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 12880b95b9c6342f4ae052dc004f49098e2b6a4f..d73254a048fced2ea7896c917121c666fdf1d50e 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -176,7 +176,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S, TemplateTy &TemplateResult, bool &MemberOfUnknownSpecialization, bool Disambiguation) { - assert(getLangOpts().CPlusPlus && "No template names in C!"); + assert((getLangOpts().CPlusPlus || getLangOpts().BSC) + && "No template names in C!"); DeclarationName TName; MemberOfUnknownSpecialization = false; @@ -1951,14 +1952,19 @@ DeclResult Sema::CheckClassTemplate( bool ShouldAddRedecl = !(TUK == TUK_Friend && CurContext->isDependentContext()); - CXXRecordDecl *NewClass = - CXXRecordDecl::Create(Context, Kind, SemanticContext, KWLoc, NameLoc, Name, - PrevClassTemplate && ShouldAddRedecl ? - PrevClassTemplate->getTemplatedDecl() : nullptr, - /*DelayTypeCreation=*/true); + RecordDecl *NewClass; + if(getLangOpts().CPlusPlus) { + NewClass = + CXXRecordDecl::Create(Context, Kind, SemanticContext, KWLoc, NameLoc, Name, + PrevClassTemplate && ShouldAddRedecl ? + PrevClassTemplate->getTemplatedDecl() : nullptr, + /*DelayTypeCreation=*/true); + } else { + NewClass = RecordDecl::Create(Context, Kind, SemanticContext, KWLoc, NameLoc, Name); + } SetNestedNameSpecifier(*this, NewClass, SS); if (NumOuterTemplateParamLists > 0) - NewClass->setTemplateParameterListsInfo( + NewClass->setTemplateParameterListsInfo( // [1]: set template parameters Context, llvm::makeArrayRef(OuterTemplateParamLists, NumOuterTemplateParamLists)); @@ -1969,7 +1975,7 @@ DeclResult Sema::CheckClassTemplate( AddMsStructLayoutForRecord(NewClass); } - ClassTemplateDecl *NewTemplate + ClassTemplateDecl *NewTemplate // [2]: ClassTemplateDecl is created = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, DeclarationName(Name), TemplateParams, NewClass); @@ -1977,16 +1983,20 @@ DeclResult Sema::CheckClassTemplate( if (ShouldAddRedecl) NewTemplate->setPreviousDecl(PrevClassTemplate); - NewClass->setDescribedClassTemplate(NewTemplate); + if (!getLangOpts().BSC) { + static_cast(NewClass)->setDescribedClassTemplate(NewTemplate); + } if (ModulePrivateLoc.isValid()) NewTemplate->setModulePrivate(); // Build the type for the class template declaration now. - QualType T = NewTemplate->getInjectedClassNameSpecialization(); - T = Context.getInjectedClassNameType(NewClass, T); - assert(T->isDependentType() && "Class template type is not dependent?"); - (void)T; + if (!getLangOpts().BSC) { + QualType T = NewTemplate->getInjectedClassNameSpecialization(); + T = Context.getInjectedClassNameType(static_cast(NewClass), T); + assert(T->isDependentType() && "Class template type is not dependent?"); + (void)T; + } // If we are providing an explicit specialization of a member that is a // class template, make a note of that. @@ -2011,7 +2021,9 @@ DeclResult Sema::CheckClassTemplate( mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl()); AddPushedVisibilityAttribute(NewClass); - inferGslOwnerPointerAttribute(NewClass); + if (!getLangOpts().BSC) { + inferGslOwnerPointerAttribute(static_cast(NewClass)); + } if (TUK != TUK_Friend) { // Per C++ [basic.scope.temp]p2, skip the template parameter scopes. diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 8bd812b39de4d32f86b547362b874432ef260693..3ba32fd9ae3c81a0f0e116f1f4d50538cfd97760 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2623,16 +2623,18 @@ namespace clang { /// \returns true if an error occurred, false otherwise. bool Sema::InstantiateClass(SourceLocation PointOfInstantiation, - CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, + RecordDecl *Instantiation, RecordDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK, bool Complain) { - CXXRecordDecl *PatternDef - = cast_or_null(Pattern->getDefinition()); - if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Instantiation, - Instantiation->getInstantiatedFromMemberClass(), - Pattern, PatternDef, TSK, Complain)) - return true; + RecordDecl *PatternDef + = cast_or_null(Pattern->getDefinition()); + if (getLangOpts().CPlusPlus) { + if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Instantiation, + (static_cast(Instantiation))->getInstantiatedFromMemberClass(), + Pattern, PatternDef, TSK, Complain)) + return true; + } llvm::TimeTraceScope TimeScope("InstantiateClass", [&]() { std::string Name; @@ -2645,12 +2647,19 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Pattern = PatternDef; // Record the point of instantiation. - if (MemberSpecializationInfo *MSInfo - = Instantiation->getMemberSpecializationInfo()) { - MSInfo->setTemplateSpecializationKind(TSK); - MSInfo->setPointOfInstantiation(PointOfInstantiation); + if (getLangOpts().CPlusPlus) { + if(MemberSpecializationInfo *MSInfo + = (static_cast(Instantiation))->getMemberSpecializationInfo()) { + MSInfo->setTemplateSpecializationKind(TSK); + MSInfo->setPointOfInstantiation(PointOfInstantiation); + } + else if (ClassTemplateSpecializationDecl *Spec + = dyn_cast(Instantiation)) { // yt: should be true for BSC + Spec->setTemplateSpecializationKind(TSK); + Spec->setPointOfInstantiation(PointOfInstantiation); + } } else if (ClassTemplateSpecializationDecl *Spec - = dyn_cast(Instantiation)) { + = dyn_cast(Instantiation)) { // yt: should be true for BSC Spec->setTemplateSpecializationKind(TSK); Spec->setPointOfInstantiation(PointOfInstantiation); } @@ -2684,7 +2693,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, InstantiateAttrs(TemplateArgs, Pattern, Instantiation); // Start the definition of this instantiation. - Instantiation->startDefinition(); + Instantiation->startDefinition(); // yt: start the instantiation! // The instantiation is visible here, even if it was first declared in an // unimported module. @@ -2694,8 +2703,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Instantiation->setTagKind(Pattern->getTagKind()); // Do substitution on the base class specifiers. - if (SubstBaseSpecifiers(Instantiation, Pattern, TemplateArgs)) - Instantiation->setInvalidDecl(); + if (getLangOpts().CPlusPlus) { + if (SubstBaseSpecifiers(static_cast(Instantiation), static_cast(Pattern), TemplateArgs)) + Instantiation->setInvalidDecl(); + } TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs); SmallVector Fields; @@ -2730,7 +2741,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, continue; } - Decl *NewMember = Instantiator.Visit(Member); + Decl *NewMember = Instantiator.Visit(Member); // yt: (1)before: Member 'T a;' (2)after: NewMember 'int a;' if (NewMember) { if (FieldDecl *Field = dyn_cast(NewMember)) { Fields.push_back(Field); @@ -2754,8 +2765,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, break; } } else if (CXXMethodDecl *MD = dyn_cast(NewMember)) { - if (MD->isConstexpr() && !MD->getFriendObjectKind() && - (MD->isVirtualAsWritten() || Instantiation->getNumBases())) + if (getLangOpts().CPlusPlus && MD->isConstexpr() && !MD->getFriendObjectKind() && + (MD->isVirtualAsWritten() || (static_cast(Instantiation))->getNumBases())) MightHaveConstexprVirtualFunctions = true; } @@ -2772,7 +2783,9 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Finish checking fields. ActOnFields(nullptr, Instantiation->getLocation(), Instantiation, Fields, SourceLocation(), SourceLocation(), ParsedAttributesView()); - CheckCompletedCXXClass(nullptr, Instantiation); + if(getLangOpts().CPlusPlus) { + CheckCompletedCXXClass(nullptr, (static_cast(Instantiation))); // FIXME: make it work for BSC RecordDecl + } // Default arguments are parsed, if not instantiated. We can go instantiate // default arg exprs for default constructors if necessary now. Unless we're @@ -2816,7 +2829,9 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, if (!Instantiation->isInvalidDecl()) { // Perform any dependent diagnostics from the pattern. - PerformDependentDiagnostics(Pattern, TemplateArgs); + if (getLangOpts().CPlusPlus) { + PerformDependentDiagnostics(Pattern, TemplateArgs); + } // Instantiate any out-of-line class template partial // specializations now. @@ -2853,11 +2868,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // of a polymorphic class template specialization. Otherwise, eagerly // instantiate only constexpr virtual functions in preparation for their use // in constant evaluation. - if (TSK == TSK_ExplicitInstantiationDefinition) - MarkVTableUsed(PointOfInstantiation, Instantiation, true); - else if (MightHaveConstexprVirtualFunctions) - MarkVirtualMembersReferenced(PointOfInstantiation, Instantiation, - /*ConstexprOnly*/ true); + if(getLangOpts().CPlusPlus) { + if (TSK == TSK_ExplicitInstantiationDefinition) + MarkVTableUsed(PointOfInstantiation, (static_cast(Instantiation)), true); + else if (MightHaveConstexprVirtualFunctions) + MarkVirtualMembersReferenced(PointOfInstantiation, static_cast(Instantiation), + /*ConstexprOnly*/ true); + } } Consumer.HandleTagDeclDefinition(Instantiation); @@ -3040,7 +3057,7 @@ bool Sema::usesPartialOrExplicitSpecialization( /// Get the instantiation pattern to use to instantiate the definition of a /// given ClassTemplateSpecializationDecl (either the pattern of the primary /// template or of a partial specialization). -static ActionResult +static ActionResult getPatternForClassTemplateSpecialization( Sema &S, SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, @@ -3157,7 +3174,7 @@ getPatternForClassTemplateSpecialization( } } - CXXRecordDecl *Pattern = nullptr; + RecordDecl *Pattern = nullptr; // yt: RecordDecl for BSC. Specialized = ClassTemplateSpec->getSpecializedTemplateOrPartial(); if (auto *PartialSpec = Specialized.dyn_cast()) { @@ -3181,7 +3198,11 @@ getPatternForClassTemplateSpecialization( Template = Template->getInstantiatedFromMemberTemplate(); } - Pattern = Template->getTemplatedDecl(); + if (S.Context.getLangOpts().BSC) { + Pattern = Template->getBSCTemplatedDecl(); + } else { + Pattern = Template->getTemplatedDecl(); + } } return Pattern; @@ -3197,7 +3218,7 @@ bool Sema::InstantiateClassTemplateSpecialization( if (ClassTemplateSpec->isInvalidDecl()) return true; - ActionResult Pattern = + ActionResult Pattern = // yt: here BSC is RecordDecl getPatternForClassTemplateSpecialization(*this, PointOfInstantiation, ClassTemplateSpec, TSK); if (!Pattern.isUsable()) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 75e8e350bd48dd209b201e03006ed34163325fb7..5a97a46ddfde17b29c5a76c3f96cc9a6a4ee9434 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8619,7 +8619,13 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, // If we have a class template specialization or a class member of a // class template specialization, or an array with known size of such, // try to instantiate it. - if (auto *RD = dyn_cast_or_null(Tag)) { + RecordDecl* RD = nullptr; + if (getLangOpts().BSC) { + RD = dyn_cast_or_null(Tag); + } else { + RD = dyn_cast_or_null(Tag); + } + if (RD) { bool Instantiated = false; bool Diagnosed = false; if (RD->isDependentContext()) { @@ -8637,15 +8643,15 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, Instantiated = true; } } else { - CXXRecordDecl *Pattern = RD->getInstantiatedFromMemberClass(); + CXXRecordDecl *Pattern = (static_cast(RD))->getInstantiatedFromMemberClass(); if (!RD->isBeingDefined() && Pattern) { - MemberSpecializationInfo *MSI = RD->getMemberSpecializationInfo(); + MemberSpecializationInfo *MSI = (static_cast(RD))->getMemberSpecializationInfo(); assert(MSI && "Missing member specialization information?"); // This record was instantiated from a class within a template. if (MSI->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) { runWithSufficientStackSpace(Loc, [&] { - Diagnosed = InstantiateClass(Loc, RD, Pattern, + Diagnosed = InstantiateClass(Loc, (static_cast(RD)), Pattern, getTemplateInstantiationArgs(RD), TSK_ImplicitInstantiation, /*Complain=*/Diagnoser); diff --git a/clang/test/BSC/Generic/Instantiation_without_LHS.cbs b/clang/test/BSC/Generic/Instantiation_without_LHS.cbs new file mode 100644 index 0000000000000000000000000000000000000000..406b7df4dc29438be0539e1799a4f385093e293b --- /dev/null +++ b/clang/test/BSC/Generic/Instantiation_without_LHS.cbs @@ -0,0 +1,36 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include + +struct A{ + int x; + float y; +}; + +struct B{ + int x; + float y; +}; + +void foo (T1 a, T2 b) { + int x1 = a.x + b.x; + printf("x1 = %d\n", x1); + float x2 = a.y + b.y; + printf("x2 = %f\n", x2); +} + +void foo2 (T1 a, T2 b) { + int x3 = a + b; + printf("x3 = %f\n", x3); +} + +int main(){ + struct A a = {.x = 2022, .y = 1.5}; + struct B b = {.x = 2023, .y = 1.6}; + foo(a, b); + foo2(1, 2); + return 0; +} + diff --git a/clang/test/BSC/Generic/bsc_generic.cbs b/clang/test/BSC/Generic/bsc_generic.cbs new file mode 100644 index 0000000000000000000000000000000000000000..1d9698d03f38b20ccfe76b62098b7cab16606d8a --- /dev/null +++ b/clang/test/BSC/Generic/bsc_generic.cbs @@ -0,0 +1,24 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include + +struct S{ + T a; +}; + +T max(T a, T b) { + return a > b ? a : b; +} + +int main() { + struct S s1 = {.a = 42}; // ClassTemplateSpecializationDecl + int a = s1.a; + printf("Generic Struct Works!\n"); + printf("a is %d\n", a); + int b = max(2023, 2022); + printf("Generic Function Works!\n"); + printf("b is %d\n", b); + return 0; +} diff --git a/clang/test/BSC/Generic/cast_in_generic_body.cbs b/clang/test/BSC/Generic/cast_in_generic_body.cbs new file mode 100644 index 0000000000000000000000000000000000000000..f5a73fb074cdc89dd79c43ae9353e31798ec2029 --- /dev/null +++ b/clang/test/BSC/Generic/cast_in_generic_body.cbs @@ -0,0 +1,17 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +int foo (T a, T b) +{ + int x = int(a) + int(b); + return x; +} + +int main () +{ + float a = 2.3; + float b = 1.1; + int res = foo(a, b); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/cast_struct_to_int.cbs b/clang/test/BSC/Generic/cast_struct_to_int.cbs new file mode 100644 index 0000000000000000000000000000000000000000..6f503faf71fb32b40ee655eac3dc7fbabba6503d --- /dev/null +++ b/clang/test/BSC/Generic/cast_struct_to_int.cbs @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -verify %s + +T1 foo (T1 a, T2 b) +{ + int x = int(b); // expected-error {{operand of type 'struct S' where arithmetic or pointer type is required}} + return x; +} + +struct S +{ + int a; +}; + +int main () +{ + float a = 2.5; + struct S s1 = {.a = 1}; + int res = foo(a, s1); // expected-note {{in instantiation of function template specialization 'foo' requested here}} + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/diagnose.cbs b/clang/test/BSC/Generic/diagnose.cbs new file mode 100644 index 0000000000000000000000000000000000000000..72995729b4e14fd5e3e8d0e1ef7257bf5c338b19 --- /dev/null +++ b/clang/test/BSC/Generic/diagnose.cbs @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -verify %s + +T foo(T a, T b { // expected-error {{expected ')'}} expected-note {{to match this '('}} + return a; +} + +int main() { + int res = foo(1, 2); + return 0; +} // expected-error {{expected ';' at end of declaration}} diff --git a/clang/test/BSC/Generic/function_call.cbs b/clang/test/BSC/Generic/function_call.cbs new file mode 100644 index 0000000000000000000000000000000000000000..26712d67df2f989208ad8d1b7bd3ee3ce2d0fdc3 --- /dev/null +++ b/clang/test/BSC/Generic/function_call.cbs @@ -0,0 +1,16 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include + +T1 FunctionCall(T1 a, T2 b) +{ + a.foo(); + b.foo(); +} + +int main() { + // Cannot combine with member function now, so we cannot have the instantiation behavior. + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/illegal_type_add.cbs b/clang/test/BSC/Generic/illegal_type_add.cbs new file mode 100644 index 0000000000000000000000000000000000000000..73c299f9d1b43f5968f54b0096c7271bcbf7248f --- /dev/null +++ b/clang/test/BSC/Generic/illegal_type_add.cbs @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -verify %s + +struct S{ + int a; +}; + +T f4(T a) { + struct S s1; + int y = 1; + T z = s1 + y; // expected-error {{invalid operands to binary expression ('struct S' and 'int')}} + return z; +} + +int main(){ + int a = 1; + int b = f4(a); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/multi_type_params.cbs b/clang/test/BSC/Generic/multi_type_params.cbs new file mode 100644 index 0000000000000000000000000000000000000000..2493aa70d42bf4efc3bba95205042f69d2a393c6 --- /dev/null +++ b/clang/test/BSC/Generic/multi_type_params.cbs @@ -0,0 +1,19 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include +T2 foo(T1 a, T2 b, T3 c) { + return b; +} + +int main() { + int f1 = foo(1, 2, 3); + float f2 = foo(1, 2.0, 3); + const char* c = "123"; + const char* f3 = foo(2, c, 3); + printf("f1 is %d\n", f1); + printf("f2 is %f\n", f2); + printf("f3 is %s\n", f3); + return 0; +} diff --git a/clang/test/BSC/Generic/return_type_int.cbs b/clang/test/BSC/Generic/return_type_int.cbs new file mode 100644 index 0000000000000000000000000000000000000000..448b8ccee79b5e54dbb91ffcca19bef554be2024 --- /dev/null +++ b/clang/test/BSC/Generic/return_type_int.cbs @@ -0,0 +1,16 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include +int bar(T1 a, T2 b) { + return 42; +} + + +int main() { + int x1 = bar(1, 2); + int x2 = bar(1.0, 2.0); + printf("%d %d\n", x1, x2); + return 0; +} diff --git a/clang/test/BSC/Generic/return_type_long_int.cbs b/clang/test/BSC/Generic/return_type_long_int.cbs new file mode 100644 index 0000000000000000000000000000000000000000..4e71a9de9e5544cd187e73099389a41fff11cfe0 --- /dev/null +++ b/clang/test/BSC/Generic/return_type_long_int.cbs @@ -0,0 +1,14 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include + +long int f2(long int x, T a) { // FIXME Ok but there is err now + return x; +} + +int main() { + float b = 1.5; + long int a = f2(a, b); +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/return_type_multi.cbs b/clang/test/BSC/Generic/return_type_multi.cbs new file mode 100644 index 0000000000000000000000000000000000000000..848ef6d8a7796f6b44180025dbdbda7aaf387684 --- /dev/null +++ b/clang/test/BSC/Generic/return_type_multi.cbs @@ -0,0 +1,26 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include + +unsigned bar(T1 a, T2 b) { + return 33; +} + +long long foo(T1 a, T2 b) { + return 44; +} + + +int main() { + unsigned x1 = bar(1, 2); + unsigned x2 = bar(1.0, 2.0); + + long long y1 = foo(1, 1.0); + long long y2 = foo(3.0, 99.0); + + printf("%uand %uand\n", x1, x2); + printf("%lld, %lld\n", y1, y2); + return 0; +} diff --git a/clang/test/BSC/Generic/return_type_multi_tok.cbs b/clang/test/BSC/Generic/return_type_multi_tok.cbs new file mode 100644 index 0000000000000000000000000000000000000000..fb6a41647e35b4b8ab73ecd3950561c5e567efdc --- /dev/null +++ b/clang/test/BSC/Generic/return_type_multi_tok.cbs @@ -0,0 +1,71 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + + +signed char Alice (T a, T b) +{ + return a > b ? a : b; +} + +unsigned char Bob (T a, T b) +{ + return 'c'; +} + +unsigned int Charlie (T a, T b) +{ + return a > b ? a : b; +} + +unsigned short Dave (T a, T b) +{ + return a > b ? a : b; +} + + +unsigned long Eve (T a, T b) +{ + return a > b ? a : b; +} + + +long double Frank (T a, T b) +{ + return 42.0; +} + + +long long Garcia (T a, T b) +{ + return a > b ? a : b; +} + + +unsigned long long Henry (T a, T b) +{ + return 42.0; +} + + +signed long long Issac (T a, T b) +{ + return 42.0; +} + + +int main () +{ + signed char alice = Alice(1, 2); + unsigned char bob = Bob(1, 2); + unsigned int charlie = Charlie(1, 2); + unsigned short dave = Dave(1, 2); + unsigned long eve = Eve(1, 2); + long double frank = Frank(1, 2); + long long garcia = Garcia(1, 2); + + unsigned long long henry = Henry(1, 2); + signed long long issac = Issac(1, 2); + + return 0; +} diff --git a/clang/test/BSC/Generic/return_type_pointer.cbs b/clang/test/BSC/Generic/return_type_pointer.cbs new file mode 100644 index 0000000000000000000000000000000000000000..83a644f23d52adf6017b7f43aece03f0d3340fc9 --- /dev/null +++ b/clang/test/BSC/Generic/return_type_pointer.cbs @@ -0,0 +1,34 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + + +#include + + +int * Foo (T a, T b) // pointer +{ + T x = a > b ? a : b; + static int res = 42; + return &res; +} + + +int * Bar (T a, T b) // array +{ + T x = a > b ? a : b; + static int array[] = {0, 1, 2}; + return array; +} + + +int main () +{ + int *res = Foo(1, 2); + printf("%d\n", *res); + + int *array = Bar(1, 2); + printf("%d %d %d\n", array[0], array[1], array[2]); + + return 0; +} diff --git a/clang/test/BSC/Generic/return_type_struct.cbs b/clang/test/BSC/Generic/return_type_struct.cbs new file mode 100644 index 0000000000000000000000000000000000000000..ce94d097bf09df76c0f706534bbbd966b0ac9685 --- /dev/null +++ b/clang/test/BSC/Generic/return_type_struct.cbs @@ -0,0 +1,28 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include + +struct Block { // MineCraft Block + char* color; + int blood; +}; + +struct Block bar(T1 a, T2 b) { + struct Block grass = {"green", 1}; + struct Block obsidian = {.color="black", .blood=100}; + struct Block oak; + oak.color = "yellow"; + oak.blood = 15; + return grass; +} + + +int main() { + struct Block br1 = bar(1, 2); + struct Block br2 = bar(1.0, 2.0); + printf("%s %d\n", br1.color, br1.blood); + printf("%s %d\n", br2.color, br2.blood); + return 0; +} diff --git a/clang/test/BSC/Generic/single_type_param.cbs b/clang/test/BSC/Generic/single_type_param.cbs new file mode 100644 index 0000000000000000000000000000000000000000..4a10ea27c2f5baf983e69839b440b7771edadc39 --- /dev/null +++ b/clang/test/BSC/Generic/single_type_param.cbs @@ -0,0 +1,23 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include + +T max(T a, T b) { + return a > b ? a : b; +} + +int main() { + int a = 10; + int b = 11; + int m1 = max(a, b); + int m2 = max(12, a); + double m3 = max(1.2, 1.3); + float m4 = max(2.12, 2.123); + printf("m1 is %d\n", m1); + printf("m2 is %d\n", m2); + printf("m3 is %f\n", m3); + printf("m4 is %f\n", m4); + return 0; +} diff --git a/clang/test/BSC/Generic/struct_template_type_struct.cbs b/clang/test/BSC/Generic/struct_template_type_struct.cbs new file mode 100644 index 0000000000000000000000000000000000000000..ebe7b74940ac71fb27a2141f773ce3c861179079 --- /dev/null +++ b/clang/test/BSC/Generic/struct_template_type_struct.cbs @@ -0,0 +1,31 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include + +struct Shape { + int width; + int hight; +}; + +struct S { + T elem; +}; + + +int main () +{ + struct Shape shape = {.width = 42, .hight = 42}; + printf("%d, %d\n", shape.width, shape.hight); + + struct S aaa = {.elem = 42}; + printf("%d\n", aaa.elem); + + struct S bbb = {.elem = shape}; + printf("%d, %d\n", bbb.elem.width, bbb.elem.hight); + + // struct S> ccc = {.elem = bbb}; + + return 0; +} diff --git a/clang/test/BSC/Generic/undefined_func_call.cbs b/clang/test/BSC/Generic/undefined_func_call.cbs new file mode 100644 index 0000000000000000000000000000000000000000..404d5482fbb03e12a840a29b4d4399337b75c976 --- /dev/null +++ b/clang/test/BSC/Generic/undefined_func_call.cbs @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -verify %s + +T1 f3(T1 a, T2 b, int c) { + T1 x1 = a + b; + foo(c); // expected-error {{use of undeclared identifier 'foo'}} + return x1; +} + +int main() { + int a = 1; + float b = 1.5; + int c = 2; + int d = f3(a, b, c); +} \ No newline at end of file diff --git a/clang/test/BSC/Generic/undefined_member_call.cbs b/clang/test/BSC/Generic/undefined_member_call.cbs new file mode 100644 index 0000000000000000000000000000000000000000..2c2b43585816dba4cce143e3785cee08110a5470 --- /dev/null +++ b/clang/test/BSC/Generic/undefined_member_call.cbs @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -verify %s + +struct S{ // expected-error {{conflicting types for 'S'}} expected-note {{while declaring the implicit copy constructor for 'S'}} expected-note {{previous definition is here}} + T a; +}; + +void test() { + struct S s1; + int a = s1.x; // expected-error {{no member named 'x' in 'struct S'}} +} \ No newline at end of file