================
@@ -20002,6 +19984,205 @@ bool Sema::EntirelyFunctionPointers(const RecordDecl 
*Record) {
   return llvm::all_of(Record->decls(), IsFunctionPointerOrForwardDecl);
 }
 
+static QualType handleCountedByAttrField(Sema &S, QualType T, Decl *D,
+                                         const ParsedAttr &AL) {
+  if (!AL.diagnoseLangOpts(S))
+    return QualType();
+
+  assert(isa<FieldDecl>(D));
+
+  auto *CountExpr = AL.getArgAsExpr(0);
+  if (!CountExpr)
+    return QualType();
+
+  bool CountInBytes;
+  bool OrNull;
+  switch (AL.getKind()) {
+  case ParsedAttr::AT_CountedBy:
+    CountInBytes = false;
+    OrNull = false;
+    break;
+  case ParsedAttr::AT_CountedByOrNull:
+    CountInBytes = false;
+    OrNull = true;
+    break;
+  case ParsedAttr::AT_SizedBy:
+    CountInBytes = true;
+    OrNull = false;
+    break;
+  case ParsedAttr::AT_SizedByOrNull:
+    CountInBytes = true;
+    OrNull = true;
+    break;
+  default:
+    llvm_unreachable("unexpected counted_by family attribute");
+  }
+
+  return S.BuildCountAttributedArrayOrPointerType(T, CountExpr, CountInBytes,
+                                                  OrNull);
+}
+struct RebuildTypeWithLateParsedAttr
+    : TreeTransform<RebuildTypeWithLateParsedAttr> {
+  FieldDecl *FD;
+  Sema::ParseLateParsedTypeAttributeCB *ParseCallback;
+
+  /// Non-zero while transforming under a pointer or array. Used to reject
+  /// nested counted_by (e.g. `int *__counted_by(n) *p` or
+  /// `int *__counted_by(n) arr[10]`), where the resolved CountAttributedType
+  /// would sit inside another wrapper.
+  unsigned PointerOrArrayDepth = 0;
+
+  RebuildTypeWithLateParsedAttr(Sema &SemaRef, FieldDecl *FD,
+                                Sema::ParseLateParsedTypeAttributeCB *ParseCB)
+      : TreeTransform(SemaRef), FD(FD), ParseCallback(ParseCB) {}
+
+  QualType TransformLateParsedAttrType(TypeLocBuilder &TLB,
+                                       LateParsedAttrTypeLoc TL) {
+    const LateParsedAttrType *LPA = TL.getTypePtr();
+    auto *LTA = LPA->getLateParsedAttribute();
+
+    assert(LTA && "LateParsedAttrType must have a LateParsedTypeAttribute");
+
+    AttributeFactory AF{};
+    ParsedAttributes Attrs(AF);
+
+    // Invoke the parser callback to parse and consume the cached tokens.
+    // ParseCallback is also responsible for deleting LTA.
+    assert(ParseCallback);
+    ParseCallback(LTA, &Attrs);
+
+    // Invalid argument
+    if (Attrs.empty())
+      return QualType();
+
+    assert(Attrs.size() == 1);
+    auto &AL = Attrs[0];
+
+    QualType InnerType = TransformType(TLB, TL.getInnerLoc());
+    if (InnerType.isNull()) {
+      FD->setInvalidDecl();
+      return QualType();
+    }
+
+    QualType T = handleCountedByAttrField(SemaRef, InnerType, FD, AL);
+    if (T.isNull()) {
+      AL.setInvalid();
+      FD->setInvalidDecl();
+      return QualType();
+    }
+
+    // Reject nested counted_by, e.g. `int *__counted_by(n) *p` or
+    // `int *__counted_by(n) arr[10]` — the resolved CountAttributedType
+    // must sit at the outermost level of the field's type.
+    //
+    // FIXME: In the -fbounds-safety model:
+    //   - `counted_by` / `sized_by` on nested pointers is permitted only
+    //     for function parameters, and only one level of nesting.
+    //   - `counted_by_or_null` / `sized_by_or_null` on nested pointers is
+    //     generally permitted, because it makes sense to allow such a
+    //     pointer to be valid when the top-level pointer is null (the
+    //     inner counted_by / sized_by simply doesn't need to hold in
+    //     that case).
+    // We reject unconditionally here because this slice only covers
+    // struct fields; extending coverage will need to relax this check
+    // along those lines.
+    if (PointerOrArrayDepth > 0) {
+      SemaRef.Diag(TL.getAttrNameLoc(), diag::err_counted_by_on_nested_pointer)
+          << T->getAs<CountAttributedType>()->getKind();
+      FD->setInvalidDecl();
+      return QualType();
+    }
+
+    AL.setUsedAsTypeAttr();
+
+    TLB.push<CountAttributedTypeLoc>(T);
+    return T;
+  }
+
+  // The five overrides below only track pointer/array depth so
+  // TransformLateParsedAttrType can reject nested counted_by. Recursion,
+  // rebuild, and TypeLoc pushing are delegated to the base TreeTransform.
+
+  QualType TransformPointerType(TypeLocBuilder &TLB, PointerTypeLoc TL) {
+    ++PointerOrArrayDepth;
+    QualType Result = TreeTransform::TransformPointerType(TLB, TL);
+    --PointerOrArrayDepth;
+    if (Result.isNull())
+      FD->setInvalidDecl();
+    return Result;
+  }
+
+  QualType TransformConstantArrayType(TypeLocBuilder &TLB,
+                                      ConstantArrayTypeLoc TL) {
+    ++PointerOrArrayDepth;
+    QualType Result = TreeTransform::TransformConstantArrayType(TLB, TL);
+    --PointerOrArrayDepth;
+    if (Result.isNull())
+      FD->setInvalidDecl();
+    return Result;
+  }
+
+  QualType TransformIncompleteArrayType(TypeLocBuilder &TLB,
+                                        IncompleteArrayTypeLoc TL) {
+    ++PointerOrArrayDepth;
+    QualType Result = TreeTransform::TransformIncompleteArrayType(TLB, TL);
+    --PointerOrArrayDepth;
+    if (Result.isNull())
+      FD->setInvalidDecl();
+    return Result;
+  }
+
+  QualType TransformVariableArrayType(TypeLocBuilder &TLB,
+                                      VariableArrayTypeLoc TL) {
+    ++PointerOrArrayDepth;
+    QualType Result = TreeTransform::TransformVariableArrayType(TLB, TL);
+    --PointerOrArrayDepth;
+    if (Result.isNull())
+      FD->setInvalidDecl();
+    return Result;
+  }
+
+  QualType TransformDependentSizedArrayType(TypeLocBuilder &TLB,
+                                            DependentSizedArrayTypeLoc TL) {
+    ++PointerOrArrayDepth;
+    QualType Result = TreeTransform::TransformDependentSizedArrayType(TLB, TL);
+    --PointerOrArrayDepth;
+    if (Result.isNull())
+      FD->setInvalidDecl();
+    return Result;
+  }
+};
+
+void Sema::ProcessLateParsedTypeAttributes(
+    RecordDecl *EnclosingDecl, ParseLateParsedTypeAttributeCB *ParseCB) {
+  for (auto *I : EnclosingDecl->decls()) {
+    FieldDecl *FD = dyn_cast<FieldDecl>(I);
+    IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(I);
+    if (!FD && IFD) {
+      FD = IFD->getAnonField();
+    }
+    if (!FD || !FD->getType()->hasLateParsedAttr() ||
+        FD->getType()->isRecordType())
+      continue;
+
+    RebuildTypeWithLateParsedAttr RebuildFieldType(*this, FD, ParseCB);
+    auto *OldTSI = FD->getTypeSourceInfo();
+    auto *TSI = RebuildFieldType.TransformType(FD->getTypeSourceInfo());
+    if (TSI && TSI != OldTSI) {
+      FD->setTypeSourceInfo(TSI);
+      FD->setType(TSI->getType());
+      if (IFD) {
----------------
ojhunt wrote:

repeated complains about braces even though I don't like the rules, but there 
it goes.

I'll leave the rest to you :D


https://github.com/llvm/llvm-project/pull/212906
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to