================
@@ -8631,17 +8632,162 @@ static void HandleNeonVectorTypeAttr(QualType 
&CurType, const ParsedAttr &Attr,
   CurType = S.Context.getVectorType(CurType, numElts, VecKind);
 }
 
+struct PointerAuthQualifierOptions {
+  PointerAuthenticationMode AuthenticationMode =
+      PointerAuthenticationMode::SignAndAuth;
+  bool IsIsaPointer = false;
+  bool AuthenticatesNullValues = false;
+};
+
+static bool
+checkPointerAuthQualiferOptions(Sema &S, Expr *OptionsExpr,
+                                PointerAuthQualifierOptions &Result) {
+  if (!OptionsExpr)
+    return true;
+  if (OptionsExpr->containsErrors())
+    return false;
+
+  if (OptionsExpr->isValueDependent() || OptionsExpr->isTypeDependent()) {
+    S.Diag(OptionsExpr->getExprLoc(),
+           diag::err_ptrauth_dependent_options_string)
+        << OptionsExpr->getSourceRange();
+    return false;
+  }
+
+  ASTContext &Ctx = S.getASTContext();
+  std::string EvaluatedOptionsBuffer;
+  StringRef OptionsString;
+  const StringLiteral *OptionsLiteral = dyn_cast<StringLiteral>(OptionsExpr);
+  if (OptionsLiteral)
+    OptionsString = OptionsLiteral->getString();
+  else if (auto EvaluatedString = OptionsExpr->tryEvaluateString(Ctx)) {
+    EvaluatedString->swap(EvaluatedOptionsBuffer);
+    OptionsString = EvaluatedOptionsBuffer;
+  } else if (!S.EvaluateAsString(
+                 OptionsExpr, EvaluatedOptionsBuffer, Ctx,
+                 Sema::StringEvaluationContext::PointerAuthOptions,
+                 /*ErrorOnInvalidMessage=*/true))
+    OptionsString = EvaluatedOptionsBuffer;
+  else
+    return false;
+
+  auto Failed = [&](SourceRange Range = {}, unsigned DiagId = 0,
+                    auto... DiagArgs) {
+    if (Range.isValid())
+      (S.Diag(Range.getBegin(), DiagId) << ... << DiagArgs) << Range;
+    if (!OptionsLiteral)
+      S.Diag(OptionsExpr->getExprLoc(), diag::note_ptrauth_evaluated_options)
+          << EvaluatedOptionsBuffer << OptionsExpr->getSourceRange();
+    return false;
+  };
+
+  SmallVector<StringRef, 4> Options;
+  auto ParseString = OptionsString.trim();
+  if (ParseString.empty())
+    return true;
+
+  auto FindDiagnosticRange = [&](auto Token) {
+    if (!OptionsLiteral)
+      return OptionsExpr->getSourceRange();
+    unsigned StartOffset = Token.begin() - OptionsString.begin();
+    unsigned EndOffset = StartOffset + Token.size();
+    SourceLocation StartLoc =
+        S.getLocationOfStringLiteralByte(OptionsLiteral, StartOffset);
+    SourceLocation EndLoc =
+        S.getLocationOfStringLiteralByte(OptionsLiteral, EndOffset);
+    return SourceRange(StartLoc, EndLoc);
+  };
+
+  // Split up the options
+  auto IsOptionCharacter = [](char Ch) {
+    return llvm::isAlpha(Ch) || Ch == '-';
+  };
+  while (!ParseString.empty()) {
+    if (!Options.empty()) {
+      if (ParseString.size() <= 1 || !ParseString.consume_front(','))
+        break;
+      ParseString = ParseString.ltrim();
+    }
+    StringRef Option = ParseString.take_while(IsOptionCharacter);
+    if (Option.empty())
+      break;
+    Options.push_back(Option);
+    ParseString = ParseString.drop_front(Option.size()).ltrim();
+  }
+
+  if (!ParseString.empty()) {
+    StringRef LastOption;
+    if (!Options.empty())
+      LastOption = Options.back();
+    if (StringRef UnexpectedOption = ParseString.take_while(IsOptionCharacter);
+        !UnexpectedOption.empty()) {
+      SourceRange DiagRange = FindDiagnosticRange(UnexpectedOption);
+      return Failed(DiagRange, diag::err_ptrauth_options_parse_error,
+                    /*Expected Comma*/ 3, UnexpectedOption);
+    }
+    unsigned DiagIdx = 2; // unexpected character
+    if (ParseString.starts_with(','))
+      DiagIdx = ParseString.size() == 1;
+    StringRef ErrorToken = ParseString.take_front();
+    SourceRange DiagRange = FindDiagnosticRange(ErrorToken);
+    return Failed(DiagRange, diag::err_ptrauth_options_parse_error, DiagIdx,
+                  ErrorToken, LastOption);
+  }
----------------
cor3ntin wrote:

I think there are 2 directions we could take this.
 - Either take the approach @apple-fcloutier tried for format string where we 
always put the string in a buffer, whether a literal or not, and get a source 
location in that buffer - that way diagnostics are consistent across literal 
and expressions - however this is very complicated.
 - Or we give up on precise location, and highlight the whole string. then the 
code can be reduced by split on comma, and check if any of the option, after 
trimming are one of the known option. I have a slight preference for that later 
approach, at least as a first iteration. Until this become an open set, we can 
just check that the stripped option after split by comma, is is a known set and 
if not say that foo is not a valid options, valid options are `strip, 
isa-pointer, sign-and-strip, and sign and-auth`.
  

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

Reply via email to