diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 1e280cb633e23..bbfef9ff3cf7c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -146,6 +146,8 @@ Non-comprehensive list of changes in this release - Clang now supports ``__builtin_assume_separate_storage`` that indicates that its arguments point to objects in separate storage allocations. - Clang now supports expressions in ``#pragma clang __debug dump``. +- Clang now supports declaration of multi-dimensional arrays with + ``__declspec(property)``. New Compiler Flags ------------------ diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h index e2b4be48c0bd1..5f45668851c73 100644 --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -896,6 +896,16 @@ class ParsedAttributesView { }); } + const ParsedAttr *getMSPropertyAttr() const { + auto It = llvm::find_if(AttrList, [](const ParsedAttr *AL) { + return AL->isDeclspecPropertyAttribute(); + }); + if (It != AttrList.end()) + return *It; + return nullptr; + } + bool hasMSPropertyAttr() const { return getMSPropertyAttr(); } + private: VecTy AttrList; }; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index e28c44f97f1fe..312b6f801c1f0 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -3235,16 +3235,6 @@ static bool InitializationHasSideEffects(const FieldDecl &FD) { return false; } -static const ParsedAttr *getMSPropertyAttr(const ParsedAttributesView &list) { - ParsedAttributesView::const_iterator Itr = - llvm::find_if(list, [](const ParsedAttr &AL) { - return AL.isDeclspecPropertyAttribute(); - }); - if (Itr != list.end()) - return &*Itr; - return nullptr; -} - // Check if there is a field shadowing. void Sema::CheckShadowInheritedFields(const SourceLocation &Loc, DeclarationName FieldName, @@ -3322,7 +3312,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, bool isFunc = D.isDeclarationOfFunction(); const ParsedAttr *MSPropertyAttr = - getMSPropertyAttr(D.getDeclSpec().getAttributes()); + D.getDeclSpec().getAttributes().getMSPropertyAttr(); if (cast(CurContext)->isInterface()) { // The Microsoft extension __interface only permits public member functions diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 53852dd930a71..e195e85ab75b7 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -5070,6 +5070,19 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr; Expr *ArraySize = static_cast(ATI.NumElts); ArrayType::ArraySizeModifier ASM; + + // Microsoft property fields can have multiple sizeless array chunks + // (i.e. int x[][][]). Skip all of these except one to avoid creating + // bad incomplete array types. + if (chunkIndex != 0 && !ArraySize && + D.getDeclSpec().getAttributes().hasMSPropertyAttr()) { + // This is a sizeless chunk. If the next is also, skip this one. + DeclaratorChunk &NextDeclType = D.getTypeObject(chunkIndex - 1); + if (NextDeclType.Kind == DeclaratorChunk::Array && + !NextDeclType.Arr.NumElts) + break; + } + if (ATI.isStar) ASM = ArrayType::Star; else if (ATI.hasStatic) @@ -6523,6 +6536,12 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State, } for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { + // Microsoft property fields can have multiple sizeless array chunks + // (i.e. int x[][][]). Don't create more than one level of incomplete array. + if (CurrTL.getTypeLocClass() == TypeLoc::IncompleteArray && e != 1 && + D.getDeclSpec().getAttributes().hasMSPropertyAttr()) + continue; + // An AtomicTypeLoc might be produced by an atomic qualifier in this // declarator chunk. if (AtomicTypeLoc ATL = CurrTL.getAs()) { diff --git a/clang/test/CodeGenCXX/ms-property.cpp b/clang/test/CodeGenCXX/ms-property.cpp index a70aa23c3213c..67f5d50a89580 100644 --- a/clang/test/CodeGenCXX/ms-property.cpp +++ b/clang/test/CodeGenCXX/ms-property.cpp @@ -23,6 +23,12 @@ class S { __declspec(property(get=GetX,put=PutX)) int x[]; int GetX(int i, int j) { return i+j; } void PutX(int i, int j, int k) { j = i = k; } + __declspec(property(get=GetY,put=PutY)) int y[][]; + int GetY(int i, int j) { return i+j; } + void PutY(int i, int j, int k) { j = i = k; } + __declspec(property(get=GetZ,put=PutZ)) int z[][][]; + int GetZ(int i, int j, int k) { return i+j+k; } + void PutZ(int i, int j, int k, int v) { j = i = k = v; } }; template @@ -58,6 +64,16 @@ int main(int argc, char **argv) { // CHECK: [[J:%.+]] = load i32, i32* % // CHECK-NEXT: call void @"?PutX@S@@QEAAXHHH@Z"(%class.S* {{[^,]*}} %{{.+}}, i32 noundef 23, i32 noundef 1, i32 noundef [[J]]) p1->x[23][1] = j; + // CHECK: call noundef i32 @"?GetY@S@@QEAAHHH@Z"(%class.S* {{[^,]*}} %{{.+}}, i32 noundef 123, i32 noundef 22) + int k = p1->y[123][22]; + // CHECK: [[K:%.+]] = load i32, i32* % + // CHECK-NEXT: call void @"?PutY@S@@QEAAXHHH@Z"(%class.S* {{[^,]*}} %{{.+}}, i32 noundef 16, i32 noundef 2, i32 noundef [[K]]) + p1->y[16][2] = k; + // CHECK: call noundef i32 @"?GetZ@S@@QEAAHHHH@Z"(%class.S* {{[^,]*}} %{{.+}}, i32 noundef 123, i32 noundef 22, i32 noundef 44) + k = p1->z[123][22][44]; + // CHECK: [[K:%.+]] = load i32, i32* % + // CHECK-NEXT: call void @"?PutZ@S@@QEAAXHHHH@Z"(%class.S* {{[^,]*}} %{{.+}}, i32 noundef 16, i32 noundef 2, i32 noundef 32, i32 noundef [[K]]) + p1->z[16][2][32] = k; // CHECK: call noundef float @"?GetX@?$St@M@@QEAAMMM@Z"(%class.St* {{[^,]*}} %{{.+}}, float noundef 2.230000e+02, float noundef 1.100000e+01) float j1 = p2->x[223][11]; // CHECK: [[J1:%.+]] = load float, float* % diff --git a/clang/test/SemaCXX/ms-property-error.cpp b/clang/test/SemaCXX/ms-property-error.cpp index 4173f840960c7..cda350e9b9672 100644 --- a/clang/test/SemaCXX/ms-property-error.cpp +++ b/clang/test/SemaCXX/ms-property-error.cpp @@ -5,6 +5,9 @@ class S { __declspec(property(get=GetX,put=PutX)) int x[]; int GetX(int i, int j) { return i+j; } // expected-note {{'GetX' declared here}} void PutX(int i, int j, int k) { j = i = k; } // expected-note {{'PutX' declared here}} + __declspec(property(get=GetY,put=PutY)) int y[][][]; + int GetY(int i, int j) { return i+j; } // expected-note {{'GetY' declared here}} + void PutY(int i, int j, int k) { j = i = k; } // expected-note {{'PutY' declared here}} }; char *ptr; @@ -30,6 +33,8 @@ int main(int argc, char **argv) { St a; // expected-note {{in instantiation of member function 'St::~St' requested here}} int j = (p1->x)[223][11][2]; // expected-error {{too many arguments to function call, expected 2, have 3}} (p1->x[23]) = argc; // expected-error {{too few arguments to function call, expected 3, have 2}} + int k = (p1->y)[223][11][2][4]; // expected-error {{too many arguments to function call, expected 2, have 4}} + (p1->y[23]) = argc; // expected-error {{too few arguments to function call, expected 3, have 2}} float j1 = (p2->x); // expected-error {{too few arguments to function call, expected 2, have 0}} ((p2->x)[23])[1][2] = *argv; // expected-error {{too many arguments to function call, expected 3, have 4}} argv = p2->x[11][22] = argc; // expected-error {{assigning to 'char **' from incompatible type 'float'}} diff --git a/clang/test/SemaCXX/ms-property.cpp b/clang/test/SemaCXX/ms-property.cpp index d33dbf0a0ded6..168987b246223 100644 --- a/clang/test/SemaCXX/ms-property.cpp +++ b/clang/test/SemaCXX/ms-property.cpp @@ -22,6 +22,12 @@ class S { __declspec(property(get=GetX,put=PutX)) int x[]; int GetX(int i, int j) { return i+j; } void PutX(int i, int j, int k) { j = i = k; } + __declspec(property(get=GetY,put=PutY)) int y[][]; + int GetY(int i, int j) { return i+j; } + void PutY(int i, int j, int k) { j = i = k; } + __declspec(property(get=GetZ,put=PutZ)) int z[][][]; + int GetZ(int i, int j, int k); + void PutZ(int i, int j, int k, int val); }; template @@ -30,11 +36,21 @@ class St { __declspec(property(get=GetX,put=PutX)) T x[]; T GetX(T i, T j) { return i+j; } T PutX(T i, T j, T k) { return j = i = k; } - ~St() { x[0][0] = x[1][1]; } + __declspec(property(get=GetY,put=PutY)) T y[][]; + T GetY(T i, T j) { return i+j; } + T PutY(T i, T j, T k) { return j = i = k; } + __declspec(property(get=GetZ,put=PutZ)) T z[][][]; + T GetZ(T i, T j, T k) { return i+j+k; } + T PutZ(T i, T j, T k, T v) { return j = i = k = v; } + ~St() { x[0][0] = x[1][1]; y[0][0] = x[1][1]; z[0][1][2] = z[2][1][0]; } }; // CHECK: this->x[0][0] = this->x[1][1]; +// CHECK: this->y[0][0] = this->x[1][1]; +// CHECK: this->z[0][1][2] = this->z[2][1][0]; // CHECK: this->x[0][0] = this->x[1][1]; +// CHECK: this->y[0][0] = this->x[1][1]; +// CHECK: this->z[0][1][2] = this->z[2][1][0]; // CHECK-LABEL: main int main(int argc, char **argv) { @@ -46,10 +62,22 @@ int main(int argc, char **argv) { int j = (p1->x)[223][11]; // CHECK-NEXT: (p1->x[23])[1] = j; (p1->x[23])[1] = j; + // CHECK-NEXT: int k = (p1->y)[223][11]; + int k = (p1->y)[223][11]; + // CHECK-NEXT: (p1->y[23])[1] = k; + (p1->y[23])[1] = k; + // CHECK-NEXT: int k3 = p1->z[1][2][3]; + int k3 = p1->z[1][2][3]; + // CHECK-NEXT: p1->z[0][2][1] = k3; + p1->z[0][2][1] = k3; // CHECK-NEXT: float j1 = (p2->x[223][11]); float j1 = (p2->x[223][11]); // CHECK-NEXT: ((p2->x)[23])[1] = j1; ((p2->x)[23])[1] = j1; + // CHECK-NEXT: float k1 = (p2->y[223][11]); + float k1 = (p2->y[223][11]); + // CHECK-NEXT: ((p2->y)[23])[1] = k1; + ((p2->y)[23])[1] = k1; // CHECK-NEXT: ++(((p2->x)[23])[1]); ++(((p2->x)[23])[1]); // CHECK-NEXT: j1 = ((p2->x)[23])[1] = j1;