================
@@ -451,6 +452,119 @@ class StmtComparer {
 };
 } // namespace
 
+namespace {
+enum class AttrComparisonKind { Equal, NotEqual };
+
+/// Represents the result of comparing the attribute sets on two decls. If the
+/// sets are incompatible, A1/A2 point to the offending attributes.
+struct AttrComparisonResult {
+  AttrComparisonKind Kind = AttrComparisonKind::Equal;
+  const Attr *A1 = nullptr, *A2 = nullptr;
+};
+} // namespace
+
+static AttrComparisonResult
+areAvailabilityAttrsEqual(const AvailabilityAttr *A1,
+                          const AvailabilityAttr *A2) {
+  if (A1->getPlatform() == A2->getPlatform() &&
+      A1->getIntroduced() == A2->getIntroduced() &&
+      A1->getDeprecated() == A2->getDeprecated() &&
+      A1->getObsoleted() == A2->getObsoleted() &&
+      A1->getUnavailable() == A2->getUnavailable() &&
+      A1->getMessage() == A2->getMessage() &&
+      A1->getReplacement() == A2->getReplacement() &&
+      A1->getStrict() == A2->getStrict() &&
+      A1->getPriority() == A2->getPriority() &&
+      A1->getEnvironment() == A2->getEnvironment())
+    return {AttrComparisonKind::Equal};
+  return {AttrComparisonKind::NotEqual, A1, A2};
+}
+
+static AttrComparisonResult
+areEnumExtensibilityAttrsEqual(const EnumExtensibilityAttr *A1,
+                               const EnumExtensibilityAttr *A2) {
+  if (A1->getExtensibility() == A2->getExtensibility())
+    return {AttrComparisonKind::Equal};
+  return {AttrComparisonKind::NotEqual, A1, A2};
+}
+
+static AttrComparisonResult areAttrsEqual(const Attr *A1, const Attr *A2) {
+  auto Kind1 = A1->getKind(), Kind2 = A2->getKind();
+  if (Kind1 != Kind2)
+    return {AttrComparisonKind::NotEqual, A1, A2};
+
+  switch (Kind1) {
+  case attr::Availability:
+    return areAvailabilityAttrsEqual(cast<AvailabilityAttr>(A1),
+                                     cast<AvailabilityAttr>(A2));
+  case attr::EnumExtensibility:
+    return areEnumExtensibilityAttrsEqual(cast<EnumExtensibilityAttr>(A1),
+                                          cast<EnumExtensibilityAttr>(A2));
+  case attr::Unused:
+    return {AttrComparisonKind::Equal};
----------------
AaronBallman wrote:

Do we want to require the spellings to be the same? e.g., `[[maybe_unused]]` vs 
`__attribute__((unused))`

I think in general we have to because we have attributes with multiple 
spellings but the same kinds. e.g., 
```
def Ownership : InheritableAttr {
  let Spellings = [Clang<"ownership_holds">, Clang<"ownership_returns">,
                   Clang<"ownership_takes">];
  let Accessors = [Accessor<"isHolds", [Clang<"ownership_holds">]>,
                   Accessor<"isReturns", [Clang<"ownership_returns">]>,
                   Accessor<"isTakes", [Clang<"ownership_takes">]>];
```

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

Reply via email to