forked from OSchip/llvm-project
Sema: Properly perform lookup when acting on fields for desig inits
Clang used a custom implementation of lookup when handling designated initializers. The custom code was not particularly optimized and relied on standard lookup for typo-correction anyway. This custom code has to go, it doesn't properly support MSVC-style anonymous structs embedded inside other records; replace it with the typo-correction path. This has the side effect of speeding up semantic handling of the fields for a designated initializer while simplifying the code at the same time. This fixes PR20573. Differential Revision: http://reviews.llvm.org/D4839 llvm-svn: 215372
This commit is contained in:
parent
d42367478d
commit
36ef89895c
|
@ -1734,24 +1734,6 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
|
||||||
&Replacements[0] + Replacements.size());
|
&Replacements[0] + Replacements.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Given an implicit anonymous field, search the IndirectField that
|
|
||||||
/// corresponds to FieldName.
|
|
||||||
static IndirectFieldDecl *FindIndirectFieldDesignator(FieldDecl *AnonField,
|
|
||||||
IdentifierInfo *FieldName) {
|
|
||||||
if (!FieldName)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
assert(AnonField->isAnonymousStructOrUnion());
|
|
||||||
Decl *NextDecl = AnonField->getNextDeclInContext();
|
|
||||||
while (IndirectFieldDecl *IF =
|
|
||||||
dyn_cast_or_null<IndirectFieldDecl>(NextDecl)) {
|
|
||||||
if (FieldName == IF->getAnonField()->getIdentifier())
|
|
||||||
return IF;
|
|
||||||
NextDecl = NextDecl->getNextDeclInContext();
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static DesignatedInitExpr *CloneDesignatedInitExpr(Sema &SemaRef,
|
static DesignatedInitExpr *CloneDesignatedInitExpr(Sema &SemaRef,
|
||||||
DesignatedInitExpr *DIE) {
|
DesignatedInitExpr *DIE) {
|
||||||
unsigned NumIndexExprs = DIE->getNumSubExprs() - 1;
|
unsigned NumIndexExprs = DIE->getNumSubExprs() - 1;
|
||||||
|
@ -1892,103 +1874,68 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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();
|
FieldDecl *KnownField = D->getField();
|
||||||
IdentifierInfo *FieldName = D->getFieldName();
|
if (!KnownField) {
|
||||||
unsigned FieldIndex = 0;
|
IdentifierInfo *FieldName = D->getFieldName();
|
||||||
RecordDecl::field_iterator
|
DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
|
||||||
Field = RT->getDecl()->field_begin(),
|
for (NamedDecl *ND : Lookup) {
|
||||||
FieldEnd = RT->getDecl()->field_end();
|
if (auto *FD = dyn_cast<FieldDecl>(ND)) {
|
||||||
for (; Field != FieldEnd; ++Field) {
|
KnownField = FD;
|
||||||
if (Field->isUnnamedBitfield())
|
break;
|
||||||
continue;
|
}
|
||||||
|
if (auto *IFD = dyn_cast<IndirectFieldDecl>(ND)) {
|
||||||
// If we find a field representing an anonymous field, look in the
|
|
||||||
// IndirectFieldDecl that follow for the designated initializer.
|
|
||||||
if (!KnownField && Field->isAnonymousStructOrUnion()) {
|
|
||||||
if (IndirectFieldDecl *IF =
|
|
||||||
FindIndirectFieldDesignator(*Field, FieldName)) {
|
|
||||||
// In verify mode, don't modify the original.
|
// In verify mode, don't modify the original.
|
||||||
if (VerifyOnly)
|
if (VerifyOnly)
|
||||||
DIE = CloneDesignatedInitExpr(SemaRef, DIE);
|
DIE = CloneDesignatedInitExpr(SemaRef, DIE);
|
||||||
ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, IF);
|
ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, IFD);
|
||||||
D = DIE->getDesignator(DesigIdx);
|
D = DIE->getDesignator(DesigIdx);
|
||||||
|
KnownField = cast<FieldDecl>(*IFD->chain_begin());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (KnownField && KnownField == *Field)
|
if (!KnownField) {
|
||||||
break;
|
if (VerifyOnly) {
|
||||||
if (FieldName && FieldName == Field->getIdentifier())
|
++Index;
|
||||||
break;
|
return true; // No typo correction when just trying this out.
|
||||||
|
}
|
||||||
|
|
||||||
++FieldIndex;
|
// Name lookup found something, but it wasn't a field.
|
||||||
}
|
if (!Lookup.empty()) {
|
||||||
|
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
|
||||||
|
<< FieldName;
|
||||||
|
SemaRef.Diag(Lookup.front()->getLocation(),
|
||||||
|
diag::note_field_designator_found);
|
||||||
|
++Index;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (Field == FieldEnd) {
|
// Name lookup didn't find anything.
|
||||||
if (VerifyOnly) {
|
// Determine whether this was a typo for another field name.
|
||||||
++Index;
|
|
||||||
return true; // No typo correction when just trying this out.
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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(FieldName);
|
|
||||||
FieldDecl *ReplacementField = nullptr;
|
|
||||||
if (Lookup.empty()) {
|
|
||||||
// Name lookup didn't find anything. Determine whether this
|
|
||||||
// was a typo for another field name.
|
|
||||||
FieldInitializerValidatorCCC Validator(RT->getDecl());
|
FieldInitializerValidatorCCC Validator(RT->getDecl());
|
||||||
if (TypoCorrection Corrected = SemaRef.CorrectTypo(
|
if (TypoCorrection Corrected = SemaRef.CorrectTypo(
|
||||||
DeclarationNameInfo(FieldName, D->getFieldLoc()),
|
DeclarationNameInfo(FieldName, D->getFieldLoc()),
|
||||||
Sema::LookupMemberName, /*Scope=*/ nullptr, /*SS=*/ nullptr,
|
Sema::LookupMemberName, /*Scope=*/nullptr, /*SS=*/nullptr,
|
||||||
Validator, Sema::CTK_ErrorRecovery, RT->getDecl())) {
|
Validator, Sema::CTK_ErrorRecovery, RT->getDecl())) {
|
||||||
SemaRef.diagnoseTypo(
|
SemaRef.diagnoseTypo(
|
||||||
Corrected,
|
Corrected,
|
||||||
SemaRef.PDiag(diag::err_field_designator_unknown_suggest)
|
SemaRef.PDiag(diag::err_field_designator_unknown_suggest)
|
||||||
<< FieldName << CurrentObjectType);
|
<< FieldName << CurrentObjectType);
|
||||||
ReplacementField = Corrected.getCorrectionDeclAs<FieldDecl>();
|
KnownField = Corrected.getCorrectionDeclAs<FieldDecl>();
|
||||||
hadError = true;
|
hadError = true;
|
||||||
} else {
|
} else {
|
||||||
|
// Typo correction didn't find anything.
|
||||||
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
|
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
|
||||||
<< FieldName << CurrentObjectType;
|
<< FieldName << CurrentObjectType;
|
||||||
++Index;
|
++Index;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ReplacementField) {
|
|
||||||
// Name lookup found something, but it wasn't a field.
|
|
||||||
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
|
|
||||||
<< FieldName;
|
|
||||||
SemaRef.Diag(Lookup.front()->getLocation(),
|
|
||||||
diag::note_field_designator_found);
|
|
||||||
++Index;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!KnownField) {
|
|
||||||
// The replacement field comes from typo correction; find it
|
|
||||||
// in the list of fields.
|
|
||||||
FieldIndex = 0;
|
|
||||||
Field = RT->getDecl()->field_begin();
|
|
||||||
for (; Field != FieldEnd; ++Field) {
|
|
||||||
if (Field->isUnnamedBitfield())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ReplacementField == *Field ||
|
|
||||||
Field->getIdentifier() == ReplacementField->getIdentifier())
|
|
||||||
break;
|
|
||||||
|
|
||||||
++FieldIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned FieldIndex = KnownField->getFieldIndex();
|
||||||
|
RecordDecl::field_iterator Field =
|
||||||
|
RecordDecl::field_iterator(DeclContext::decl_iterator(KnownField));
|
||||||
|
|
||||||
// All of the fields of a union are located at the same place in
|
// All of the fields of a union are located at the same place in
|
||||||
// the initializer list.
|
// the initializer list.
|
||||||
if (RT->getDecl()->isUnion()) {
|
if (RT->getDecl()->isUnion()) {
|
||||||
|
|
|
@ -39,6 +39,8 @@ struct nested2 {
|
||||||
NESTED1; // expected-warning {{anonymous structs are a Microsoft extension}}
|
NESTED1; // expected-warning {{anonymous structs are a Microsoft extension}}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct nested2 PR20573 = { .a = 3 };
|
||||||
|
|
||||||
struct nested3 {
|
struct nested3 {
|
||||||
long d;
|
long d;
|
||||||
struct nested4 { // expected-warning {{anonymous structs are a Microsoft extension}}
|
struct nested4 { // expected-warning {{anonymous structs are a Microsoft extension}}
|
||||||
|
|
Loading…
Reference in New Issue