Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators)
<< DS.getSourceRange();
}
+ }
- // Microsoft allows unnamed struct/union fields. Don't complain
- // about them.
- // FIXME: Should we support Microsoft's extensions in this area?
- if (Record->getDeclName() && getLangOptions().Microsoft)
- return Tag;
+ // Check for Microsoft C extension: anonymous struct.
+ if (getLangOptions().Microsoft && !getLangOptions().CPlusPlus &&
+ CurContext->isRecord() &&
+ DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) {
+ // Handle 2 kinds of anonymous struct:
+ // struct STRUCT;
+ // and
+ // STRUCT_TYPE; <- where STRUCT_TYPE is a typedef struct.
+ RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag);
+ if ((Record && Record->getDeclName() && !Record->isDefinition()) ||
+ (DS.getTypeSpecType() == DeclSpec::TST_typename &&
+ DS.getRepAsType().get()->isStructureType())) {
+ Diag(DS.getSourceRange().getBegin(), diag::ext_ms_anonymous_struct)
+ << DS.getSourceRange();
+ return BuildMicrosoftCAnonymousStruct(S, DS, Record);
+ }
}
if (getLangOptions().CPlusPlus &&
DeclContext *Owner,
RecordDecl *AnonRecord,
AccessSpecifier AS,
- llvm::SmallVector<NamedDecl*, 2> &Chaining) {
+ llvm::SmallVector<NamedDecl*, 2> &Chaining,
+ bool MSAnonStruct) {
unsigned diagKind
= AnonRecord->isUnion() ? diag::err_anonymous_union_member_redecl
: diag::err_anonymous_struct_member_redecl;
bool Invalid = false;
- for (RecordDecl::field_iterator F = AnonRecord->field_begin(),
- FEnd = AnonRecord->field_end();
- F != FEnd; ++F) {
- if ((*F)->getDeclName()) {
- if (CheckAnonMemberRedeclaration(SemaRef, S, Owner, (*F)->getDeclName(),
- (*F)->getLocation(), diagKind)) {
+
+ // Look every FieldDecl and IndirectFieldDecl with a name.
+ for (RecordDecl::decl_iterator D = AnonRecord->decls_begin(),
+ DEnd = AnonRecord->decls_end();
+ D != DEnd; ++D) {
+ if ((isa<FieldDecl>(*D) || isa<IndirectFieldDecl>(*D)) &&
+ cast<NamedDecl>(*D)->getDeclName()) {
+ ValueDecl *VD = cast<ValueDecl>(*D);
+ if (CheckAnonMemberRedeclaration(SemaRef, S, Owner, VD->getDeclName(),
+ VD->getLocation(), diagKind)) {
// C++ [class.union]p2:
// The names of the members of an anonymous union shall be
// distinct from the names of any other entity in the
// definition, the members of the anonymous union are
// considered to have been defined in the scope in which the
// anonymous union is declared.
- Chaining.push_back(*F);
+ unsigned OldChainingSize = Chaining.size();
+ if (IndirectFieldDecl *IF = dyn_cast<IndirectFieldDecl>(VD))
+ for (IndirectFieldDecl::chain_iterator PI = IF->chain_begin(),
+ PE = IF->chain_end(); PI != PE; ++PI)
+ Chaining.push_back(*PI);
+ else
+ Chaining.push_back(VD);
+
assert(Chaining.size() >= 2);
NamedDecl **NamedChain =
new (SemaRef.Context)NamedDecl*[Chaining.size()];
NamedChain[i] = Chaining[i];
IndirectFieldDecl* IndirectField =
- IndirectFieldDecl::Create(SemaRef.Context, Owner, F->getLocation(),
- F->getIdentifier(), F->getType(),
+ IndirectFieldDecl::Create(SemaRef.Context, Owner, VD->getLocation(),
+ VD->getIdentifier(), VD->getType(),
NamedChain, Chaining.size());
IndirectField->setAccess(AS);
SemaRef.PushOnScopeChains(IndirectField, S);
// That includes picking up the appropriate access specifier.
- if (AS != AS_none) (*F)->setAccess(AS);
+ if (AS != AS_none) IndirectField->setAccess(AS);
- Chaining.pop_back();
+ Chaining.resize(OldChainingSize);
}
- } else if (const RecordType *InnerRecordType
- = (*F)->getType()->getAs<RecordType>()) {
- RecordDecl *InnerRecord = InnerRecordType->getDecl();
-
- Chaining.push_back(*F);
- if (InnerRecord->isAnonymousStructOrUnion())
- Invalid = Invalid ||
- InjectAnonymousStructOrUnionMembers(SemaRef, S, Owner,
- InnerRecord, AS, Chaining);
- Chaining.pop_back();
}
}
llvm_unreachable("unknown storage class specifier");
}
-/// ActOnAnonymousStructOrUnion - Handle the declaration of an
+/// BuildAnonymousStructOrUnion - Handle the declaration of an
/// anonymous structure or union. Anonymous unions are a C++ feature
/// (C++ [class.union]) and a GNU C extension; anonymous structures
/// are a GNU C and GNU C++ extension.
llvm::SmallVector<NamedDecl*, 2> Chain;
Chain.push_back(Anon);
- if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS, Chain))
+ if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS,
+ Chain, false))
Invalid = true;
// Mark this as an anonymous struct/union type. Note that we do not
return Anon;
}
+/// BuildMicrosoftCAnonymousStruct - Handle the declaration of an
+/// Microsoft C anonymous structure.
+/// Ref: http://msdn.microsoft.com/en-us/library/z2cx9y4f.aspx
+/// Example:
+///
+/// struct A { int a; };
+/// struct B { struct A; int b; };
+///
+/// void foo() {
+/// B var;
+/// var.a = 3;
+/// }
+///
+Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
+ RecordDecl *Record) {
+
+ // If there is no Record, get the record via the typedef.
+ if (!Record)
+ Record = DS.getRepAsType().get()->getAsStructureType()->getDecl();
+
+ // Mock up a declarator.
+ Declarator Dc(DS, Declarator::TypeNameContext);
+ TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S);
+ assert(TInfo && "couldn't build declarator info for anonymous struct");
+
+ // Create a declaration for this anonymous struct.
+ NamedDecl* Anon = FieldDecl::Create(Context,
+ cast<RecordDecl>(CurContext),
+ DS.getSourceRange().getBegin(),
+ /*IdentifierInfo=*/0,
+ Context.getTypeDeclType(Record),
+ TInfo,
+ /*BitWidth=*/0, /*Mutable=*/false);
+ Anon->setImplicit();
+
+ // Add the anonymous struct object to the current context.
+ CurContext->addDecl(Anon);
+
+ // Inject the members of the anonymous struct into the current
+ // context and into the identifier resolver chain for name lookup
+ // purposes.
+ llvm::SmallVector<NamedDecl*, 2> Chain;
+ Chain.push_back(Anon);
+
+ if (InjectAnonymousStructOrUnionMembers(*this, S, CurContext,
+ Record->getDefinition(),
+ AS_none, Chain, true))
+ Anon->setInvalidDecl();
+
+ return Anon;
+}
/// GetNameForDeclarator - Determine the full declaration name for the
/// given Declarator.
--- /dev/null
+// RUN: %clang_cc1 -fms-extensions -emit-llvm -o - %s | FileCheck %s\r
+\r
+// CHECK: %struct.nested1 = type { i32, i32 }\r
+typedef struct nested1 {\r
+ long a1;\r
+ long b1;\r
+} NESTED1;\r
+\r
+// CHECK: %struct.nested2 = type { i32, %struct.nested1, i32 }\r
+struct nested2 {\r
+ long a;\r
+ NESTED1; \r
+ long b;\r
+};\r
+\r
+// CHECK: %struct.test = type { i32, %struct.nested2, i32 }\r
+struct test {\r
+ int x;\r
+ struct nested2; \r
+ int y;\r
+};\r
+\r
+\r
+void foo()\r
+{\r
+ // CHECK: %var = alloca %struct.test, align 4\r
+ struct test var;\r
+\r
+ // CHECK: getelementptr inbounds %struct.test* %var, i32 0, i32 1\r
+ // CHECK-NEXT: getelementptr inbounds %struct.nested2* %{{.*}}, i32 0, i32 0\r
+ // CHECK-NEXT: load i32* %{{.*}}, align 4\r
+ var.a;\r
+\r
+ // CHECK-NEXT: getelementptr inbounds %struct.test* %var, i32 0, i32 1\r
+ // CHECK-NEXT: getelementptr inbounds %struct.nested2* %{{.*}}, i32 0, i32 2\r
+ // CHECK-NEXT: load i32* %{{.*}}, align 4\r
+ var.b;\r
+\r
+ // CHECK-NEXT: getelementptr inbounds %struct.test* %var, i32 0, i32 1\r
+ // CHECK-NEXT: getelementptr inbounds %struct.nested2* %{{.*}}, i32 0, i32 1\r
+ // CHECK-NEXT: getelementptr inbounds %struct.nested1* %{{.*}}, i32 0, i32 0\r
+ // CHECK-NEXT: load i32* %{{.*}}, align 4\r
+ var.a1;\r
+\r
+ // CHECK-NEXT: getelementptr inbounds %struct.test* %{{.*}}var, i32 0, i32 1\r
+ // CHECK-NEXT: getelementptr inbounds %struct.nested2* %{{.*}}, i32 0, i32 1\r
+ // CHECK-NEXT: getelementptr inbounds %struct.nested1* %{{.*}}, i32 0, i32 1\r
+ // CHECK-NEXT: load i32* %{{.*}}, align 4\r
+ var.b1;\r
+\r
+ // CHECK-NEXT: getelementptr inbounds %struct.test* %var, i32 0, i32 0\r
+ // CHECK-NEXT: load i32* %{{.*}}, align 4\r
+ var.x;\r
+\r
+ // CHECK-NEXT: getelementptr inbounds %struct.test* %var, i32 0, i32 2\r
+ // CHECK-NEXT: load i32* %{{.*}}, align 4\r
+ var.y;\r
+}\r
+\r
+void foo2(struct test* var)\r
+{\r
+ // CHECK: alloca %struct.test*, align 4\r
+ // CHECK-NEXT: store %struct.test* %var, %struct.test** %{{.*}}, align 4\r
+ // CHECK-NEXT: load %struct.test** %{{.*}}, align 4\r
+ // CHECK-NEXT: getelementptr inbounds %struct.test* %{{.*}}, i32 0, i32 1\r
+ // CHECK-NEXT: getelementptr inbounds %struct.nested2* %{{.*}}, i32 0, i32 0\r
+ // CHECK-NEXT: load i32* %{{.*}}, align 4\r
+ var->a;\r
+\r
+ // CHECK-NEXT: load %struct.test** %{{.*}}, align 4\r
+ // CHECK-NEXT: getelementptr inbounds %struct.test* %{{.*}}, i32 0, i32 1\r
+ // CHECK-NEXT: getelementptr inbounds %struct.nested2* %{{.*}}, i32 0, i32 2\r
+ // CHECK-NEXT: load i32* %{{.*}}, align 4\r
+ var->b;\r
+\r
+ // CHECK-NEXT: load %struct.test** %{{.*}}, align 4\r
+ // CHECK-NEXT: getelementptr inbounds %struct.test* %{{.*}}, i32 0, i32 1\r
+ // CHECK-NEXT: getelementptr inbounds %struct.nested2* %{{.*}}, i32 0, i32 1\r
+ // CHECK-NEXT: getelementptr inbounds %struct.nested1* %{{.*}}, i32 0, i32 0\r
+ // CHECK-NEXT: load i32* %{{.*}}, align 4\r
+ var->a1;\r
+\r
+ // CHECK-NEXT: load %struct.test** %{{.*}}, align 4\r
+ // CHECK-NEXT: getelementptr inbounds %struct.test* %{{.*}}, i32 0, i32 1\r
+ // CHECK-NEXT: getelementptr inbounds %struct.nested2* %{{.*}}, i32 0, i32 1\r
+ // CHECK-NEXT: getelementptr inbounds %struct.nested1* %{{.*}}, i32 0, i32 1\r
+ // CHECK-NEXT: load i32* %{{.*}}, align 4\r
+ var->b1;\r
+\r
+ // CHECK-NEXT: load %struct.test** %{{.*}}, align 4\r
+ // CHECK-NEXT: getelementptr inbounds %struct.test* %{{.*}}, i32 0, i32 0\r
+ // CHECK-NEXT: load i32* %{{.*}}, align 4\r
+ var->x;\r
+\r
+ // CHECK-NEXT: load %struct.test** %{{.*}}, align 4\r
+ // CHECK-NEXT: getelementptr inbounds %struct.test* %{{.*}}, i32 0, i32 2\r
+ // CHECK-NEXT: load i32* %{{.*}}, align 4\r
+ var->y;\r
+}\r