From c9dc0a277de1100f456e88780fe797225d3cd55b Mon Sep 17 00:00:00 2001 From: zhaoxuhui Date: Mon, 20 Feb 2023 14:34:54 +0800 Subject: [PATCH 1/2] [BSC] support function pointer --- clang/include/clang/AST/Expr.h | 1 + clang/include/clang/Parse/Parser.h | 4 +- clang/include/clang/Sema/Sema.h | 6 +- clang/lib/Parse/ParseExpr.cpp | 40 +- clang/lib/Parse/ParseStmt.cpp | 2 +- clang/lib/Sema/SemaDecl.cpp | 5 +- clang/lib/Sema/SemaExpr.cpp | 21 +- clang/lib/Sema/SemaLookup.cpp | 11 +- clang/lib/Sema/SemaType.cpp | 444 ++++++++++++++++++ .../BuiltInType/int_conflict_param_type.cbs | 6 + .../BuiltInType/int_conflict_return_type.cbs | 6 + .../int_function_pointer_undeclared.cbs | 11 + .../int_instance_function_call.cbs | 11 + .../int_instance_function_pointer.cbs | 15 + .../int_instance_function_with_typedef.cbs | 16 + .../Method/Enum/enum_conflict_param_type.cbs | 11 + .../Method/Enum/enum_conflict_return_type.cbs | 11 + .../Enum/enum_function_pointer_undeclared.cbs | 16 + .../Enum/enum_instance_function_call.cbs | 17 + .../Enum/enum_instance_function_pointer.cbs | 20 + .../enum_instance_function_with_typedef.cbs | 19 + .../Struct/struct_conflict_no_param_1.cbs | 10 + .../Struct/struct_conflict_no_param_2.cbs | 8 + .../Struct/struct_conflict_param_type.cbs | 10 + .../Struct/struct_conflict_return_type.cbs | 10 + .../Struct/struct_function_undeclared.cbs | 15 + .../Struct/struct_instance_function.cbs} | 14 +- .../Struct/struct_instance_function_call.cbs | 16 + .../struct_instance_function_declaration.cbs | 18 + ...ct_instance_function_multi_declaration.cbs | 19 + .../struct_instance_function_not_found.cbs | 16 + .../struct_instance_function_pointer.cbs | 20 + .../struct_instance_function_redefinition.cbs | 19 + ...struct_instance_function_with_typedef.cbs} | 20 +- .../Union/union_conflict_param_type.cbs | 12 + .../Union/union_conflict_return_type.cbs | 12 + .../union_function_pointer_undeclared.cbs | 17 + .../Union/union_instance_function_call.cbs | 18 + .../Union/union_instance_function_pointer.cbs | 21 + .../union_instance_function_with_typedef.cbs | 20 + .../BSC/ParamCheck/this_not_first_param.cbs | 37 ++ .../ParamCheck/this_param_type_no_match.cbs | 40 ++ .../BSC/ParamCheck/this_param_with_const.cbs | 50 ++ .../ParamCheck/this_param_with_volatile.cbs | 49 ++ clang/test/BSC/pending/CallBeforeDefine.cbs | 17 - clang/test/BSC/pending/OverloadFunc.cbs | 24 - clang/test/BSC/pending/StaticMemberFunc.cbs | 20 - clang/test/BSC/pending/ThisParamCheck1.cbs | 17 - clang/test/BSC/pending/ThisParamCheck2.cbs | 21 - 49 files changed, 1127 insertions(+), 136 deletions(-) create mode 100644 clang/test/BSC/Method/BuiltInType/int_conflict_param_type.cbs create mode 100644 clang/test/BSC/Method/BuiltInType/int_conflict_return_type.cbs create mode 100644 clang/test/BSC/Method/BuiltInType/int_function_pointer_undeclared.cbs create mode 100644 clang/test/BSC/Method/BuiltInType/int_instance_function_call.cbs create mode 100644 clang/test/BSC/Method/BuiltInType/int_instance_function_pointer.cbs create mode 100644 clang/test/BSC/Method/BuiltInType/int_instance_function_with_typedef.cbs create mode 100644 clang/test/BSC/Method/Enum/enum_conflict_param_type.cbs create mode 100644 clang/test/BSC/Method/Enum/enum_conflict_return_type.cbs create mode 100644 clang/test/BSC/Method/Enum/enum_function_pointer_undeclared.cbs create mode 100644 clang/test/BSC/Method/Enum/enum_instance_function_call.cbs create mode 100644 clang/test/BSC/Method/Enum/enum_instance_function_pointer.cbs create mode 100644 clang/test/BSC/Method/Enum/enum_instance_function_with_typedef.cbs create mode 100644 clang/test/BSC/Method/Struct/struct_conflict_no_param_1.cbs create mode 100644 clang/test/BSC/Method/Struct/struct_conflict_no_param_2.cbs create mode 100644 clang/test/BSC/Method/Struct/struct_conflict_param_type.cbs create mode 100644 clang/test/BSC/Method/Struct/struct_conflict_return_type.cbs create mode 100644 clang/test/BSC/Method/Struct/struct_function_undeclared.cbs rename clang/test/BSC/{pending/InstanceMemberFunc.cbs => Method/Struct/struct_instance_function.cbs} (39%) create mode 100644 clang/test/BSC/Method/Struct/struct_instance_function_call.cbs create mode 100644 clang/test/BSC/Method/Struct/struct_instance_function_declaration.cbs create mode 100644 clang/test/BSC/Method/Struct/struct_instance_function_multi_declaration.cbs create mode 100644 clang/test/BSC/Method/Struct/struct_instance_function_not_found.cbs create mode 100644 clang/test/BSC/Method/Struct/struct_instance_function_pointer.cbs create mode 100644 clang/test/BSC/Method/Struct/struct_instance_function_redefinition.cbs rename clang/test/BSC/{pending/Typedef.cbs => Method/Struct/struct_instance_function_with_typedef.cbs} (45%) create mode 100644 clang/test/BSC/Method/Union/union_conflict_param_type.cbs create mode 100644 clang/test/BSC/Method/Union/union_conflict_return_type.cbs create mode 100644 clang/test/BSC/Method/Union/union_function_pointer_undeclared.cbs create mode 100644 clang/test/BSC/Method/Union/union_instance_function_call.cbs create mode 100644 clang/test/BSC/Method/Union/union_instance_function_pointer.cbs create mode 100644 clang/test/BSC/Method/Union/union_instance_function_with_typedef.cbs create mode 100644 clang/test/BSC/ParamCheck/this_not_first_param.cbs create mode 100644 clang/test/BSC/ParamCheck/this_param_type_no_match.cbs create mode 100644 clang/test/BSC/ParamCheck/this_param_with_const.cbs create mode 100644 clang/test/BSC/ParamCheck/this_param_with_volatile.cbs delete mode 100644 clang/test/BSC/pending/CallBeforeDefine.cbs delete mode 100644 clang/test/BSC/pending/OverloadFunc.cbs delete mode 100644 clang/test/BSC/pending/StaticMemberFunc.cbs delete mode 100644 clang/test/BSC/pending/ThisParamCheck1.cbs delete mode 100644 clang/test/BSC/pending/ThisParamCheck2.cbs diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index a44d06967431..1de83e190e41 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -138,6 +138,7 @@ protected: friend class ASTStmtReader; // Sets dependence dircetly. public: + bool IsColonColon = false; QualType getType() const { return TR; } void setType(QualType t) { // In C++, the type of an expression is always adjusted so that it diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index bcc93854e543..6a2e6bf39835 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1792,7 +1792,9 @@ private: bool &NotCastExpr, TypeCastState isTypeCast, bool isVectorLiteral = false, - bool *NotPrimaryExpression = nullptr); + bool *NotPrimaryExpression = nullptr, + QualType T = QualType(), + bool IsColonColon = false); ExprResult ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand = false, TypeCastState isTypeCast = NotTypeCast, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 7d3b1be8bbc2..c4f5319679cb 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2671,6 +2671,7 @@ public: QualType NewT, QualType OldT); void CheckMain(FunctionDecl *FD, const DeclSpec &D); void CheckMSVCRTEntryPoint(FunctionDecl *FD); + QualType GetTypeForDeclSpec(DeclSpec &BSCScopeSpec); void ConvertBSCScopeSpecToType(Declarator &D, SourceLocation Loc); Attr *getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD, bool IsDefinition); @@ -4072,7 +4073,7 @@ public: CXXScopeSpec &SS); bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, bool AllowBuiltinCreation = false, - bool EnteringContext = false); + bool EnteringContext = false, QualType T = QualType()); ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc, RedeclarationKind Redecl = NotForRedeclaration); @@ -5072,7 +5073,8 @@ public: Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, bool HasTrailingLParen, bool IsAddressOfOperand, CorrectionCandidateCallback *CCC = nullptr, - bool IsInlineAsmIdentifier = false, Token *KeywordReplacement = nullptr); + bool IsInlineAsmIdentifier = false, Token *KeywordReplacement = nullptr, + QualType T = QualType()); void DecomposeUnqualifiedId(const UnqualifiedId &Id, TemplateArgumentListInfo &Buffer, diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 6acf76d713fd..5831c0ff0917 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -914,7 +914,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, bool &NotCastExpr, TypeCastState isTypeCast, bool isVectorLiteral, - bool *NotPrimaryExpression) { + bool *NotPrimaryExpression, + QualType T, bool IsColonColon) { ExprResult Res; tok::TokenKind SavedKind = Tok.getKind(); auto SavedType = PreferredType; @@ -1036,10 +1037,31 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, assert(Tok.isNot(tok::kw_decltype) && Tok.isNot(tok::kw___super)); return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast, isVectorLiteral, NotPrimaryExpression); - + case tok::kw_union: + case tok::kw_enum: + case tok::kw_struct: + if (getLangOpts().BSC && NextToken().is(tok::identifier) && GetLookAheadToken(2).is(tok::coloncolon)) { + BSCScopeSpec BSS(*this); + ParseBSCScopeSpecifiers(BSS); + QualType T = Actions.GetTypeForDeclSpec(BSS); // get scope type for BSC + IsColonColon = TryConsumeToken(tok::coloncolon); + return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, + isTypeCast, isVectorLiteral, + NotPrimaryExpression, T, IsColonColon); + } + break; case tok::identifier: { // primary-expression: identifier // unqualified-id: identifier // constant: enumeration-constant + if (getLangOpts().BSC && NextToken().is(tok::coloncolon)) { + BSCScopeSpec BSS(*this); + ParseBSCScopeSpecifiers(BSS); + IsColonColon = TryConsumeToken(tok::coloncolon); + return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, + isTypeCast, isVectorLiteral, + NotPrimaryExpression, QualType(), IsColonColon); + break; + } // 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) { @@ -1251,7 +1273,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, getCurScope(), ScopeSpec, TemplateKWLoc, Name, Tok.is(tok::l_paren), isAddressOfOperand, &Validator, /*IsInlineAsmIdentifier=*/false, - Tok.is(tok::r_paren) ? nullptr : &Replacement); + Tok.is(tok::r_paren) ? nullptr : &Replacement, T); if (!Res.isInvalid() && Res.isUnset()) { UnconsumeToken(Replacement); return ParseCastExpression(ParseKind, isAddressOfOperand, @@ -1525,6 +1547,16 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, #define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t: #include "clang/Basic/OpenCLImageTypes.def" { + if (getLangOpts().BSC &&NextToken().is(tok::coloncolon)) { + BSCScopeSpec BSS(*this); + ParseBSCScopeSpecifiers(BSS); + QualType T = Actions.GetTypeForDeclSpec(BSS); // get scope type for BSC + IsColonColon = TryConsumeToken(tok::coloncolon); + return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, + isTypeCast, isVectorLiteral, + NotPrimaryExpression, T, IsColonColon); + break; + } if (!getLangOpts().CPlusPlus) { Diag(Tok, diag::err_expected_expression); return ExprError(); @@ -1806,6 +1838,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, // These can be followed by postfix-expr pieces. PreferredType = SavedType; + if (Res.get()) + Res.get()->IsColonColon = IsColonColon; Res = ParsePostfixExpressionSuffix(Res); if (getLangOpts().OpenCL) if (Expr *PostfixExpr = Res.get()) { diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 35d3b4b718db..24ad429a31e5 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -211,7 +211,7 @@ Default: if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) != ParsedStmtContext()) && - (GNUAttributeLoc.isValid() || isDeclarationStatement())) { + (GNUAttributeLoc.isValid() || (isDeclarationStatement() && !(getLangOpts().BSC && (NextToken().is(tok::coloncolon) || GetLookAheadToken(2).is(tok::coloncolon)))))) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; DeclGroupPtrTy Decl; if (GNUAttributeLoc.isValid()) { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 718ef43f7cd3..dc80bde5f638 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3680,7 +3680,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, // C: Function types need to be compatible, not identical. This handles // duplicate function decls like "void f(int); void f(enum X);" properly. - if (!getLangOpts().CPlusPlus && + if (!getLangOpts().CPlusPlus && ! getLangOpts().BSC && Context.typesAreCompatible(OldQType, NewQType)) { const FunctionType *OldFuncType = OldQType->getAs(); const FunctionType *NewFuncType = NewQType->getAs(); @@ -13615,7 +13615,8 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D, int ParamSize, // Check for redeclaration of parameters, e.g. int foo(int x, int x); IdentifierInfo *II = D.getIdentifier(); bool IsThisParam = false; - if (TypePtr != nullptr && DeclarationName(II).getAsString() == "this") { + // if TypePtr is nullptr, it is not a BSCMethod + if (TypePtr && DeclarationName(II).getAsString() == "this") { if (ParamSize == 0) { auto ThisTypePtr = parmDeclType.getTypePtrOrNull(); if (ThisTypePtr) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index aea9cacdfa53..f589786fb5f0 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2422,7 +2422,8 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, bool HasTrailingLParen, bool IsAddressOfOperand, CorrectionCandidateCallback *CCC, - bool IsInlineAsmIdentifier, Token *KeywordReplacement) { + bool IsInlineAsmIdentifier, Token *KeywordReplacement, + QualType T) { assert(!(IsAddressOfOperand && HasTrailingLParen) && "cannot be direct & operand and have a trailing lparen"); if (SS.isInvalid()) @@ -2472,7 +2473,6 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, if (DependentID) return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo, IsAddressOfOperand, TemplateArgs); - // Perform the required lookup. LookupResult R(*this, NameInfo, (Id.getKind() == UnqualifiedIdKind::IK_ImplicitSelfParam) @@ -2497,7 +2497,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, IsAddressOfOperand, TemplateArgs); } else { bool IvarLookupFollowUp = II && !SS.isSet() && getCurMethodDecl(); - LookupParsedName(R, S, &SS, !IvarLookupFollowUp); + LookupParsedName(R, S, &SS, !IvarLookupFollowUp, false, T); // If the result might be in a dependent base class, this is a dependent // id-expression. @@ -2522,7 +2522,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, // This could be an implicitly declared function reference (legal in C90, // extension in C99, forbidden in C++). - if (R.empty() && HasTrailingLParen && II && !getLangOpts().CPlusPlus) { + if (R.empty() && HasTrailingLParen && II && !getLangOpts().CPlusPlus && !getLangOpts().BSC) { NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *II, S); if (D) R.addDecl(D); } @@ -3423,7 +3423,12 @@ ExprResult Sema::BuildDeclarationNameExpr( valueKind = VK_RValue; break; } - LLVM_FALLTHROUGH; + + // BSC methods are l-values if static, r-values if non-static. + if (cast(VD)->isStatic()) { + valueKind = VK_LValue; + } + break; case Decl::CXXMethod: // If we're referring to a method with an __unknown_anytype @@ -5780,8 +5785,8 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, : (IsExecConfig ? 3 /* kernel function (exec config) */ : 0 /* function */); bool isBSCInstanceFunc = false; - if (FDecl) { - BSCMethodDecl *MD = dyn_cast_or_null(FDecl); + if (FDecl && !Fn->IsColonColon) { + BSCMethodDecl* MD = dyn_cast_or_null(FDecl); if (MD && MD->getHasThisParam()) { isBSCInstanceFunc = true; NumParams = NumParams - 1; @@ -6616,6 +6621,7 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, ArrayRef Args, SourceLocation RParenLoc, Expr *Config, bool IsExecConfig, ADLCallKind UsesADL) { + bool IsColonColon = Fn->IsColonColon; FunctionDecl *FDecl = dyn_cast_or_null(NDecl); unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0); @@ -6657,6 +6663,7 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, if (Result.isInvalid()) return ExprError(); Fn = Result.get(); + Fn->IsColonColon = IsColonColon; // Check for a valid function type, but only if it is not a builtin which // requires custom type checking. These will be handled by diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 2d8a65dcaae6..f9b5e7dc2a6c 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -2405,7 +2405,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, /// /// @returns True if any decls were found (but possibly ambiguous) bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, - bool AllowBuiltinCreation, bool EnteringContext) { + bool AllowBuiltinCreation, bool EnteringContext, + QualType T) { if (SS && SS->isInvalid()) { // When the scope specifier is invalid, don't even look for // anything. @@ -2435,6 +2436,14 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, return false; } + if (!T.isNull() && getLangOpts().BSC) { + DeclContext *DC = getASTContext().BSCDeclContextMap[T.getCanonicalType().getTypePtr()]; + if (DC) + return LookupQualifiedName(R, DC); + else + Diag(R.getNameLoc(), diag::err_undeclared_var_use) << R.getLookupName(); + } + // Perform unqualified name lookup starting in the given scope. return LookupName(R, S, AllowBuiltinCreation); } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 52b0fecf8551..5bb952a02dea 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1276,6 +1276,450 @@ static QualType ConvertConstrainedAutoDeclSpecToType(Sema &S, DeclSpec &DS, TemplateArgs); } +QualType Sema::GetTypeForDeclSpec(DeclSpec &BSCScopeSpec) { + DeclSpec &DS = BSCScopeSpec; + + QualType Result; + switch (DS.getTypeSpecType()) { + case DeclSpec::TST_void: + Result = Context.VoidTy; + break; + case DeclSpec::TST_char: + if (DS.getTypeSpecSign() == TypeSpecifierSign::Unspecified) + Result = Context.CharTy; + else if (DS.getTypeSpecSign() == TypeSpecifierSign::Signed) + Result = Context.SignedCharTy; + else { + assert(DS.getTypeSpecSign() == TypeSpecifierSign::Unsigned && + "Unknown TSS value"); + Result = Context.UnsignedCharTy; + } + break; + case DeclSpec::TST_wchar: + if (DS.getTypeSpecSign() == TypeSpecifierSign::Unspecified) + Result = Context.WCharTy; + else if (DS.getTypeSpecSign() == TypeSpecifierSign::Signed) { + Diag(DS.getTypeSpecSignLoc(), diag::ext_wchar_t_sign_spec) + << DS.getSpecifierName(DS.getTypeSpecType(), + Context.getPrintingPolicy()); + Result = Context.getSignedWCharType(); + } else { + assert(DS.getTypeSpecSign() == TypeSpecifierSign::Unsigned && + "Unknown TSS value"); + Diag(DS.getTypeSpecSignLoc(), diag::ext_wchar_t_sign_spec) + << DS.getSpecifierName(DS.getTypeSpecType(), + Context.getPrintingPolicy()); + Result = Context.getUnsignedWCharType(); + } + break; + case DeclSpec::TST_char8: + assert(DS.getTypeSpecSign() == TypeSpecifierSign::Unspecified && + "Unknown TSS value"); + Result = Context.Char8Ty; + break; + case DeclSpec::TST_char16: + assert(DS.getTypeSpecSign() == TypeSpecifierSign::Unspecified && + "Unknown TSS value"); + Result = Context.Char16Ty; + break; + case DeclSpec::TST_char32: + assert(DS.getTypeSpecSign() == TypeSpecifierSign::Unspecified && + "Unknown TSS value"); + Result = Context.Char32Ty; + break; + case DeclSpec::TST_int: { + if (DS.getTypeSpecSign() != TypeSpecifierSign::Unsigned) { + switch (DS.getTypeSpecWidth()) { + case TypeSpecifierWidth::Unspecified: + Result = Context.IntTy; + break; + case TypeSpecifierWidth::Short: + Result = Context.ShortTy; + break; + case TypeSpecifierWidth::Long: + Result = Context.LongTy; + break; + case TypeSpecifierWidth::LongLong: + Result = Context.LongLongTy; + + // 'long long' is a C99 or C++11 feature. + if (!getLangOpts().C99) { + if (getLangOpts().CPlusPlus) + Diag(DS.getTypeSpecWidthLoc(), + getLangOpts().CPlusPlus11 ? + diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong); + else + Diag(DS.getTypeSpecWidthLoc(), diag::ext_c99_longlong); + } + break; + } + } else { + switch (DS.getTypeSpecWidth()) { + case TypeSpecifierWidth::Unspecified: + Result = Context.UnsignedIntTy; + break; + case TypeSpecifierWidth::Short: + Result = Context.UnsignedShortTy; + break; + case TypeSpecifierWidth::Long: + Result = Context.UnsignedLongTy; + break; + case TypeSpecifierWidth::LongLong: + Result = Context.UnsignedLongLongTy; + + // 'long long' is a C99 or C++11 feature. + if (!getLangOpts().C99) { + if (getLangOpts().CPlusPlus) + Diag(DS.getTypeSpecWidthLoc(), + getLangOpts().CPlusPlus11 ? + diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong); + else + Diag(DS.getTypeSpecWidthLoc(), diag::ext_c99_longlong); + } + break; + } + } + break; + } + case DeclSpec::TST_extint: { + if (!Context.getTargetInfo().hasExtIntType()) + Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) + << "_ExtInt"; + Result = + BuildExtIntType(DS.getTypeSpecSign() == TypeSpecifierSign::Unsigned, + DS.getRepAsExpr(), DS.getBeginLoc()); + if (Result.isNull()) { + Result = Context.IntTy; + } + break; + } + case DeclSpec::TST_accum: { + switch (DS.getTypeSpecWidth()) { + case TypeSpecifierWidth::Short: + Result = Context.ShortAccumTy; + break; + case TypeSpecifierWidth::Unspecified: + Result = Context.AccumTy; + break; + case TypeSpecifierWidth::Long: + Result = Context.LongAccumTy; + break; + case TypeSpecifierWidth::LongLong: + llvm_unreachable("Unable to specify long long as _Accum width"); + } + + if (DS.getTypeSpecSign() == TypeSpecifierSign::Unsigned) + Result = Context.getCorrespondingUnsignedType(Result); + + if (DS.isTypeSpecSat()) + Result = Context.getCorrespondingSaturatedType(Result); + + break; + } + case DeclSpec::TST_fract: { + switch (DS.getTypeSpecWidth()) { + case TypeSpecifierWidth::Short: + Result = Context.ShortFractTy; + break; + case TypeSpecifierWidth::Unspecified: + Result = Context.FractTy; + break; + case TypeSpecifierWidth::Long: + Result = Context.LongFractTy; + break; + case TypeSpecifierWidth::LongLong: + llvm_unreachable("Unable to specify long long as _Fract width"); + } + + if (DS.getTypeSpecSign() == TypeSpecifierSign::Unsigned) + Result = Context.getCorrespondingUnsignedType(Result); + + if (DS.isTypeSpecSat()) + Result = Context.getCorrespondingSaturatedType(Result); + + break; + } + case DeclSpec::TST_int128: + if (!Context.getTargetInfo().hasInt128Type() && + !getLangOpts().SYCLIsDevice && + !(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice)) + Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) + << "__int128"; + if (DS.getTypeSpecSign() == TypeSpecifierSign::Unsigned) + Result = Context.UnsignedInt128Ty; + else + Result = Context.Int128Ty; + break; + case DeclSpec::TST_float16: + // CUDA host and device may have different _Float16 support, therefore + // do not diagnose _Float16 usage to avoid false alarm. + // ToDo: more precise diagnostics for CUDA. + if (!Context.getTargetInfo().hasFloat16Type() && !getLangOpts().CUDA && + !(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice)) + Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) + << "_Float16"; + Result = Context.Float16Ty; + break; + case DeclSpec::TST_half: Result = Context.HalfTy; break; + case DeclSpec::TST_BFloat16: + if (!Context.getTargetInfo().hasBFloat16Type()) + Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) + << "__bf16"; + Result = Context.BFloat16Ty; + break; + case DeclSpec::TST_float: Result = Context.FloatTy; break; + case DeclSpec::TST_double: + if (DS.getTypeSpecWidth() == TypeSpecifierWidth::Long) + Result = Context.LongDoubleTy; + else + Result = Context.DoubleTy; + break; + case DeclSpec::TST_float128: + if (!Context.getTargetInfo().hasFloat128Type() && + !getLangOpts().SYCLIsDevice && + !(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice)) + Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) + << "__float128"; + Result = Context.Float128Ty; + break; + case DeclSpec::TST_bool: + Result = Context.BoolTy; // _Bool or bool + break; + case DeclSpec::TST_decimal32: // _Decimal32 + case DeclSpec::TST_decimal64: // _Decimal64 + case DeclSpec::TST_decimal128: // _Decimal128 + Diag(DS.getTypeSpecTypeLoc(), diag::err_decimal_unsupported); + Result = Context.IntTy; + break; + case DeclSpec::TST_class: + case DeclSpec::TST_enum: + case DeclSpec::TST_union: + case DeclSpec::TST_struct: + case DeclSpec::TST_interface: { + TagDecl *D = dyn_cast_or_null(DS.getRepAsDecl()); + if (!D) { + // This can happen in C++ with ambiguous lookups. + Result = Context.IntTy; + break; + } + + // If the type is deprecated or unavailable, diagnose it. + DiagnoseUseOfDecl(D, DS.getTypeSpecTypeNameLoc()); + + assert(DS.getTypeSpecWidth() == TypeSpecifierWidth::Unspecified && + DS.getTypeSpecComplex() == 0 && + DS.getTypeSpecSign() == TypeSpecifierSign::Unspecified && + "No qualifiers on tag names!"); + + // TypeQuals handled by caller. + Result = Context.getTypeDeclType(D); + + // In both C and C++, make an ElaboratedType. + ElaboratedTypeKeyword Keyword + = ElaboratedType::getKeywordForTypeSpec(DS.getTypeSpecType()); + Result = getElaboratedType(Keyword, DS.getTypeSpecScope(), Result, + DS.isTypeSpecOwned() ? D : nullptr); + break; + } + case DeclSpec::TST_typename: { + assert(DS.getTypeSpecWidth() == TypeSpecifierWidth::Unspecified && + DS.getTypeSpecComplex() == 0 && + DS.getTypeSpecSign() == TypeSpecifierSign::Unspecified && + "Can't handle qualifiers on typedef names yet!"); + Result = GetTypeFromParser(DS.getRepAsType()); + + // TypeQuals handled by caller. + break; + } + case DeclSpec::TST_typeofType: + // FIXME: Preserve type source info. + Result = GetTypeFromParser(DS.getRepAsType()); + assert(!Result.isNull() && "Didn't get a type for typeof?"); + if (!Result->isDependentType()) + if (const TagType *TT = Result->getAs()) + DiagnoseUseOfDecl(TT->getDecl(), DS.getTypeSpecTypeLoc()); + // TypeQuals handled by caller. + Result = Context.getTypeOfType(Result); + break; + case DeclSpec::TST_typeofExpr: { + Expr *E = DS.getRepAsExpr(); + assert(E && "Didn't get an expression for typeof?"); + // TypeQuals handled by caller. + Result = BuildTypeofExprType(E, DS.getTypeSpecTypeLoc()); + if (Result.isNull()) { + Result = Context.IntTy; + } + break; + } + case DeclSpec::TST_decltype: { + Expr *E = DS.getRepAsExpr(); + assert(E && "Didn't get an expression for decltype?"); + // TypeQuals handled by caller. + Result = BuildDecltypeType(E, DS.getTypeSpecTypeLoc()); + if (Result.isNull()) { + Result = Context.IntTy; + } + break; + } + case DeclSpec::TST_underlyingType: + Result = GetTypeFromParser(DS.getRepAsType()); + assert(!Result.isNull() && "Didn't get a type for __underlying_type?"); + Result = BuildUnaryTransformType(Result, + UnaryTransformType::EnumUnderlyingType, + DS.getTypeSpecTypeLoc()); + if (Result.isNull()) { + Result = Context.IntTy; + } + break; + + case DeclSpec::TST_auto: + if (DS.isConstrainedAuto()) { + Result = ConvertConstrainedAutoDeclSpecToType(*this, DS, + AutoTypeKeyword::Auto); + break; + } + Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false); + break; + + case DeclSpec::TST_auto_type: + Result = Context.getAutoType(QualType(), AutoTypeKeyword::GNUAutoType, false); + break; + + case DeclSpec::TST_decltype_auto: + if (DS.isConstrainedAuto()) { + Result = + ConvertConstrainedAutoDeclSpecToType(*this, DS, + AutoTypeKeyword::DecltypeAuto); + break; + } + Result = Context.getAutoType(QualType(), AutoTypeKeyword::DecltypeAuto, + /*IsDependent*/ false); + break; + + case DeclSpec::TST_unknown_anytype: + Result = Context.UnknownAnyTy; + break; + + case DeclSpec::TST_atomic: + Result = GetTypeFromParser(DS.getRepAsType()); + assert(!Result.isNull() && "Didn't get a type for _Atomic?"); + Result = BuildAtomicType(Result, DS.getTypeSpecTypeLoc()); + if (Result.isNull()) { + Result = Context.IntTy; + } + break; + +#define GENERIC_IMAGE_TYPE(ImgType, Id) \ + case DeclSpec::TST_##ImgType##_t: \ + switch (getImageAccess(DS.getAttributes())) { \ + case OpenCLAccessAttr::Keyword_write_only: \ + Result = Context.Id##WOTy; \ + break; \ + case OpenCLAccessAttr::Keyword_read_write: \ + Result = Context.Id##RWTy; \ + break; \ + case OpenCLAccessAttr::Keyword_read_only: \ + Result = Context.Id##ROTy; \ + break; \ + case OpenCLAccessAttr::SpellingNotCalculated: \ + llvm_unreachable("Spelling not yet calculated"); \ + } \ + break; +#include "clang/Basic/OpenCLImageTypes.def" + + case DeclSpec::TST_error: + Result = Context.IntTy; + break; + } + + bool IsFixedPointType = DS.getTypeSpecType() == DeclSpec::TST_accum || + DS.getTypeSpecType() == DeclSpec::TST_fract; + + // Only fixed point types can be saturated + if (DS.isTypeSpecSat() && !IsFixedPointType) + Diag(DS.getTypeSpecSatLoc(), diag::err_invalid_saturation_spec) + << DS.getSpecifierName(DS.getTypeSpecType(), + Context.getPrintingPolicy()); + + // Handle complex types. + if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) { + if (getLangOpts().Freestanding) + Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex); + Result = Context.getComplexType(Result); + } else if (DS.isTypeAltiVecVector()) { + unsigned typeSize = static_cast(Context.getTypeSize(Result)); + assert(typeSize > 0 && "type size for vector must be greater than 0 bits"); + VectorType::VectorKind VecKind = VectorType::AltiVecVector; + if (DS.isTypeAltiVecPixel()) + VecKind = VectorType::AltiVecPixel; + else if (DS.isTypeAltiVecBool()) + VecKind = VectorType::AltiVecBool; + Result = Context.getVectorType(Result, 128/typeSize, VecKind); + } + + // FIXME: Imaginary. + if (DS.getTypeSpecComplex() == DeclSpec::TSC_imaginary) + Diag(DS.getTypeSpecComplexLoc(), diag::err_imaginary_not_supported); + + // Apply const/volatile/restrict qualifiers to T. + if (unsigned TypeQuals = DS.getTypeQualifiers()) { + // Warn about CV qualifiers on function types. + // C99 6.7.3p8: + // If the specification of a function type includes any type qualifiers, + // the behavior is undefined. + // C++11 [dcl.fct]p7: + // The effect of a cv-qualifier-seq in a function declarator is not the + // same as adding cv-qualification on top of the function type. In the + // latter case, the cv-qualifiers are ignored. + if (Result->isFunctionType()) { + diagnoseAndRemoveTypeQualifiers( + *this, DS, TypeQuals, Result, DeclSpec::TQ_const | DeclSpec::TQ_volatile, + getLangOpts().CPlusPlus + ? diag::warn_typecheck_function_qualifiers_ignored + : diag::warn_typecheck_function_qualifiers_unspecified); + // No diagnostic for 'restrict' or '_Atomic' applied to a + // function type; we'll diagnose those later, in BuildQualifiedType. + } + + // C++11 [dcl.ref]p1: + // Cv-qualified references are ill-formed except when the + // cv-qualifiers are introduced through the use of a typedef-name + // or decltype-specifier, in which case the cv-qualifiers are ignored. + // + // There don't appear to be any other contexts in which a cv-qualified + // reference type could be formed, so the 'ill-formed' clause here appears + // to never happen. + if (TypeQuals && Result->isReferenceType()) { + diagnoseAndRemoveTypeQualifiers( + *this, DS, TypeQuals, Result, + DeclSpec::TQ_const | DeclSpec::TQ_volatile | DeclSpec::TQ_atomic, + diag::warn_typecheck_reference_qualifiers); + } + + // C90 6.5.3 constraints: "The same type qualifier shall not appear more + // than once in the same specifier-list or qualifier-list, either directly + // or via one or more typedefs." + if (!getLangOpts().C99 && !getLangOpts().CPlusPlus + && TypeQuals & Result.getCVRQualifiers()) { + if (TypeQuals & DeclSpec::TQ_const && Result.isConstQualified()) { + Diag(DS.getConstSpecLoc(), diag::ext_duplicate_declspec) + << "const"; + } + + if (TypeQuals & DeclSpec::TQ_volatile && Result.isVolatileQualified()) { + Diag(DS.getVolatileSpecLoc(), diag::ext_duplicate_declspec) + << "volatile"; + } + + // C90 doesn't have restrict nor _Atomic, so it doesn't force us to + // produce a warning in this case. + } + } + + assert(!Result.isNull() && "This function should not return a null type"); + return Result; +} + /// Convert the specified declspec to the appropriate type /// object. /// \param state Specifies the declarator containing the declaration specifier diff --git a/clang/test/BSC/Method/BuiltInType/int_conflict_param_type.cbs b/clang/test/BSC/Method/BuiltInType/int_conflict_param_type.cbs new file mode 100644 index 000000000000..af4bfb2c8ad0 --- /dev/null +++ b/clang/test/BSC/Method/BuiltInType/int_conflict_param_type.cbs @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -verify %s + +void int::increase(int a); // expected-note {{previous declaration is here}} +void int::increase(int* this) { // expected-error {{conflicting types for 'increase'}} + *this = *this +1; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/BuiltInType/int_conflict_return_type.cbs b/clang/test/BSC/Method/BuiltInType/int_conflict_return_type.cbs new file mode 100644 index 000000000000..2007a3dadd2f --- /dev/null +++ b/clang/test/BSC/Method/BuiltInType/int_conflict_return_type.cbs @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -verify %s + +double int::increase(int* this); // expected-note {{previous declaration is here}} +void int::increase(int* this) { // expected-error {{conflicting types for 'increase'}} + *this = *this +1; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/BuiltInType/int_function_pointer_undeclared.cbs b/clang/test/BSC/Method/BuiltInType/int_function_pointer_undeclared.cbs new file mode 100644 index 000000000000..274e6134f102 --- /dev/null +++ b/clang/test/BSC/Method/BuiltInType/int_function_pointer_undeclared.cbs @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -verify %s + +int getA() { + return 1; +} + +int main() { + int (*fp)() = int::getA; // expected-error {{use of undeclared identifier 'getA'}} + int (*fp1)() = &int::getA; // expected-error {{use of undeclared identifier 'getA'}} + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/BuiltInType/int_instance_function_call.cbs b/clang/test/BSC/Method/BuiltInType/int_instance_function_call.cbs new file mode 100644 index 000000000000..ff822dbe784f --- /dev/null +++ b/clang/test/BSC/Method/BuiltInType/int_instance_function_call.cbs @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -verify %s + +void int::increase(int* this) { // expected-note {{'increase' declared here}} + *this = *this + 1; +} + +int main() { + int x = 1; + x.increase(&x); // expected-error {{too many arguments to function call, expected 0, have 1}} + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/BuiltInType/int_instance_function_pointer.cbs b/clang/test/BSC/Method/BuiltInType/int_instance_function_pointer.cbs new file mode 100644 index 000000000000..5869645b7c24 --- /dev/null +++ b/clang/test/BSC/Method/BuiltInType/int_instance_function_pointer.cbs @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -verify %s +// expected-no-diagnostics + +void int::increase(int* this) { + *this = *this +1; +} + +int main() { + int foo = 1; + void (*fp1)(int *) = int::increase; + void (*fp2)(int *) = &int::increase; + fp1(&foo); + fp2(&foo); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/BuiltInType/int_instance_function_with_typedef.cbs b/clang/test/BSC/Method/BuiltInType/int_instance_function_with_typedef.cbs new file mode 100644 index 000000000000..6b5890a2b442 --- /dev/null +++ b/clang/test/BSC/Method/BuiltInType/int_instance_function_with_typedef.cbs @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -verify %s +// expected-no-diagnostics + +typedef int bscInt; + +void bscInt::increase_1(bscInt* this) { + *this = *this + 1; +} + +void int::increase_2(bscInt* this) { + *this = *this + 1; +} + +void int::increase_3(int* this) { + *this = *this + 1; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/Enum/enum_conflict_param_type.cbs b/clang/test/BSC/Method/Enum/enum_conflict_param_type.cbs new file mode 100644 index 000000000000..6155a971d31a --- /dev/null +++ b/clang/test/BSC/Method/Enum/enum_conflict_param_type.cbs @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -verify %s + +enum E { + X3, + X4 +}; + +int enum E::getA(int a); // expected-note {{previous declaration is here}} +int enum E::getA(enum E* this) { // expected-error {{conflicting types for 'getA'}} + return X4; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/Enum/enum_conflict_return_type.cbs b/clang/test/BSC/Method/Enum/enum_conflict_return_type.cbs new file mode 100644 index 000000000000..b14149765fc9 --- /dev/null +++ b/clang/test/BSC/Method/Enum/enum_conflict_return_type.cbs @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -verify %s + +enum E { + X3, + X4 +}; + +double enum E::getA(enum E* this); // expected-note {{previous declaration is here}} +int enum E::getA(enum E* this) { // expected-error {{conflicting types for 'getA'}} + return X4; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/Enum/enum_function_pointer_undeclared.cbs b/clang/test/BSC/Method/Enum/enum_function_pointer_undeclared.cbs new file mode 100644 index 000000000000..595e5db3448a --- /dev/null +++ b/clang/test/BSC/Method/Enum/enum_function_pointer_undeclared.cbs @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -verify %s + +enum E { + X3, + X4 +}; + +int getA() { + return 1; +} + +int main() { + int (*fp)() = enum E::getA; // expected-error {{use of undeclared identifier 'getA'}} + int (*fp1)() = &enum E::getA; // expected-error {{use of undeclared identifier 'getA'}} + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/Enum/enum_instance_function_call.cbs b/clang/test/BSC/Method/Enum/enum_instance_function_call.cbs new file mode 100644 index 000000000000..446adccb1d04 --- /dev/null +++ b/clang/test/BSC/Method/Enum/enum_instance_function_call.cbs @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -verify %s + +enum E { + X3, + X4 +}; + +int enum E::getA(enum E* this) { // expected-note {{'getA' declared here}} + return X4; +} + + +int main() { + enum E e= X3; + e.getA(&e); // expected-error {{too many arguments to function call, expected 0, have 1}} + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/Enum/enum_instance_function_pointer.cbs b/clang/test/BSC/Method/Enum/enum_instance_function_pointer.cbs new file mode 100644 index 000000000000..2681e682d0d6 --- /dev/null +++ b/clang/test/BSC/Method/Enum/enum_instance_function_pointer.cbs @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -verify %s +// expected-no-diagnostics + +enum E { + X3, + X4 +}; + +int enum E::getA(enum E* this) { + return X4; +} + +int main() { + enum E foo = X3; + int (*fp1)(enum E *) = enum E::getA; + int (*fp2)(enum E *) = &enum E::getA; + fp1(&foo); + fp2(&foo); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/Enum/enum_instance_function_with_typedef.cbs b/clang/test/BSC/Method/Enum/enum_instance_function_with_typedef.cbs new file mode 100644 index 000000000000..2042dba0cef0 --- /dev/null +++ b/clang/test/BSC/Method/Enum/enum_instance_function_with_typedef.cbs @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -verify %s +// expected-no-diagnostics + +typedef enum E { + X3, + X4 +}E; + +int E::getX4_1(E* this) { + return X4; +} + +int E::getX4_2(enum E* this) { + return X4; +} + +int enum E::getX4_3(enum E* this) { + return X4; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/Struct/struct_conflict_no_param_1.cbs b/clang/test/BSC/Method/Struct/struct_conflict_no_param_1.cbs new file mode 100644 index 000000000000..9809668a6c97 --- /dev/null +++ b/clang/test/BSC/Method/Struct/struct_conflict_no_param_1.cbs @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -verify %s + +struct Foo { + int a; +}; + +int struct Foo::getA(); // expected-note {{previous declaration is here}} +int struct Foo::getA(struct Foo* this) { // expected-error {{conflicting types for 'getA'}} + return this->a; +} diff --git a/clang/test/BSC/Method/Struct/struct_conflict_no_param_2.cbs b/clang/test/BSC/Method/Struct/struct_conflict_no_param_2.cbs new file mode 100644 index 000000000000..9e97ea8f6845 --- /dev/null +++ b/clang/test/BSC/Method/Struct/struct_conflict_no_param_2.cbs @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -verify %s + +struct Foo { + int a; +}; + +int struct Foo::getA(); // expected-note {{previous declaration is here}} +int struct Foo::getA(struct Foo* this); // expected-error {{conflicting types for 'getA'}} diff --git a/clang/test/BSC/Method/Struct/struct_conflict_param_type.cbs b/clang/test/BSC/Method/Struct/struct_conflict_param_type.cbs new file mode 100644 index 000000000000..0ee0da65372b --- /dev/null +++ b/clang/test/BSC/Method/Struct/struct_conflict_param_type.cbs @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -verify %s + +struct Foo { + int a; +}; + +int struct Foo::getA(int a); // expected-note {{previous declaration is here}} +int struct Foo::getA(struct Foo* this) { // expected-error {{conflicting types for 'getA'}} + return this->a; +} diff --git a/clang/test/BSC/Method/Struct/struct_conflict_return_type.cbs b/clang/test/BSC/Method/Struct/struct_conflict_return_type.cbs new file mode 100644 index 000000000000..b294fecd1800 --- /dev/null +++ b/clang/test/BSC/Method/Struct/struct_conflict_return_type.cbs @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -verify %s + +struct Foo { + int a; +}; + +double struct Foo::getA(struct Foo* this); // expected-note {{previous declaration is here}} +int struct Foo::getA(struct Foo* this) { // expected-error {{conflicting types for 'getA'}} + return this->a; +} diff --git a/clang/test/BSC/Method/Struct/struct_function_undeclared.cbs b/clang/test/BSC/Method/Struct/struct_function_undeclared.cbs new file mode 100644 index 000000000000..5849ca25dfcc --- /dev/null +++ b/clang/test/BSC/Method/Struct/struct_function_undeclared.cbs @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -verify %s + +struct Foo { + int a; +}; + +int getA() { + return 1; +} + +int main() { + int (*fp)() = struct Foo::getA; // expected-error {{use of undeclared identifier 'getA'}} + int (*fp1)() = &struct Foo::getA; // expected-error {{use of undeclared identifier 'getA'}} + return 0; +} diff --git a/clang/test/BSC/pending/InstanceMemberFunc.cbs b/clang/test/BSC/Method/Struct/struct_instance_function.cbs similarity index 39% rename from clang/test/BSC/pending/InstanceMemberFunc.cbs rename to clang/test/BSC/Method/Struct/struct_instance_function.cbs index 0cdd03d421b1..416f7e75c499 100644 --- a/clang/test/BSC/pending/InstanceMemberFunc.cbs +++ b/clang/test/BSC/Method/Struct/struct_instance_function.cbs @@ -1,17 +1,17 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -verify %s // expected-no-diagnostics -typedef struct Foo{ + +struct Foo { int a; -}Foo; +}; -int Foo::getA(struct Foo* this) { +int struct Foo::getA(struct Foo* this) { return this->a; } + int main() { - Foo foo; - foo.a = 42; + struct Foo foo = {.a = 1}; foo.getA(); - Foo::getA(&foo); return 0; } \ No newline at end of file diff --git a/clang/test/BSC/Method/Struct/struct_instance_function_call.cbs b/clang/test/BSC/Method/Struct/struct_instance_function_call.cbs new file mode 100644 index 000000000000..0e6a528eebfe --- /dev/null +++ b/clang/test/BSC/Method/Struct/struct_instance_function_call.cbs @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -verify %s + +struct Foo { + int a; +}; + +int struct Foo::getA(struct Foo* this) { // expected-note {{'getA' declared here}} + return this->a; +} + + +int main() { + struct Foo foo = {.a = 1}; + foo.getA(&foo); // expected-error {{too many arguments to function call, expected 0, have 1}} + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/Struct/struct_instance_function_declaration.cbs b/clang/test/BSC/Method/Struct/struct_instance_function_declaration.cbs new file mode 100644 index 000000000000..e6c4c2fcd2f3 --- /dev/null +++ b/clang/test/BSC/Method/Struct/struct_instance_function_declaration.cbs @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -verify %s +// expected-no-diagnostics + +struct Foo { + int a; +}; + +int struct Foo::getA(struct Foo* this); + +int main() { + struct Foo foo = {.a = 1}; + foo.getA(); + return 0; +} + +int struct Foo::getA(struct Foo* this) { + return this->a; +} diff --git a/clang/test/BSC/Method/Struct/struct_instance_function_multi_declaration.cbs b/clang/test/BSC/Method/Struct/struct_instance_function_multi_declaration.cbs new file mode 100644 index 000000000000..ff1fdddc42e4 --- /dev/null +++ b/clang/test/BSC/Method/Struct/struct_instance_function_multi_declaration.cbs @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -verify %s +// expected-no-diagnostics + +struct Foo { + int a; +}; + +int struct Foo::getA(struct Foo* this); +int struct Foo::getA(struct Foo* this); + +int main() { + struct Foo foo = {.a = 1}; + foo.getA(); + return 0; +} + +int struct Foo::getA(struct Foo* this) { + return this->a; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/Struct/struct_instance_function_not_found.cbs b/clang/test/BSC/Method/Struct/struct_instance_function_not_found.cbs new file mode 100644 index 000000000000..e7665e9cb107 --- /dev/null +++ b/clang/test/BSC/Method/Struct/struct_instance_function_not_found.cbs @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -verify %s + +struct Foo { + int a; +}; + +int struct Foo::getA(struct Foo* this) { + return this->a; +} + + +int main() { + struct Foo foo = {.a = 1}; + foo.getB(); // expected-error {{no member named 'getB' in 'struct Foo'}} + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/Struct/struct_instance_function_pointer.cbs b/clang/test/BSC/Method/Struct/struct_instance_function_pointer.cbs new file mode 100644 index 000000000000..ebd1a859d149 --- /dev/null +++ b/clang/test/BSC/Method/Struct/struct_instance_function_pointer.cbs @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -verify %s +// expected-no-diagnostics + +struct Foo { + int a; +}; + +int struct Foo::getA(struct Foo* this) { + return this->a; +} + + +int main() { + struct Foo foo = {.a = 1}; + int (*fp1)(struct Foo *) = struct Foo::getA; + int (*fp2)(struct Foo *) = &struct Foo::getA; + fp1(&foo); + fp2(&foo); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/Struct/struct_instance_function_redefinition.cbs b/clang/test/BSC/Method/Struct/struct_instance_function_redefinition.cbs new file mode 100644 index 000000000000..d8aa505bd885 --- /dev/null +++ b/clang/test/BSC/Method/Struct/struct_instance_function_redefinition.cbs @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -verify %s + +struct Foo { + int a; +}; + +int struct Foo::getA(struct Foo* this) { // expected-note {{previous definition is here}} + return this->a; +} + +int struct Foo::getA(struct Foo* this) { // expected-error {{redefinition of 'getA'}} + return this->a; +} + +int main() { + struct Foo foo = {.a = 1}; + foo.getA(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/pending/Typedef.cbs b/clang/test/BSC/Method/Struct/struct_instance_function_with_typedef.cbs similarity index 45% rename from clang/test/BSC/pending/Typedef.cbs rename to clang/test/BSC/Method/Struct/struct_instance_function_with_typedef.cbs index ee779a449bcb..a48f320d52ff 100644 --- a/clang/test/BSC/pending/Typedef.cbs +++ b/clang/test/BSC/Method/Struct/struct_instance_function_with_typedef.cbs @@ -1,10 +1,10 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -verify %s // expected-no-diagnostics -struct Foo { + +typedef struct Foo { int a; int b; -}; -typedef struct Foo Foo; +}Foo; int Foo::getB(Foo* this) { return this->b; @@ -14,12 +14,6 @@ int Foo::getAPlusB(struct Foo* this) { return this->a + this->b; } -int main() { - Foo foo; - foo.a = 42; - foo.b = 2023; - int b = foo.getB(); - int ab = foo.getAPlusB(); - return 0; -} - +int struct Foo::getA(struct Foo* this) { + return this->a; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/Union/union_conflict_param_type.cbs b/clang/test/BSC/Method/Union/union_conflict_param_type.cbs new file mode 100644 index 000000000000..3950cd93c3b1 --- /dev/null +++ b/clang/test/BSC/Method/Union/union_conflict_param_type.cbs @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -verify %s + +union SimpleUnion { + float uf; + int ui; + char uc; +}; + +int union SimpleUnion::getA(int a); // expected-note {{previous declaration is here}} +int union SimpleUnion::getA(union SimpleUnion * this) { // expected-error {{conflicting types for 'getA'}} + return this->ui; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/Union/union_conflict_return_type.cbs b/clang/test/BSC/Method/Union/union_conflict_return_type.cbs new file mode 100644 index 000000000000..bad0123c1d9e --- /dev/null +++ b/clang/test/BSC/Method/Union/union_conflict_return_type.cbs @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -verify %s + +union SimpleUnion { + float uf; + int ui; + char uc; +}; + +double union SimpleUnion::getA(union SimpleUnion * this); // expected-note {{previous declaration is here}} +int union SimpleUnion::getA(union SimpleUnion * this) { // expected-error {{conflicting types for 'getA'}} + return this->ui; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/Union/union_function_pointer_undeclared.cbs b/clang/test/BSC/Method/Union/union_function_pointer_undeclared.cbs new file mode 100644 index 000000000000..8993ac904fb7 --- /dev/null +++ b/clang/test/BSC/Method/Union/union_function_pointer_undeclared.cbs @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -verify %s + +union SimpleUnion { + float uf; + int ui; + char uc; +}; + +int getA() { + return 1; +} + +int main() { + int (*fp)() = union SimpleUnion::getA; // expected-error {{use of undeclared identifier 'getA'}} + int (*fp1)() = &union SimpleUnion::getA; // expected-error {{use of undeclared identifier 'getA'}} + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/Union/union_instance_function_call.cbs b/clang/test/BSC/Method/Union/union_instance_function_call.cbs new file mode 100644 index 000000000000..e0bab4d1de38 --- /dev/null +++ b/clang/test/BSC/Method/Union/union_instance_function_call.cbs @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -verify %s + +union SimpleUnion { + float uf; + int ui; + char uc; +}; + +int union SimpleUnion::getA(union SimpleUnion* this) { // expected-note {{'getA' declared here}} + return this->ui; +} + + +int main() { + union SimpleUnion u = {.ui = 1}; + u.getA(&u); // expected-error {{too many arguments to function call, expected 0, have 1}} + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/Union/union_instance_function_pointer.cbs b/clang/test/BSC/Method/Union/union_instance_function_pointer.cbs new file mode 100644 index 000000000000..3dc1847eb71a --- /dev/null +++ b/clang/test/BSC/Method/Union/union_instance_function_pointer.cbs @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -verify %s +// expected-no-diagnostics + +union SimpleUnion { + float uf; + int ui; + char uc; +}; + +int union SimpleUnion::getA(union SimpleUnion * this) { + return this->ui; +} + +int main() { + union SimpleUnion foo = {.ui = 1}; + int (*fp1)(union SimpleUnion *) = union SimpleUnion::getA; + int (*fp2)(union SimpleUnion *) = &union SimpleUnion::getA; + fp1(&foo); + fp2(&foo); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/Union/union_instance_function_with_typedef.cbs b/clang/test/BSC/Method/Union/union_instance_function_with_typedef.cbs new file mode 100644 index 000000000000..153b409a1d00 --- /dev/null +++ b/clang/test/BSC/Method/Union/union_instance_function_with_typedef.cbs @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -verify %s +// expected-no-diagnostics + +typedef union SimpleUnion { + float uf; + int ui; + char uc; +}SimpleUnion; + +int SimpleUnion::getui_1(SimpleUnion* this) { + return this->ui; +} + +int SimpleUnion::getui_2(union SimpleUnion* this) { + return this->ui; +} + +int union SimpleUnion::getui_3(union SimpleUnion* this) { + return this->ui; +} \ No newline at end of file diff --git a/clang/test/BSC/ParamCheck/this_not_first_param.cbs b/clang/test/BSC/ParamCheck/this_not_first_param.cbs new file mode 100644 index 000000000000..7fe4902bed43 --- /dev/null +++ b/clang/test/BSC/ParamCheck/this_not_first_param.cbs @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -verify %s + +// struct +struct Foo { + int a; +}; + +int struct Foo::getA(int b, struct Foo* this) { // expected-error {{'this' cannot be the name of a parameter}} + return this->a; +} + +// enum +enum E { + X3, + X4 +}; + +int enum E::getA(int b, enum E* this) { // expected-error {{'this' cannot be the name of a parameter}} + return X4; +} + +// union +union SimpleUnion { + float uf; + int ui; + char uc; +}; + +int union SimpleUnion::getA(int b, union SimpleUnion* this) { // expected-error {{'this' cannot be the name of a parameter}} + return this->ui; +} + +// BuiltinType +void int::increase(int b, int* this) { // expected-error {{'this' cannot be the name of a parameter}} + *this = *this + b; +} + diff --git a/clang/test/BSC/ParamCheck/this_param_type_no_match.cbs b/clang/test/BSC/ParamCheck/this_param_type_no_match.cbs new file mode 100644 index 000000000000..bcb0222f9857 --- /dev/null +++ b/clang/test/BSC/ParamCheck/this_param_type_no_match.cbs @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -verify %s + +// struct +struct Foo { + int a; +}; + +struct Bar { + int a; +}; + +int struct Foo::getBarA(struct Bar* this) { // expected-error {{struct Bar * is not supported on this target}} + return this->a; +} + +// enum +enum E { + X3, + X4 +}; + +int enum E::getBarA(struct Bar* this) { // expected-error {{struct Bar * is not supported on this target}} + return this->a; +} + +// union +union SimpleUnion { + float uf; + int ui; + char uc; +}; + +int union SimpleUnion::getBarA(struct Bar* this) { // expected-error {{struct Bar * is not supported on this target}} + return this->a; +} + +// BuiltinType +int int::getBarA(struct Bar* this) { // expected-error {{struct Bar * is not supported on this target}} + return this->a; +} \ No newline at end of file diff --git a/clang/test/BSC/ParamCheck/this_param_with_const.cbs b/clang/test/BSC/ParamCheck/this_param_with_const.cbs new file mode 100644 index 000000000000..a6c7aa7e29f1 --- /dev/null +++ b/clang/test/BSC/ParamCheck/this_param_with_const.cbs @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -verify %s +// expected-no-diagnostics + +// struct +struct Foo { + int a; +}; + +int struct Foo::getA(const struct Foo* this) { + return this->a; +} + +// enum +enum E { + X3, + X4 +}; + +int enum E::getA(const enum E* this) { + return X4; +} + +// union +union SimpleUnion { + float uf; + int ui; + char uc; +}; + +int union SimpleUnion::getA(const union SimpleUnion* this) { + return this->ui; +} + +// BuiltinType +int int::getA(const int* this) { + return *this; +} + +int main() { + struct Foo foo ={.a = 42}; + foo.getA(); + enum E e= X3; + e.getA(); + union SimpleUnion u = {.ui = 1}; + u.getA(); + int one = 1; + one.getA(); + return 0; +} + diff --git a/clang/test/BSC/ParamCheck/this_param_with_volatile.cbs b/clang/test/BSC/ParamCheck/this_param_with_volatile.cbs new file mode 100644 index 000000000000..2402e40ffdbe --- /dev/null +++ b/clang/test/BSC/ParamCheck/this_param_with_volatile.cbs @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 -verify %s +// expected-no-diagnostics + +// struct +struct Foo { + int a; +}; + +int struct Foo::getA(volatile struct Foo* this) { + return this->a; +} + +// enum +enum E { + X3, + X4 +}; + +int enum E::getA(volatile enum E* this) { + return X4; +} + +// union +union SimpleUnion { + float uf; + int ui; + char uc; +}; + +int union SimpleUnion::getA(volatile union SimpleUnion* this) { + return this->ui; +} + +// BuiltinType +int int::getA(volatile int* this) { + return *this; +} + +int main() { + struct Foo foo ={.a = 42}; + foo.getA(); + enum E e= X3; + e.getA(); + union SimpleUnion u = {.ui = 1}; + u.getA(); + int one = 1; + one.getA(); + return 0; +} diff --git a/clang/test/BSC/pending/CallBeforeDefine.cbs b/clang/test/BSC/pending/CallBeforeDefine.cbs deleted file mode 100644 index c8e9187030a7..000000000000 --- a/clang/test/BSC/pending/CallBeforeDefine.cbs +++ /dev/null @@ -1,17 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -// expected-no-diagnostics -typedef struct Foo { - int a; -}Foo; - -int Foo::getA(struct Foo* this); - -int main() { - struct Foo foo; - foo.a = 42; - return foo.getA(); -} - -int Foo::getA(struct Foo* this) { - return this->a; -} \ No newline at end of file diff --git a/clang/test/BSC/pending/OverloadFunc.cbs b/clang/test/BSC/pending/OverloadFunc.cbs deleted file mode 100644 index 442a57b87669..000000000000 --- a/clang/test/BSC/pending/OverloadFunc.cbs +++ /dev/null @@ -1,24 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s - -struct Foo { - int a; -}; -typedef struct Foo F; - -int F::f2(F* this) { -// expected-note@-1 {{previous definition is here}} -// expected-note@-2 {{passing argument to parameter 'this' here}} - return 1; -} - -int F::f2(F* this, int a) { // expected-error {{conflicting types for 'f2'}} - return a; -} - -int main(){ - Foo foo; - foo.a = 1; - foo.f2(); - foo.f2(1); // expected-warning {{incompatible integer to pointer conversion passing 'int' to parameter of type 'F *' (aka 'struct Foo *')}} - return 0; -} \ No newline at end of file diff --git a/clang/test/BSC/pending/StaticMemberFunc.cbs b/clang/test/BSC/pending/StaticMemberFunc.cbs deleted file mode 100644 index f9b2068cfd7e..000000000000 --- a/clang/test/BSC/pending/StaticMemberFunc.cbs +++ /dev/null @@ -1,20 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -// expected-no-diagnostics -typedef struct Foo{ - int a; -}Foo; - -int Foo::s1() { - return 1; -} - -int Foo::s2(struct Foo* other) { - return other->a; -} - -int main() { - struct Foo x = {0}; - Foo::s1(); - Foo::s2(&x); - return 0; -} \ No newline at end of file diff --git a/clang/test/BSC/pending/ThisParamCheck1.cbs b/clang/test/BSC/pending/ThisParamCheck1.cbs deleted file mode 100644 index 05281fbfb1fb..000000000000 --- a/clang/test/BSC/pending/ThisParamCheck1.cbs +++ /dev/null @@ -1,17 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s - -typedef struct Foo { - int a; -}Foo; - -typedef struct Bar { - int a; -}Bar; - -int Foo::getA(int b, struct Foo* this) { // expected-error {{'this' cannot be the name of a parameter}} - return this->a; -} - -int Foo::getBarA(struct Bar* this) { // expected-error {{struct Bar * is not supported on this target}} - return this->a; -} \ No newline at end of file diff --git a/clang/test/BSC/pending/ThisParamCheck2.cbs b/clang/test/BSC/pending/ThisParamCheck2.cbs deleted file mode 100644 index 1fee3762a580..000000000000 --- a/clang/test/BSC/pending/ThisParamCheck2.cbs +++ /dev/null @@ -1,21 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s - -typedef struct Foo{ - int a; -}Foo; - -int Foo::s1() { - return 1; -} - -int Foo::s2(struct Foo* other) { - return other->a; -} - -int main() { - struct Foo x = {0}; - x.s1(); // expected-error {{no member named 's1' in 'struct Foo'; did you mean to use '::' instead of '.'?}} - - x.s2(); // expected-error {{no member named 's2' in 'struct Foo'; did you mean to use '::' instead of '.'?}} - return 0; -} \ No newline at end of file -- Gitee From 12457de9ac20830c174a5fc4b5cea602d74061be Mon Sep 17 00:00:00 2001 From: zhaoxuhui Date: Thu, 2 Mar 2023 13:00:11 +0800 Subject: [PATCH 2/2] fix review suggestions --- clang/include/clang/AST/Expr.h | 2 +- clang/include/clang/Parse/Parser.h | 2 +- clang/include/clang/Sema/Sema.h | 4 +- clang/lib/Parse/ParseDecl.cpp | 2 +- clang/lib/Parse/ParseExpr.cpp | 57 ++- clang/lib/Parse/ParseStmt.cpp | 4 +- clang/lib/Sema/SemaExpr.cpp | 6 +- clang/lib/Sema/SemaType.cpp | 450 +----------------- .../BuiltInType/int_static_function_call.cbs | 12 + .../Struct/struct_static_function_call.cbs | 19 + 10 files changed, 78 insertions(+), 480 deletions(-) create mode 100644 clang/test/BSC/Method/BuiltInType/int_static_function_call.cbs create mode 100644 clang/test/BSC/Method/Struct/struct_static_function_call.cbs diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 1de83e190e41..b19f98326eeb 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -138,7 +138,7 @@ protected: friend class ASTStmtReader; // Sets dependence dircetly. public: - bool IsColonColon = false; + bool HasBSCScopeSpce = false; QualType getType() const { return TR; } void setType(QualType t) { // In C++, the type of an expression is always adjusted so that it diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 6a2e6bf39835..6f53fea395be 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1794,7 +1794,7 @@ private: bool isVectorLiteral = false, bool *NotPrimaryExpression = nullptr, QualType T = QualType(), - bool IsColonColon = false); + bool HasBSCScopeSpce = false); ExprResult ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand = false, TypeCastState isTypeCast = NotTypeCast, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index c4f5319679cb..b0c085d98044 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2671,8 +2671,8 @@ public: QualType NewT, QualType OldT); void CheckMain(FunctionDecl *FD, const DeclSpec &D); void CheckMSVCRTEntryPoint(FunctionDecl *FD); - QualType GetTypeForDeclSpec(DeclSpec &BSCScopeSpec); - void ConvertBSCScopeSpecToType(Declarator &D, SourceLocation Loc); + QualType ConvertBSCScopeSpecToType(Declarator &D, SourceLocation Loc, + bool AddToContextMap); Attr *getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD, bool IsDefinition); void CheckFunctionOrTemplateParamDeclarator(Scope *S, Declarator &D); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index bbda96757d33..f475e675c455 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -5702,7 +5702,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, TryConsumeToken(tok::coloncolon); D.setBSCScopeSpec(&BSS); - Actions.ConvertBSCScopeSpecToType(D, BSS.getBeginLoc()); + Actions.ConvertBSCScopeSpecToType(D, BSS.getBeginLoc(), true); (this->*DirectDeclParser)(D); return; } diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 5831c0ff0917..6fb1a7dba79a 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -909,13 +909,11 @@ class CastExpressionIdValidator final : public CorrectionCandidateCallback { /// '__is_rvalue_expr' /// \endverbatim /// -ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, - bool isAddressOfOperand, - bool &NotCastExpr, - TypeCastState isTypeCast, - bool isVectorLiteral, - bool *NotPrimaryExpression, - QualType T, bool IsColonColon) { +ExprResult +Parser::ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand, + bool &NotCastExpr, TypeCastState isTypeCast, + bool isVectorLiteral, bool *NotPrimaryExpression, + QualType T, bool HasBSCScopeSpce) { ExprResult Res; tok::TokenKind SavedKind = Tok.getKind(); auto SavedType = PreferredType; @@ -1040,27 +1038,34 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, case tok::kw_union: case tok::kw_enum: case tok::kw_struct: - if (getLangOpts().BSC && NextToken().is(tok::identifier) && GetLookAheadToken(2).is(tok::coloncolon)) { - BSCScopeSpec BSS(*this); + if (getLangOpts().BSC && FindUntil(tok::coloncolon)) { + ParsingDeclSpec BSS(*this); ParseBSCScopeSpecifiers(BSS); - QualType T = Actions.GetTypeForDeclSpec(BSS); // get scope type for BSC - IsColonColon = TryConsumeToken(tok::coloncolon); + ParsingDeclarator D(*this, BSS, DeclaratorContext::File); + D.setBSCScopeSpec(&BSS); + QualType T = Actions.ConvertBSCScopeSpecToType( + D, BSS.getBeginLoc(), false); // get scope type for BSC + HasBSCScopeSpce = TryConsumeToken(tok::coloncolon); return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, isTypeCast, isVectorLiteral, - NotPrimaryExpression, T, IsColonColon); + NotPrimaryExpression, T, HasBSCScopeSpce); } - break; + // Fall through; this isn't a message send. + LLVM_FALLTHROUGH; case tok::identifier: { // primary-expression: identifier // unqualified-id: identifier // constant: enumeration-constant - if (getLangOpts().BSC && NextToken().is(tok::coloncolon)) { - BSCScopeSpec BSS(*this); + if (getLangOpts().BSC && FindUntil(tok::coloncolon)) { + ParsingDeclSpec BSS(*this); ParseBSCScopeSpecifiers(BSS); - IsColonColon = TryConsumeToken(tok::coloncolon); + ParsingDeclarator D(*this, BSS, DeclaratorContext::File); + D.setBSCScopeSpec(&BSS); + QualType T = Actions.ConvertBSCScopeSpecToType( + D, BSS.getBeginLoc(), false); // get scope type for BSC + HasBSCScopeSpce = TryConsumeToken(tok::coloncolon); return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, isTypeCast, isVectorLiteral, - NotPrimaryExpression, QualType(), IsColonColon); - break; + NotPrimaryExpression, T, HasBSCScopeSpce); } // Turn a potentially qualified name into a annot_typename or // annot_cxxscope if it would be valid. This handles things like x::y, etc. @@ -1547,15 +1552,17 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, #define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t: #include "clang/Basic/OpenCLImageTypes.def" { - if (getLangOpts().BSC &&NextToken().is(tok::coloncolon)) { - BSCScopeSpec BSS(*this); + if (getLangOpts().BSC && FindUntil(tok::coloncolon)) { + ParsingDeclSpec BSS(*this); ParseBSCScopeSpecifiers(BSS); - QualType T = Actions.GetTypeForDeclSpec(BSS); // get scope type for BSC - IsColonColon = TryConsumeToken(tok::coloncolon); + ParsingDeclarator D(*this, BSS, DeclaratorContext::File); + D.setBSCScopeSpec(&BSS); + QualType T = Actions.ConvertBSCScopeSpecToType( + D, BSS.getBeginLoc(), false); // get scope type for BSC + HasBSCScopeSpce = TryConsumeToken(tok::coloncolon); return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, isTypeCast, isVectorLiteral, - NotPrimaryExpression, T, IsColonColon); - break; + NotPrimaryExpression, T, HasBSCScopeSpce); } if (!getLangOpts().CPlusPlus) { Diag(Tok, diag::err_expected_expression); @@ -1839,7 +1846,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, // These can be followed by postfix-expr pieces. PreferredType = SavedType; if (Res.get()) - Res.get()->IsColonColon = IsColonColon; + Res.get()->HasBSCScopeSpce = HasBSCScopeSpce; Res = ParsePostfixExpressionSuffix(Res); if (getLangOpts().OpenCL) if (Expr *PostfixExpr = Res.get()) { diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 24ad429a31e5..0170003db76e 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -211,7 +211,9 @@ Default: if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) != ParsedStmtContext()) && - (GNUAttributeLoc.isValid() || (isDeclarationStatement() && !(getLangOpts().BSC && (NextToken().is(tok::coloncolon) || GetLookAheadToken(2).is(tok::coloncolon)))))) { + (GNUAttributeLoc.isValid() || + (isDeclarationStatement() && + !(getLangOpts().BSC && FindUntil(tok::coloncolon))))) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; DeclGroupPtrTy Decl; if (GNUAttributeLoc.isValid()) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index f589786fb5f0..8843c1f8d082 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -5785,7 +5785,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, : (IsExecConfig ? 3 /* kernel function (exec config) */ : 0 /* function */); bool isBSCInstanceFunc = false; - if (FDecl && !Fn->IsColonColon) { + if (FDecl && !Fn->HasBSCScopeSpce) { BSCMethodDecl* MD = dyn_cast_or_null(FDecl); if (MD && MD->getHasThisParam()) { isBSCInstanceFunc = true; @@ -6621,7 +6621,7 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, ArrayRef Args, SourceLocation RParenLoc, Expr *Config, bool IsExecConfig, ADLCallKind UsesADL) { - bool IsColonColon = Fn->IsColonColon; + bool HasBSCScopeSpce = Fn->HasBSCScopeSpce; FunctionDecl *FDecl = dyn_cast_or_null(NDecl); unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0); @@ -6663,7 +6663,7 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, if (Result.isInvalid()) return ExprError(); Fn = Result.get(); - Fn->IsColonColon = IsColonColon; + Fn->HasBSCScopeSpce = HasBSCScopeSpce; // Check for a valid function type, but only if it is not a builtin which // requires custom type checking. These will be handled by diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 5bb952a02dea..75e8e350bd48 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1276,450 +1276,6 @@ static QualType ConvertConstrainedAutoDeclSpecToType(Sema &S, DeclSpec &DS, TemplateArgs); } -QualType Sema::GetTypeForDeclSpec(DeclSpec &BSCScopeSpec) { - DeclSpec &DS = BSCScopeSpec; - - QualType Result; - switch (DS.getTypeSpecType()) { - case DeclSpec::TST_void: - Result = Context.VoidTy; - break; - case DeclSpec::TST_char: - if (DS.getTypeSpecSign() == TypeSpecifierSign::Unspecified) - Result = Context.CharTy; - else if (DS.getTypeSpecSign() == TypeSpecifierSign::Signed) - Result = Context.SignedCharTy; - else { - assert(DS.getTypeSpecSign() == TypeSpecifierSign::Unsigned && - "Unknown TSS value"); - Result = Context.UnsignedCharTy; - } - break; - case DeclSpec::TST_wchar: - if (DS.getTypeSpecSign() == TypeSpecifierSign::Unspecified) - Result = Context.WCharTy; - else if (DS.getTypeSpecSign() == TypeSpecifierSign::Signed) { - Diag(DS.getTypeSpecSignLoc(), diag::ext_wchar_t_sign_spec) - << DS.getSpecifierName(DS.getTypeSpecType(), - Context.getPrintingPolicy()); - Result = Context.getSignedWCharType(); - } else { - assert(DS.getTypeSpecSign() == TypeSpecifierSign::Unsigned && - "Unknown TSS value"); - Diag(DS.getTypeSpecSignLoc(), diag::ext_wchar_t_sign_spec) - << DS.getSpecifierName(DS.getTypeSpecType(), - Context.getPrintingPolicy()); - Result = Context.getUnsignedWCharType(); - } - break; - case DeclSpec::TST_char8: - assert(DS.getTypeSpecSign() == TypeSpecifierSign::Unspecified && - "Unknown TSS value"); - Result = Context.Char8Ty; - break; - case DeclSpec::TST_char16: - assert(DS.getTypeSpecSign() == TypeSpecifierSign::Unspecified && - "Unknown TSS value"); - Result = Context.Char16Ty; - break; - case DeclSpec::TST_char32: - assert(DS.getTypeSpecSign() == TypeSpecifierSign::Unspecified && - "Unknown TSS value"); - Result = Context.Char32Ty; - break; - case DeclSpec::TST_int: { - if (DS.getTypeSpecSign() != TypeSpecifierSign::Unsigned) { - switch (DS.getTypeSpecWidth()) { - case TypeSpecifierWidth::Unspecified: - Result = Context.IntTy; - break; - case TypeSpecifierWidth::Short: - Result = Context.ShortTy; - break; - case TypeSpecifierWidth::Long: - Result = Context.LongTy; - break; - case TypeSpecifierWidth::LongLong: - Result = Context.LongLongTy; - - // 'long long' is a C99 or C++11 feature. - if (!getLangOpts().C99) { - if (getLangOpts().CPlusPlus) - Diag(DS.getTypeSpecWidthLoc(), - getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong); - else - Diag(DS.getTypeSpecWidthLoc(), diag::ext_c99_longlong); - } - break; - } - } else { - switch (DS.getTypeSpecWidth()) { - case TypeSpecifierWidth::Unspecified: - Result = Context.UnsignedIntTy; - break; - case TypeSpecifierWidth::Short: - Result = Context.UnsignedShortTy; - break; - case TypeSpecifierWidth::Long: - Result = Context.UnsignedLongTy; - break; - case TypeSpecifierWidth::LongLong: - Result = Context.UnsignedLongLongTy; - - // 'long long' is a C99 or C++11 feature. - if (!getLangOpts().C99) { - if (getLangOpts().CPlusPlus) - Diag(DS.getTypeSpecWidthLoc(), - getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong); - else - Diag(DS.getTypeSpecWidthLoc(), diag::ext_c99_longlong); - } - break; - } - } - break; - } - case DeclSpec::TST_extint: { - if (!Context.getTargetInfo().hasExtIntType()) - Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) - << "_ExtInt"; - Result = - BuildExtIntType(DS.getTypeSpecSign() == TypeSpecifierSign::Unsigned, - DS.getRepAsExpr(), DS.getBeginLoc()); - if (Result.isNull()) { - Result = Context.IntTy; - } - break; - } - case DeclSpec::TST_accum: { - switch (DS.getTypeSpecWidth()) { - case TypeSpecifierWidth::Short: - Result = Context.ShortAccumTy; - break; - case TypeSpecifierWidth::Unspecified: - Result = Context.AccumTy; - break; - case TypeSpecifierWidth::Long: - Result = Context.LongAccumTy; - break; - case TypeSpecifierWidth::LongLong: - llvm_unreachable("Unable to specify long long as _Accum width"); - } - - if (DS.getTypeSpecSign() == TypeSpecifierSign::Unsigned) - Result = Context.getCorrespondingUnsignedType(Result); - - if (DS.isTypeSpecSat()) - Result = Context.getCorrespondingSaturatedType(Result); - - break; - } - case DeclSpec::TST_fract: { - switch (DS.getTypeSpecWidth()) { - case TypeSpecifierWidth::Short: - Result = Context.ShortFractTy; - break; - case TypeSpecifierWidth::Unspecified: - Result = Context.FractTy; - break; - case TypeSpecifierWidth::Long: - Result = Context.LongFractTy; - break; - case TypeSpecifierWidth::LongLong: - llvm_unreachable("Unable to specify long long as _Fract width"); - } - - if (DS.getTypeSpecSign() == TypeSpecifierSign::Unsigned) - Result = Context.getCorrespondingUnsignedType(Result); - - if (DS.isTypeSpecSat()) - Result = Context.getCorrespondingSaturatedType(Result); - - break; - } - case DeclSpec::TST_int128: - if (!Context.getTargetInfo().hasInt128Type() && - !getLangOpts().SYCLIsDevice && - !(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice)) - Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) - << "__int128"; - if (DS.getTypeSpecSign() == TypeSpecifierSign::Unsigned) - Result = Context.UnsignedInt128Ty; - else - Result = Context.Int128Ty; - break; - case DeclSpec::TST_float16: - // CUDA host and device may have different _Float16 support, therefore - // do not diagnose _Float16 usage to avoid false alarm. - // ToDo: more precise diagnostics for CUDA. - if (!Context.getTargetInfo().hasFloat16Type() && !getLangOpts().CUDA && - !(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice)) - Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) - << "_Float16"; - Result = Context.Float16Ty; - break; - case DeclSpec::TST_half: Result = Context.HalfTy; break; - case DeclSpec::TST_BFloat16: - if (!Context.getTargetInfo().hasBFloat16Type()) - Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) - << "__bf16"; - Result = Context.BFloat16Ty; - break; - case DeclSpec::TST_float: Result = Context.FloatTy; break; - case DeclSpec::TST_double: - if (DS.getTypeSpecWidth() == TypeSpecifierWidth::Long) - Result = Context.LongDoubleTy; - else - Result = Context.DoubleTy; - break; - case DeclSpec::TST_float128: - if (!Context.getTargetInfo().hasFloat128Type() && - !getLangOpts().SYCLIsDevice && - !(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice)) - Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) - << "__float128"; - Result = Context.Float128Ty; - break; - case DeclSpec::TST_bool: - Result = Context.BoolTy; // _Bool or bool - break; - case DeclSpec::TST_decimal32: // _Decimal32 - case DeclSpec::TST_decimal64: // _Decimal64 - case DeclSpec::TST_decimal128: // _Decimal128 - Diag(DS.getTypeSpecTypeLoc(), diag::err_decimal_unsupported); - Result = Context.IntTy; - break; - case DeclSpec::TST_class: - case DeclSpec::TST_enum: - case DeclSpec::TST_union: - case DeclSpec::TST_struct: - case DeclSpec::TST_interface: { - TagDecl *D = dyn_cast_or_null(DS.getRepAsDecl()); - if (!D) { - // This can happen in C++ with ambiguous lookups. - Result = Context.IntTy; - break; - } - - // If the type is deprecated or unavailable, diagnose it. - DiagnoseUseOfDecl(D, DS.getTypeSpecTypeNameLoc()); - - assert(DS.getTypeSpecWidth() == TypeSpecifierWidth::Unspecified && - DS.getTypeSpecComplex() == 0 && - DS.getTypeSpecSign() == TypeSpecifierSign::Unspecified && - "No qualifiers on tag names!"); - - // TypeQuals handled by caller. - Result = Context.getTypeDeclType(D); - - // In both C and C++, make an ElaboratedType. - ElaboratedTypeKeyword Keyword - = ElaboratedType::getKeywordForTypeSpec(DS.getTypeSpecType()); - Result = getElaboratedType(Keyword, DS.getTypeSpecScope(), Result, - DS.isTypeSpecOwned() ? D : nullptr); - break; - } - case DeclSpec::TST_typename: { - assert(DS.getTypeSpecWidth() == TypeSpecifierWidth::Unspecified && - DS.getTypeSpecComplex() == 0 && - DS.getTypeSpecSign() == TypeSpecifierSign::Unspecified && - "Can't handle qualifiers on typedef names yet!"); - Result = GetTypeFromParser(DS.getRepAsType()); - - // TypeQuals handled by caller. - break; - } - case DeclSpec::TST_typeofType: - // FIXME: Preserve type source info. - Result = GetTypeFromParser(DS.getRepAsType()); - assert(!Result.isNull() && "Didn't get a type for typeof?"); - if (!Result->isDependentType()) - if (const TagType *TT = Result->getAs()) - DiagnoseUseOfDecl(TT->getDecl(), DS.getTypeSpecTypeLoc()); - // TypeQuals handled by caller. - Result = Context.getTypeOfType(Result); - break; - case DeclSpec::TST_typeofExpr: { - Expr *E = DS.getRepAsExpr(); - assert(E && "Didn't get an expression for typeof?"); - // TypeQuals handled by caller. - Result = BuildTypeofExprType(E, DS.getTypeSpecTypeLoc()); - if (Result.isNull()) { - Result = Context.IntTy; - } - break; - } - case DeclSpec::TST_decltype: { - Expr *E = DS.getRepAsExpr(); - assert(E && "Didn't get an expression for decltype?"); - // TypeQuals handled by caller. - Result = BuildDecltypeType(E, DS.getTypeSpecTypeLoc()); - if (Result.isNull()) { - Result = Context.IntTy; - } - break; - } - case DeclSpec::TST_underlyingType: - Result = GetTypeFromParser(DS.getRepAsType()); - assert(!Result.isNull() && "Didn't get a type for __underlying_type?"); - Result = BuildUnaryTransformType(Result, - UnaryTransformType::EnumUnderlyingType, - DS.getTypeSpecTypeLoc()); - if (Result.isNull()) { - Result = Context.IntTy; - } - break; - - case DeclSpec::TST_auto: - if (DS.isConstrainedAuto()) { - Result = ConvertConstrainedAutoDeclSpecToType(*this, DS, - AutoTypeKeyword::Auto); - break; - } - Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false); - break; - - case DeclSpec::TST_auto_type: - Result = Context.getAutoType(QualType(), AutoTypeKeyword::GNUAutoType, false); - break; - - case DeclSpec::TST_decltype_auto: - if (DS.isConstrainedAuto()) { - Result = - ConvertConstrainedAutoDeclSpecToType(*this, DS, - AutoTypeKeyword::DecltypeAuto); - break; - } - Result = Context.getAutoType(QualType(), AutoTypeKeyword::DecltypeAuto, - /*IsDependent*/ false); - break; - - case DeclSpec::TST_unknown_anytype: - Result = Context.UnknownAnyTy; - break; - - case DeclSpec::TST_atomic: - Result = GetTypeFromParser(DS.getRepAsType()); - assert(!Result.isNull() && "Didn't get a type for _Atomic?"); - Result = BuildAtomicType(Result, DS.getTypeSpecTypeLoc()); - if (Result.isNull()) { - Result = Context.IntTy; - } - break; - -#define GENERIC_IMAGE_TYPE(ImgType, Id) \ - case DeclSpec::TST_##ImgType##_t: \ - switch (getImageAccess(DS.getAttributes())) { \ - case OpenCLAccessAttr::Keyword_write_only: \ - Result = Context.Id##WOTy; \ - break; \ - case OpenCLAccessAttr::Keyword_read_write: \ - Result = Context.Id##RWTy; \ - break; \ - case OpenCLAccessAttr::Keyword_read_only: \ - Result = Context.Id##ROTy; \ - break; \ - case OpenCLAccessAttr::SpellingNotCalculated: \ - llvm_unreachable("Spelling not yet calculated"); \ - } \ - break; -#include "clang/Basic/OpenCLImageTypes.def" - - case DeclSpec::TST_error: - Result = Context.IntTy; - break; - } - - bool IsFixedPointType = DS.getTypeSpecType() == DeclSpec::TST_accum || - DS.getTypeSpecType() == DeclSpec::TST_fract; - - // Only fixed point types can be saturated - if (DS.isTypeSpecSat() && !IsFixedPointType) - Diag(DS.getTypeSpecSatLoc(), diag::err_invalid_saturation_spec) - << DS.getSpecifierName(DS.getTypeSpecType(), - Context.getPrintingPolicy()); - - // Handle complex types. - if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) { - if (getLangOpts().Freestanding) - Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex); - Result = Context.getComplexType(Result); - } else if (DS.isTypeAltiVecVector()) { - unsigned typeSize = static_cast(Context.getTypeSize(Result)); - assert(typeSize > 0 && "type size for vector must be greater than 0 bits"); - VectorType::VectorKind VecKind = VectorType::AltiVecVector; - if (DS.isTypeAltiVecPixel()) - VecKind = VectorType::AltiVecPixel; - else if (DS.isTypeAltiVecBool()) - VecKind = VectorType::AltiVecBool; - Result = Context.getVectorType(Result, 128/typeSize, VecKind); - } - - // FIXME: Imaginary. - if (DS.getTypeSpecComplex() == DeclSpec::TSC_imaginary) - Diag(DS.getTypeSpecComplexLoc(), diag::err_imaginary_not_supported); - - // Apply const/volatile/restrict qualifiers to T. - if (unsigned TypeQuals = DS.getTypeQualifiers()) { - // Warn about CV qualifiers on function types. - // C99 6.7.3p8: - // If the specification of a function type includes any type qualifiers, - // the behavior is undefined. - // C++11 [dcl.fct]p7: - // The effect of a cv-qualifier-seq in a function declarator is not the - // same as adding cv-qualification on top of the function type. In the - // latter case, the cv-qualifiers are ignored. - if (Result->isFunctionType()) { - diagnoseAndRemoveTypeQualifiers( - *this, DS, TypeQuals, Result, DeclSpec::TQ_const | DeclSpec::TQ_volatile, - getLangOpts().CPlusPlus - ? diag::warn_typecheck_function_qualifiers_ignored - : diag::warn_typecheck_function_qualifiers_unspecified); - // No diagnostic for 'restrict' or '_Atomic' applied to a - // function type; we'll diagnose those later, in BuildQualifiedType. - } - - // C++11 [dcl.ref]p1: - // Cv-qualified references are ill-formed except when the - // cv-qualifiers are introduced through the use of a typedef-name - // or decltype-specifier, in which case the cv-qualifiers are ignored. - // - // There don't appear to be any other contexts in which a cv-qualified - // reference type could be formed, so the 'ill-formed' clause here appears - // to never happen. - if (TypeQuals && Result->isReferenceType()) { - diagnoseAndRemoveTypeQualifiers( - *this, DS, TypeQuals, Result, - DeclSpec::TQ_const | DeclSpec::TQ_volatile | DeclSpec::TQ_atomic, - diag::warn_typecheck_reference_qualifiers); - } - - // C90 6.5.3 constraints: "The same type qualifier shall not appear more - // than once in the same specifier-list or qualifier-list, either directly - // or via one or more typedefs." - if (!getLangOpts().C99 && !getLangOpts().CPlusPlus - && TypeQuals & Result.getCVRQualifiers()) { - if (TypeQuals & DeclSpec::TQ_const && Result.isConstQualified()) { - Diag(DS.getConstSpecLoc(), diag::ext_duplicate_declspec) - << "const"; - } - - if (TypeQuals & DeclSpec::TQ_volatile && Result.isVolatileQualified()) { - Diag(DS.getVolatileSpecLoc(), diag::ext_duplicate_declspec) - << "volatile"; - } - - // C90 doesn't have restrict nor _Atomic, so it doesn't force us to - // produce a warning in this case. - } - } - - assert(!Result.isNull() && "This function should not return a null type"); - return Result; -} - /// Convert the specified declspec to the appropriate type /// object. /// \param state Specifies the declarator containing the declaration specifier @@ -2281,7 +1837,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state, return Result; } -void Sema::ConvertBSCScopeSpecToType(Declarator &D, SourceLocation Loc) { +QualType Sema::ConvertBSCScopeSpecToType(Declarator &D, SourceLocation Loc, + bool AddToContextMap) { TypeProcessingState state(*this, D); bool BSCMethodFlag = true; QualType T = ConvertDeclSpecToType(state, BSCMethodFlag); @@ -2289,7 +1846,7 @@ void Sema::ConvertBSCScopeSpecToType(Declarator &D, SourceLocation Loc) { if (T->isIncompleteType(&Def)) { BoundTypeDiagnoser<> Diagnoser(diag::err_typecheck_decl_incomplete_type); Diagnoser.diagnose(*this, Loc, T); - } else { + } else if (AddToContextMap) { D.setExtendedType(T); const Type *BasedType = T.getCanonicalType().getTypePtr(); // build declcontext map @@ -2314,6 +1871,7 @@ void Sema::ConvertBSCScopeSpecToType(Declarator &D, SourceLocation Loc) { } } } + return T; } static std::string getPrintableNameForEntity(DeclarationName Entity) { diff --git a/clang/test/BSC/Method/BuiltInType/int_static_function_call.cbs b/clang/test/BSC/Method/BuiltInType/int_static_function_call.cbs new file mode 100644 index 000000000000..9c747a9ed771 --- /dev/null +++ b/clang/test/BSC/Method/BuiltInType/int_static_function_call.cbs @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -verify %s +// expected-no-diagnostics + +int int::getA() { + return 2; +} + +int main() { + int::getA(); + int a = int::getA(); + return a - 2; +} \ No newline at end of file diff --git a/clang/test/BSC/Method/Struct/struct_static_function_call.cbs b/clang/test/BSC/Method/Struct/struct_static_function_call.cbs new file mode 100644 index 000000000000..995c843391ff --- /dev/null +++ b/clang/test/BSC/Method/Struct/struct_static_function_call.cbs @@ -0,0 +1,19 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +struct Foo { + int a; +}; + +int struct Foo::getA() { + return 1; +} + + +int main() { + struct Foo foo = {.a = 1}; + struct Foo::getA(); + int a = struct Foo::getA(); + return a - 1; +} \ No newline at end of file -- Gitee