Sema: Handle declspecs without declarators in records properly in C mode
We had two bugs:
- We wouldn't properly warn when a struct/union/enum was mentioned
inside of a record definition if no declarator was provided. We
should have mentioned that this declaration declares nothing.
- We didn't properly support Microsoft's extension where certain
declspecs without declarators would act as anonymous structs/unions.
* We completely ignored the case where such a declspec could be a
union.
* We didn't properly handle the case where a record was defined inside
another record:
struct X {
int a;
struct Y {
int b;
};
};
llvm-svn: 215347
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 85c88a3..53a6471 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -3444,21 +3444,36 @@
}
}
- // Check for Microsoft C extension: anonymous struct member.
- if (getLangOpts().MicrosoftExt && !getLangOpts().CPlusPlus &&
- CurContext->isRecord() &&
+ // C11 6.7.2.1p2:
+ // A struct-declaration that does not declare an anonymous structure or
+ // anonymous union shall contain a struct-declarator-list.
+ if (!getLangOpts().CPlusPlus && CurContext->isRecord() &&
DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) {
- // Handle 2 kinds of anonymous struct:
+ // Check for Microsoft C extension: anonymous struct/union member.
+ // Handle 2 kinds of anonymous struct/union:
// struct STRUCT;
+ // union UNION;
// and
// STRUCT_TYPE; <- where STRUCT_TYPE is a typedef struct.
- RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag);
- if ((Record && Record->getDeclName() && !Record->isCompleteDefinition()) ||
- (DS.getTypeSpecType() == DeclSpec::TST_typename &&
- DS.getRepAsType().get()->isStructureType())) {
- Diag(DS.getLocStart(), diag::ext_ms_anonymous_struct)
- << DS.getSourceRange();
- return BuildMicrosoftCAnonymousStruct(S, DS, Record);
+ // UNION_TYPE; <- where UNION_TYPE is a typedef union.
+ if ((Tag && Tag->getDeclName()) ||
+ DS.getTypeSpecType() == DeclSpec::TST_typename) {
+ RecordDecl *Record = nullptr;
+ if (Tag)
+ Record = dyn_cast<RecordDecl>(Tag);
+ else if (const RecordType *RT =
+ DS.getRepAsType().get()->getAsStructureType())
+ Record = RT->getDecl();
+ else if (const RecordType *UT = DS.getRepAsType().get()->getAsUnionType())
+ Record = UT->getDecl();
+
+ if (Record && getLangOpts().MicrosoftExt) {
+ Diag(DS.getLocStart(), diag::ext_ms_anonymous_record)
+ << Record->isUnion() << DS.getSourceRange();
+ return BuildMicrosoftCAnonymousStruct(S, DS, Record);
+ }
+
+ DeclaresAnything = false;
}
}
@@ -3999,15 +4014,12 @@
///
/// void foo() {
/// B var;
-/// var.a = 3;
+/// 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();
+ assert(Record && "expected a record!");
// Mock up a declarator.
Declarator Dc(DS, Declarator::TypeNameContext);