================ @@ -8374,20 +8376,191 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T, IsInvalid |= !S.checkPointerAuthDiscriminatorArg( ExtraDiscriminatorArg, Sema::PADAK_ExtraDiscPtrAuth, ExtraDiscriminator); - if (IsInvalid) { - Attr.setInvalid(); - return; + std::optional<PointerAuthenticationMode> AuthenticationMode = std::nullopt; + SourceRange AuthenticationModeRange; + + if (AuthenticationOptionsArg && !AuthenticationOptionsArg->containsErrors() ) { + std::string OptionsString; + bool IsInitialized = false; + const StringLiteral *OptionsStringLiteral = dyn_cast<StringLiteral>(AuthenticationOptionsArg); + auto ReportEvaluationOfExpressionIfNeeded = [&](){ + if (OptionsStringLiteral || !IsInitialized) + return; + S.Diag(AuthenticationOptionsArg->getBeginLoc(), + diag::note_ptrauth_evaluating_options) << OptionsString << AuthenticationOptionsArg->getSourceRange(); + }; + auto DiagnoseInvalidOptionsParameter = [&](llvm::StringRef Reason, std::optional<char> InvalidCh, auto Location) { + S.Diag(AuthenticationOptionsArg->getExprLoc(), + diag::err_ptrauth_invalid_option) + << AttrName << Reason << Location << !!InvalidCh << (InvalidCh ? *InvalidCh : '\0'); + Attr.setInvalid(); + ReportEvaluationOfExpressionIfNeeded(); + }; + if (AuthenticationOptionsArg->isValueDependent() || AuthenticationOptionsArg->isTypeDependent()) { + DiagnoseInvalidOptionsParameter("is dependent", std::nullopt, AuthenticationOptionsArg->getSourceRange()); + return; + } + if (OptionsStringLiteral) { + if (OptionsStringLiteral->containsNonAsciiOrNull()) { + DiagnoseInvalidOptionsParameter("contains invalid characters", std::nullopt, AuthenticationOptionsArg->getSourceRange()); + return; + } + OptionsString = OptionsStringLiteral->getString(); + } else if (S.EvaluateAsString(AuthenticationOptionsArg, OptionsString, S.Context, Sema::StringEvaluationContext::PtrauthOptions, /*ErrorOnInvalidMessage=*/false)) { + for (char Ch : OptionsString) { + if (!Ch || !isascii(Ch)) { + DiagnoseInvalidOptionsParameter("contains invalid characters", Ch, AuthenticationOptionsArg->getSourceRange()); + return; + } + } + } else { + Attr.setInvalid(); + return; + } + IsInitialized = true; + bool HasSeenOption = false; + unsigned CurrentIdx = 0; + + auto OptionStringIdxLocation = [&](unsigned Idx) { + if (OptionsStringLiteral) + return OptionsStringLiteral->getLocationOfByte(Idx, Ctx.getSourceManager(), Ctx.getLangOpts(), Ctx.getTargetInfo()); + return AuthenticationOptionsArg->getBeginLoc(); + }; + auto OptionStringRange = [&](unsigned StartIdx, unsigned EndIdx) { + if (!OptionsStringLiteral) + return AuthenticationOptionsArg->getSourceRange(); + return SourceRange(OptionStringIdxLocation(StartIdx), + OptionStringIdxLocation(EndIdx)); + }; + auto NextOption = [&]() -> std::optional<std::pair<unsigned, unsigned>> { + auto ConsumeChar = [&](auto Filter) -> char { + if (CurrentIdx >= OptionsString.size()) + return 0; + char Current = OptionsString[CurrentIdx]; + if (!Filter(Current)) + return 0; + ++CurrentIdx; + return Current; + }; + auto SkipWhiteSpace = [&]() { + while (ConsumeChar(isWhitespace)) { + // this space is intentionally left blank + } + }; + auto MatchCharacter = [](char MatchChar) { + return [MatchChar](char Ch){ return MatchChar == Ch; }; + }; + SkipWhiteSpace(); + if (CurrentIdx == OptionsString.size()) + return std::nullopt; + if (HasSeenOption) { + if (!ConsumeChar(MatchCharacter(','))) { + SourceLocation ErrorLocation = OptionStringIdxLocation(CurrentIdx); + S.Diag(ErrorLocation, diag::err_ptrauth_option_missing_comma) + << AttrName << ErrorLocation; + ReportEvaluationOfExpressionIfNeeded(); + return std::nullopt; + } + SkipWhiteSpace(); + } + HasSeenOption = true; + if (CurrentIdx == OptionsString.size()) { + SourceLocation ErrorLocation = OptionStringIdxLocation(CurrentIdx); + S.Diag(ErrorLocation, diag::err_ptrauth_unexpected_option_end) + << AttrName << ErrorLocation; + ReportEvaluationOfExpressionIfNeeded(); + } + unsigned OptionStartIdx = CurrentIdx; + while (ConsumeChar(isalpha) || ConsumeChar(MatchCharacter('-'))) { + // this space is intentionally left blank + } + unsigned OptionEndIdx = CurrentIdx; + if (OptionStartIdx == OptionEndIdx) { + StringRef ErrorString(&OptionsString[CurrentIdx], 1); + SourceLocation ErrorLocation = OptionStringIdxLocation(OptionStartIdx); + S.Diag(ErrorLocation, diag::err_ptrauth_option_unexpected_token) << ErrorString << AttrName << ErrorLocation; + ReportEvaluationOfExpressionIfNeeded(); + IsInvalid = true; + return std::nullopt; + } + return std::make_pair(OptionStartIdx, OptionEndIdx); + }; + + auto OptionHandler = [&](StringRef TokenStr, SourceRange TokenRange, ---------------- ojhunt wrote:
This is more generic than is strictly needed at this point, because future PRs add additional option types and flags https://github.com/llvm/llvm-project/pull/136828 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits