- 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
------------------
});
}
+ 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;
};
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,
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
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)
}
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>()) {
__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>
// 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* %
__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;
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'}}
__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>
__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) {
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;