зеркало из https://github.com/microsoft/clang-1.git
Implement support for designated initializers that refer to members of
anonymous structs or unions. Fixes PR3778. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69153 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
3ac86b59b0
Коммит
ffb4b6e299
|
@ -1963,6 +1963,11 @@ private:
|
|||
/// designators, one array designator for @c [2] followed by one field
|
||||
/// designator for @c .y. The initalization expression will be 1.0.
|
||||
class DesignatedInitExpr : public Expr {
|
||||
public:
|
||||
/// \brief Forward declaration of the Designator class.
|
||||
class Designator;
|
||||
|
||||
private:
|
||||
/// The location of the '=' or ':' prior to the actual initializer
|
||||
/// expression.
|
||||
SourceLocation EqualOrColonLoc;
|
||||
|
@ -1974,17 +1979,20 @@ class DesignatedInitExpr : public Expr {
|
|||
/// The number of designators in this initializer expression.
|
||||
unsigned NumDesignators : 15;
|
||||
|
||||
/// \brief The designators in this designated initialization
|
||||
/// expression.
|
||||
Designator *Designators;
|
||||
|
||||
/// The number of subexpressions of this initializer expression,
|
||||
/// which contains both the initializer and any additional
|
||||
/// expressions used by array and array-range designators.
|
||||
unsigned NumSubExprs : 16;
|
||||
|
||||
|
||||
DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
|
||||
const Designator *Designators,
|
||||
SourceLocation EqualOrColonLoc, bool GNUSyntax,
|
||||
unsigned NumSubExprs)
|
||||
: Expr(DesignatedInitExprClass, Ty),
|
||||
EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax),
|
||||
NumDesignators(NumDesignators), NumSubExprs(NumSubExprs) { }
|
||||
unsigned NumSubExprs);
|
||||
|
||||
public:
|
||||
/// A field designator, e.g., ".x".
|
||||
|
@ -2041,6 +2049,8 @@ public:
|
|||
friend class DesignatedInitExpr;
|
||||
|
||||
public:
|
||||
Designator() {}
|
||||
|
||||
/// @brief Initializes a field designator.
|
||||
Designator(const IdentifierInfo *FieldName, SourceLocation DotLoc,
|
||||
SourceLocation FieldLoc)
|
||||
|
@ -2136,8 +2146,10 @@ public:
|
|||
|
||||
// Iterator access to the designators.
|
||||
typedef Designator* designators_iterator;
|
||||
designators_iterator designators_begin();
|
||||
designators_iterator designators_end();
|
||||
designators_iterator designators_begin() { return Designators; }
|
||||
designators_iterator designators_end() {
|
||||
return Designators + NumDesignators;
|
||||
}
|
||||
|
||||
Designator *getDesignator(unsigned Idx) { return &designators_begin()[Idx]; }
|
||||
|
||||
|
@ -2162,8 +2174,15 @@ public:
|
|||
*child_begin() = init;
|
||||
}
|
||||
|
||||
/// \brief Replaces the designator at index @p Idx with the series
|
||||
/// of designators in [First, Last).
|
||||
void ExpandDesignator(unsigned Idx, const Designator *First,
|
||||
const Designator *Last);
|
||||
|
||||
virtual SourceRange getSourceRange() const;
|
||||
|
||||
virtual void Destroy(ASTContext &C);
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == DesignatedInitExprClass;
|
||||
}
|
||||
|
|
|
@ -49,9 +49,6 @@ def err_field_designator_unknown : Error<
|
|||
def err_field_designator_nonfield : Error<
|
||||
"field designator %0 does not refer to a non-static data member">;
|
||||
def note_field_designator_found : Note<"field designator refers here">;
|
||||
def err_field_designator_anon_class : Error<
|
||||
"field designator %0 refers to a member of an anonymous "
|
||||
"%select{struct|class|union}1">;
|
||||
def err_designator_for_scalar_init : Error<
|
||||
"designator in initializer for scalar type %0">;
|
||||
def warn_subobject_initializer_overrides : Warning<
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "clang/AST/RecordLayout.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include <algorithm>
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -1499,6 +1500,19 @@ IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() {
|
|||
return getField()->getIdentifier();
|
||||
}
|
||||
|
||||
DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
|
||||
const Designator *Designators,
|
||||
SourceLocation EqualOrColonLoc,
|
||||
bool GNUSyntax,
|
||||
unsigned NumSubExprs)
|
||||
: Expr(DesignatedInitExprClass, Ty),
|
||||
EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax),
|
||||
NumDesignators(NumDesignators), NumSubExprs(NumSubExprs) {
|
||||
this->Designators = new Designator[NumDesignators];
|
||||
for (unsigned I = 0; I != NumDesignators; ++I)
|
||||
this->Designators[I] = Designators[I];
|
||||
}
|
||||
|
||||
DesignatedInitExpr *
|
||||
DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
|
||||
unsigned NumDesignators,
|
||||
|
@ -1506,10 +1520,9 @@ DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
|
|||
SourceLocation ColonOrEqualLoc,
|
||||
bool UsesColonSyntax, Expr *Init) {
|
||||
void *Mem = C.Allocate(sizeof(DesignatedInitExpr) +
|
||||
sizeof(Designator) * NumDesignators +
|
||||
sizeof(Stmt *) * (NumIndexExprs + 1), 8);
|
||||
DesignatedInitExpr *DIE
|
||||
= new (Mem) DesignatedInitExpr(C.VoidTy, NumDesignators,
|
||||
= new (Mem) DesignatedInitExpr(C.VoidTy, NumDesignators, Designators,
|
||||
ColonOrEqualLoc, UsesColonSyntax,
|
||||
NumIndexExprs + 1);
|
||||
|
||||
|
@ -1517,7 +1530,6 @@ DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
|
|||
unsigned ExpectedNumSubExprs = 0;
|
||||
designators_iterator Desig = DIE->designators_begin();
|
||||
for (unsigned Idx = 0; Idx < NumDesignators; ++Idx, ++Desig) {
|
||||
new (static_cast<void*>(Desig)) Designator(Designators[Idx]);
|
||||
if (Designators[Idx].isArrayDesignator())
|
||||
++ExpectedNumSubExprs;
|
||||
else if (Designators[Idx].isArrayRangeDesignator())
|
||||
|
@ -1549,22 +1561,10 @@ SourceRange DesignatedInitExpr::getSourceRange() const {
|
|||
return SourceRange(StartLoc, getInit()->getSourceRange().getEnd());
|
||||
}
|
||||
|
||||
DesignatedInitExpr::designators_iterator
|
||||
DesignatedInitExpr::designators_begin() {
|
||||
char* Ptr = static_cast<char*>(static_cast<void *>(this));
|
||||
Ptr += sizeof(DesignatedInitExpr);
|
||||
return static_cast<Designator*>(static_cast<void*>(Ptr));
|
||||
}
|
||||
|
||||
DesignatedInitExpr::designators_iterator DesignatedInitExpr::designators_end() {
|
||||
return designators_begin() + NumDesignators;
|
||||
}
|
||||
|
||||
Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) {
|
||||
assert(D.Kind == Designator::ArrayDesignator && "Requires array designator");
|
||||
char* Ptr = static_cast<char*>(static_cast<void *>(this));
|
||||
Ptr += sizeof(DesignatedInitExpr);
|
||||
Ptr += sizeof(Designator) * NumDesignators;
|
||||
Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
|
||||
return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1));
|
||||
}
|
||||
|
@ -1574,7 +1574,6 @@ Expr *DesignatedInitExpr::getArrayRangeStart(const Designator& D) {
|
|||
"Requires array range designator");
|
||||
char* Ptr = static_cast<char*>(static_cast<void *>(this));
|
||||
Ptr += sizeof(DesignatedInitExpr);
|
||||
Ptr += sizeof(Designator) * NumDesignators;
|
||||
Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
|
||||
return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1));
|
||||
}
|
||||
|
@ -1584,11 +1583,43 @@ Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) {
|
|||
"Requires array range designator");
|
||||
char* Ptr = static_cast<char*>(static_cast<void *>(this));
|
||||
Ptr += sizeof(DesignatedInitExpr);
|
||||
Ptr += sizeof(Designator) * NumDesignators;
|
||||
Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
|
||||
return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 2));
|
||||
}
|
||||
|
||||
/// \brief Replaces the designator at index @p Idx with the series
|
||||
/// of designators in [First, Last).
|
||||
void DesignatedInitExpr::ExpandDesignator(unsigned Idx,
|
||||
const Designator *First,
|
||||
const Designator *Last) {
|
||||
unsigned NumNewDesignators = Last - First;
|
||||
if (NumNewDesignators == 0) {
|
||||
std::copy_backward(Designators + Idx + 1,
|
||||
Designators + NumDesignators,
|
||||
Designators + Idx);
|
||||
--NumNewDesignators;
|
||||
return;
|
||||
} else if (NumNewDesignators == 1) {
|
||||
Designators[Idx] = *First;
|
||||
return;
|
||||
}
|
||||
|
||||
Designator *NewDesignators
|
||||
= new Designator[NumDesignators - 1 + NumNewDesignators];
|
||||
std::copy(Designators, Designators + Idx, NewDesignators);
|
||||
std::copy(First, Last, NewDesignators + Idx);
|
||||
std::copy(Designators + Idx + 1, Designators + NumDesignators,
|
||||
NewDesignators + Idx + NumNewDesignators);
|
||||
delete [] Designators;
|
||||
Designators = NewDesignators;
|
||||
NumDesignators = NumDesignators - 1 + NumNewDesignators;
|
||||
}
|
||||
|
||||
void DesignatedInitExpr::Destroy(ASTContext &C) {
|
||||
delete [] Designators;
|
||||
Expr::Destroy(C);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ExprIterator.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -1774,7 +1805,6 @@ Stmt::child_iterator InitListExpr::child_end() {
|
|||
Stmt::child_iterator DesignatedInitExpr::child_begin() {
|
||||
char* Ptr = static_cast<char*>(static_cast<void *>(this));
|
||||
Ptr += sizeof(DesignatedInitExpr);
|
||||
Ptr += sizeof(Designator) * NumDesignators;
|
||||
return reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
|
||||
}
|
||||
Stmt::child_iterator DesignatedInitExpr::child_end() {
|
||||
|
|
|
@ -1226,6 +1226,8 @@ public:
|
|||
DeclRefExpr *BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
|
||||
bool TypeDependent, bool ValueDependent,
|
||||
const CXXScopeSpec *SS = 0);
|
||||
VarDecl *BuildAnonymousStructUnionMemberPath(FieldDecl *Field,
|
||||
llvm::SmallVectorImpl<FieldDecl *> &Path);
|
||||
OwningExprResult
|
||||
BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
|
||||
FieldDecl *Field,
|
||||
|
|
|
@ -486,29 +486,33 @@ static Decl *getObjectForAnonymousRecordDecl(ASTContext &Context,
|
|||
return 0;
|
||||
}
|
||||
|
||||
Sema::OwningExprResult
|
||||
Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
|
||||
FieldDecl *Field,
|
||||
Expr *BaseObjectExpr,
|
||||
SourceLocation OpLoc) {
|
||||
/// \brief Given a field that represents a member of an anonymous
|
||||
/// struct/union, build the path from that field's context to the
|
||||
/// actual member.
|
||||
///
|
||||
/// Construct the sequence of field member references we'll have to
|
||||
/// perform to get to the field in the anonymous union/struct. The
|
||||
/// list of members is built from the field outward, so traverse it
|
||||
/// backwards to go from an object in the current context to the field
|
||||
/// we found.
|
||||
///
|
||||
/// \returns The variable from which the field access should begin,
|
||||
/// for an anonymous struct/union that is not a member of another
|
||||
/// class. Otherwise, returns NULL.
|
||||
VarDecl *Sema::BuildAnonymousStructUnionMemberPath(FieldDecl *Field,
|
||||
llvm::SmallVectorImpl<FieldDecl *> &Path) {
|
||||
assert(Field->getDeclContext()->isRecord() &&
|
||||
cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion()
|
||||
&& "Field must be stored inside an anonymous struct or union");
|
||||
|
||||
// Construct the sequence of field member references
|
||||
// we'll have to perform to get to the field in the anonymous
|
||||
// union/struct. The list of members is built from the field
|
||||
// outward, so traverse it backwards to go from an object in
|
||||
// the current context to the field we found.
|
||||
llvm::SmallVector<FieldDecl *, 4> AnonFields;
|
||||
AnonFields.push_back(Field);
|
||||
Path.push_back(Field);
|
||||
VarDecl *BaseObject = 0;
|
||||
DeclContext *Ctx = Field->getDeclContext();
|
||||
do {
|
||||
RecordDecl *Record = cast<RecordDecl>(Ctx);
|
||||
Decl *AnonObject = getObjectForAnonymousRecordDecl(Context, Record);
|
||||
if (FieldDecl *AnonField = dyn_cast<FieldDecl>(AnonObject))
|
||||
AnonFields.push_back(AnonField);
|
||||
Path.push_back(AnonField);
|
||||
else {
|
||||
BaseObject = cast<VarDecl>(AnonObject);
|
||||
break;
|
||||
|
@ -517,6 +521,18 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
|
|||
} while (Ctx->isRecord() &&
|
||||
cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion());
|
||||
|
||||
return BaseObject;
|
||||
}
|
||||
|
||||
Sema::OwningExprResult
|
||||
Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
|
||||
FieldDecl *Field,
|
||||
Expr *BaseObjectExpr,
|
||||
SourceLocation OpLoc) {
|
||||
llvm::SmallVector<FieldDecl *, 4> AnonFields;
|
||||
VarDecl *BaseObject = BuildAnonymousStructUnionMemberPath(Field,
|
||||
AnonFields);
|
||||
|
||||
// Build the expression that refers to the base object, from
|
||||
// which we will build a sequence of member references to each
|
||||
// of the anonymous union objects and, eventually, the field we
|
||||
|
|
|
@ -1031,6 +1031,64 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
|
|||
StructuredIndex);
|
||||
}
|
||||
|
||||
/// \brief Expand a field designator that refers to a member of an
|
||||
/// anonymous struct or union into a series of field designators that
|
||||
/// refers to the field within the appropriate subobject.
|
||||
///
|
||||
/// Field/FieldIndex will be updated to point to the (new)
|
||||
/// currently-designated field.
|
||||
static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
|
||||
DesignatedInitExpr *DIE,
|
||||
unsigned DesigIdx,
|
||||
FieldDecl *Field,
|
||||
RecordDecl::field_iterator &FieldIter,
|
||||
unsigned &FieldIndex) {
|
||||
typedef DesignatedInitExpr::Designator Designator;
|
||||
|
||||
// Build the path from the current object to the member of the
|
||||
// anonymous struct/union (backwards).
|
||||
llvm::SmallVector<FieldDecl *, 4> Path;
|
||||
SemaRef.BuildAnonymousStructUnionMemberPath(Field, Path);
|
||||
|
||||
// Build the replacement designators.
|
||||
llvm::SmallVector<Designator, 4> Replacements;
|
||||
for (llvm::SmallVector<FieldDecl *, 4>::reverse_iterator
|
||||
FI = Path.rbegin(), FIEnd = Path.rend();
|
||||
FI != FIEnd; ++FI) {
|
||||
if (FI + 1 == FIEnd)
|
||||
Replacements.push_back(Designator((IdentifierInfo *)0,
|
||||
DIE->getDesignator(DesigIdx)->getDotLoc(),
|
||||
DIE->getDesignator(DesigIdx)->getFieldLoc()));
|
||||
else
|
||||
Replacements.push_back(Designator((IdentifierInfo *)0, SourceLocation(),
|
||||
SourceLocation()));
|
||||
Replacements.back().setField(*FI);
|
||||
}
|
||||
|
||||
// Expand the current designator into the set of replacement
|
||||
// designators, so we have a full subobject path down to where the
|
||||
// member of the anonymous struct/union is actually stored.
|
||||
DIE->ExpandDesignator(DesigIdx, &Replacements[0],
|
||||
&Replacements[0] + Replacements.size());
|
||||
|
||||
// Update FieldIter/FieldIndex;
|
||||
RecordDecl *Record = cast<RecordDecl>(Path.back()->getDeclContext());
|
||||
FieldIter = Record->field_begin(SemaRef.Context);
|
||||
FieldIndex = 0;
|
||||
for (RecordDecl::field_iterator FEnd = Record->field_end(SemaRef.Context);
|
||||
FieldIter != FEnd; ++FieldIter) {
|
||||
if (FieldIter->isUnnamedBitfield())
|
||||
continue;
|
||||
|
||||
if (*FieldIter == Path.back())
|
||||
return;
|
||||
|
||||
++FieldIndex;
|
||||
}
|
||||
|
||||
assert(false && "Unable to find anonymous struct/union field");
|
||||
}
|
||||
|
||||
/// @brief Check the well-formedness of a C99 designated initializer.
|
||||
///
|
||||
/// Determines whether the designated initializer @p DIE, which
|
||||
|
@ -1138,6 +1196,7 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
|
|||
// Note: we perform a linear search of the fields here, despite
|
||||
// the fact that we have a faster lookup method, because we always
|
||||
// need to compute the field's index.
|
||||
FieldDecl *KnownField = D->getField();
|
||||
IdentifierInfo *FieldName = D->getFieldName();
|
||||
unsigned FieldIndex = 0;
|
||||
RecordDecl::field_iterator
|
||||
|
@ -1147,40 +1206,50 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
|
|||
if (Field->isUnnamedBitfield())
|
||||
continue;
|
||||
|
||||
if (Field->getIdentifier() == FieldName)
|
||||
if (KnownField == *Field || Field->getIdentifier() == FieldName)
|
||||
break;
|
||||
|
||||
++FieldIndex;
|
||||
}
|
||||
|
||||
if (Field == FieldEnd) {
|
||||
// We did not find the field we're looking for. Produce a
|
||||
// suitable diagnostic and return a failure.
|
||||
// There was no normal field in the struct with the designated
|
||||
// name. Perform another lookup for this name, which may find
|
||||
// something that we can't designate (e.g., a member function),
|
||||
// may find nothing, or may find a member of an anonymous
|
||||
// struct/union.
|
||||
DeclContext::lookup_result Lookup
|
||||
= RT->getDecl()->lookup(SemaRef.Context, FieldName);
|
||||
if (Lookup.first == Lookup.second) {
|
||||
// Name lookup didn't find anything.
|
||||
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
|
||||
<< FieldName << CurrentObjectType;
|
||||
++Index;
|
||||
return true;
|
||||
} else if (!KnownField && isa<FieldDecl>(*Lookup.first) &&
|
||||
cast<RecordDecl>((*Lookup.first)->getDeclContext())
|
||||
->isAnonymousStructOrUnion()) {
|
||||
// Handle an field designator that refers to a member of an
|
||||
// anonymous struct or union.
|
||||
ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx,
|
||||
cast<FieldDecl>(*Lookup.first),
|
||||
Field, FieldIndex);
|
||||
} else {
|
||||
// Name lookup found something, but it wasn't a field.
|
||||
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
|
||||
<< FieldName;
|
||||
SemaRef.Diag((*Lookup.first)->getLocation(),
|
||||
diag::note_field_designator_found);
|
||||
}
|
||||
|
||||
++Index;
|
||||
return true;
|
||||
} else if (cast<RecordDecl>((*Field)->getDeclContext())
|
||||
}
|
||||
} else if (!KnownField &&
|
||||
cast<RecordDecl>((*Field)->getDeclContext())
|
||||
->isAnonymousStructOrUnion()) {
|
||||
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_anon_class)
|
||||
<< FieldName
|
||||
<< (cast<RecordDecl>((*Field)->getDeclContext())->isUnion()? 2 :
|
||||
(int)SemaRef.getLangOptions().CPlusPlus);
|
||||
SemaRef.Diag((*Field)->getLocation(), diag::note_field_designator_found);
|
||||
++Index;
|
||||
return true;
|
||||
ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, *Field,
|
||||
Field, FieldIndex);
|
||||
D = DIE->getDesignator(DesigIdx);
|
||||
}
|
||||
|
||||
// All of the fields of a union are located at the same place in
|
||||
|
@ -1284,6 +1353,10 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
|
|||
if (!FinishSubobjectInit)
|
||||
return false;
|
||||
|
||||
// We've already initialized something in the union; we're done.
|
||||
if (RT->getDecl()->isUnion())
|
||||
return hadError;
|
||||
|
||||
// Check the remaining fields within this class/struct/union subobject.
|
||||
bool prevHadError = hadError;
|
||||
CheckStructUnionTypes(IList, CurrentObjectType, Field, false, Index,
|
||||
|
|
|
@ -187,3 +187,37 @@ const union wibble wobble = { .arr2[0] = 0xffff,
|
|||
.arr2[2] = 0xffff };
|
||||
|
||||
const union wibble wobble2 = { .arr2 = {4, 5, 6}, 7 }; // expected-warning{{excess elements in union initializer}}
|
||||
|
||||
// PR3778
|
||||
struct s {
|
||||
union { int i; };
|
||||
};
|
||||
struct s si = {
|
||||
{ .i = 1 }
|
||||
};
|
||||
|
||||
double d0;
|
||||
char c0;
|
||||
float f0;
|
||||
int i0;
|
||||
|
||||
struct Enigma {
|
||||
union {
|
||||
struct {
|
||||
struct {
|
||||
double *double_ptr;
|
||||
char *string;
|
||||
};
|
||||
float *float_ptr;
|
||||
};
|
||||
int *int_ptr;
|
||||
};
|
||||
char *string2;
|
||||
};
|
||||
|
||||
struct Enigma enigma = {
|
||||
.double_ptr = &d0, &c0,
|
||||
&f0, // expected-note{{previous}}
|
||||
&c0,
|
||||
.float_ptr = &f0 // expected-warning{{overrides}}
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче