From f73c0abd977e4beb496e63f1b0169c894e92248c Mon Sep 17 00:00:00 2001 From: liuzhenwei Date: Mon, 26 Jun 2023 17:24:10 +0800 Subject: [PATCH 1/2] add owned type qualifier Add owned type qulifier like const so we can generate QualType in ast as follows: int owned a; >>>>'owned int' int* owned p1; >>>>'int *owned' int* owned* owned p2; >>>>'int *owned *owned' --- clang/include/clang/AST/Type.h | 57 +++++++++---- clang/include/clang/Basic/TokenKinds.def | 4 + clang/include/clang/Sema/DeclSpec.h | 33 ++++---- clang/lib/AST/TypePrinter.cpp | 5 ++ clang/lib/Basic/IdentifierTable.cpp | 83 ++++++++++--------- clang/lib/Parse/ParseDecl.cpp | 13 +++ clang/lib/Sema/DeclSpec.cpp | 4 + clang/lib/Sema/SemaOverload.cpp | 8 +- clang/test/BSC/Ownership/owned_ast_check.cbs | 61 ++++++++++++++ .../SemaTemplate/address_space-dependent.cpp | 4 +- 10 files changed, 199 insertions(+), 73 deletions(-) create mode 100644 clang/test/BSC/Ownership/owned_ast_check.cbs diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 15c470915bc7..20be635a02d4 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -66,7 +66,7 @@ class TemplateParameterList; class Type; enum { - TypeAlignmentInBits = 4, + TypeAlignmentInBits = 5, TypeAlignment = 1 << TypeAlignmentInBits }; @@ -150,7 +150,8 @@ public: Const = 0x1, Restrict = 0x2, Volatile = 0x4, - CVRMask = Const | Volatile | Restrict + Owned = 0x8, + CVRMask = Const | Volatile | Restrict | Owned }; enum GC { @@ -183,11 +184,11 @@ public: enum { /// The maximum supported address space number. - /// 23 bits should be enough for anyone. - MaxAddressSpace = 0x7fffffu, + /// 22 bits should be enough for anyone. + MaxAddressSpace = 0x3fffffu, /// The width of the "fast" qualifier mask. - FastWidth = 3, + FastWidth = 4, /// The fast qualifier mask. FastMask = (1 << FastWidth) - 1 @@ -271,6 +272,16 @@ public: return Qs; } + bool hasOwned() const { return Mask & Owned; } + bool hasOnlyOwned() const { return Mask == Owned; } + void removeOwned() { Mask &= ~Owned; } + void addOwned() { Mask |= Owned; } + Qualifiers withOwned() const { + Qualifiers Qs = *this; + Qs.addOwned(); + return Qs; + } + bool hasVolatile() const { return Mask & Volatile; } bool hasOnlyVolatile() const { return Mask == Volatile; } void removeVolatile() { Mask &= ~Volatile; } @@ -609,19 +620,19 @@ public: } private: - // bits: |0 1 2|3|4 .. 5|6 .. 8|9 ... 31| - // |C R V|U|GCAttr|Lifetime|AddressSpace| + // bits: |0 1 2 3|4|5 .. 6|7 .. 9|10 ... 31| + // |C R V O|U|GCAttr|Lifetime|AddressSpace| uint32_t Mask = 0; - static const uint32_t UMask = 0x8; - static const uint32_t UShift = 3; - static const uint32_t GCAttrMask = 0x30; - static const uint32_t GCAttrShift = 4; - static const uint32_t LifetimeMask = 0x1C0; - static const uint32_t LifetimeShift = 6; + static const uint32_t UMask = 0x10; + static const uint32_t UShift = 4; + static const uint32_t GCAttrMask = 0x60; + static const uint32_t GCAttrShift = 5; + static const uint32_t LifetimeMask = 0x380; + static const uint32_t LifetimeShift = 7; static const uint32_t AddressSpaceMask = ~(CVRMask | UMask | GCAttrMask | LifetimeMask); - static const uint32_t AddressSpaceShift = 9; + static const uint32_t AddressSpaceShift = 10; }; class QualifiersAndAtomic { @@ -637,16 +648,19 @@ public: bool hasVolatile() const { return Quals.hasVolatile(); } bool hasConst() const { return Quals.hasConst(); } + bool hasOwned() const { return Quals.hasOwned(); } bool hasRestrict() const { return Quals.hasRestrict(); } bool hasAtomic() const { return HasAtomic; } void addVolatile() { Quals.addVolatile(); } void addConst() { Quals.addConst(); } + void addOwned() { Quals.addOwned(); } void addRestrict() { Quals.addRestrict(); } void addAtomic() { HasAtomic = true; } void removeVolatile() { Quals.removeVolatile(); } void removeConst() { Quals.removeConst(); } + void removeOwned() { Quals.removeOwned(); } void removeRestrict() { Quals.removeRestrict(); } void removeAtomic() { HasAtomic = false; } @@ -654,6 +668,7 @@ public: return {Quals.withVolatile(), HasAtomic}; } QualifiersAndAtomic withConst() { return {Quals.withConst(), HasAtomic}; } + QualifiersAndAtomic withOwned() { return {Quals.withOwned(), HasAtomic}; } QualifiersAndAtomic withRestrict() { return {Quals.withRestrict(), HasAtomic}; } @@ -906,6 +921,14 @@ public: return withFastQualifiers(Qualifiers::Const); } + /// Add the `owned` type qualifier to this QualType. + void addOwned() { + addFastQualifiers(Qualifiers::Owned); + } + QualType withOwned() const { + return withFastQualifiers(Qualifiers::Owned); + } + /// Add the `volatile` type qualifier to this QualType. void addVolatile() { addFastQualifiers(Qualifiers::Volatile); @@ -933,6 +956,7 @@ public: } void removeLocalConst(); + void removeLocalOwned(); void removeLocalVolatile(); void removeLocalRestrict(); void removeLocalCVRQualifiers(unsigned Mask); @@ -6654,6 +6678,11 @@ inline void QualType::removeLocalConst() { removeLocalFastQualifiers(Qualifiers::Const); } + +inline void QualType::removeLocalOwned() { + removeLocalFastQualifiers(Qualifiers::Owned); +} + inline void QualType::removeLocalRestrict() { removeLocalFastQualifiers(Qualifiers::Restrict); } diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 7fb354506c55..4450ed17894b 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -280,6 +280,7 @@ PUNCTUATOR(caretcaret, "^^") // HALFSUPPORT - This is a keyword if 'half' is a built-in type // WCHARSUPPORT - This is a keyword if 'wchar_t' is a built-in type // CHAR8SUPPORT - This is a keyword if 'char8_t' is a built-in type +// KEYBSC - This is a keyword introduced to BSC // KEYWORD(auto , KEYALL) KEYWORD(break , KEYALL) @@ -459,6 +460,9 @@ ALIAS("async", __async, KEYBSC) // GNU Extensions (outside impl-reserved namespace) KEYWORD(typeof , KEYGNU) +// BSC Keywords: +KEYWORD(owned , KEYBSC) + // MS Extensions KEYWORD(__FUNCDNAME__ , KEYMS) KEYWORD(__FUNCSIG__ , KEYMS) diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 159d70d96134..5e461779366c 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -333,10 +333,11 @@ public: TQ_const = 1, TQ_restrict = 2, TQ_volatile = 4, - TQ_unaligned = 8, + TQ_owned = 8, + TQ_unaligned = 16, // This has no corresponding Qualifiers::TQ value, because it's not treated // as a qualifier in our type system. - TQ_atomic = 16 + TQ_atomic = 32 }; /// ParsedSpecifiers - Flags to query which specifiers were applied. This is @@ -370,7 +371,7 @@ private: unsigned ConstrainedAuto : 1; // type-qualifiers - unsigned TypeQualifiers : 5; // Bitwise OR of TQ. + unsigned TypeQualifiers : 6; // Bitwise OR of TQ. // function-specifier unsigned FS_inline_specified : 1; @@ -419,9 +420,8 @@ private: SourceLocation TSTNameLoc; SourceRange TypeofParensRange; SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc, - TQ_unalignedLoc; - SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc, - FS_asyncLoc; + TQ_unalignedLoc, TQ_ownedLoc; + SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc, FS_asyncLoc; SourceLocation FS_explicitCloseParenLoc; SourceLocation FS_forceinlineLoc; SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc; @@ -581,6 +581,7 @@ public: /// getTypeQualifiers - Return a set of TQs. unsigned getTypeQualifiers() const { return TypeQualifiers; } SourceLocation getConstSpecLoc() const { return TQ_constLoc; } + SourceLocation getOwnedSpecLoc() const { return TQ_ownedLoc; } SourceLocation getRestrictSpecLoc() const { return TQ_restrictLoc; } SourceLocation getVolatileSpecLoc() const { return TQ_volatileLoc; } SourceLocation getAtomicSpecLoc() const { return TQ_atomicLoc; } @@ -591,6 +592,7 @@ public: void ClearTypeQualifiers() { TypeQualifiers = 0; TQ_constLoc = SourceLocation(); + TQ_ownedLoc = SourceLocation(); TQ_restrictLoc = SourceLocation(); TQ_volatileLoc = SourceLocation(); TQ_atomicLoc = SourceLocation(); @@ -1245,12 +1247,15 @@ struct DeclaratorChunk { ParsedAttributesView AttrList; struct PointerTypeInfo { - /// The type qualifiers: const/volatile/restrict/unaligned/atomic. - unsigned TypeQuals : 5; + /// The type qualifiers: const/volatile/restrict/owned/unaligned/atomic. + unsigned TypeQuals : 6; /// The location of the const-qualifier, if any. SourceLocation ConstQualLoc; + /// The location of the owned-qualifier, if any. + SourceLocation OwnedQualLoc; + /// The location of the volatile-qualifier, if any. SourceLocation VolatileQualLoc; @@ -1278,8 +1283,8 @@ struct DeclaratorChunk { struct ArrayTypeInfo { /// The type qualifiers for the array: - /// const/volatile/restrict/__unaligned/_Atomic. - unsigned TypeQuals : 5; + /// const/volatile/restrict/owned/__unaligned/_Atomic. + unsigned TypeQuals : 6; /// True if this dimension included the 'static' keyword. unsigned hasStatic : 1; @@ -1566,16 +1571,16 @@ struct DeclaratorChunk { struct BlockPointerTypeInfo { /// For now, sema will catch these as invalid. - /// The type qualifiers: const/volatile/restrict/__unaligned/_Atomic. - unsigned TypeQuals : 5; + /// The type qualifiers: const/volatile/restrict/owned/__unaligned/_Atomic. + unsigned TypeQuals : 6; void destroy() { } }; struct MemberPointerTypeInfo { - /// The type qualifiers: const/volatile/restrict/__unaligned/_Atomic. - unsigned TypeQuals : 5; + /// The type qualifiers: const/volatile/restrict/owned/__unaligned/_Atomic. + unsigned TypeQuals : 6; /// Location of the '*' token. SourceLocation StarLoc; // CXXScopeSpec has a constructor, so it can't be a direct member. diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 6b13d3806037..da9b09f62540 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -160,6 +160,11 @@ static void AppendTypeQualList(raw_ostream &OS, unsigned TypeQuals, OS << "const"; appendSpace = true; } + if (TypeQuals & Qualifiers::Owned) { + if (appendSpace) OS << ' '; + OS << "owned"; + appendSpace = true; + } if (TypeQuals & Qualifiers::Volatile) { if (appendSpace) OS << ' '; OS << "volatile"; diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index 8dffb5ad016c..26dc83937930 100644 --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -82,47 +82,47 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts, // Constants for TokenKinds.def namespace { -enum { - KEYC99 = 0x1, - KEYCXX = 0x2, - KEYCXX11 = 0x4, - KEYGNU = 0x8, - KEYMS = 0x10, - BOOLSUPPORT = 0x20, - KEYALTIVEC = 0x40, - KEYNOCXX = 0x80, - KEYBORLAND = 0x100, - KEYOPENCLC = 0x200, - KEYC11 = 0x400, - KEYNOMS18 = 0x800, - KEYNOOPENCL = 0x1000, - WCHARSUPPORT = 0x2000, - HALFSUPPORT = 0x4000, - CHAR8SUPPORT = 0x8000, - KEYCONCEPTS = 0x10000, - KEYOBJC = 0x20000, - KEYZVECTOR = 0x40000, - KEYCOROUTINES = 0x80000, - KEYMODULES = 0x100000, - KEYCXX20 = 0x200000, - KEYOPENCLCXX = 0x400000, - KEYMSCOMPAT = 0x800000, - KEYSYCL = 0x1000000, - KEYCUDA = 0x2000000, - KEYBSC = 0x3000000, - KEYMAX = KEYCUDA, // The maximum key - KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20, - KEYALL = (KEYMAX | (KEYMAX - 1)) & ~KEYNOMS18 & - ~KEYNOOPENCL // KEYNOMS18 and KEYNOOPENCL are used to exclude. -}; - -/// How a keyword is treated in the selected standard. -enum KeywordStatus { - KS_Disabled, // Disabled - KS_Extension, // Is an extension - KS_Enabled, // Enabled - KS_Future // Is a keyword in future standard -}; + enum { + KEYC99 = 0x1, + KEYCXX = 0x2, + KEYCXX11 = 0x4, + KEYGNU = 0x8, + KEYMS = 0x10, + BOOLSUPPORT = 0x20, + KEYALTIVEC = 0x40, + KEYNOCXX = 0x80, + KEYBORLAND = 0x100, + KEYOPENCLC = 0x200, + KEYC11 = 0x400, + KEYNOMS18 = 0x800, + KEYNOOPENCL = 0x1000, + WCHARSUPPORT = 0x2000, + HALFSUPPORT = 0x4000, + CHAR8SUPPORT = 0x8000, + KEYCONCEPTS = 0x10000, + KEYOBJC = 0x20000, + KEYZVECTOR = 0x40000, + KEYCOROUTINES = 0x80000, + KEYMODULES = 0x100000, + KEYCXX20 = 0x200000, + KEYOPENCLCXX = 0x400000, + KEYMSCOMPAT = 0x800000, + KEYSYCL = 0x1000000, + KEYCUDA = 0x2000000, + KEYBSC = 0x4000000, + KEYMAX = KEYBSC, // The maximum key + KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20, + KEYALL = (KEYMAX | (KEYMAX-1)) & ~KEYNOMS18 & + ~KEYNOOPENCL // KEYNOMS18 and KEYNOOPENCL are used to exclude. + }; + + /// How a keyword is treated in the selected standard. + enum KeywordStatus { + KS_Disabled, // Disabled + KS_Extension, // Is an extension + KS_Enabled, // Enabled + KS_Future // Is a keyword in future standard + }; } // namespace @@ -165,6 +165,7 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts, return KS_Enabled; if (LangOpts.CUDA && (Flags & KEYCUDA)) return KS_Enabled; + if (LangOpts.BSC && (Flags & KEYBSC)) return KS_Enabled; return KS_Disabled; } diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 601d8f2293b7..e26e6f247f6e 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -4238,6 +4238,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, getLangOpts()); break; + // owned-qualifier: + case tok::kw_owned: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_owned, Loc, PrevSpec, DiagID, + getLangOpts()); + break; + // C++ typename-specifier: case tok::kw_typename: if (TryAnnotateTypeOrScopeToken()) { @@ -5468,6 +5474,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw_const: case tok::kw_volatile: case tok::kw_restrict: + case tok::kw_owned: case tok::kw__Sat: // function-specifier @@ -5772,6 +5779,12 @@ void Parser::ParseTypeQualifierListOpt( isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID, getLangOpts()); break; + + // owned-qualifier: + case tok::kw_owned: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_owned, Loc, PrevSpec, DiagID, + getLangOpts()); + break; case tok::kw__Atomic: if (!AtomicAllowed) goto DoneWithTypeQuals; diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index c9c25d7331c7..1a3cb6629bf1 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -426,6 +426,8 @@ void DeclSpec::forEachCVRUQualifier( llvm::function_ref Handle) { if (TypeQualifiers & TQ_const) Handle(TQ_const, "const", TQ_constLoc); + if (TypeQualifiers & TQ_owned) + Handle(TQ_owned, "owned", TQ_ownedLoc); if (TypeQualifiers & TQ_volatile) Handle(TQ_volatile, "volatile", TQ_volatileLoc); if (TypeQualifiers & TQ_restrict) @@ -608,6 +610,7 @@ const char *DeclSpec::getSpecifierName(TQ T) { switch (T) { case DeclSpec::TQ_unspecified: return "unspecified"; case DeclSpec::TQ_const: return "const"; + case DeclSpec::TQ_owned: return "owned"; case DeclSpec::TQ_restrict: return "restrict"; case DeclSpec::TQ_volatile: return "volatile"; case DeclSpec::TQ_atomic: return "_Atomic"; @@ -976,6 +979,7 @@ bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc) { switch (T) { case TQ_unspecified: break; case TQ_const: TQ_constLoc = Loc; return false; + case TQ_owned: TQ_ownedLoc = Loc; return false; case TQ_restrict: TQ_restrictLoc = Loc; return false; case TQ_volatile: TQ_volatileLoc = Loc; return false; case TQ_unaligned: TQ_unalignedLoc = Loc; return false; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index c7e1c7775a03..fb0cf3101fa5 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -6412,7 +6412,7 @@ void Sema::AddOverloadCandidate( NamedDecl *ND = Function; if (auto *SpecInfo = Function->getTemplateSpecializationInfo()) ND = SpecInfo->getTemplate(); - + if (ND->getFormalLinkage() == Linkage::InternalLinkage) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_module_mismatched; @@ -7977,6 +7977,7 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty, unsigned BaseCVR = PointeeTy.getCVRQualifiers(); bool hasVolatile = VisibleQuals.hasVolatile(); bool hasRestrict = VisibleQuals.hasRestrict(); + bool hasOwned = VisibleQuals.hasOwned(); // Iterate through all strict supersets of BaseCVR. for (unsigned CVR = BaseCVR+1; CVR <= Qualifiers::CVRMask; ++CVR) { @@ -7984,6 +7985,9 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty, // Skip over volatile if no volatile found anywhere in the types. if ((CVR & Qualifiers::Volatile) && !hasVolatile) continue; + // Skip over owned if no owned found anywhere in the types. + if ((CVR & Qualifiers::Owned) && !hasOwned) continue; + // Skip over restrict if no restrict found anywhere in the types, or if // the type cannot be restrict-qualified. if ((CVR & Qualifiers::Restrict) && @@ -9677,7 +9681,7 @@ static bool canCompareFunctionConstraints(Sema &S, const OverloadCandidate &Cand1, const OverloadCandidate &Cand2) { // FIXME: Per P2113R0 we also need to compare the template parameter lists - // when comparing template functions. + // when comparing template functions. if (Cand1.Function && Cand2.Function && Cand1.Function->hasPrototype() && Cand2.Function->hasPrototype()) { auto *PT1 = cast(Cand1.Function->getFunctionType()); diff --git a/clang/test/BSC/Ownership/owned_ast_check.cbs b/clang/test/BSC/Ownership/owned_ast_check.cbs new file mode 100644 index 000000000000..ba586433672f --- /dev/null +++ b/clang/test/BSC/Ownership/owned_ast_check.cbs @@ -0,0 +1,61 @@ +// Test without serialization: +// RUN: %clang_cc1 -ast-dump %s \ +// RUN: | FileCheck -strict-whitespace %s + +// Test without serialization: +// RUN: %clang_cc1 -ast-dump %s \ +// RUN: | FileCheck -strict-whitespace %s + +struct A { + owned int a; + int owned b; + int owned * c; + int* owned d; + int* owned* owned e; +}; +// CHECK: RecordDecl 0x{{[^ ]*}} {{.*}}struct A definition +// CHECK-NEXT: FieldDecl 0x{{[^ ]*}} {{.*}}a 'owned int' +// CHECK-NEXT: FieldDecl 0x{{[^ ]*}} {{.*}}b 'owned int' +// CHECK-NEXT: FieldDecl 0x{{[^ ]*}} {{.*}}c 'owned int *' +// CHECK-NEXT: FieldDecl 0x{{[^ ]*}} {{.*}}d 'int *owned' +// CHECK-NEXT: FieldDecl 0x{{[^ ]*}} {{.*}}e 'int *owned *owned' + +void ownedTest0() { + int owned a; + int* owned b; + int* owned * owned d; + return; +} +// CHECK: FunctionDecl 0x{{[^ ]*}} {{.*}}ownedTest0 'void (void)' +// CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} {{.*}} +// CHECK-NEXT: DeclStmt 0x{{[^ ]*}} {{.*}} +// CHECK-NEXT: VarDecl 0x{{[^ ]*}} {{.*}}a 'owned int' +// CHECK-NEXT: DeclStmt 0x{{[^ ]*}} {{.*}} +// CHECK-NEXT: VarDecl 0x{{[^ ]*}} {{.*}}b 'int *owned' +// CHECK-NEXT: DeclStmt 0x{{[^ ]*}} {{.*}} +// CHECK-NEXT: VarDecl 0x{{[^ ]*}} {{.*}}d 'int *owned *owned' +// CHECK-NEXT: ReturnStmt 0x{{[^ ]*}} {{.*}} + +int ownedTest1(owned int x, owned int* y, owned int* owned c, owned int* owned * d) { + return 0; +} +// CHECK: FunctionDecl 0x{{[^ ]*}} {{.*}}ownedTest1 'int (owned int, owned int *, owned int *owned, owned int *owned *)' +// CHECK-NEXT: ParmVarDecl 0x{{[^ ]*}} {{.*}}x 'owned int' +// CHECK-NEXT: ParmVarDecl 0x{{[^ ]*}} {{.*}}y 'owned int *' +// CHECK-NEXT: ParmVarDecl 0x{{[^ ]*}} {{.*}}c 'owned int *owned' +// CHECK-NEXT: ParmVarDecl 0x{{[^ ]*}} {{.*}}d 'owned int *owned *' +// CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} {{.*}} +// CHECK-NEXT: ReturnStmt 0x{{[^ ]*}} {{.*}} +// CHECK-NEXT: IntegerLiteral 0x{{[^ ]*}} {{.*}}'int' 0 + +int* owned ownedTest2(int* owned p) { + return p; +} +// CHECK: FunctionDecl 0x{{[^ ]*}} {{.*}}ownedTest2 'int *owned (int *owned)' +// CHECK-NEXT: ParmVarDecl 0x{{[^ ]*}} {{.*}}p 'int *owned' +// CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} {{.*}} +// CHECK-NEXT: ReturnStmt 0x{{[^ ]*}} {{.*}} +// CHECK-NEXT: ImplicitCastExpr 0x{{[^ ]*}} {{.*}}'int *' +// CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} {{.*}}'int *owned' + + diff --git a/clang/test/SemaTemplate/address_space-dependent.cpp b/clang/test/SemaTemplate/address_space-dependent.cpp index 682ab75c7692..94c7c6bdc353 100644 --- a/clang/test/SemaTemplate/address_space-dependent.cpp +++ b/clang/test/SemaTemplate/address_space-dependent.cpp @@ -43,7 +43,7 @@ void neg() { template void tooBig() { - __attribute__((address_space(I))) int *bounds; // expected-error {{address space is larger than the maximum supported (8388588)}} + __attribute__((address_space(I))) int *bounds; // expected-error {{address space is larger than the maximum supported (4194284)}} } template @@ -101,7 +101,7 @@ int main() { car<1, 2, 3>(); // expected-note {{in instantiation of function template specialization 'car<1, 2, 3>' requested here}} HasASTemplateFields<1> HASTF; neg<-1>(); // expected-note {{in instantiation of function template specialization 'neg<-1>' requested here}} - correct<0x7FFFEB>(); + correct<0x3FFFEB>(); tooBig<8388650>(); // expected-note {{in instantiation of function template specialization 'tooBig<8388650L>' requested here}} __attribute__((address_space(1))) char *x; -- Gitee From 8e23a9a5b3b3d743ee204bf40ae2409974f72f58 Mon Sep 17 00:00:00 2001 From: liuzhenwei Date: Wed, 28 Jun 2023 10:16:22 +0800 Subject: [PATCH 2/2] owned syntax check add syntax check on owned type: 1.global variable cannot be owned type or owned-like type 2.union or union field cannot be owned type or owned-like type 3.owned or owned-like type cannot be member of array 4.owned type op check 5.cast rules(implicit or CStyleCast) 6.functionPointer check rules --- clang/include/clang/AST/CanonicalType.h | 4 + clang/include/clang/AST/Type.h | 36 +++- .../clang/Basic/DiagnosticCommonKinds.td | 16 ++ .../clang/Basic/DiagnosticSemaKinds.td | 25 +++ clang/include/clang/Sema/DeclSpec.h | 5 +- clang/include/clang/Sema/Sema.h | 10 + clang/lib/AST/Type.cpp | 78 +++++++ clang/lib/Sema/SemaCast.cpp | 9 + clang/lib/Sema/SemaDecl.cpp | 13 ++ clang/lib/Sema/SemaExpr.cpp | 198 ++++++++++++++++++ clang/lib/Sema/SemaType.cpp | 10 +- clang/test/BSC/Ownership/hasOwnedFields.cbs | 22 ++ clang/test/BSC/Ownership/owned_CStyleCast.cbs | 29 +++ clang/test/BSC/Ownership/owned_arr.cbs | 23 ++ clang/test/BSC/Ownership/owned_ast_check.cbs | 6 +- clang/test/BSC/Ownership/owned_err_c.c | 6 + clang/test/BSC/Ownership/owned_funcPtr.cbs | 39 ++++ clang/test/BSC/Ownership/owned_funcPtr2.cbs | 14 ++ clang/test/BSC/Ownership/owned_global_err.cbs | 19 ++ .../BSC/Ownership/owned_global_pointer.cbs | 12 ++ .../BSC/Ownership/owned_global_typedef.cbs | 16 ++ clang/test/BSC/Ownership/owned_impCast.cbs | 29 +++ clang/test/BSC/Ownership/owned_init.cbs | 36 ++++ clang/test/BSC/Ownership/owned_pointer_op.cbs | 20 ++ clang/test/BSC/Ownership/owned_struct.c | 8 + clang/test/BSC/Ownership/owned_struct.cbs | 9 + clang/test/BSC/Ownership/owned_struct_c.h | 4 + clang/test/BSC/Ownership/owned_struct_cbs.h | 4 + clang/test/BSC/Ownership/owned_union_err.cbs | 32 +++ 29 files changed, 723 insertions(+), 9 deletions(-) create mode 100644 clang/test/BSC/Ownership/hasOwnedFields.cbs create mode 100644 clang/test/BSC/Ownership/owned_CStyleCast.cbs create mode 100644 clang/test/BSC/Ownership/owned_arr.cbs create mode 100644 clang/test/BSC/Ownership/owned_err_c.c create mode 100644 clang/test/BSC/Ownership/owned_funcPtr.cbs create mode 100644 clang/test/BSC/Ownership/owned_funcPtr2.cbs create mode 100644 clang/test/BSC/Ownership/owned_global_err.cbs create mode 100644 clang/test/BSC/Ownership/owned_global_pointer.cbs create mode 100644 clang/test/BSC/Ownership/owned_global_typedef.cbs create mode 100644 clang/test/BSC/Ownership/owned_impCast.cbs create mode 100644 clang/test/BSC/Ownership/owned_init.cbs create mode 100644 clang/test/BSC/Ownership/owned_pointer_op.cbs create mode 100644 clang/test/BSC/Ownership/owned_struct.c create mode 100644 clang/test/BSC/Ownership/owned_struct.cbs create mode 100644 clang/test/BSC/Ownership/owned_struct_c.h create mode 100644 clang/test/BSC/Ownership/owned_struct_cbs.h create mode 100644 clang/test/BSC/Ownership/owned_union_err.cbs diff --git a/clang/include/clang/AST/CanonicalType.h b/clang/include/clang/AST/CanonicalType.h index 15d7e9efc26a..02134e22294a 100644 --- a/clang/include/clang/AST/CanonicalType.h +++ b/clang/include/clang/AST/CanonicalType.h @@ -138,6 +138,10 @@ public: return Stored.isLocalConstQualified(); } + bool isOwnedQualified() const { + return Stored.isLocalOwnedQualified(); + } + bool isVolatileQualified() const { return Stored.isLocalVolatileQualified(); } diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 20be635a02d4..ecc9f2c1cb19 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -822,6 +822,16 @@ public: /// Determine whether this type is const-qualified. bool isConstQualified() const; + /// Determine whether this particular QualType instance has the + /// "owned" qualifier set, without looking through typedefs that may have + /// added "owned" at a different level. + bool isLocalOwnedQualified() const { + return (getLocalFastQualifiers() & Qualifiers::Owned); + } + + /// Determine whether this type is owned-qualified. + bool isOwnedQualified() const; + /// Determine whether this particular QualType instance has the /// "restrict" qualifier set, without looking through typedefs that may have /// added "restrict" at a different level. @@ -2046,6 +2056,8 @@ public: /// Returns true if the type is a builtin type. bool isBuiltinType() const; + bool hasOwnedFields() const; + /// Test for a particular builtin type. bool isSpecificBuiltinType(unsigned K) const; @@ -2757,6 +2769,7 @@ public: } static bool classof(const Type *T) { return T->getTypeClass() == Pointer; } + bool hasOwnedFields() const; }; /// Represents a type which was implicitly adjusted by the semantic @@ -3920,6 +3933,7 @@ public: "the fast qualifiers."); bool isConst() const { return getFastTypeQuals().hasConst(); } + bool isOwned() const { return getFastTypeQuals().hasOwned(); } bool isVolatile() const { return getFastTypeQuals().hasVolatile(); } bool isRestrict() const { return getFastTypeQuals().hasRestrict(); } @@ -4238,6 +4252,9 @@ public: /// spec. bool hasInstantiationDependentExceptionSpec() const; + // return true if any 'owned' here + bool hasOwnedRetOrParams() const; + /// Return all the available information about this type's exception spec. ExceptionSpecInfo getExceptionSpecInfo() const { ExceptionSpecInfo Result; @@ -4736,6 +4753,13 @@ protected: explicit RecordType(TypeClass TC, RecordDecl *D) : TagType(TC, reinterpret_cast(D), QualType()) {} + enum ownedStatus { + unInit, + withOwned, + withoutOwned + }; + mutable ownedStatus hasOwn = ownedStatus::unInit; + public: RecordDecl *getDecl() const { return reinterpret_cast(TagType::getDecl()); @@ -4745,6 +4769,10 @@ public: /// is declared const, return true. Otherwise, return false. bool hasConstFields() const; + bool hasOwnedFields() const; + + void initOwnedStatus() const; + bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } @@ -6644,6 +6672,11 @@ inline bool QualType::isConstQualified() const { getCommonPtr()->CanonicalType.isLocalConstQualified(); } +inline bool QualType::isOwnedQualified() const { + return isLocalOwnedQualified() || + getCommonPtr()->CanonicalType.isLocalOwnedQualified(); +} + inline bool QualType::isRestrictQualified() const { return isLocalRestrictQualified() || getCommonPtr()->CanonicalType.isLocalRestrictQualified(); @@ -6661,8 +6694,9 @@ inline bool QualType::hasQualifiers() const { } inline QualType QualType::getUnqualifiedType() const { + int addOwned = isOwnedQualified() ? Qualifiers::Owned : 0; if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers()) - return QualType(getTypePtr(), 0); + return QualType(getTypePtr(), addOwned); return QualType(getSplitUnqualifiedTypeImpl(*this).Ty, 0); } diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td index 39dee7e683ff..1fabb76eedd8 100644 --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -182,6 +182,22 @@ def err_duplicate_declspec : Error<"%sub{duplicate_declspec}0">; def err_friend_decl_spec : Error<"'%0' is invalid in friend declarations">; +def err_owned_inderictOwned_type_check : Error< + "%select{" + "type of %1 cannot be 'owned' |" + "type of %1 cannot be 'owned', %2 contains 'owned' type |" + "type of %1 cannot be 'owned'(even indirectly), %2 contains 'owned' type}0">; + +def err_owned_union_spec: Error<"union cannot be qualifiered by '%0'">; +def err_owned_union_field_spec: Error<"field of union cannot be qualifiered by 'owned'">; +def err_owned_union_field_typedef: Error<"field of union cannot be qualifiered by 'owned', %0 contains owned type">; +def err_owned_union_field_qual: Error<"field of union cannot be owned-like type, %0 contains owned type">; +def err_owned_global_decl: Error<"'owned' type cannot be global variable">; +def err_owned_global_decl_typedef: Error<"'owned' type cannot be global variable %0 contains owned type">; +def err_owned_global_qual: Error<"'owned' type cannot be global variable, %0 contains owned type">; +def err_owned_arr_decl: Error<"member of array cannot be 'owned' type">; +def err_owned_arr_qual: Error<"member of array cannot be 'owned' type, '%0 %1' contains owned type">; + def err_invalid_member_in_interface : Error< "%select{data member |non-public member function |static member function |" "user-declared constructor|user-declared destructor|operator |" diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 9cfd1de6f017..5e855e9a187b 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2318,6 +2318,8 @@ def err_illegal_decl_array_of_auto : Error< "'%0' declared as array of %1">; def err_new_array_of_auto : Error< "cannot allocate array of 'auto'">; +def err_owned_array_decl : Error< + "type of array cannot qualified by 'owned'">; def err_auto_not_allowed : Error< "%select{'auto'|'decltype(auto)'|'__auto_type'|" "use of " @@ -6776,6 +6778,16 @@ def err_specialization_not_primary_template : Error< "template specialization %0 is %select{instantiated from a partial|" "an explicit}1 specialization">; +def err_owned_qualcheck_incompatible : Error< + "incompatible owned types, " + "%select{" + "cannot cast ownedType %1 to ownedType %2|" + "cannot cast UnOwnedType %1 to OwnedType %2|" + "cannot cast OwnedType %1 to UnOwnedType %2}0">; + +def err_owned_funcPtr_incompatible : Error< + "cannot cast %0 to %1">; + def err_member_redeclared : Error<"class member cannot be redeclared">; def ext_member_redeclared : ExtWarn<"class member cannot be redeclared">, InGroup; @@ -6964,6 +6976,12 @@ def err_objc_object_assignment : Error< "cannot assign to class object (%0 invalid)">; def err_typecheck_invalid_operands : Error< "invalid operands to binary expression (%0 and %1)">, Deferrable; +def err_typecheck_invalid_owned_binOp : Error< + "invalid operands to binary expression (%0 and %1)">, Deferrable; +def err_typecheck_invalid_owned_unaOp : Error< + "invalid operands to unary expression (%0)">, Deferrable; +def err_typecheck_invalid_owned_arrsub : Error< + "owned pointer type (%0) do not support ArraySubscript operate">, Deferrable; def note_typecheck_invalid_operands_converted : Note< "%select{first|second}0 operand was implicitly converted to type %1">; def err_typecheck_logical_vector_expr_gnu_cpp_restrict : Error< @@ -8087,6 +8105,13 @@ def err_typecheck_convert_pointer_int : Error< "; take the address with &|" "; remove *|" "; remove &}3">; +def err_owned_qualcheck_incompatible_pointer : Error< + "incompatible owned types, " + "%select{" + "cannot cast ownedType %1 to ownedType %2|" + "cannot cast UnOwnedType %1 to OwnedType %2|" + "cannot cast %1 to OwnedType %2|" + "cannot cast OwnedType %1 to UnOwnedType %2}0">; def ext_typecheck_convert_pointer_int : ExtWarn< err_typecheck_convert_pointer_int.Text>, InGroup, DefaultError; diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 5e461779366c..3d5a278db45f 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -333,7 +333,7 @@ public: TQ_const = 1, TQ_restrict = 2, TQ_volatile = 4, - TQ_owned = 8, + TQ_owned = 8, TQ_unaligned = 16, // This has no corresponding Qualifiers::TQ value, because it's not treated // as a qualifier in our type system. @@ -421,7 +421,8 @@ private: SourceRange TypeofParensRange; SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc, TQ_unalignedLoc, TQ_ownedLoc; - SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc, FS_asyncLoc; + SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc, + FS_asyncLoc; SourceLocation FS_explicitCloseParenLoc; SourceLocation FS_forceinlineLoc; SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index f889a9a8c3d6..a110b014bbfa 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -12092,6 +12092,11 @@ public: /// object with __weak qualifier. IncompatibleObjCWeakRef, + /// IncompatibleOwnedPointer - The assignment is between a owned qualified pointer + /// type with a unOwned qualified pointer type or two owned qualified pointer type + /// with different base types + IncompatibleOwnedPointer, + /// Incompatible - We reject this conversion outright, it is invalid to /// represent it in the AST. Incompatible @@ -12155,6 +12160,11 @@ public: AssignConvertType CheckTransparentUnionArgumentConstraints(QualType ArgType, ExprResult &RHS); + bool CheckOwnedQualTypeCStyleCast(QualType LHSType, Expr* RHSExpr); + bool CheckOwnedQualTypeAssignment(QualType LHSType, Expr* RHSExpr); + bool CheckOwnedFunctionPointerType(QualType LHSType, Expr* RHSExpr); + void CheckOwnedOrIndirectOwnedType(SourceLocation ErrLoc, QualType T, StringRef Env); + bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType); bool CheckExceptionSpecCompatibility(Expr *From, QualType ToType); diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 8ad710a9bed8..23136ae1cc1a 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -836,6 +836,17 @@ const ObjCObjectPointerType *ObjCObjectPointerType::stripObjCKindOfTypeAndQuals( return ctx.getObjCObjectPointerType(obj)->castAs(); } +bool PointerType::hasOwnedFields() const { + QualType R = getPointeeType(); + if (R.isOwnedQualified()) { + return true; + } + if (R.getTypePtr()->hasOwnedFields()) { + return true; + } + return false; +} + namespace { /// Visitor used to perform a simple type transformation that does not change @@ -1992,6 +2003,15 @@ bool Type::isChar32Type() const { return false; } +bool Type::hasOwnedFields() const { + if (const auto *RecTy = dyn_cast(CanonicalType)) { + return RecTy->hasOwnedFields(); + } else if (const auto *PointerTy = dyn_cast(CanonicalType)) { + return PointerTy->hasOwnedFields(); + } + return false; +} + /// Determine whether this type is any of the built-in character /// types. bool Type::isAnyCharacterType() const { @@ -3375,6 +3395,18 @@ bool FunctionProtoType::isTemplateVariadic() const { return false; } +bool FunctionProtoType::hasOwnedRetOrParams() const { + if (getReturnType().isOwnedQualified()) { + return true; + } + for (auto ParamType:getParamTypes()) { + if (ParamType.isOwnedQualified()) { + return true; + } + } + return false; +} + void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, const QualType *ArgTys, unsigned NumParams, const ExtProtoInfo &epi, @@ -3577,6 +3609,52 @@ bool RecordType::hasConstFields() const { return false; } +void RecordType::initOwnedStatus() const { + if (hasOwn != ownedStatus::unInit) return; + std::vector RecordTypeList; + RecordTypeList.push_back(this); + unsigned NextToCheckIndex = 0; + + while (RecordTypeList.size() > NextToCheckIndex) { + for (FieldDecl *FD : + RecordTypeList[NextToCheckIndex]->getDecl()->fields()) { + QualType FieldTy = FD->getType(); + if (FieldTy.isOwnedQualified()) { + hasOwn = ownedStatus::withOwned; + return; + } + QualType tempQT = FieldTy; + const Type* tempT = tempQT.getTypePtr(); + while(tempT->isPointerType()) { + tempQT = tempT->getPointeeType(); + if (tempQT.isOwnedQualified()) { + hasOwn = ownedStatus::withOwned; + return; + } else { + tempQT = tempQT.getCanonicalType(); + tempT = tempQT.getTypePtr(); + } + } + FieldTy = tempQT.getCanonicalType(); + if (const auto *FieldRecTy = FieldTy->getAs()) { + if (llvm::find(RecordTypeList, FieldRecTy) == RecordTypeList.end()) + RecordTypeList.push_back(FieldRecTy); + } + } + ++NextToCheckIndex; + } + hasOwn = ownedStatus::withoutOwned; + return; +} + +bool RecordType::hasOwnedFields() const { + if (hasOwn == ownedStatus::unInit) + initOwnedStatus(); + if (hasOwn == ownedStatus::withOwned) + return true; + return false; +} + bool AttributedType::isQualifier() const { // FIXME: Generate this with TableGen. switch (getAttrKind()) { diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 26cf381a2019..99108ed22eaa 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -2869,6 +2869,15 @@ void CastOperation::CheckCStyleCast() { return; } + // bsc owned type CStyleCast + if (Self.getLangOpts().BSC + && (SrcExpr.get()->getType().isOwnedQualified() || DestType.isOwnedQualified())) { + if(!Self.CheckOwnedQualTypeCStyleCast(DestType, SrcExpr.get())) { + SrcExpr = ExprError(); + return; + } + } + // If the type is dependent, we won't do any other semantic analysis now. if (Self.getASTContext().isDependenceAllowed() && (DestType->isDependentType() || SrcExpr.get()->isTypeDependent() || diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 7b5435f2b4bd..bc396aed9798 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -5219,6 +5219,8 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, if (DS.getTypeQualifiers()) { if (DS.getTypeQualifiers() & DeclSpec::TQ_const) Diag(DS.getConstSpecLoc(), DiagID) << "const"; + if (DS.getTypeQualifiers() & DeclSpec::TQ_owned) + Diag(DS.getOwnedSpecLoc(), DiagID) << "owned"; if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) Diag(DS.getConstSpecLoc(), DiagID) << "volatile"; // Restrict is covered above. @@ -7979,6 +7981,13 @@ NamedDecl *Sema::ActOnVariableDeclarator( if (IsMemberSpecialization && !NewVD->isInvalidDecl()) CompleteMemberSpecialization(NewVD, Previous); + // BSC global variable owned type check + // 'typedef owned int myInt;' is legal + bool IsTypedefName = D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef; + if (!IsTypedefName && getLangOpts().BSC && NewVD + && NewVD->getDeclContext()->isFileContext()) + CheckOwnedOrIndirectOwnedType(D.getIdentifierLoc(), R, "global variable"); + return NewVD; } @@ -17518,6 +17527,10 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, diag::err_invalid_thread) << DeclSpec::getSpecifierName(TSCS); + // BSC union fileds owned type check + if (getLangOpts().BSC && Record->isUnion()) + CheckOwnedOrIndirectOwnedType(D.getIdentifierLoc(), T, "union field"); + // Check to see if this name was declared as a member previously NamedDecl *PrevDecl = nullptr; LookupResult Previous(*this, II, Loc, LookupMemberName, diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d6c20ea63183..70783efc1c8f 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -5010,6 +5010,13 @@ ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, return CreateOverloadedArraySubscriptExpr(lbLoc, rbLoc, base, ArgExprs); } + // BSC owned pointer index check + if (getLangOpts().BSC && base->getType()->isPointerType() && base->getType().isOwnedQualified()) { + Diag(lbLoc, diag::err_typecheck_invalid_owned_arrsub) + << base->getType() << base->getSourceRange(); + return ExprError(); + } + ExprResult Res = CreateBuiltinArraySubscriptExpr(base, lbLoc, ArgExprs.front(), rbLoc); @@ -10109,6 +10116,153 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, return Compatible; } +// for union fields/array/global variable type check +void Sema::CheckOwnedOrIndirectOwnedType(SourceLocation ErrLoc, QualType T, StringRef Env) { + enum { + ownedQualified, + ownedTypedef, + ownedFields + }; + if (T.getCanonicalType().isOwnedQualified() && !T.getTypePtr()->getAs()) { + Diag(ErrLoc, diag::err_owned_inderictOwned_type_check) << ownedQualified << Env; + } else if (T.getCanonicalType().isOwnedQualified() && T.getTypePtr()->getAs()) { + Diag(ErrLoc, diag::err_owned_inderictOwned_type_check) << ownedTypedef << Env << T; + } else if (T.getCanonicalType().getTypePtr()->hasOwnedFields()) { + Diag(ErrLoc, diag::err_owned_inderictOwned_type_check) << ownedFields << Env << T; + } +} + +// modify err_owned_qualcheck_incompatible synchronously if OwnErr changed +enum OwnedErr { + ownedToOwned, + unOwnedToOwned, + ownedToUnowned +}; + +bool Sema::CheckOwnedQualTypeCStyleCast(QualType LHSType, Expr* RHSExpr) { + QualType RHSCanType = RHSExpr->getType().getCanonicalType(); + QualType LHSCanType = LHSType.getCanonicalType(); + SourceLocation ExprLoc = RHSExpr->getBeginLoc(); + bool IsSameType = (LHSCanType.getTypePtr() == RHSCanType.getTypePtr()); + + // owned to owned cases: + // int owned a; + // (int owned)a; //legal + // (float owned); //illegal + // int* owned p0; + // (void* owned)p0; //legal + // (int* owned)((void* owned)p0); //legal + if (LHSCanType.isOwnedQualified() && RHSCanType.isOwnedQualified() + && !IsSameType) { + if (RHSCanType->isPointerType() && LHSCanType->isPointerType() + && (LHSCanType.getTypePtr()->isVoidPointerType() || RHSCanType.getTypePtr()->isVoidPointerType())) { + return true; + } + Diag(RHSExpr->getBeginLoc(), diag::err_owned_qualcheck_incompatible) << ownedToOwned << RHSCanType << LHSCanType; + return false; + } + + // unOwned to owned cases: + // int a; + // (int owned)a; //legal + // (float owned)a; //illegal + if (LHSCanType.isOwnedQualified() && !RHSCanType.isOwnedQualified() + && !IsSameType) { + Diag(ExprLoc, diag::err_owned_qualcheck_incompatible) << unOwnedToOwned << RHSCanType << LHSCanType; + return false; + } + + // owned to unOwned cases: + // int owned a; + // (int)a; //legal + // (float)a; //illegal + if (!LHSCanType.isOwnedQualified() && RHSCanType.isOwnedQualified() + && !IsSameType) { + Diag(ExprLoc, diag::err_owned_qualcheck_incompatible) << ownedToUnowned << RHSCanType << LHSCanType; + return false; + } + return true; +} + +bool Sema::CheckOwnedQualTypeAssignment(QualType LHSType, Expr* RHSExpr) { + QualType RHSCanType = RHSExpr->getType().getCanonicalType(); + QualType LHSCanType = LHSType.getCanonicalType(); + bool isLiteral = false; + Stmt::StmtClass RHSClass = RHSExpr->getStmtClass(); + if (RHSClass == Expr::IntegerLiteralClass + || RHSClass == Expr::FloatingLiteralClass + || RHSClass == Expr::CharacterLiteralClass) { + isLiteral = true; + } + SourceLocation ExprLoc = RHSExpr->getBeginLoc(); + + // owned to owned cases: + // int owned a = 10; + // int owned b = a; //legal + // float owned c = a; //illegal + if (LHSCanType.isOwnedQualified() && RHSCanType.isOwnedQualified()) { + if (LHSCanType != RHSCanType) { + Diag(ExprLoc, diag::err_owned_qualcheck_incompatible) << ownedToOwned << RHSCanType << LHSCanType; + return false; + } + } + + // unOwned to owned cases: + // int owned a = 10; //legal even 10 is not owned type + // int owned b = 10 + 10; //ilegal + // char owned c = 'c'; // legal even 'c' is int type + // int owned d = (int)a; // illegal + if (LHSCanType.isOwnedQualified() && !RHSCanType.isOwnedQualified()) { + if (!isLiteral) { + Diag(ExprLoc, diag::err_owned_qualcheck_incompatible) << unOwnedToOwned << RHSCanType << LHSCanType; + return false; + } else if (LHSCanType.getTypePtr() != RHSCanType.getTypePtr() + && !(LHSCanType.getTypePtr()->isCharType() && RHSCanType.getTypePtr()->isIntegerType())) { + Diag(ExprLoc, diag::err_owned_qualcheck_incompatible) << unOwnedToOwned << RHSCanType << LHSCanType; + return false; + } + } + + // owned to unOwned cases: + // int owned a = 10; + // int b = a; //illegal + if (!LHSCanType.isOwnedQualified() && RHSCanType.isOwnedQualified()) { + Diag(ExprLoc, diag::err_owned_qualcheck_incompatible) << ownedToUnowned << RHSCanType << LHSCanType; + return false; + } + return true; +} + +bool Sema::CheckOwnedFunctionPointerType(QualType LHSType, Expr* RHSExpr) { + const FunctionProtoType* LSHFuncType = LHSType->getAs()->getPointeeType()->getAs(); + const FunctionProtoType* RSHFuncType = RHSExpr->getType()->isFunctionPointerType()? + RHSExpr->getType()->getAs()->getPointeeType()->getAs(): + RHSExpr->getType()->getAs(); + SourceLocation ExprLoc = RHSExpr->getBeginLoc(); + + // return if no 'owned' in both side + if (!LSHFuncType->hasOwnedRetOrParams() && !RSHFuncType->hasOwnedRetOrParams()) { + return true; + } + if ((LSHFuncType->getReturnType().isOwnedQualified() && !RSHFuncType->getReturnType().isOwnedQualified()) + || (!LSHFuncType->getReturnType().isOwnedQualified() && RSHFuncType->getReturnType().isOwnedQualified())) { + Diag(ExprLoc, diag::err_owned_funcPtr_incompatible) << LHSType << RHSExpr->getType(); + return false; + } + if (LSHFuncType->getNumParams() != RSHFuncType->getNumParams()) { + Diag(ExprLoc, diag::err_owned_funcPtr_incompatible) << LHSType << RHSExpr->getType(); + return false; + } + for (unsigned i = 0; i < LSHFuncType->getNumParams(); i++) { + if ((LSHFuncType->getParamType(i).isOwnedQualified() && !RSHFuncType->getParamType(i).isOwnedQualified()) + || (!LSHFuncType->getParamType(i).isOwnedQualified() && RSHFuncType->getParamType(i).isOwnedQualified())) { + Diag(ExprLoc, diag::err_owned_funcPtr_incompatible) << LHSType << RHSExpr->getType(); + return false; + } + } + return true; +} + Sema::AssignConvertType Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, bool Diagnose, @@ -10135,6 +10289,18 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, } } + if (getLangOpts().BSC) { + if (RHS.get()->getType().isOwnedQualified() || LHSType.isOwnedQualified()) { + if (!CheckOwnedQualTypeAssignment(LHSType, RHS.get())) + return IncompatibleOwnedPointer; + } + if (LHSType->isFunctionPointerType() + && (RHS.get()->getType()->isFunctionPointerType() || RHS.get()->getType()->isFunctionType())) { + if (!CheckOwnedFunctionPointerType(LHSType, RHS.get())) + return IncompatibleOwnedPointer; + } + } + if (getLangOpts().CPlusPlus) { if (!LHSType->isRecordType() && !LHSType->isAtomicType()) { // C++ 5.17p3: If the left operand is not of class type, the @@ -15471,6 +15637,24 @@ static void DiagnoseShiftCompare(Sema &S, SourceLocation OpLoc, SourceRange(OCE->getArg(1)->getBeginLoc(), RHSExpr->getEndLoc())); } +static void DiagnoseOwnedPointerBinaryOp(Sema &Self, BinaryOperatorKind Opc, + SourceLocation OpLoc, Expr *LHSExpr, + Expr *RHSExpr) { + if (!BinaryOperator::isComparisonOp(Opc)) { + Self.Diag(OpLoc, diag::err_typecheck_invalid_owned_binOp) + << LHSExpr->getType() << RHSExpr->getType() + << LHSExpr->getSourceRange() << RHSExpr->getSourceRange(); + } +} + +static void DiagnoseOwnedPointerUnaryOp(Sema &Self, UnaryOperatorKind Opc, + SourceLocation OpLoc, Expr *Input) { + if (Opc != UO_AddrOf && Opc != UO_Deref) { + Self.Diag(OpLoc, diag::err_typecheck_invalid_owned_unaOp) + << Input->getType() << Input->getSourceRange(); + } +} + /// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky /// precedence. static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc, @@ -15505,6 +15689,14 @@ static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc, // cout << 5 == 4; if (BinaryOperator::isComparisonOp(Opc)) DiagnoseShiftCompare(Self, OpLoc, LHSExpr, RHSExpr); + + //bsc owned pointer type check + if (Self.getLangOpts().BSC + && ((LHSExpr->getType()->isPointerType() && LHSExpr->getType().isOwnedQualified()) + || (RHSExpr->getType()->isPointerType() && RHSExpr->getType().isOwnedQualified()))) { + DiagnoseOwnedPointerBinaryOp(Self, Opc, OpLoc, LHSExpr, RHSExpr); + } + } // Binary Operators. 'Tok' is the token for the operator. @@ -16033,6 +16225,10 @@ ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, Input); } + if (getLangOpts().BSC && Input->getType()->isPointerType() + && Input->getType().isOwnedQualified()) { + DiagnoseOwnedPointerUnaryOp(*this, Opc, OpLoc, Input); + } return CreateBuiltinUnaryOp(OpLoc, Opc, Input); } @@ -17267,6 +17463,8 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, isInvalid = true; MayHaveFunctionDiff = true; break; + case IncompatibleOwnedPointer: + return false; } QualType FirstType, SecondType; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index f062397301b5..41300221d219 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1877,6 +1877,10 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state, // produce a warning in this case. } + if(S.getLangOpts().BSC && (TypeQuals & DeclSpec::TQ_owned) && DS.getTypeSpecType() == DeclSpec::TST_union) { + S.Diag(DS.getOwnedSpecLoc(), diag::err_owned_union_spec) << "owned"; + } + QualType Qualified = S.BuildQualifiedType(Result, DeclLoc, TypeQuals, &DS); // If adding qualifiers fails, just use the unqualified type. @@ -5045,6 +5049,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, D.setInvalidType(true); } + // BSC rules: ele of array cannot be qualified by owned or owned-like + if (LangOpts.BSC) + S.CheckOwnedOrIndirectOwnedType(D.getIdentifierLoc(), T, "array"); + // C99 6.7.5.2p1: The optional type qualifiers and the keyword static // shall appear only in a declaration of a function parameter with an // array type, ... @@ -5340,7 +5348,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // OpenCL disallows functions without a prototype, but it doesn't enforce // strict prototypes as in C2x because it allows a function definition to // have an identifier list. See OpenCL 3.0 6.11/g for more details. - // + // if (!FTI.NumParams && !FTI.isVariadic && !LangOpts.BSC && !LangOpts.requiresStrictPrototypes() && !LangOpts.OpenCL) { // Simple void foo(), where the incoming T is the result type. diff --git a/clang/test/BSC/Ownership/hasOwnedFields.cbs b/clang/test/BSC/Ownership/hasOwnedFields.cbs new file mode 100644 index 000000000000..1e177e537df5 --- /dev/null +++ b/clang/test/BSC/Ownership/hasOwnedFields.cbs @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -ast-dump -verify %s +// expected-no-diagnostics + +// check if hasOwnedFields() can properly deal with the following cases: +// 1. A struct contains itself +// 2. Two struct contains each other +typedef struct node { + struct node * next; +} Node; + +Node node1; + +struct A { + struct B* b; +}; + +struct B { + struct A* a; +}; + +struct A a; + diff --git a/clang/test/BSC/Ownership/owned_CStyleCast.cbs b/clang/test/BSC/Ownership/owned_CStyleCast.cbs new file mode 100644 index 000000000000..b64adf21b3f2 --- /dev/null +++ b/clang/test/BSC/Ownership/owned_CStyleCast.cbs @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -ast-dump -verify %s + +//owned to owned +void test1() { + int* owned p1; + int* owned p3 = (int* owned)p1; //legal + void* owned p4 = (void* owned)p1; //legal + float* owned p2 = (float* owned)p1; //expected-error {{incompatible owned types, cannot cast ownedType 'int *owned' to ownedType 'float *owned'}} + int owned a = 10; + float owned b = (float owned)a; //expected-error {{incompatible owned types, cannot cast ownedType 'owned int' to ownedType 'owned float'}} + void* owned p5; + int* owned p6 = (int* owned)p5; //legal +} + +//owned to unOwned +void test2() { + int* p1; + int* owned p2 = (int* owned)p1; + float* owned p3 = (float* owned)p1; //expected-error {{incompatible owned types, cannot cast UnOwnedType 'int *' to OwnedType 'float *owned'}} +} + +//unOwned to owned +void test3() { + int* owned p1; + int* p2 = (int*)p1; + float* p3 = (float*)p1; //expected-error {{incompatible owned types, cannot cast OwnedType 'int *owned' to UnOwnedType 'float *'}} +} + + diff --git a/clang/test/BSC/Ownership/owned_arr.cbs b/clang/test/BSC/Ownership/owned_arr.cbs new file mode 100644 index 000000000000..63d2f10dd387 --- /dev/null +++ b/clang/test/BSC/Ownership/owned_arr.cbs @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -ast-dump -verify %s + +typedef struct A { + owned int a; +} SA; + +void test() { + owned int arr1[10]; // expected-error {{type of array cannot be 'owned}} + SA arr2[3]; // expected-error {{type of array cannot be 'owned'(even indirectly), 'SA' (aka 'struct A') contains 'owned' type}} + struct A arr[4]; // expected-error {{type of array cannot be 'owned'(even indirectly), 'struct A' contains 'owned' type}} + owned int* arr3[2]; // expected-error {{type of array cannot be 'owned'(even indirectly), 'owned int *' contains 'owned' type}} + SA* arr4[3]; // expected-error {{type of array cannot be 'owned'(even indirectly), 'SA *' (aka 'struct A *') contains 'owned' type}} + return; +} + +void test2() { + int arr[3]; + int* owned p1 = &arr[1]; // expected-error {{incompatible owned types, cannot cast UnOwnedType 'int *' to OwnedType 'int *owned'}} +} + +struct B { + owned int arr1[3]; // expected-error {{type of array cannot be 'owned'}} +}; \ No newline at end of file diff --git a/clang/test/BSC/Ownership/owned_ast_check.cbs b/clang/test/BSC/Ownership/owned_ast_check.cbs index ba586433672f..48c6b30ef77c 100644 --- a/clang/test/BSC/Ownership/owned_ast_check.cbs +++ b/clang/test/BSC/Ownership/owned_ast_check.cbs @@ -2,10 +2,6 @@ // RUN: %clang_cc1 -ast-dump %s \ // RUN: | FileCheck -strict-whitespace %s -// Test without serialization: -// RUN: %clang_cc1 -ast-dump %s \ -// RUN: | FileCheck -strict-whitespace %s - struct A { owned int a; int owned b; @@ -55,7 +51,7 @@ int* owned ownedTest2(int* owned p) { // CHECK-NEXT: ParmVarDecl 0x{{[^ ]*}} {{.*}}p 'int *owned' // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} {{.*}} // CHECK-NEXT: ReturnStmt 0x{{[^ ]*}} {{.*}} -// CHECK-NEXT: ImplicitCastExpr 0x{{[^ ]*}} {{.*}}'int *' +// CHECK-NEXT: ImplicitCastExpr 0x{{[^ ]*}} {{.*}}'int *owned' // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} {{.*}}'int *owned' diff --git a/clang/test/BSC/Ownership/owned_err_c.c b/clang/test/BSC/Ownership/owned_err_c.c new file mode 100644 index 000000000000..61794ea0af6a --- /dev/null +++ b/clang/test/BSC/Ownership/owned_err_c.c @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -ast-dump -verify %s + +struct A { + owned int a; // expected-error {{unknown type name 'owned'}} + owned int* b; // expected-error {{unknown type name 'owned'}} +}; diff --git a/clang/test/BSC/Ownership/owned_funcPtr.cbs b/clang/test/BSC/Ownership/owned_funcPtr.cbs new file mode 100644 index 000000000000..d6327f8a3135 --- /dev/null +++ b/clang/test/BSC/Ownership/owned_funcPtr.cbs @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -ast-dump -verify %s + +int myadd(int* a, int* b) { + return *a + *b; +} + +int owned myadd2(int* a, int* b) { + int owned x = 10; + return x; +} + +typedef int (*FTP)(int*, int*); +typedef int (*FTPO)(int* owned, int*); + +//case1: callExpr through funcPtr +void test1() { + FTP ftp1 = myadd; + int a = 10; + int b = 10; + int* owned p1 = (int* owned)&a; + int* p2 = &b; + int res = ftp1(p1, p2); //expected-error {{incompatible owned types, cannot cast OwnedType 'int *owned' to UnOwnedType 'int *'}} +} + +// case2: unOwned to owned +void test2() { + FTP owned ftp1 = myadd; //expected-error {{incompatible owned types, cannot cast UnOwnedType 'int (int *, int *)' to OwnedType 'int (*owned)(int *, int *)'}} +} + +// case3: inner owned check +void test3() { + FTP ftp1 = myadd; + FTP ftp2 = myadd2; //expected-error {{cannot cast 'FTP' (aka 'int (*)(int *, int *)') to 'owned int (int *, int *)'}} + FTPO ftpo1 = ftp1; //expected-error {{cannot cast 'FTPO' (aka 'int (*)(int *owned, int *)') to 'FTP' (aka 'int (*)(int *, int *)')}} + FTPO ftpo2 = (FTPO)ftp1; +} + +// case4: no owned-like property +FTPO ftpo1; //legal even FTPO contains owned \ No newline at end of file diff --git a/clang/test/BSC/Ownership/owned_funcPtr2.cbs b/clang/test/BSC/Ownership/owned_funcPtr2.cbs new file mode 100644 index 000000000000..230f4157c00c --- /dev/null +++ b/clang/test/BSC/Ownership/owned_funcPtr2.cbs @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -ast-dump -verify %s + +int myadd(int* a, int* b) { + return *a + *b; +} + + +typedef int (*FTP)(int*); +typedef int (*FTPO)(int* owned); + +void test() { + FTP ftp1 = myadd; //expected-warning {{incompatible function pointer types initializing 'FTP' (aka 'int (*)(int *)') with an expression of type 'int (int *, int *)'}} + FTPO ftpo1 = myadd; //expected-error {{cannot cast 'FTPO' (aka 'int (*)(int *owned)') to 'int (int *, int *)'}} +} \ No newline at end of file diff --git a/clang/test/BSC/Ownership/owned_global_err.cbs b/clang/test/BSC/Ownership/owned_global_err.cbs new file mode 100644 index 000000000000..6e694afda1bb --- /dev/null +++ b/clang/test/BSC/Ownership/owned_global_err.cbs @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -ast-dump -verify %s + +owned int a = 10; //expected-error {{type of global variable cannot be 'owned'}} + +typedef struct A { + owned int num; +}SA; + +SA sa1 = {.num = 10}; //expected-error {{type of global variable cannot be 'owned'(even indirectly), 'SA' (aka 'struct A') contains 'owned' type}} + +struct A sa2 = {.num = 20}; //expected-error {{type of global variable cannot be 'owned'(even indirectly), 'struct A' contains 'owned' type}} + +typedef struct B { + SA* sa; +}SB; + +SB* sb1; //expected-error{{type of global variable cannot be 'owned'(even indirectly), 'SB *' (aka 'struct B *') contains 'owned' type}} + + diff --git a/clang/test/BSC/Ownership/owned_global_pointer.cbs b/clang/test/BSC/Ownership/owned_global_pointer.cbs new file mode 100644 index 000000000000..dad4d10cfb42 --- /dev/null +++ b/clang/test/BSC/Ownership/owned_global_pointer.cbs @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -ast-dump -verify %s + +int owned a; //expected-error {{type of global variable cannot be 'owned'}} +owned int b; //expected-error {{type of global variable cannot be 'owned'}} + +int owned* p1; //expected-error {{type of global variable cannot be 'owned'(even indirectly), 'owned int *' contains 'owned' type}} +int* owned p3; //expected-error {{type of global variable cannot be 'owned'}} + +int** owned p4; //expected-error {{type of global variable cannot be 'owned'}} + +int* owned* p5; //expected-error {{type of global variable cannot be 'owned'(even indirectly), 'int *owned *' contains 'owned' type}} +owned int** p6; //expected-error {{type of global variable cannot be 'owned'(even indirectly), 'owned int **' contains 'owned' type}} \ No newline at end of file diff --git a/clang/test/BSC/Ownership/owned_global_typedef.cbs b/clang/test/BSC/Ownership/owned_global_typedef.cbs new file mode 100644 index 000000000000..810249e313c8 --- /dev/null +++ b/clang/test/BSC/Ownership/owned_global_typedef.cbs @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -ast-dump -verify %s + +typedef owned int ownInt; +ownInt a = 10; //expected-error {{type of global variable cannot be 'owned', 'ownInt' (aka 'owned int') contains 'owned' type}} + +typedef struct A { + owned int a; +}AA; + +AA aa; //expected-error {{type of global variable cannot be 'owned'(even indirectly), 'AA' (aka 'struct A') contains 'owned' type}} + +typedef owned struct B { + int a; +}BB; + +BB bb; //expected-error {{type of global variable cannot be 'owned', 'BB' (aka 'owned struct B') contains 'owned' type}} \ No newline at end of file diff --git a/clang/test/BSC/Ownership/owned_impCast.cbs b/clang/test/BSC/Ownership/owned_impCast.cbs new file mode 100644 index 000000000000..547eec2f5fda --- /dev/null +++ b/clang/test/BSC/Ownership/owned_impCast.cbs @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -ast-dump -verify %s + +//owned to owned +void test1() { + float owned a1 = 10.0f; + int owned a2 = a1; //expected-error {{incompatible owned types, cannot cast ownedType 'owned float' to ownedType 'owned int'}} +} + +//unOwned to owned +void test2() { + int b1 = 10; + int owned b2 = b1; //expected-error {{incompatible owned types, cannot cast UnOwnedType 'int' to OwnedType 'owned int'}} +} + +//owned to unOwned +void test3() { + int owned c1 = 10; + int c2 = c1; //expected-error {{incompatible owned types, cannot cast OwnedType 'owned int' to UnOwnedType 'int'}} +} + +//unOwned to owned with typedef +typedef int* owned myInt; +void test4() { + int b = 10; + int* p1 = &b; + myInt p2 = p1; //expected-error {{incompatible owned types, cannot cast UnOwnedType 'int *' to OwnedType 'int *owned'}} +} + + diff --git a/clang/test/BSC/Ownership/owned_init.cbs b/clang/test/BSC/Ownership/owned_init.cbs new file mode 100644 index 000000000000..b0913edf90e2 --- /dev/null +++ b/clang/test/BSC/Ownership/owned_init.cbs @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -ast-dump -verify %s + +void test1() { + int owned a = 10; //legal + int owned a1 = 10.0f; //expected-error {{incompatible owned types, cannot cast UnOwnedType 'float' to OwnedType 'owned int'}} + int owned c = 10 + 20; //expected-error {{incompatible owned types, cannot cast UnOwnedType 'int' to OwnedType 'owned int'}} + int owned b = (int owned)10; //legal + + int d = 10; + int owned e = d; //expected-error {{incompatible owned types, cannot cast UnOwnedType 'int' to OwnedType 'owned int'}} + int owned f = (int owned)d; //legal + + float owned f1 = 1.0f; + char owned c1 = 'c'; +} + +typedef struct A { + int num; +}SA; + +typedef struct B { + owned int num; +}SB; + +void test2() { + struct A owned a1 = {.num = 10}; + SA owned a2 = {.num = 20}; + + struct B owned b1 = {.num = 10}; + SB owned b2 = {.num = 20}; +} + +void test3() { + int a = 10; + int* owned b = &a; //expected-error {{incompatible owned types, cannot cast UnOwnedType 'int *' to OwnedType 'int *owned'}} +} \ No newline at end of file diff --git a/clang/test/BSC/Ownership/owned_pointer_op.cbs b/clang/test/BSC/Ownership/owned_pointer_op.cbs new file mode 100644 index 000000000000..69129949766f --- /dev/null +++ b/clang/test/BSC/Ownership/owned_pointer_op.cbs @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -ast-dump -verify %s + +void test1() { + int* owned p1; + int* owned p2 = p1 + 1; //expected-error {{invalid operands to binary expression ('int *owned' and 'int')}} + int* owned p3 = 1 + p1; //expected-error {{invalid operands to binary expression ('int' and 'int *owned')}} + int* owned p4; + + if (p1 == p4) { + return; + } +} + +void test2() { + int* owned p1; + p1++; //expected-error {{invalid operands to unary expression ('int *owned')}} + int* owned p2 = p1[0]; //expected-error {{owned pointer type ('int *owned') do not support ArraySubscript operate}} + int x = *p1; + int* owned* p3 = &p1; +} \ No newline at end of file diff --git a/clang/test/BSC/Ownership/owned_struct.c b/clang/test/BSC/Ownership/owned_struct.c new file mode 100644 index 000000000000..12c4510c51ff --- /dev/null +++ b/clang/test/BSC/Ownership/owned_struct.c @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -ast-dump -verify %s + +#include "owned_struct_c.h" + +int main() { + struct A a; + return 0; +} diff --git a/clang/test/BSC/Ownership/owned_struct.cbs b/clang/test/BSC/Ownership/owned_struct.cbs new file mode 100644 index 000000000000..6de3ef3a17cc --- /dev/null +++ b/clang/test/BSC/Ownership/owned_struct.cbs @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -ast-dump -verify %s +// expected-no-diagnostics + +#include "owned_struct_cbs.h" + +int main() { + struct A owned a; + return 0; +} diff --git a/clang/test/BSC/Ownership/owned_struct_c.h b/clang/test/BSC/Ownership/owned_struct_c.h new file mode 100644 index 000000000000..1450805d8635 --- /dev/null +++ b/clang/test/BSC/Ownership/owned_struct_c.h @@ -0,0 +1,4 @@ +struct A { + owned int a; // expected-error {{unknown type name 'owned'}} + owned int* b; // expected-error {{unknown type name 'owned'}} +}; diff --git a/clang/test/BSC/Ownership/owned_struct_cbs.h b/clang/test/BSC/Ownership/owned_struct_cbs.h new file mode 100644 index 000000000000..f27b7b79851b --- /dev/null +++ b/clang/test/BSC/Ownership/owned_struct_cbs.h @@ -0,0 +1,4 @@ +struct A { + owned int a; + owned int* b; +}; diff --git a/clang/test/BSC/Ownership/owned_union_err.cbs b/clang/test/BSC/Ownership/owned_union_err.cbs new file mode 100644 index 000000000000..f777d393ffa0 --- /dev/null +++ b/clang/test/BSC/Ownership/owned_union_err.cbs @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -ast-dump -verify %s + +union D { + owned int a; //expected-error {{type of union field cannot be 'owned'}} +}; + + +union E { + int a; +}; + +int main() { + owned union E e = {.a = 10}; //expected-error {{union cannot be qualifiered by 'owned'}} + return 0; +} + +union A { + owned int* a; //expected-error {{type of union field cannot be 'owned'(even indirectly), 'owned int *' contains 'owned' type}} +}; + +typedef owned int ownedInt; +union B { + ownedInt a; //expected-error {{type of union field cannot be 'owned', 'ownedInt' (aka 'owned int') contains 'owned' type}} +}; + +struct S { + owned int num; +}; + +union C { + struct S* s1; //expected-error {{type of union field cannot be 'owned'(even indirectly), 'struct S *' contains 'owned' type}} +}; -- Gitee