[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