[clang] 57caadc - [MSVC] Allow declaration of multi-dim 'property' array fields
Mike Rice via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 5 10:30:32 PDT 2023
Author: Mike Rice
Date: 2023-04-05T10:29:37-07:00
New Revision: 57caadc57a30f2279099e5b86bb555b4aab621ce
URL: https://github.com/llvm/llvm-project/commit/57caadc57a30f2279099e5b86bb555b4aab621ce
DIFF: https://github.com/llvm/llvm-project/commit/57caadc57a30f2279099e5b86bb555b4aab621ce.diff
LOG: [MSVC] Allow declaration of multi-dim 'property' array fields
MSVC allows declaration of multi-dim arrays like this:
__declspec(property(get=GetX, put=PutX)) int x[][][];
This syntax can appear in generated typelib headers.
Currently clang errors on declarators like this since it forms an array
type of incomplete array. Rather than try to handle such a type, ignore
adjacent empty chunks so this is treated as if there was only one empty
array chunk (i.e. int x[]).
The functionality to handle multi-dim subscripts of property fields
already works, but only if declared as a single-dim array.
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/Sema/ParsedAttr.h
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaType.cpp
clang/test/CodeGenCXX/ms-property.cpp
clang/test/SemaCXX/ms-property-error.cpp
clang/test/SemaCXX/ms-property.cpp
Removed:
################################################################################
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<CXXRecordDecl>(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<Expr*>(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<AtomicTypeLoc>()) {
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 <typename T>
@@ -58,6 +64,16 @@ int main(int argc, char **argv) {
// CHECK: [[J:%.+]] = load i32, i32* %
// CHECK-NEXT: call void @"?PutX at S@@QEAAXHHH at Z"(%class.S* {{[^,]*}} %{{.+}}, i32 noundef 23, i32 noundef 1, i32 noundef [[J]])
p1->x[23][1] = j;
+ // CHECK: call noundef i32 @"?GetY at S@@QEAAHHH at 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 at S@@QEAAXHHH at Z"(%class.S* {{[^,]*}} %{{.+}}, i32 noundef 16, i32 noundef 2, i32 noundef [[K]])
+ p1->y[16][2] = k;
+ // CHECK: call noundef i32 @"?GetZ at S@@QEAAHHHH at 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 at S@@QEAAXHHHH at 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 at M@@QEAAMMM at 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<int> a; // expected-note {{in instantiation of member function 'St<int>::~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 <typename T>
@@ -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;
More information about the cfe-commits
mailing list