[PATCH] D148381: [Clang] Implement the 'counted_by' attribute
Bill Wendling via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 3 02:02:45 PDT 2023
void added inline comments.
================
Comment at: clang/lib/Sema/SemaDeclAttr.cpp:8420-8428
+ if (Result.getResultKind() == LookupResult::Found) {
+ SourceRange SR = CBA->getCountedByFieldLoc();
+ Diag(SR.getBegin(),
+ diag::err_flexible_array_counted_by_attr_field_not_found_in_struct)
+ << CBA->getCountedByField() << SR;
+
+ SR = Result.getAsSingle<NamedDecl>()->getSourceRange();
----------------
aaron.ballman wrote:
> The logic here still seems incorrect. I was expecting the code to look more like this:
> ```
> bool Sema::CheckCountedByAttr(Scope *S, const FieldDecl *FD) {
> const RecordDecl *RD = FD->getParent();
> const auto *CBA = FD->getAttr<CountedByAttr>();
> const IdentifierInfo *FieldName = CBA->getCountedByField();
> DeclarationNameInfo NameInfo(FieldName,
> CBA->getCountedByFieldLoc().getBegin());
> LookupResult Result(*this, NameInfo, Sema::LookupMemberName);
>
> LookupName(Result, S);
> if (Result.empty()) {
> CXXScopeSpec SS;
> DeclFilterCCC<FieldDecl> Filter(const_cast<IdentifierInfo *>(FieldName));
> if (DiagnoseEmptyLookup(S, SS, Result, Filter, nullptr, std::nullopt,
> const_cast<DeclContext *>(FD->getDeclContext())))
> return true;
> }
>
> const FieldDecl *Field = Result.getAsSingle<FieldDecl>();
> LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
> Context.getLangOpts().getStrictFlexArraysLevel();
> ...
> ```
> I tested this locally on code like:
> ```
> struct not_a_fam {
> int foo;
> int fam[] __attribute__((counted_by(fob)));
> };
> ```
> and get a diagnostic like:
> ```
> C:\Users\aballman\OneDrive - Intel Corporation\Desktop\test.c:3:39: error: use of undeclared identifier 'fob'; did you
> mean 'foo'?
> 3 | int fam[] __attribute__((counted_by(fob)));
> | ^~~
> | foo
> C:\Users\aballman\OneDrive - Intel Corporation\Desktop\test.c:2:7: note: 'foo' declared here
> 2 | int foo;
> | ^
> 1 error generated.
> ```
> Note, I had to add a constructor to `DeclFilterCCC` to expose the base class constructor, and modify `DiagnoseEmptyLookup()` like this:
> ```
> diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
> index 2ed31a90c5dc..3c4ade391a5e 100644
> --- a/clang/lib/Sema/SemaExpr.cpp
> +++ b/clang/lib/Sema/SemaExpr.cpp
> @@ -2458,7 +2458,8 @@ bool Sema::DiagnoseDependentMemberLookup(const LookupResult &R) {
> bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
> CorrectionCandidateCallback &CCC,
> TemplateArgumentListInfo *ExplicitTemplateArgs,
> - ArrayRef<Expr *> Args, TypoExpr **Out) {
> + ArrayRef<Expr *> Args, DeclContext *LookupCtx,
> + TypoExpr **Out) {
> DeclarationName Name = R.getLookupName();
>
> unsigned diagnostic = diag::err_undeclared_var_use;
> @@ -2474,7 +2475,9 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
> // unqualified lookup. This is useful when (for example) the
> // original lookup would not have found something because it was a
> // dependent name.
> - DeclContext *DC = SS.isEmpty() ? CurContext : nullptr;
> + DeclContext *DC =
> + LookupCtx ? LookupCtx : (SS.isEmpty() ? CurContext : nullptr);
> + DeclContext *OrigLookupCtx = DC;
> while (DC) {
> if (isa<CXXRecordDecl>(DC)) {
> LookupQualifiedName(R, DC);
> @@ -2517,12 +2520,12 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
> emitEmptyLookupTypoDiagnostic(TC, *this, SS, Name, TypoLoc, Args,
> diagnostic, diagnostic_suggest);
> },
> - nullptr, CTK_ErrorRecovery);
> + nullptr, CTK_ErrorRecovery, OrigLookupCtx);
> if (*Out)
> return true;
> - } else if (S &&
> - (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(),
> - S, &SS, CCC, CTK_ErrorRecovery))) {
> + } else if (S && (Corrected = CorrectTypo(R.getLookupNameInfo(),
> + R.getLookupKind(), S, &SS, CCC,
> + CTK_ErrorRecovery, OrigLookupCtx))) {
> std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
> bool DroppedSpecifier =
> Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr;
> @@ -2812,7 +2815,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
> // a template name, but we happen to have always already looked up the name
> // before we get here if it must be a template name.
> if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator, nullptr,
> - std::nullopt, &TE)) {
> + std::nullopt, nullptr, &TE)) {
> if (TE && KeywordReplacement) {
> auto &State = getTypoExprState(TE);
> auto BestTC = State.Consumer->getNextCorrection();
> ```
> Can you give something like this a shot and see how well it works for you?
I wanted to check for two different issues when the field isn't found:
1. The field is outside of the struct, or
2. The field isn't found (or is misspelled).
If I do your version, that distinction goes away.
But if you want me to work on this more, would you mind if I did it in a follow-up commit? I'm not at all happy about adding yet another parameter to a method that already has a million parameters. It would be nice if that was cleaned up.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D148381/new/
https://reviews.llvm.org/D148381
More information about the cfe-commits
mailing list