forked from OSchip/llvm-project
Finished semantic analysis of anonymous unions in C++.
Duplicate-member checking within classes is still a little messy, and anonymous unions are still completely broken in C. We'll need to unify the handling of fields in C and C++ to make this code applicable in both languages. llvm-svn: 61878
This commit is contained in:
parent
289f59f233
commit
f4d332797b
|
@ -160,6 +160,9 @@ public:
|
|||
const_cast<const ScopedDecl*>(this)->getDeclContext());
|
||||
}
|
||||
|
||||
void setAccess(AccessSpecifier AS) { Access = AS; }
|
||||
AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
|
||||
|
||||
/// getLexicalDeclContext - The declaration context where this ScopedDecl was
|
||||
/// lexically declared (LexicalDC). May be different from
|
||||
/// getDeclContext() (SemanticDC).
|
||||
|
@ -360,7 +363,7 @@ public:
|
|||
StorageClass getStorageClass() const { return (StorageClass)SClass; }
|
||||
|
||||
SourceLocation getTypeSpecStartLoc() const { return TypeSpecStartLoc; }
|
||||
|
||||
|
||||
const Expr *getInit() const { return (const Expr*) Init; }
|
||||
Expr *getInit() { return (Expr*) Init; }
|
||||
void setInit(Expr *I) { Init = (Stmt*) I; }
|
||||
|
@ -624,7 +627,6 @@ private:
|
|||
// NOTE: VC++ treats enums as signed, avoid using the StorageClass enum
|
||||
unsigned SClass : 2;
|
||||
bool IsInline : 1;
|
||||
bool IsImplicit : 1;
|
||||
|
||||
// Move to DeclGroup when it is implemented.
|
||||
SourceLocation TypeSpecStartLoc;
|
||||
|
@ -636,7 +638,7 @@ protected:
|
|||
: ValueDecl(DK, DC, L, N, T, PrevDecl),
|
||||
DeclContext(DK),
|
||||
ParamInfo(0), Body(0), PreviousDeclaration(0),
|
||||
SClass(S), IsInline(isInline), IsImplicit(0), TypeSpecStartLoc(TSSL) {}
|
||||
SClass(S), IsInline(isInline), TypeSpecStartLoc(TSSL) {}
|
||||
|
||||
virtual ~FunctionDecl();
|
||||
virtual void Destroy(ASTContext& C);
|
||||
|
@ -670,9 +672,6 @@ public:
|
|||
|
||||
void setBody(Stmt *B) { Body = B; }
|
||||
|
||||
bool isImplicit() { return IsImplicit; }
|
||||
void setImplicit() { IsImplicit = true; }
|
||||
|
||||
/// getPreviousDeclaration - Return the previous declaration of this
|
||||
/// function.
|
||||
const FunctionDecl *getPreviousDeclaration() const {
|
||||
|
@ -776,6 +775,12 @@ public:
|
|||
/// isBitfield - Determines whether this field is a bitfield.
|
||||
bool isBitField() const { return BitWidth != NULL; }
|
||||
|
||||
/// isAnonymousStructOrUnion - Determines whether this field is a
|
||||
/// representative for an anonymous struct or union. Such fields are
|
||||
/// unnamed and are implicitly generated by the implementation to
|
||||
/// store the data for the anonymous union or struct.
|
||||
bool isAnonymousStructOrUnion() const;
|
||||
|
||||
Expr *getBitWidth() const { return BitWidth; }
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
|
@ -852,10 +857,8 @@ protected:
|
|||
TypeDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, ScopedDecl *PrevDecl)
|
||||
: ScopedDecl(DK, DC, L, Id, PrevDecl), TypeForDecl(0) {}
|
||||
public:
|
||||
void setAccess(AccessSpecifier AS) { Access = AS; }
|
||||
AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
|
||||
|
||||
public:
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() >= TypeFirst && D->getKind() <= TypeLast;
|
||||
|
|
|
@ -141,6 +141,10 @@ private:
|
|||
/// HasAttrs - This indicates whether the decl has attributes or not.
|
||||
unsigned int HasAttrs : 1;
|
||||
|
||||
/// Implicit - Whether this declaration was implicitly generated by
|
||||
/// the implementation rather than explicitly written by the user.
|
||||
bool Implicit : 1;
|
||||
|
||||
protected:
|
||||
/// Access - Used by C++ decls for the access specifier.
|
||||
// NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum
|
||||
|
@ -178,6 +182,12 @@ public:
|
|||
/// allows for graceful error recovery.
|
||||
void setInvalidDecl() { InvalidDecl = 1; }
|
||||
bool isInvalidDecl() const { return (bool) InvalidDecl; }
|
||||
|
||||
/// isImplicit - Indicates whether the declaration was implicitly
|
||||
/// generated by the implementation. If false, this declaration
|
||||
/// was written explicitly in the source code.
|
||||
bool isImplicit() const { return Implicit; }
|
||||
void setImplicit(bool I = true) { Implicit = I; }
|
||||
|
||||
IdentifierNamespace getIdentifierNamespace() const {
|
||||
switch (DeclKind) {
|
||||
|
|
|
@ -463,9 +463,6 @@ public:
|
|||
return getLexicalDeclContext() != getDeclContext();
|
||||
}
|
||||
|
||||
void setAccess(AccessSpecifier AS) { Access = AS; }
|
||||
AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
|
||||
|
||||
/// getParent - Returns the parent of this method declaration, which
|
||||
/// is the class in which this method is defined.
|
||||
const CXXRecordDecl *getParent() const {
|
||||
|
@ -617,16 +614,12 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
|||
/// Explicit - Whether this constructor is explicit.
|
||||
bool Explicit : 1;
|
||||
|
||||
/// ImplicitlyDeclared - Whether this constructor was implicitly
|
||||
/// declared. When false, the constructor was declared by the user.
|
||||
bool ImplicitlyDeclared : 1;
|
||||
|
||||
/// ImplicitlyDefined - Whether this constructor was implicitly
|
||||
/// defined by the compiler. When false, the constructor was defined
|
||||
/// by the user. In C++03, this flag will have the same value as
|
||||
/// ImplicitlyDeclared. In C++0x, however, a constructor that is
|
||||
/// Implicit. In C++0x, however, a constructor that is
|
||||
/// explicitly defaulted (i.e., defined with " = default") will have
|
||||
/// @c !ImplicitlyDeclared && ImplicitlyDefined.
|
||||
/// @c !Implicit && ImplicitlyDefined.
|
||||
bool ImplicitlyDefined : 1;
|
||||
|
||||
/// FIXME: Add support for base and member initializers.
|
||||
|
@ -636,8 +629,9 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
|||
bool isExplicit, bool isInline, bool isImplicitlyDeclared)
|
||||
: CXXMethodDecl(CXXConstructor, RD, L, N, T, false, isInline,
|
||||
/*PrevDecl=*/0),
|
||||
Explicit(isExplicit), ImplicitlyDeclared(isImplicitlyDeclared),
|
||||
ImplicitlyDefined(false) { }
|
||||
Explicit(isExplicit), ImplicitlyDefined(false) {
|
||||
setImplicit(isImplicitlyDeclared);
|
||||
}
|
||||
|
||||
public:
|
||||
static CXXConstructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
|
||||
|
@ -648,11 +642,6 @@ public:
|
|||
/// isExplicit - Whether this constructor was marked "explicit" or not.
|
||||
bool isExplicit() const { return Explicit; }
|
||||
|
||||
/// isImplicitlyDeclared - Whether this constructor was implicitly
|
||||
/// declared. If false, then this constructor was explicitly
|
||||
/// declared by the user.
|
||||
bool isImplicitlyDeclared() const { return ImplicitlyDeclared; }
|
||||
|
||||
/// isImplicitlyDefined - Whether this constructor was implicitly
|
||||
/// defined. If false, then this constructor was defined by the
|
||||
/// user. This operation can only be invoked if the constructor has
|
||||
|
@ -728,16 +717,12 @@ public:
|
|||
/// };
|
||||
/// @endcode
|
||||
class CXXDestructorDecl : public CXXMethodDecl {
|
||||
/// ImplicitlyDeclared - Whether this destructor was implicitly
|
||||
/// declared. When false, the destructor was declared by the user.
|
||||
bool ImplicitlyDeclared : 1;
|
||||
|
||||
/// ImplicitlyDefined - Whether this destructor was implicitly
|
||||
/// defined by the compiler. When false, the destructor was defined
|
||||
/// by the user. In C++03, this flag will have the same value as
|
||||
/// ImplicitlyDeclared. In C++0x, however, a destructor that is
|
||||
/// Implicit. In C++0x, however, a destructor that is
|
||||
/// explicitly defaulted (i.e., defined with " = default") will have
|
||||
/// @c !ImplicitlyDeclared && ImplicitlyDefined.
|
||||
/// @c !Implicit && ImplicitlyDefined.
|
||||
bool ImplicitlyDefined : 1;
|
||||
|
||||
CXXDestructorDecl(CXXRecordDecl *RD, SourceLocation L,
|
||||
|
@ -745,8 +730,9 @@ class CXXDestructorDecl : public CXXMethodDecl {
|
|||
bool isInline, bool isImplicitlyDeclared)
|
||||
: CXXMethodDecl(CXXDestructor, RD, L, N, T, false, isInline,
|
||||
/*PrevDecl=*/0),
|
||||
ImplicitlyDeclared(isImplicitlyDeclared),
|
||||
ImplicitlyDefined(false) { }
|
||||
ImplicitlyDefined(false) {
|
||||
setImplicit(isImplicitlyDeclared);
|
||||
}
|
||||
|
||||
public:
|
||||
static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
|
||||
|
@ -754,11 +740,6 @@ public:
|
|||
QualType T, bool isInline,
|
||||
bool isImplicitlyDeclared);
|
||||
|
||||
/// isImplicitlyDeclared - Whether this destructor was implicitly
|
||||
/// declared. If false, then this destructor was explicitly
|
||||
/// declared by the user.
|
||||
bool isImplicitlyDeclared() const { return ImplicitlyDeclared; }
|
||||
|
||||
/// isImplicitlyDefined - Whether this destructor was implicitly
|
||||
/// defined. If false, then this destructor was defined by the
|
||||
/// user. This operation can only be invoked if the destructor has
|
||||
|
@ -857,9 +838,6 @@ public:
|
|||
SourceLocation L,IdentifierInfo *Id,
|
||||
QualType T, ScopedDecl *PrevDecl);
|
||||
|
||||
void setAccess(AccessSpecifier AS) { Access = AS; }
|
||||
AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return D->getKind() == CXXClassVar; }
|
||||
static bool classof(const CXXClassVarDecl *D) { return true; }
|
||||
|
|
|
@ -1476,7 +1476,7 @@ DIAG(err_base_init_direct_and_virtual, ERROR,
|
|||
"base class initializer %0 names both a direct base class and an"
|
||||
" inherited virtual base class")
|
||||
|
||||
// C++ anonymous unions and GNU anonymous structs
|
||||
// C++ anonymous unions and GNU anonymous structs/unions
|
||||
DIAG(ext_anonymous_union, EXTENSION,
|
||||
"anonymous unions are a GNU extension in C")
|
||||
DIAG(ext_anonymous_struct, EXTENSION,
|
||||
|
@ -1491,6 +1491,16 @@ DIAG(err_anonymous_union_member_redecl, ERROR,
|
|||
"member of anonymous union redeclares %0")
|
||||
DIAG(err_anonymous_struct_member_redecl, ERROR,
|
||||
"member of anonymous struct redeclares %0")
|
||||
DIAG(err_anonymous_record_with_type, ERROR,
|
||||
"types cannot be declared in an anonymous %select{struct|union}0")
|
||||
DIAG(err_anonymous_record_with_function, ERROR,
|
||||
"functions cannot be declared in an anonymous %select{struct|union}0")
|
||||
DIAG(err_anonymous_record_with_static, ERROR,
|
||||
"static members cannot be declared in an anonymous %select{struct|union}0")
|
||||
DIAG(err_anonymous_record_bad_member, ERROR,
|
||||
"anonymous %select{struct|union}0 can only contain non-static data members")
|
||||
DIAG(err_anonymous_record_nonpublic_member, ERROR,
|
||||
"anonymous %select{struct|union}0 cannot contain a %select{private|protected}1 data member")
|
||||
|
||||
// Derived classes.
|
||||
DIAG(err_dup_virtual, ERROR,
|
||||
|
|
|
@ -97,6 +97,15 @@ FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
|
|||
return new (Mem) FieldDecl(Decl::Field, DC, L, Id, T, BW, Mutable, PrevDecl);
|
||||
}
|
||||
|
||||
bool FieldDecl::isAnonymousStructOrUnion() const {
|
||||
if (!isImplicit() || getDeclName())
|
||||
return false;
|
||||
|
||||
if (const RecordType *Record = getType()->getAsRecordType())
|
||||
return Record->getDecl()->isAnonymousStructOrUnion();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD,
|
||||
SourceLocation L,
|
||||
|
|
|
@ -153,7 +153,7 @@ bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const {
|
|||
void
|
||||
CXXRecordDecl::addedConstructor(ASTContext &Context,
|
||||
CXXConstructorDecl *ConDecl) {
|
||||
if (!ConDecl->isImplicitlyDeclared()) {
|
||||
if (!ConDecl->isImplicit()) {
|
||||
// Note that we have a user-declared constructor.
|
||||
UserDeclaredConstructor = true;
|
||||
|
||||
|
|
|
@ -924,6 +924,48 @@ Sema::DeclTy *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
|
|||
DS.SetStorageClassSpec(DeclSpec::SCS_unspecified, SourceLocation(),
|
||||
PrevSpec);
|
||||
}
|
||||
|
||||
// C++ [class.union]p2:
|
||||
// The member-specification of an anonymous union shall only
|
||||
// define non-static data members. [Note: nested types and
|
||||
// functions cannot be declared within an anonymous union. ]
|
||||
for (DeclContext::decl_iterator Mem = Record->decls_begin(),
|
||||
MemEnd = Record->decls_end();
|
||||
Mem != MemEnd; ++Mem) {
|
||||
if (FieldDecl *FD = dyn_cast<FieldDecl>(*Mem)) {
|
||||
// C++ [class.union]p3:
|
||||
// An anonymous union shall not have private or protected
|
||||
// members (clause 11).
|
||||
if (FD->getAccess() == AS_protected || FD->getAccess() == AS_private) {
|
||||
Diag(FD->getLocation(), diag::err_anonymous_record_nonpublic_member)
|
||||
<< (int)Record->isUnion() << (int)(FD->getAccess() == AS_protected);
|
||||
Invalid = true;
|
||||
}
|
||||
} else if ((*Mem)->isImplicit()) {
|
||||
// Any implicit members are fine.
|
||||
} else if (RecordDecl *MemRecord = dyn_cast<RecordDecl>(*Mem)) {
|
||||
if (!MemRecord->isAnonymousStructOrUnion() &&
|
||||
MemRecord->getDeclName()) {
|
||||
// This is a nested type declaration.
|
||||
Diag(MemRecord->getLocation(), diag::err_anonymous_record_with_type)
|
||||
<< (int)Record->isUnion();
|
||||
Invalid = true;
|
||||
}
|
||||
} else {
|
||||
// We have something that isn't a non-static data
|
||||
// member. Complain about it.
|
||||
unsigned DK = diag::err_anonymous_record_bad_member;
|
||||
if (isa<TypeDecl>(*Mem))
|
||||
DK = diag::err_anonymous_record_with_type;
|
||||
else if (isa<FunctionDecl>(*Mem))
|
||||
DK = diag::err_anonymous_record_with_function;
|
||||
else if (isa<VarDecl>(*Mem))
|
||||
DK = diag::err_anonymous_record_with_static;
|
||||
Diag((*Mem)->getLocation(), DK)
|
||||
<< (int)Record->isUnion();
|
||||
Invalid = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// FIXME: Check GNU C semantics
|
||||
}
|
||||
|
@ -941,6 +983,9 @@ Sema::DeclTy *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
|
|||
Context.getTypeDeclType(Record),
|
||||
/*BitWidth=*/0, /*Mutable=*/false,
|
||||
/*PrevDecl=*/0);
|
||||
Anon->setAccess(AS_public);
|
||||
if (getLangOptions().CPlusPlus)
|
||||
FieldCollector->Add(cast<FieldDecl>(Anon));
|
||||
} else {
|
||||
VarDecl::StorageClass SC;
|
||||
switch (DS.getStorageClassSpec()) {
|
||||
|
@ -966,6 +1011,7 @@ Sema::DeclTy *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
|
|||
SC, /*FIXME:LastDeclarator=*/0,
|
||||
DS.getSourceRange().getBegin());
|
||||
}
|
||||
Anon->setImplicit();
|
||||
|
||||
// Add the anonymous struct/union object to the current
|
||||
// context. We'll be referencing this object when we refer to one of
|
||||
|
@ -3176,18 +3222,52 @@ void Sema::ActOnFields(Scope* S,
|
|||
// Verify that all the fields are okay.
|
||||
unsigned NumNamedMembers = 0;
|
||||
llvm::SmallVector<FieldDecl*, 32> RecFields;
|
||||
llvm::SmallSet<const IdentifierInfo*, 32> FieldIDs;
|
||||
|
||||
// FIXME: Eventually, we'd like to eliminate this in favor of
|
||||
// checking for redeclarations on-the-fly.
|
||||
llvm::DenseMap<const IdentifierInfo*, FieldDecl *> FieldIDs;
|
||||
|
||||
for (unsigned i = 0; i != NumFields; ++i) {
|
||||
|
||||
FieldDecl *FD = cast_or_null<FieldDecl>(static_cast<Decl*>(Fields[i]));
|
||||
assert(FD && "missing field decl");
|
||||
|
||||
// Remember all fields.
|
||||
RecFields.push_back(FD);
|
||||
|
||||
// Get the type for the field.
|
||||
Type *FDTy = FD->getType().getTypePtr();
|
||||
|
||||
if (FD->isAnonymousStructOrUnion()) {
|
||||
// We have found a field that represents an anonymous struct
|
||||
// or union. Introduce all of the inner fields (recursively)
|
||||
// into the list of fields we know about, so that we can produce
|
||||
// an appropriate error message in cases like:
|
||||
//
|
||||
// struct X {
|
||||
// union {
|
||||
// int x;
|
||||
// float f;
|
||||
// };
|
||||
// double x;
|
||||
// };
|
||||
llvm::SmallVector<FieldDecl *, 4> AnonStructUnionFields;
|
||||
AnonStructUnionFields.push_back(FD);
|
||||
while (!AnonStructUnionFields.empty()) {
|
||||
FieldDecl *AnonField = AnonStructUnionFields.back();
|
||||
AnonStructUnionFields.pop_back();
|
||||
|
||||
RecordDecl *AnonRecord
|
||||
= AnonField->getType()->getAsRecordType()->getDecl();
|
||||
for (RecordDecl::field_iterator F = AnonRecord->field_begin(),
|
||||
FEnd = AnonRecord->field_end();
|
||||
F != FEnd; ++F) {
|
||||
if ((*F)->isAnonymousStructOrUnion())
|
||||
AnonStructUnionFields.push_back(*F);
|
||||
else if (const IdentifierInfo *II = (*F)->getIdentifier())
|
||||
FieldIDs[II] = *F;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Remember all fields written by the user.
|
||||
RecFields.push_back(FD);
|
||||
}
|
||||
|
||||
// C99 6.7.2.1p2 - A field may not be a function type.
|
||||
if (FDTy->isFunctionType()) {
|
||||
|
@ -3262,23 +3342,16 @@ void Sema::ActOnFields(Scope* S,
|
|||
// Keep track of the number of named members.
|
||||
if (IdentifierInfo *II = FD->getIdentifier()) {
|
||||
// Detect duplicate member names.
|
||||
if (!FieldIDs.insert(II)) {
|
||||
if (FieldIDs[II]) {
|
||||
Diag(FD->getLocation(), diag::err_duplicate_member) << II;
|
||||
// Find the previous decl.
|
||||
SourceLocation PrevLoc;
|
||||
for (unsigned i = 0; ; ++i) {
|
||||
assert(i != RecFields.size() && "Didn't find previous def!");
|
||||
if (RecFields[i]->getIdentifier() == II) {
|
||||
PrevLoc = RecFields[i]->getLocation();
|
||||
break;
|
||||
}
|
||||
}
|
||||
Diag(PrevLoc, diag::note_previous_definition);
|
||||
Diag(FieldIDs[II]->getLocation(), diag::note_previous_definition);
|
||||
FD->setInvalidDecl();
|
||||
EnclosingDecl->setInvalidDecl();
|
||||
continue;
|
||||
}
|
||||
++NumNamedMembers;
|
||||
FieldIDs[II] = FD;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -427,9 +427,12 @@ void Sema::ActOnStartCXXClassDef(Scope *S, DeclTy *D, SourceLocation LBrace) {
|
|||
// class itself; this is known as the injected-class-name. For
|
||||
// purposes of access checking, the injected-class-name is treated
|
||||
// as if it were a public member name.
|
||||
PushOnScopeChains(CXXRecordDecl::Create(Context, Dcl->getTagKind(),
|
||||
CurContext, Dcl->getLocation(),
|
||||
Dcl->getIdentifier(), Dcl), S);
|
||||
RecordDecl *InjectedClassName
|
||||
= CXXRecordDecl::Create(Context, Dcl->getTagKind(),
|
||||
CurContext, Dcl->getLocation(),
|
||||
Dcl->getIdentifier(), Dcl);
|
||||
InjectedClassName->setImplicit();
|
||||
PushOnScopeChains(InjectedClassName, S);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -789,6 +792,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
|
|||
/*isInline=*/true,
|
||||
/*isImplicitlyDeclared=*/true);
|
||||
DefaultCon->setAccess(AS_public);
|
||||
DefaultCon->setImplicit();
|
||||
ClassDecl->addDecl(Context, DefaultCon);
|
||||
|
||||
// Notify the class that we've added a constructor.
|
||||
|
@ -860,6 +864,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
|
|||
/*isInline=*/true,
|
||||
/*isImplicitlyDeclared=*/true);
|
||||
CopyConstructor->setAccess(AS_public);
|
||||
CopyConstructor->setImplicit();
|
||||
|
||||
// Add the parameter to the constructor.
|
||||
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor,
|
||||
|
@ -936,6 +941,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
|
|||
false, 0),
|
||||
/*isStatic=*/false, /*isInline=*/true, 0);
|
||||
CopyAssignment->setAccess(AS_public);
|
||||
CopyAssignment->setImplicit();
|
||||
|
||||
// Add the parameter to the operator.
|
||||
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
|
||||
|
@ -964,6 +970,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
|
|||
/*isInline=*/true,
|
||||
/*isImplicitlyDeclared=*/true);
|
||||
Destructor->setAccess(AS_public);
|
||||
Destructor->setImplicit();
|
||||
ClassDecl->addDecl(Context, Destructor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,11 +66,11 @@ struct Redecl {
|
|||
union {
|
||||
int x; // expected-error{{member of anonymous union redeclares 'x'}}
|
||||
float y;
|
||||
double z; // FIXME: note here
|
||||
double z; // expected-note{{previous definition is here}}
|
||||
double zz; // expected-note{{previous definition is here}}
|
||||
};
|
||||
|
||||
int z; // FIXME: should complain here!
|
||||
int z; // expected-error{{duplicate member 'z'}}
|
||||
void zz(); // expected-error{{redefinition of 'zz' as different kind of symbol}}
|
||||
};
|
||||
|
||||
|
@ -92,8 +92,19 @@ void f() {
|
|||
void g() {
|
||||
union {
|
||||
int i;
|
||||
float f;
|
||||
float f2;
|
||||
};
|
||||
i = 0;
|
||||
f = 0.0;
|
||||
f2 = 0.0;
|
||||
}
|
||||
|
||||
struct BadMembers {
|
||||
union {
|
||||
struct X { }; // expected-error {{types cannot be declared in an anonymous union}}
|
||||
struct { int x; int y; } y;
|
||||
|
||||
void f(); // expected-error{{functions cannot be declared in an anonymous union}}
|
||||
private: int x1; // expected-error{{anonymous union cannot contain a private data member}}
|
||||
protected: float x2; // expected-error{{anonymous union cannot contain a protected data member}}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1077,10 +1077,10 @@ welcome!</p>
|
|||
<tr>
|
||||
<td> 9.5 [class.union]</td>
|
||||
<td class="complete" align="center">✓</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td class="complete" align="center">✓</td>
|
||||
<td class="medium"></td>
|
||||
<td class="medium"></td>
|
||||
<td>Semantic analysis does not yet check all of the requirements placed on the members of unions.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 9.6 [class.bit]</td>
|
||||
|
|
Loading…
Reference in New Issue