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:
David Majnemer 2014-08-11 18:33:59 +00:00
parent d42367478d
commit 36ef89895c
2 changed files with 37 additions and 88 deletions
clang

View File

@ -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,77 +1874,33 @@ 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();
if (!KnownField) {
IdentifierInfo *FieldName = D->getFieldName(); IdentifierInfo *FieldName = D->getFieldName();
unsigned FieldIndex = 0; DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
RecordDecl::field_iterator for (NamedDecl *ND : Lookup) {
Field = RT->getDecl()->field_begin(), if (auto *FD = dyn_cast<FieldDecl>(ND)) {
FieldEnd = RT->getDecl()->field_end(); KnownField = FD;
for (; Field != FieldEnd; ++Field) { break;
if (Field->isUnnamedBitfield()) }
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 (FieldName && FieldName == Field->getIdentifier())
break;
++FieldIndex;
}
if (Field == FieldEnd) {
if (VerifyOnly) { if (VerifyOnly) {
++Index; ++Index;
return true; // No typo correction when just trying this out. 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());
if (TypoCorrection Corrected = SemaRef.CorrectTypo(
DeclarationNameInfo(FieldName, D->getFieldLoc()),
Sema::LookupMemberName, /*Scope=*/ nullptr, /*SS=*/ nullptr,
Validator, Sema::CTK_ErrorRecovery, RT->getDecl())) {
SemaRef.diagnoseTypo(
Corrected,
SemaRef.PDiag(diag::err_field_designator_unknown_suggest)
<< FieldName << CurrentObjectType);
ReplacementField = Corrected.getCorrectionDeclAs<FieldDecl>();
hadError = true;
} else {
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
<< FieldName << CurrentObjectType;
++Index;
return true;
}
}
if (!ReplacementField) {
// Name lookup found something, but it wasn't a field. // Name lookup found something, but it wasn't a field.
if (!Lookup.empty()) {
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield) SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
<< FieldName; << FieldName;
SemaRef.Diag(Lookup.front()->getLocation(), SemaRef.Diag(Lookup.front()->getLocation(),
@ -1971,23 +1909,32 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
return true; return true;
} }
if (!KnownField) { // Name lookup didn't find anything.
// The replacement field comes from typo correction; find it // Determine whether this was a typo for another field name.
// in the list of fields. FieldInitializerValidatorCCC Validator(RT->getDecl());
FieldIndex = 0; if (TypoCorrection Corrected = SemaRef.CorrectTypo(
Field = RT->getDecl()->field_begin(); DeclarationNameInfo(FieldName, D->getFieldLoc()),
for (; Field != FieldEnd; ++Field) { Sema::LookupMemberName, /*Scope=*/nullptr, /*SS=*/nullptr,
if (Field->isUnnamedBitfield()) Validator, Sema::CTK_ErrorRecovery, RT->getDecl())) {
continue; SemaRef.diagnoseTypo(
Corrected,
SemaRef.PDiag(diag::err_field_designator_unknown_suggest)
<< FieldName << CurrentObjectType);
KnownField = Corrected.getCorrectionDeclAs<FieldDecl>();
hadError = true;
} else {
// Typo correction didn't find anything.
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
<< FieldName << CurrentObjectType;
++Index;
return true;
}
}
}
if (ReplacementField == *Field || unsigned FieldIndex = KnownField->getFieldIndex();
Field->getIdentifier() == ReplacementField->getIdentifier()) RecordDecl::field_iterator Field =
break; RecordDecl::field_iterator(DeclContext::decl_iterator(KnownField));
++FieldIndex;
}
}
}
// 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.

View File

@ -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}}