[ARM][CMSE] Implement CMSE attributes
This patch adds CMSE attributes `cmse_nonsecure_call` and
`cmse_nonsecure_entry`. As usual, specification is available here:
https://developer.arm.com/docs/ecm0359818/latest
Patch by Javed Absar, Bradley Smith, David Green, Momchil Velikov,
possibly others.
Differential Revision: https://reviews.llvm.org/D71129
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 13fae1e..336b415 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -8762,6 +8762,9 @@
QualType R = TInfo->getType();
assert(R->isFunctionType());
+ if (R.getCanonicalType()->castAs<FunctionType>()->getCmseNSCallAttr())
+ Diag(D.getIdentifierLoc(), diag::err_function_decl_cmse_ns_call);
+
SmallVector<TemplateParameterList *, 4> TemplateParamLists;
for (TemplateParameterList *TPL : TemplateParamListsRef)
TemplateParamLists.push_back(TPL);
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 5ea5103..061a7d0 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -1992,6 +1992,20 @@
D->addAttr(CA);
}
+static void handleCmseNSEntryAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (S.LangOpts.CPlusPlus && !D->getDeclContext()->isExternCContext()) {
+ S.Diag(AL.getLoc(), diag::err_attribute_not_clinkage) << AL;
+ return;
+ }
+
+ if (cast<FunctionDecl>(D)->getStorageClass() == SC_Static) {
+ S.Diag(AL.getLoc(), diag::warn_attribute_cmse_entry_static);
+ return;
+ }
+
+ D->addAttr(::new (S.Context) CmseNSEntryAttr(S.Context, AL));
+}
+
static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (checkAttrMutualExclusion<DisableTailCallsAttr>(S, D, AL))
return;
@@ -7145,6 +7159,9 @@
case ParsedAttr::AT_NoDebug:
handleNoDebugAttr(S, D, AL);
break;
+ case ParsedAttr::AT_CmseNSEntry:
+ handleCmseNSEntryAttr(S, D, AL);
+ break;
case ParsedAttr::AT_StdCall:
case ParsedAttr::AT_CDecl:
case ParsedAttr::AT_FastCall:
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 335ccab..2e1231c 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -8029,6 +8029,24 @@
ColonLoc, result, VK, OK);
}
+// Check if we have a conversion between incompatible cmse function pointer
+// types, that is, a conversion between a function pointer with the
+// cmse_nonsecure_call attribute and one without.
+static bool IsInvalidCmseNSCallConversion(Sema &S, QualType FromType,
+ QualType ToType) {
+ if (const auto *ToFn =
+ dyn_cast<FunctionType>(S.Context.getCanonicalType(ToType))) {
+ if (const auto *FromFn =
+ dyn_cast<FunctionType>(S.Context.getCanonicalType(FromType))) {
+ FunctionType::ExtInfo ToEInfo = ToFn->getExtInfo();
+ FunctionType::ExtInfo FromEInfo = FromFn->getExtInfo();
+
+ return ToEInfo.getCmseNSCall() != FromEInfo.getCmseNSCall();
+ }
+ }
+ return false;
+}
+
// checkPointerTypesForAssignment - This is a very tricky routine (despite
// being closely modeled after the C99 spec:-). The odd characteristic of this
// routine is it effectively iqnores the qualifiers on the top level pointee.
@@ -8167,6 +8185,8 @@
if (!S.getLangOpts().CPlusPlus &&
S.IsFunctionConversion(ltrans, rtrans, ltrans))
return Sema::IncompatibleFunctionPointer;
+ if (IsInvalidCmseNSCallConversion(S, ltrans, rtrans))
+ return Sema::IncompatibleFunctionPointer;
return ConvTy;
}
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 356b51e..55ce028 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -129,6 +129,7 @@
case ParsedAttr::AT_NSReturnsRetained: \
case ParsedAttr::AT_NoReturn: \
case ParsedAttr::AT_Regparm: \
+ case ParsedAttr::AT_CmseNSCall: \
case ParsedAttr::AT_AnyX86NoCallerSavedRegisters: \
case ParsedAttr::AT_AnyX86NoCfCheck: \
CALLING_CONV_ATTRS_CASELIST
@@ -7093,6 +7094,25 @@
return true;
}
+ if (attr.getKind() == ParsedAttr::AT_CmseNSCall) {
+ // Delay if this is not a function type.
+ if (!unwrapped.isFunctionType())
+ return false;
+
+ // Ignore if we don't have CMSE enabled.
+ if (!S.getLangOpts().Cmse) {
+ S.Diag(attr.getLoc(), diag::warn_attribute_ignored) << attr;
+ attr.setInvalid();
+ return true;
+ }
+
+ // Otherwise we can process right away.
+ FunctionType::ExtInfo EI =
+ unwrapped.get()->getExtInfo().withCmseNSCall(true);
+ type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
+ return true;
+ }
+
// ns_returns_retained is not always a type attribute, but if we got
// here, we're treating it as one right now.
if (attr.getKind() == ParsedAttr::AT_NSReturnsRetained) {