29 changes: 13 additions & 16 deletions clang/lib/Format/QualifierAlignmentFixer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,24 +268,20 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight(
if (isPossibleMacro(TypeToken))
return Tok;

const bool IsCpp = Style.isCpp();

// The case `const long long int volatile` -> `long long int const volatile`
// The case `long const long int volatile` -> `long long int const volatile`
// The case `long long volatile int const` -> `long long int const volatile`
// The case `const long long volatile int` -> `long long int const volatile`
if (TypeToken->isTypeName(IsCpp)) {
if (TypeToken->isTypeName()) {
// The case `const decltype(foo)` -> `const decltype(foo)`
// The case `const typeof(foo)` -> `const typeof(foo)`
// The case `const _Atomic(foo)` -> `const _Atomic(foo)`
if (TypeToken->isOneOf(tok::kw_decltype, tok::kw_typeof, tok::kw__Atomic))
return Tok;

const FormatToken *LastSimpleTypeSpecifier = TypeToken;
while (isQualifierOrType(LastSimpleTypeSpecifier->getNextNonComment(),
IsCpp)) {
while (isQualifierOrType(LastSimpleTypeSpecifier->getNextNonComment()))
LastSimpleTypeSpecifier = LastSimpleTypeSpecifier->getNextNonComment();
}

rotateTokens(SourceMgr, Fixes, Tok, LastSimpleTypeSpecifier,
/*Left=*/false);
Expand All @@ -295,7 +291,7 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight(
// The case `unsigned short const` -> `unsigned short const`
// The case:
// `unsigned short volatile const` -> `unsigned short const volatile`
if (PreviousCheck && PreviousCheck->isTypeName(IsCpp)) {
if (PreviousCheck && PreviousCheck->isTypeName()) {
if (LastQual != Tok)
rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false);
return Tok;
Expand Down Expand Up @@ -412,11 +408,11 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft(
// The case `volatile long long const int` -> `const volatile long long int`
// The case `const long long volatile int` -> `const volatile long long int`
// The case `long volatile long int const` -> `const volatile long long int`
if (const bool IsCpp = Style.isCpp(); TypeToken->isTypeName(IsCpp)) {
if (TypeToken->isTypeName()) {
const FormatToken *LastSimpleTypeSpecifier = TypeToken;
while (isConfiguredQualifierOrType(
LastSimpleTypeSpecifier->getPreviousNonComment(),
ConfiguredQualifierTokens, IsCpp)) {
ConfiguredQualifierTokens)) {
LastSimpleTypeSpecifier =
LastSimpleTypeSpecifier->getPreviousNonComment();
}
Expand Down Expand Up @@ -531,7 +527,9 @@ LeftRightQualifierAlignmentFixer::LeftRightQualifierAlignmentFixer(
const std::string &Qualifier,
const std::vector<tok::TokenKind> &QualifierTokens, bool RightAlign)
: TokenAnalyzer(Env, Style), Qualifier(Qualifier), RightAlign(RightAlign),
ConfiguredQualifierTokens(QualifierTokens) {}
ConfiguredQualifierTokens(QualifierTokens) {
IsCpp = Style.isCpp();
}

std::pair<tooling::Replacements, unsigned>
LeftRightQualifierAlignmentFixer::analyze(
Expand Down Expand Up @@ -614,16 +612,15 @@ void prepareLeftRightOrderingForQualifierAlignmentFixer(
}
}

bool LeftRightQualifierAlignmentFixer::isQualifierOrType(const FormatToken *Tok,
bool IsCpp) {
bool LeftRightQualifierAlignmentFixer::isQualifierOrType(
const FormatToken *Tok) {
return Tok &&
(Tok->isTypeName(IsCpp) || Tok->is(tok::kw_auto) || isQualifier(Tok));
(Tok->isTypeName() || Tok->is(tok::kw_auto) || isQualifier(Tok));
}

bool LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType(
const FormatToken *Tok, const std::vector<tok::TokenKind> &Qualifiers,
bool IsCpp) {
return Tok && (Tok->isTypeName(IsCpp) || Tok->is(tok::kw_auto) ||
const FormatToken *Tok, const std::vector<tok::TokenKind> &Qualifiers) {
return Tok && (Tok->isTypeName() || Tok->is(tok::kw_auto) ||
isConfiguredQualifier(Tok, Qualifiers));
}

Expand Down
5 changes: 2 additions & 3 deletions clang/lib/Format/QualifierAlignmentFixer.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,10 @@ class LeftRightQualifierAlignmentFixer : public TokenAnalyzer {
tok::TokenKind QualifierType);

// Is the Token a simple or qualifier type
static bool isQualifierOrType(const FormatToken *Tok, bool IsCpp = true);
static bool isQualifierOrType(const FormatToken *Tok);
static bool
isConfiguredQualifierOrType(const FormatToken *Tok,
const std::vector<tok::TokenKind> &Qualifiers,
bool IsCpp = true);
const std::vector<tok::TokenKind> &Qualifiers);

// Is the Token likely a Macro
static bool isPossibleMacro(const FormatToken *Tok);
Expand Down
49 changes: 23 additions & 26 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ static bool isKeywordWithCondition(const FormatToken &Tok) {
}

/// Returns \c true if the token starts a C++ attribute, \c false otherwise.
static bool isCppAttribute(bool IsCpp, const FormatToken &Tok) {
static bool isCppAttribute(const FormatToken &Tok) {
if (!IsCpp || !Tok.startsSequence(tok::l_square, tok::l_square))
return false;
// The first square bracket is part of an ObjC array literal
Expand Down Expand Up @@ -126,7 +126,8 @@ class AnnotatingParser {
const AdditionalKeywords &Keywords,
SmallVector<ScopeType> &Scopes)
: Style(Style), Line(Line), CurrentToken(Line.First), AutoFound(false),
IsCpp(Style.isCpp()), Keywords(Keywords), Scopes(Scopes) {
Keywords(Keywords), Scopes(Scopes) {
assert(IsCpp == Style.isCpp());
Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false));
resetTokenMetadata();
}
Expand Down Expand Up @@ -562,7 +563,7 @@ class AnnotatingParser {
(CurrentToken->is(tok::l_paren) && CurrentToken->Next &&
CurrentToken->Next->isOneOf(tok::star, tok::amp, tok::caret));
if ((CurrentToken->Previous->isOneOf(tok::kw_const, tok::kw_auto) ||
CurrentToken->Previous->isTypeName(IsCpp)) &&
CurrentToken->Previous->isTypeName()) &&
!(CurrentToken->is(tok::l_brace) ||
(CurrentToken->is(tok::l_paren) && !ProbablyFunctionTypeLParen))) {
Contexts.back().IsExpression = false;
Expand Down Expand Up @@ -682,15 +683,15 @@ class AnnotatingParser {

const bool IsInnerSquare = Contexts.back().InCpp11AttributeSpecifier;
const bool IsCpp11AttributeSpecifier =
isCppAttribute(IsCpp, *Left) || IsInnerSquare;
isCppAttribute(*Left) || IsInnerSquare;

// Treat C# Attributes [STAThread] much like C++ attributes [[...]].
bool IsCSharpAttributeSpecifier =
isCSharpAttributeSpecifier(*Left) ||
Contexts.back().InCSharpAttributeSpecifier;

bool InsideInlineASM = Line.startsWith(tok::kw_asm);
bool IsCppStructuredBinding = Left->isCppStructuredBinding(IsCpp);
bool IsCppStructuredBinding = Left->isCppStructuredBinding();
bool StartsObjCMethodExpr =
!IsCppStructuredBinding && !InsideInlineASM && !CppArrayTemplates &&
IsCpp && !IsCpp11AttributeSpecifier && !IsCSharpAttributeSpecifier &&
Expand Down Expand Up @@ -2573,7 +2574,7 @@ class AnnotatingParser {
return true;

// MyClass a;
if (PreviousNotConst->isTypeName(IsCpp))
if (PreviousNotConst->isTypeName())
return true;

// type[] a in Java
Expand Down Expand Up @@ -2688,7 +2689,7 @@ class AnnotatingParser {
if (Tok.Next->isOneOf(tok::kw_noexcept, tok::kw_volatile, tok::kw_const,
tok::kw_requires, tok::kw_throw, tok::arrow,
Keywords.kw_override, Keywords.kw_final) ||
isCppAttribute(IsCpp, *Tok.Next)) {
isCppAttribute(*Tok.Next)) {
return false;
}

Expand All @@ -2704,10 +2705,9 @@ class AnnotatingParser {
}

// Heuristically try to determine whether the parentheses contain a type.
auto IsQualifiedPointerOrReference = [this](FormatToken *T) {
auto IsQualifiedPointerOrReference = [](FormatToken *T) {
// This is used to handle cases such as x = (foo *const)&y;
assert(!T->isTypeName(IsCpp) && "Should have already been checked");
(void)IsCpp; // Avoid -Wunused-lambda-capture when assertion is disabled.
assert(!T->isTypeName() && "Should have already been checked");
// Strip trailing qualifiers such as const or volatile when checking
// whether the parens could be a cast to a pointer/reference type.
while (T) {
Expand Down Expand Up @@ -2739,7 +2739,7 @@ class AnnotatingParser {
bool ParensAreType =
!Tok.Previous ||
Tok.Previous->isOneOf(TT_TemplateCloser, TT_TypeDeclarationParen) ||
Tok.Previous->isTypeName(IsCpp) ||
Tok.Previous->isTypeName() ||
IsQualifiedPointerOrReference(Tok.Previous);
bool ParensCouldEndDecl =
Tok.Next->isOneOf(tok::equal, tok::semi, tok::l_brace, tok::greater);
Expand Down Expand Up @@ -3010,7 +3010,6 @@ class AnnotatingParser {
AnnotatedLine &Line;
FormatToken *CurrentToken;
bool AutoFound;
bool IsCpp;
const AdditionalKeywords &Keywords;

SmallVector<ScopeType> &Scopes;
Expand Down Expand Up @@ -3585,7 +3584,7 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) {

// This function heuristically determines whether 'Current' starts the name of a
// function declaration.
static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
static bool isFunctionDeclarationName(const FormatToken &Current,
const AnnotatedLine &Line,
FormatToken *&ClosingParen) {
assert(Current.Previous);
Expand All @@ -3596,8 +3595,7 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
if (!Current.Tok.getIdentifierInfo())
return false;

auto skipOperatorName =
[IsCpp](const FormatToken *Next) -> const FormatToken * {
auto skipOperatorName = [](const FormatToken *Next) -> const FormatToken * {
for (; Next; Next = Next->Next) {
if (Next->is(TT_OverloadedOperatorLParen))
return Next;
Expand All @@ -3616,8 +3614,8 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
Next = Next->Next;
continue;
}
if ((Next->isTypeName(IsCpp) || Next->is(tok::identifier)) &&
Next->Next && Next->Next->isPointerOrReference()) {
if ((Next->isTypeName() || Next->is(tok::identifier)) && Next->Next &&
Next->Next->isPointerOrReference()) {
// For operator void*(), operator char*(), operator Foo*().
Next = Next->Next;
continue;
Expand Down Expand Up @@ -3665,7 +3663,7 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
}
if (Next->isNot(tok::identifier))
return false;
} else if (isCppAttribute(IsCpp, *Next)) {
} else if (isCppAttribute(*Next)) {
Next = Next->MatchingParen;
if (!Next)
return false;
Expand Down Expand Up @@ -3714,7 +3712,7 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
Tok = Tok->MatchingParen;
continue;
}
if (Tok->is(tok::kw_const) || Tok->isTypeName(IsCpp) ||
if (Tok->is(tok::kw_const) || Tok->isTypeName() ||
Tok->isOneOf(TT_PointerOrReference, TT_StartOfName, tok::ellipsis)) {
return true;
}
Expand Down Expand Up @@ -3776,8 +3774,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
if (Tok->Previous->EndsCppAttributeGroup)
AfterLastAttribute = Tok;
if (const bool IsCtorOrDtor = Tok->is(TT_CtorDtorDeclName);
IsCtorOrDtor ||
isFunctionDeclarationName(IsCpp, *Tok, Line, ClosingParen)) {
IsCtorOrDtor || isFunctionDeclarationName(*Tok, Line, ClosingParen)) {
if (!IsCtorOrDtor)
Tok->setFinalizedType(TT_FunctionDeclarationName);
LineIsFunctionDeclaration = true;
Expand Down Expand Up @@ -4377,7 +4374,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (Left.Tok.isLiteral())
return true;
// for (auto a = 0, b = 0; const auto & c : {1, 2, 3})
if (Left.isTypeOrIdentifier(IsCpp) && Right.Next && Right.Next->Next &&
if (Left.isTypeOrIdentifier() && Right.Next && Right.Next->Next &&
Right.Next->Next->is(TT_RangeBasedForLoopColon)) {
return getTokenPointerOrReferenceAlignment(Right) !=
FormatStyle::PAS_Left;
Expand Down Expand Up @@ -4420,8 +4417,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (Right.is(tok::l_brace) && Right.is(BK_Block))
return true;
// for (auto a = 0, b = 0; const auto& c : {1, 2, 3})
if (Left.Previous && Left.Previous->isTypeOrIdentifier(IsCpp) &&
Right.Next && Right.Next->is(TT_RangeBasedForLoopColon)) {
if (Left.Previous && Left.Previous->isTypeOrIdentifier() && Right.Next &&
Right.Next->is(TT_RangeBasedForLoopColon)) {
return getTokenPointerOrReferenceAlignment(Left) !=
FormatStyle::PAS_Right;
}
Expand Down Expand Up @@ -4459,7 +4456,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (Right.isPointerOrReference()) {
const FormatToken *Previous = &Left;
while (Previous && Previous->isNot(tok::kw_operator)) {
if (Previous->is(tok::identifier) || Previous->isTypeName(IsCpp)) {
if (Previous->is(tok::identifier) || Previous->isTypeName()) {
Previous = Previous->getPreviousNonComment();
continue;
}
Expand Down Expand Up @@ -4648,7 +4645,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (!Style.isVerilog() &&
(Left.isOneOf(tok::identifier, tok::greater, tok::r_square,
tok::r_paren) ||
Left.isTypeName(IsCpp)) &&
Left.isTypeName()) &&
Right.is(tok::l_brace) && Right.getNextNonComment() &&
Right.isNot(BK_Block)) {
return false;
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Format/TokenAnnotator.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,9 @@ class AnnotatedLine {
class TokenAnnotator {
public:
TokenAnnotator(const FormatStyle &Style, const AdditionalKeywords &Keywords)
: Style(Style), IsCpp(Style.isCpp()), Keywords(Keywords) {}
: Style(Style), Keywords(Keywords) {
assert(IsCpp == Style.isCpp());
}

/// Adapts the indent levels of comment lines to the indent of the
/// subsequent line.
Expand Down Expand Up @@ -260,8 +262,6 @@ class TokenAnnotator {

const FormatStyle &Style;

bool IsCpp;

const AdditionalKeywords &Keywords;

SmallVector<ScopeType> Scopes;
Expand Down
22 changes: 12 additions & 10 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,16 @@ UnwrappedLineParser::UnwrappedLineParser(
llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator,
IdentifierTable &IdentTable)
: Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
CurrentLines(&Lines), Style(Style), IsCpp(Style.isCpp()),
Keywords(Keywords), CommentPragmasRegex(Style.CommentPragmas),
Tokens(nullptr), Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1),
CurrentLines(&Lines), Style(Style), Keywords(Keywords),
CommentPragmasRegex(Style.CommentPragmas), Tokens(nullptr),
Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1),
IncludeGuard(Style.IndentPPDirectives == FormatStyle::PPDIS_None
? IG_Rejected
: IG_Inited),
IncludeGuardToken(nullptr), FirstStartColumn(FirstStartColumn),
Macros(Style.Macros, SourceMgr, Style, Allocator, IdentTable) {}
Macros(Style.Macros, SourceMgr, Style, Allocator, IdentTable) {
assert(IsCpp == Style.isCpp());
}

void UnwrappedLineParser::reset() {
PPBranchLevel = -1;
Expand Down Expand Up @@ -1865,7 +1867,7 @@ void UnwrappedLineParser::parseStructuralElement(
case tok::caret:
nextToken();
// Block return type.
if (FormatTok->Tok.isAnyIdentifier() || FormatTok->isTypeName(IsCpp)) {
if (FormatTok->Tok.isAnyIdentifier() || FormatTok->isTypeName()) {
nextToken();
// Return types: pointers are ok too.
while (FormatTok->is(tok::star))
Expand Down Expand Up @@ -2221,7 +2223,7 @@ bool UnwrappedLineParser::tryToParseLambda() {
bool InTemplateParameterList = false;

while (FormatTok->isNot(tok::l_brace)) {
if (FormatTok->isTypeName(IsCpp)) {
if (FormatTok->isTypeName()) {
nextToken();
continue;
}
Expand Down Expand Up @@ -2338,7 +2340,7 @@ bool UnwrappedLineParser::tryToParseLambdaIntroducer() {
!Previous->isOneOf(tok::kw_return, tok::kw_co_await,
tok::kw_co_yield, tok::kw_co_return)) ||
Previous->closesScope())) ||
LeftSquare->isCppStructuredBinding(IsCpp)) {
LeftSquare->isCppStructuredBinding()) {
return false;
}
if (FormatTok->is(tok::l_square) || tok::isLiteral(FormatTok->Tok.getKind()))
Expand Down Expand Up @@ -3414,7 +3416,7 @@ bool clang::format::UnwrappedLineParser::parseRequires() {
break;
}
default:
if (PreviousNonComment->isTypeOrIdentifier(IsCpp)) {
if (PreviousNonComment->isTypeOrIdentifier()) {
// This is a requires clause.
parseRequiresClause(RequiresToken);
return true;
Expand Down Expand Up @@ -3477,7 +3479,7 @@ bool clang::format::UnwrappedLineParser::parseRequires() {
--OpenAngles;
break;
default:
if (NextToken->isTypeName(IsCpp)) {
if (NextToken->isTypeName()) {
FormatTok = Tokens->setPosition(StoredPosition);
parseRequiresExpression(RequiresToken);
return false;
Expand Down Expand Up @@ -3962,7 +3964,7 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
if (FormatTok->is(tok::l_square)) {
FormatToken *Previous = FormatTok->Previous;
if (!Previous || (Previous->isNot(tok::r_paren) &&
!Previous->isTypeOrIdentifier(IsCpp))) {
!Previous->isTypeOrIdentifier())) {
// Don't try parsing a lambda if we had a closing parenthesis before,
// it was probably a pointer to an array: int (*)[].
if (!tryToParseLambda())
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Format/UnwrappedLineParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,6 @@ class UnwrappedLineParser {
llvm::BitVector DeclarationScopeStack;

const FormatStyle &Style;
bool IsCpp;
const AdditionalKeywords &Keywords;

llvm::Regex CommentPragmasRegex;
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3293,6 +3293,17 @@ static void ParseAPINotesArgs(APINotesOptions &Opts, ArgList &Args,
Opts.ModuleSearchPaths.push_back(A->getValue());
}

static void GeneratePointerAuthArgs(const LangOptions &Opts,
ArgumentConsumer Consumer) {
if (Opts.PointerAuthIntrinsics)
GenerateArg(Consumer, OPT_fptrauth_intrinsics);
}

static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
DiagnosticsEngine &Diags) {
Opts.PointerAuthIntrinsics = Args.hasArg(OPT_fptrauth_intrinsics);
}

/// Check if input file kind and language standard are compatible.
static bool IsInputCompatibleWithStandard(InputKind IK,
const LangStandard &S) {
Expand Down Expand Up @@ -4014,6 +4025,7 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,

if (TT.getArch() == llvm::Triple::UnknownArch ||
!(TT.getArch() == llvm::Triple::aarch64 || TT.isPPC() ||
TT.getArch() == llvm::Triple::systemz ||
TT.getArch() == llvm::Triple::nvptx ||
TT.getArch() == llvm::Triple::nvptx64 ||
TT.getArch() == llvm::Triple::amdgcn ||
Expand Down Expand Up @@ -4612,6 +4624,8 @@ bool CompilerInvocation::CreateFromArgsImpl(
Res.getFileSystemOpts().WorkingDir);
ParseAPINotesArgs(Res.getAPINotesOpts(), Args, Diags);

ParsePointerAuthArgs(LangOpts, Args, Diags);

ParseLangArgs(LangOpts, Args, DashX, T, Res.getPreprocessorOpts().Includes,
Diags);
if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
Expand Down Expand Up @@ -4842,6 +4856,7 @@ void CompilerInvocationBase::generateCC1CommandLine(
GenerateTargetArgs(getTargetOpts(), Consumer);
GenerateHeaderSearchArgs(getHeaderSearchOpts(), Consumer);
GenerateAPINotesArgs(getAPINotesOpts(), Consumer);
GeneratePointerAuthArgs(getLangOpts(), Consumer);
GenerateLangArgs(getLangOpts(), Consumer, T, getFrontendOpts().DashX);
GenerateCodeGenArgs(getCodeGenOpts(), Consumer, T,
getFrontendOpts().OutputFile, &getLangOpts());
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Headers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ set(x86_files
popcntintrin.h
prfchiintrin.h
prfchwintrin.h
ptrauth.h
ptwriteintrin.h
raointintrin.h
rdpruintrin.h
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Headers/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -315,3 +315,8 @@ module opencl_c {
header "opencl-c.h"
header "opencl-c-base.h"
}

module ptrauth {
header "ptrauth.h"
export *
}
185 changes: 185 additions & 0 deletions clang/lib/Headers/ptrauth.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/*===---- ptrauth.h - Pointer authentication -------------------------------===
*
* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
* See https://llvm.org/LICENSE.txt for license information.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*
*===-----------------------------------------------------------------------===
*/

#ifndef __PTRAUTH_H
#define __PTRAUTH_H

typedef enum {
ptrauth_key_asia = 0,
ptrauth_key_asib = 1,
ptrauth_key_asda = 2,
ptrauth_key_asdb = 3,
} ptrauth_key;

/* An integer type of the appropriate size for a discriminator argument. */
typedef __UINTPTR_TYPE__ ptrauth_extra_data_t;

/* An integer type of the appropriate size for a generic signature. */
typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;

/* A signed pointer value embeds the original pointer together with
a signature that attests to the validity of that pointer. Because
this signature must use only "spare" bits of the pointer, a
signature's validity is probabilistic in practice: it is unlikely
but still plausible that an invalidly-derived signature will
somehow equal the correct signature and therefore successfully
authenticate. Nonetheless, this scheme provides a strong degree
of protection against certain kinds of attacks. */

/* Authenticating a pointer that was not signed with the given key
and extra-data value will (likely) fail by trapping. */

#if __has_feature(ptrauth_intrinsics)

/* Strip the signature from a value without authenticating it.
If the value is a function pointer, the result will not be a
legal function pointer because of the missing signature, and
attempting to call it will result in an authentication failure.
The value must be an expression of pointer type.
The key must be a constant expression of type ptrauth_key.
The result will have the same type as the original value. */
#define ptrauth_strip(__value, __key) __builtin_ptrauth_strip(__value, __key)

/* Blend a constant discriminator into the given pointer-like value
to form a new discriminator. Not all bits of the inputs are
guaranteed to contribute to the result.
On arm64e, the integer must fall within the range of a uint16_t;
other bits may be ignored.
The first argument must be an expression of pointer type.
The second argument must be an expression of integer type.
The result will have type uintptr_t. */
#define ptrauth_blend_discriminator(__pointer, __integer) \
__builtin_ptrauth_blend_discriminator(__pointer, __integer)

/* Add a signature to the given pointer value using a specific key,
using the given extra data as a salt to the signing process.
This operation does not authenticate the original value and is
therefore potentially insecure if an attacker could possibly
control that value.
The value must be an expression of pointer type.
The key must be a constant expression of type ptrauth_key.
The extra data must be an expression of pointer or integer type;
if an integer, it will be coerced to ptrauth_extra_data_t.
The result will have the same type as the original value. */
#define ptrauth_sign_unauthenticated(__value, __key, __data) \
__builtin_ptrauth_sign_unauthenticated(__value, __key, __data)

/* Authenticate a pointer using one scheme and resign it using another.
If the result is subsequently authenticated using the new scheme, that
authentication is guaranteed to fail if and only if the initial
authentication failed.
The value must be an expression of pointer type.
The key must be a constant expression of type ptrauth_key.
The extra data must be an expression of pointer or integer type;
if an integer, it will be coerced to ptrauth_extra_data_t.
The result will have the same type as the original value.
This operation is guaranteed to not leave the intermediate value
available for attack before it is re-signed.
Do not pass a null pointer to this function. A null pointer
will not successfully authenticate.
This operation traps if the authentication fails. */
#define ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, \
__new_data) \
__builtin_ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, \
__new_data)

/* Authenticate a data pointer.
The value must be an expression of non-function pointer type.
The key must be a constant expression of type ptrauth_key.
The extra data must be an expression of pointer or integer type;
if an integer, it will be coerced to ptrauth_extra_data_t.
The result will have the same type as the original value.
This operation traps if the authentication fails. */
#define ptrauth_auth_data(__value, __old_key, __old_data) \
__builtin_ptrauth_auth(__value, __old_key, __old_data)

/* Compute a signature for the given pair of pointer-sized values.
The order of the arguments is significant.
Like a pointer signature, the resulting signature depends on
private key data and therefore should not be reliably reproducible
by attackers. That means that this can be used to validate the
integrity of arbitrary data by storing a signature for that data
alongside it, then checking that the signature is still valid later.
Data which exceeds two pointers in size can be signed by either
computing a tree of generic signatures or just signing an ordinary
cryptographic hash of the data.
The result has type ptrauth_generic_signature_t. However, it may
not have as many bits of entropy as that type's width would suggest;
some implementations are known to compute a compressed signature as
if the arguments were a pointer and a discriminator.
The arguments must be either pointers or integers; if integers, they
will be coerce to uintptr_t. */
#define ptrauth_sign_generic_data(__value, __data) \
__builtin_ptrauth_sign_generic_data(__value, __data)

#else

#define ptrauth_strip(__value, __key) \
({ \
(void)__key; \
__value; \
})

#define ptrauth_blend_discriminator(__pointer, __integer) \
({ \
(void)__pointer; \
(void)__integer; \
((ptrauth_extra_data_t)0); \
})

#define ptrauth_sign_unauthenticated(__value, __key, __data) \
({ \
(void)__key; \
(void)__data; \
__value; \
})

#define ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, \
__new_data) \
({ \
(void)__old_key; \
(void)__old_data; \
(void)__new_key; \
(void)__new_data; \
__value; \
})

#define ptrauth_auth_data(__value, __old_key, __old_data) \
({ \
(void)__old_key; \
(void)__old_data; \
__value; \
})

#define ptrauth_sign_generic_data(__value, __data) \
({ \
(void)__value; \
(void)__data; \
((ptrauth_generic_signature_t)0); \
})

#endif /* __has_feature(ptrauth_intrinsics) */

#endif /* __PTRAUTH_H */
33 changes: 9 additions & 24 deletions clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1494,15 +1494,6 @@ void Parser::ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs) {
}
}

void Parser::ParseNullabilityClassAttributes(ParsedAttributes &attrs) {
while (Tok.is(tok::kw__Nullable)) {
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
auto Kind = Tok.getKind();
SourceLocation AttrNameLoc = ConsumeToken();
attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, Kind);
}
}

/// Determine whether the following tokens are valid after a type-specifier
/// which could be a standalone declaration. This will conservatively return
/// true if there's any doubt, and is appropriate for insert-';' fixits.
Expand Down Expand Up @@ -1684,21 +1675,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,

ParsedAttributes attrs(AttrFactory);
// If attributes exist after tag, parse them.
for (;;) {
MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs);
// Parse inheritance specifiers.
if (Tok.isOneOf(tok::kw___single_inheritance,
tok::kw___multiple_inheritance,
tok::kw___virtual_inheritance)) {
ParseMicrosoftInheritanceClassAttributes(attrs);
continue;
}
if (Tok.is(tok::kw__Nullable)) {
ParseNullabilityClassAttributes(attrs);
continue;
}
break;
}
MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs);

// Parse inheritance specifiers.
if (Tok.isOneOf(tok::kw___single_inheritance, tok::kw___multiple_inheritance,
tok::kw___virtual_inheritance))
ParseMicrosoftInheritanceClassAttributes(attrs);

// Allow attributes to precede or succeed the inheritance specifiers.
MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs);

// Source location used by FIXIT to insert misplaced
// C++11 attributes
Expand Down
12 changes: 0 additions & 12 deletions clang/lib/Sema/SemaAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,18 +215,6 @@ void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) {
inferGslPointerAttribute(Record, Record);
}

void Sema::inferNullableClassAttribute(CXXRecordDecl *CRD) {
static llvm::StringSet<> Nullable{
"auto_ptr", "shared_ptr", "unique_ptr", "exception_ptr",
"coroutine_handle", "function", "move_only_function",
};

if (CRD->isInStdNamespace() && Nullable.count(CRD->getName()) &&
!CRD->hasAttr<TypeNullableAttr>())
for (Decl *Redecl : CRD->redecls())
Redecl->addAttr(TypeNullableAttr::CreateImplicit(Context));
}

void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
SourceLocation PragmaLoc) {
PragmaMsStackAction Action = Sema::PSK_Reset;
Expand Down
257 changes: 234 additions & 23 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/FormatString.h"
#include "clang/AST/IgnoreExpr.h"
#include "clang/AST/NSAPI.h"
#include "clang/AST/NonTrivialTypeVisitor.h"
#include "clang/AST/OperationKinds.h"
Expand Down Expand Up @@ -1972,6 +1971,191 @@ static bool SemaOpenCLBuiltinToAddr(Sema &S, unsigned BuiltinID,
return false;
}

namespace {
enum PointerAuthOpKind {
PAO_Strip,
PAO_Sign,
PAO_Auth,
PAO_SignGeneric,
PAO_Discriminator,
PAO_BlendPointer,
PAO_BlendInteger
};
}

static bool checkPointerAuthEnabled(Sema &S, Expr *E) {
if (S.getLangOpts().PointerAuthIntrinsics)
return false;

S.Diag(E->getExprLoc(), diag::err_ptrauth_disabled) << E->getSourceRange();
return true;
}

static bool checkPointerAuthKey(Sema &S, Expr *&Arg) {
// Convert it to type 'int'.
if (convertArgumentToType(S, Arg, S.Context.IntTy))
return true;

// Value-dependent expressions are okay; wait for template instantiation.
if (Arg->isValueDependent())
return false;

unsigned KeyValue;
return S.checkConstantPointerAuthKey(Arg, KeyValue);
}

bool Sema::checkConstantPointerAuthKey(Expr *Arg, unsigned &Result) {
// Attempt to constant-evaluate the expression.
std::optional<llvm::APSInt> KeyValue = Arg->getIntegerConstantExpr(Context);
if (!KeyValue) {
Diag(Arg->getExprLoc(), diag::err_expr_not_ice)
<< 0 << Arg->getSourceRange();
return true;
}

// Ask the target to validate the key parameter.
if (!Context.getTargetInfo().validatePointerAuthKey(*KeyValue)) {
llvm::SmallString<32> Value;
{
llvm::raw_svector_ostream Str(Value);
Str << *KeyValue;
}

Diag(Arg->getExprLoc(), diag::err_ptrauth_invalid_key)
<< Value << Arg->getSourceRange();
return true;
}

Result = KeyValue->getZExtValue();
return false;
}

static bool checkPointerAuthValue(Sema &S, Expr *&Arg,
PointerAuthOpKind OpKind) {
if (Arg->hasPlaceholderType()) {
ExprResult R = S.CheckPlaceholderExpr(Arg);
if (R.isInvalid())
return true;
Arg = R.get();
}

auto AllowsPointer = [](PointerAuthOpKind OpKind) {
return OpKind != PAO_BlendInteger;
};
auto AllowsInteger = [](PointerAuthOpKind OpKind) {
return OpKind == PAO_Discriminator || OpKind == PAO_BlendInteger ||
OpKind == PAO_SignGeneric;
};

// Require the value to have the right range of type.
QualType ExpectedTy;
if (AllowsPointer(OpKind) && Arg->getType()->isPointerType()) {
ExpectedTy = Arg->getType().getUnqualifiedType();
} else if (AllowsPointer(OpKind) && Arg->getType()->isNullPtrType()) {
ExpectedTy = S.Context.VoidPtrTy;
} else if (AllowsInteger(OpKind) &&
Arg->getType()->isIntegralOrUnscopedEnumerationType()) {
ExpectedTy = S.Context.getUIntPtrType();

} else {
// Diagnose the failures.
S.Diag(Arg->getExprLoc(), diag::err_ptrauth_value_bad_type)
<< unsigned(OpKind == PAO_Discriminator ? 1
: OpKind == PAO_BlendPointer ? 2
: OpKind == PAO_BlendInteger ? 3
: 0)
<< unsigned(AllowsInteger(OpKind) ? (AllowsPointer(OpKind) ? 2 : 1) : 0)
<< Arg->getType() << Arg->getSourceRange();
return true;
}

// Convert to that type. This should just be an lvalue-to-rvalue
// conversion.
if (convertArgumentToType(S, Arg, ExpectedTy))
return true;

// Warn about null pointers for non-generic sign and auth operations.
if ((OpKind == PAO_Sign || OpKind == PAO_Auth) &&
Arg->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull)) {
S.Diag(Arg->getExprLoc(), OpKind == PAO_Sign
? diag::warn_ptrauth_sign_null_pointer
: diag::warn_ptrauth_auth_null_pointer)
<< Arg->getSourceRange();
}

return false;
}

static ExprResult SemaPointerAuthStrip(Sema &S, CallExpr *Call) {
if (checkArgCount(S, Call, 2))
return ExprError();
if (checkPointerAuthEnabled(S, Call))
return ExprError();
if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_Strip) ||
checkPointerAuthKey(S, Call->getArgs()[1]))
return ExprError();

Call->setType(Call->getArgs()[0]->getType());
return Call;
}

static ExprResult SemaPointerAuthBlendDiscriminator(Sema &S, CallExpr *Call) {
if (checkArgCount(S, Call, 2))
return ExprError();
if (checkPointerAuthEnabled(S, Call))
return ExprError();
if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_BlendPointer) ||
checkPointerAuthValue(S, Call->getArgs()[1], PAO_BlendInteger))
return ExprError();

Call->setType(S.Context.getUIntPtrType());
return Call;
}

static ExprResult SemaPointerAuthSignGenericData(Sema &S, CallExpr *Call) {
if (checkArgCount(S, Call, 2))
return ExprError();
if (checkPointerAuthEnabled(S, Call))
return ExprError();
if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_SignGeneric) ||
checkPointerAuthValue(S, Call->getArgs()[1], PAO_Discriminator))
return ExprError();

Call->setType(S.Context.getUIntPtrType());
return Call;
}

static ExprResult SemaPointerAuthSignOrAuth(Sema &S, CallExpr *Call,
PointerAuthOpKind OpKind) {
if (checkArgCount(S, Call, 3))
return ExprError();
if (checkPointerAuthEnabled(S, Call))
return ExprError();
if (checkPointerAuthValue(S, Call->getArgs()[0], OpKind) ||
checkPointerAuthKey(S, Call->getArgs()[1]) ||
checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator))
return ExprError();

Call->setType(Call->getArgs()[0]->getType());
return Call;
}

static ExprResult SemaPointerAuthAuthAndResign(Sema &S, CallExpr *Call) {
if (checkArgCount(S, Call, 5))
return ExprError();
if (checkPointerAuthEnabled(S, Call))
return ExprError();
if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_Auth) ||
checkPointerAuthKey(S, Call->getArgs()[1]) ||
checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator) ||
checkPointerAuthKey(S, Call->getArgs()[3]) ||
checkPointerAuthValue(S, Call->getArgs()[4], PAO_Discriminator))
return ExprError();

Call->setType(Call->getArgs()[0]->getType());
return Call;
}

static ExprResult SemaBuiltinLaunder(Sema &S, CallExpr *TheCall) {
if (checkArgCount(S, TheCall, 1))
return ExprError();
Expand Down Expand Up @@ -2684,6 +2868,18 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
}
break;
}
case Builtin::BI__builtin_ptrauth_strip:
return SemaPointerAuthStrip(*this, TheCall);
case Builtin::BI__builtin_ptrauth_blend_discriminator:
return SemaPointerAuthBlendDiscriminator(*this, TheCall);
case Builtin::BI__builtin_ptrauth_sign_unauthenticated:
return SemaPointerAuthSignOrAuth(*this, TheCall, PAO_Sign);
case Builtin::BI__builtin_ptrauth_auth:
return SemaPointerAuthSignOrAuth(*this, TheCall, PAO_Auth);
case Builtin::BI__builtin_ptrauth_sign_generic_data:
return SemaPointerAuthSignGenericData(*this, TheCall);
case Builtin::BI__builtin_ptrauth_auth_and_resign:
return SemaPointerAuthAuthAndResign(*this, TheCall);
// OpenCL v2.0, s6.13.16 - Pipe functions
case Builtin::BIread_pipe:
case Builtin::BIwrite_pipe:
Expand Down Expand Up @@ -5234,10 +5430,6 @@ bool CheckVectorElementCallArgs(Sema *S, CallExpr *TheCall) {
TheCall->getArg(1)->getEndLoc());
retValue = true;
}

if (!retValue)
TheCall->setType(VecTyA->getElementType());

return retValue;
}
}
Expand All @@ -5251,11 +5443,12 @@ bool CheckVectorElementCallArgs(Sema *S, CallExpr *TheCall) {
return true;
}

bool CheckAllArgsHaveFloatRepresentation(Sema *S, CallExpr *TheCall) {
QualType ExpectedType = S->Context.FloatTy;
bool CheckArgsTypesAreCorrect(
Sema *S, CallExpr *TheCall, QualType ExpectedType,
llvm::function_ref<bool(clang::QualType PassedType)> Check) {
for (unsigned i = 0; i < TheCall->getNumArgs(); ++i) {
QualType PassedType = TheCall->getArg(i)->getType();
if (!PassedType->hasFloatingRepresentation()) {
if (Check(PassedType)) {
if (auto *VecTyA = PassedType->getAs<VectorType>())
ExpectedType = S->Context.getVectorType(
ExpectedType, VecTyA->getNumElements(), VecTyA->getVectorKind());
Expand All @@ -5268,6 +5461,26 @@ bool CheckAllArgsHaveFloatRepresentation(Sema *S, CallExpr *TheCall) {
return false;
}

bool CheckAllArgsHaveFloatRepresentation(Sema *S, CallExpr *TheCall) {
auto checkAllFloatTypes = [](clang::QualType PassedType) -> bool {
return !PassedType->hasFloatingRepresentation();
};
return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy,
checkAllFloatTypes);
}

bool CheckFloatOrHalfRepresentations(Sema *S, CallExpr *TheCall) {
auto checkFloatorHalf = [](clang::QualType PassedType) -> bool {
clang::QualType BaseType =
PassedType->isVectorType()
? PassedType->getAs<clang::VectorType>()->getElementType()
: PassedType;
return !BaseType->isHalfType() && !BaseType->isFloat32Type();
};
return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy,
checkFloatorHalf);
}

void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall,
QualType ReturnType) {
auto *VecTyA = TheCall->getArg(0)->getType()->getAs<VectorType>();
Expand Down Expand Up @@ -5295,31 +5508,37 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return true;
break;
}
case Builtin::BI__builtin_hlsl_elementwise_isinf: {
if (checkArgCount(*this, TheCall, 1))
return true;
case Builtin::BI__builtin_hlsl_elementwise_rcp: {
if (CheckAllArgsHaveFloatRepresentation(this, TheCall))
return true;
SetElementTypeAsReturnType(this, TheCall, this->Context.BoolTy);
if (PrepareBuiltinElementwiseMathOneArgCall(TheCall))
return true;
break;
}
case Builtin::BI__builtin_hlsl_elementwise_rsqrt:
case Builtin::BI__builtin_hlsl_elementwise_rcp:
case Builtin::BI__builtin_hlsl_elementwise_frac: {
if (CheckAllArgsHaveFloatRepresentation(this, TheCall))
if (CheckFloatOrHalfRepresentations(this, TheCall))
return true;
if (PrepareBuiltinElementwiseMathOneArgCall(TheCall))
return true;
break;
}
case Builtin::BI__builtin_hlsl_elementwise_isinf: {
if (CheckFloatOrHalfRepresentations(this, TheCall))
return true;
if (PrepareBuiltinElementwiseMathOneArgCall(TheCall))
return true;
SetElementTypeAsReturnType(this, TheCall, this->Context.BoolTy);
break;
}
case Builtin::BI__builtin_hlsl_lerp: {
if (checkArgCount(*this, TheCall, 3))
return true;
if (CheckVectorElementCallArgs(this, TheCall))
return true;
if (SemaBuiltinElementwiseTernaryMath(TheCall))
return true;
if (CheckAllArgsHaveFloatRepresentation(this, TheCall))
if (CheckFloatOrHalfRepresentations(this, TheCall))
return true;
break;
}
Expand Down Expand Up @@ -7335,14 +7554,6 @@ bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember,
///
/// Returns true if the value evaluates to null.
static bool CheckNonNullExpr(Sema &S, const Expr *Expr) {
// Treat (smart) pointers constructed from nullptr as null, whether we can
// const-evaluate them or not.
// This must happen first: the smart pointer expr might have _Nonnull type!
if (isa<CXXNullPtrLiteralExpr>(
IgnoreExprNodes(Expr, IgnoreImplicitAsWrittenSingleStep,
IgnoreElidableImplicitConstructorSingleStep)))
return true;

// If the expression has non-null type, it doesn't evaluate to null.
if (auto nullability = Expr->IgnoreImplicit()->getType()->getNullability()) {
if (*nullability == NullabilityKind::NonNull)
Expand Down
4 changes: 1 addition & 3 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18254,10 +18254,8 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
if (PrevDecl)
mergeDeclAttributes(New, PrevDecl);

if (auto *CXXRD = dyn_cast<CXXRecordDecl>(New)) {
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(New))
inferGslOwnerPointerAttribute(CXXRD);
inferNullableClassAttribute(CXXRD);
}

// If there's a #pragma GCC visibility in scope, set the visibility of this
// record.
Expand Down
18 changes: 0 additions & 18 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5976,20 +5976,6 @@ static void handleBuiltinAliasAttr(Sema &S, Decl *D,
D->addAttr(::new (S.Context) BuiltinAliasAttr(S.Context, AL, Ident));
}

static void handleNullableTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (AL.isUsedAsTypeAttr())
return;

if (auto *CRD = dyn_cast<CXXRecordDecl>(D);
!CRD || !(CRD->isClass() || CRD->isStruct())) {
S.Diag(AL.getRange().getBegin(), diag::err_attribute_wrong_decl_type_str)
<< AL << AL.isRegularKeywordAttribute() << "classes";
return;
}

handleSimpleAttribute<TypeNullableAttr>(S, D, AL);
}

static void handlePreferredTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!AL.hasParsedType()) {
S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
Expand Down Expand Up @@ -9959,10 +9945,6 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_UsingIfExists:
handleSimpleAttribute<UsingIfExistsAttr>(S, D, AL);
break;

case ParsedAttr::AT_TypeNullable:
handleNullableTypeAttr(S, D, AL);
break;
}
}

Expand Down
5 changes: 0 additions & 5 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7075,11 +7075,6 @@ PerformConstructorInitialization(Sema &S,
hasCopyOrMoveCtorParam(S.Context,
getConstructorInfo(Step.Function.FoundDecl));

// A smart pointer constructed from a nullable pointer is nullable.
if (NumArgs == 1 && !Kind.isExplicitCast())
S.diagnoseNullableToNonnullConversion(
Entity.getType(), Args.front()->getType(), Kind.getLocation());

// Determine the arguments required to actually perform the constructor
// call.
if (S.CompleteConstructorCall(Constructor, Step.Type, Args, Loc,
Expand Down
7 changes: 0 additions & 7 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14797,13 +14797,6 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
}
}

// Check for nonnull = nullable.
// This won't be caught in the arg's initialization: the parameter to
// the assignment operator is not marked nonnull.
if (Op == OO_Equal)
diagnoseNullableToNonnullConversion(Args[0]->getType(),
Args[1]->getType(), OpLoc);

// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
// Best->Access is only meaningful for class members.
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2171,7 +2171,6 @@ DeclResult Sema::CheckClassTemplate(

AddPushedVisibilityAttribute(NewClass);
inferGslOwnerPointerAttribute(NewClass);
inferNullableClassAttribute(NewClass);

if (TUK != TUK_Friend) {
// Per C++ [basic.scope.temp]p2, skip the template parameter scopes.
Expand Down
18 changes: 4 additions & 14 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4711,18 +4711,6 @@ static bool DiagnoseMultipleAddrSpaceAttributes(Sema &S, LangAS ASOld,
return false;
}

// Whether this is a type broadly expected to have nullability attached.
// These types are affected by `#pragma assume_nonnull`, and missing nullability
// will be diagnosed with -Wnullability-completeness.
static bool shouldHaveNullability(QualType T) {
return T->canHaveNullability(/*ResultIfUnknown=*/false) &&
// For now, do not infer/require nullability on C++ smart pointers.
// It's unclear whether the pragma's behavior is useful for C++.
// e.g. treating type-aliases and template-type-parameters differently
// from types of declarations can be surprising.
!isa<RecordType>(T);
}

static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
QualType declSpecType,
TypeSourceInfo *TInfo) {
Expand Down Expand Up @@ -4841,7 +4829,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// inner pointers.
complainAboutMissingNullability = CAMN_InnerPointers;

if (shouldHaveNullability(T) && !T->getNullability()) {
if (T->canHaveNullability(/*ResultIfUnknown*/ false) &&
!T->getNullability()) {
// Note that we allow but don't require nullability on dependent types.
++NumPointersRemaining;
}
Expand Down Expand Up @@ -5064,7 +5053,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// If the type itself could have nullability but does not, infer pointer
// nullability and perform consistency checking.
if (S.CodeSynthesisContexts.empty()) {
if (shouldHaveNullability(T) && !T->getNullability()) {
if (T->canHaveNullability(/*ResultIfUnknown*/ false) &&
!T->getNullability()) {
if (isVaList(T)) {
// Record that we've seen a pointer, but do nothing else.
if (NumPointersRemaining > 0)
Expand Down
9 changes: 9 additions & 0 deletions clang/test/AST/Interp/builtin-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -510,3 +510,12 @@ namespace bswap {
int h4 = __builtin_bswap32(0x1234) == 0x34120000 ? 1 : f();
int h5 = __builtin_bswap64(0x1234) == 0x3412000000000000 ? 1 : f();
}

#define CFSTR __builtin___CFStringMakeConstantString
void test7(void) {
const void *X;
X = CFSTR("\242"); // both-warning {{input conversion stopped}}
X = CFSTR("\0"); // no-warning
X = CFSTR(242); // both-error {{cannot initialize a parameter of type 'const char *' with an rvalue of type 'int'}}
X = CFSTR("foo", "bar"); // both-error {{too many arguments to function call}}
}
33 changes: 29 additions & 4 deletions clang/test/AST/Interp/cxx23.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=ref20,all,all-20 %s
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=ref20,all,all20 %s
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -fcxx-exceptions -verify=ref23,all %s
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=expected20,all,all-20 %s -fexperimental-new-constant-interpreter
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify=expected20,all,all20 %s -fexperimental-new-constant-interpreter
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -fcxx-exceptions -verify=expected23,all %s -fexperimental-new-constant-interpreter

/// FIXME: The new interpreter is missing all the 'control flows through...' diagnostics.
Expand Down Expand Up @@ -108,9 +108,9 @@ namespace StaticOperators {
static_assert(f2() == 3);

struct S1 {
constexpr S1() { // all-20-error {{never produces a constant expression}}
constexpr S1() { // all20-error {{never produces a constant expression}}
throw; // all-note {{not valid in a constant expression}} \
// all-20-note {{not valid in a constant expression}}
// all20-note {{not valid in a constant expression}}
}
static constexpr int operator()() { return 3; } // ref20-warning {{C++23 extension}} \
// expected20-warning {{C++23 extension}}
Expand All @@ -121,3 +121,28 @@ namespace StaticOperators {


}

int test_in_lambdas() {
auto c = [](int n) constexpr {
if (n == 0)
return 0;
else
goto test; // all-note {{subexpression not valid in a constant expression}} \
// all20-warning {{use of this statement in a constexpr function is a C++23 extension}}
test:
return 1;
};
c(0);
constexpr auto A = c(1); // all-error {{must be initialized by a constant expression}} \
// all-note {{in call to}}
return 0;
}

/// PackIndexExpr.
template <auto... p>
struct check_ice {
enum e {
x = p...[0] // all-warning {{is a C++2c extension}}
};
};
static_assert(check_ice<42>::x == 42);
10 changes: 8 additions & 2 deletions clang/test/AST/Interp/cxx98.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@ template struct C<cval>;

/// FIXME: This example does not get properly diagnosed in the new interpreter.
extern const int recurse1;
const int recurse2 = recurse1; // both-note {{declared here}}
const int recurse2 = recurse1; // ref-note {{declared here}}
const int recurse1 = 1;
int array1[recurse1];
int array2[recurse2]; // ref-warning 2{{variable length array}} \
// ref-note {{initializer of 'recurse2' is not a constant expression}} \
// expected-warning {{variable length array}} \
// expected-note {{read of non-const variable 'recurse2'}} \
// expected-error {{variable length array}}

int NCI; // both-note {{declared here}}
Expand All @@ -39,3 +38,10 @@ struct V {
// both-error {{constructor cannot have a return type}}
};
_Static_assert(V().c[0], ""); // both-error {{is not an integral constant expression}}

struct C0 {
template<typename U> static U Data; // both-warning {{C++14 extension}}
template<typename U> static const U Data<U*> = U();
};
const int c0_test = C0::Data<int*>;
_Static_assert(c0_test == 0, "");
17 changes: 12 additions & 5 deletions clang/test/AST/Interp/if.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -fexperimental-new-constant-interpreter %s -verify
// RUN: %clang_cc1 -std=c++23 -fsyntax-only %s -verify=ref

// expected-no-diagnostics
// ref-no-diagnostics
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -fexperimental-new-constant-interpreter %s -verify=expected,both
// RUN: %clang_cc1 -std=c++23 -fsyntax-only %s -verify=ref,both

namespace ConstEval {
constexpr int f() {
Expand Down Expand Up @@ -51,3 +48,13 @@ namespace InitDecl {
}
static_assert(attrs() == 1, "");
};

/// The faulty if statement creates a RecoveryExpr with contains-errors,
/// but the execution will never reach that.
constexpr char g(char const (&x)[2]) {
return 'x';
if (auto [a, b] = x) // both-error {{an array type is not allowed here}} \
// both-warning {{ISO C++17 does not permit structured binding declaration in a condition}}
;
}
static_assert(g("x") == 'x');
6 changes: 6 additions & 0 deletions clang/test/AST/Interp/records.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1238,3 +1238,9 @@ namespace InvalidCtorInitializer {
// no crash on evaluating the constexpr ctor.
constexpr int Z = X().Y; // both-error {{constexpr variable 'Z' must be initialized by a constant expression}}
}

extern int f(); // both-note {{here}}
struct HasNonConstExprMemInit {
int x = f(); // both-note {{non-constexpr function}}
constexpr HasNonConstExprMemInit() {} // both-error {{never produces a constant expression}}
};
73 changes: 73 additions & 0 deletions clang/test/CodeGen/ptrauth-intrinsics.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s

void (*fnptr)(void);
long int_discriminator;
void *ptr_discriminator;
long signature;

// CHECK-LABEL: define void @test_auth()
void test_auth() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[PTR]] to i64
// CHECK-NEXT: [[DISC:%.*]] = ptrtoint ptr [[DISC0]] to i64
// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[T0]], i32 0, i64 [[DISC]])
// CHECK-NEXT: [[RESULT:%.*]] = inttoptr i64 [[T1]] to ptr
// CHECK-NEXT: store ptr [[RESULT]], ptr @fnptr,
fnptr = __builtin_ptrauth_auth(fnptr, 0, ptr_discriminator);
}

// CHECK-LABEL: define void @test_strip()
void test_strip() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[PTR]] to i64
// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.strip(i64 [[T0]], i32 0)
// CHECK-NEXT: [[RESULT:%.*]] = inttoptr i64 [[T1]] to ptr
// CHECK-NEXT: store ptr [[RESULT]], ptr @fnptr,
fnptr = __builtin_ptrauth_strip(fnptr, 0);
}

// CHECK-LABEL: define void @test_sign_unauthenticated()
void test_sign_unauthenticated() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[PTR]] to i64
// CHECK-NEXT: [[DISC:%.*]] = ptrtoint ptr [[DISC0]] to i64
// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[T0]], i32 0, i64 [[DISC]])
// CHECK-NEXT: [[RESULT:%.*]] = inttoptr i64 [[T1]] to ptr
// CHECK-NEXT: store ptr [[RESULT]], ptr @fnptr,
fnptr = __builtin_ptrauth_sign_unauthenticated(fnptr, 0, ptr_discriminator);
}

// CHECK-LABEL: define void @test_auth_and_resign()
void test_auth_and_resign() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[PTR]] to i64
// CHECK-NEXT: [[DISC:%.*]] = ptrtoint ptr [[DISC0]] to i64
// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 0, i64 [[DISC]], i32 3, i64 15)
// CHECK-NEXT: [[RESULT:%.*]] = inttoptr i64 [[T1]] to ptr
// CHECK-NEXT: store ptr [[RESULT]], ptr @fnptr,
fnptr = __builtin_ptrauth_auth_and_resign(fnptr, 0, ptr_discriminator, 3, 15);
}

// CHECK-LABEL: define void @test_blend_discriminator()
void test_blend_discriminator() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[DISC:%.*]] = load i64, ptr @int_discriminator,
// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[PTR]] to i64
// CHECK-NEXT: [[RESULT:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 [[DISC]])
// CHECK-NEXT: store i64 [[RESULT]], ptr @int_discriminator,
int_discriminator = __builtin_ptrauth_blend_discriminator(fnptr, int_discriminator);
}

// CHECK-LABEL: define void @test_sign_generic_data()
void test_sign_generic_data() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[PTR]] to i64
// CHECK-NEXT: [[DISC:%.*]] = ptrtoint ptr [[DISC0]] to i64
// CHECK-NEXT: [[RESULT:%.*]] = call i64 @llvm.ptrauth.sign.generic(i64 [[T0]], i64 [[DISC]])
// CHECK-NEXT: store i64 [[RESULT]], ptr @signature,
signature = __builtin_ptrauth_sign_generic_data(fnptr, ptr_discriminator);
}
22 changes: 0 additions & 22 deletions clang/test/CodeGenHLSL/builtins/lerp-builtin.hlsl
Original file line number Diff line number Diff line change
@@ -1,27 +1,5 @@
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -o - | FileCheck %s



// CHECK-LABEL: builtin_lerp_half_scalar
// CHECK: %3 = fsub double %conv1, %conv
// CHECK: %4 = fmul double %conv2, %3
// CHECK: %dx.lerp = fadd double %conv, %4
// CHECK: %conv3 = fptrunc double %dx.lerp to half
// CHECK: ret half %conv3
half builtin_lerp_half_scalar (half p0) {
return __builtin_hlsl_lerp ( p0, p0, p0 );
}

// CHECK-LABEL: builtin_lerp_float_scalar
// CHECK: %3 = fsub double %conv1, %conv
// CHECK: %4 = fmul double %conv2, %3
// CHECK: %dx.lerp = fadd double %conv, %4
// CHECK: %conv3 = fptrunc double %dx.lerp to float
// CHECK: ret float %conv3
float builtin_lerp_float_scalar ( float p0) {
return __builtin_hlsl_lerp ( p0, p0, p0 );
}

// CHECK-LABEL: builtin_lerp_half_vector
// CHECK: %dx.lerp = call <3 x half> @llvm.dx.lerp.v3f16(<3 x half> %0, <3 x half> %1, <3 x half> %2)
// CHECK: ret <3 x half> %dx.lerp
Expand Down
27 changes: 11 additions & 16 deletions clang/test/CodeGenHLSL/builtins/lerp.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -6,51 +6,46 @@
// RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \
// RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF

// NATIVE_HALF: %3 = fsub half %1, %0
// NATIVE_HALF: %4 = fmul half %2, %3
// NATIVE_HALF: %dx.lerp = fadd half %0, %4

// NATIVE_HALF: %dx.lerp = call half @llvm.dx.lerp.f16(half %0, half %1, half %2)
// NATIVE_HALF: ret half %dx.lerp
// NO_HALF: %3 = fsub float %1, %0
// NO_HALF: %4 = fmul float %2, %3
// NO_HALF: %dx.lerp = fadd float %0, %4
// NO_HALF: %dx.lerp = call float @llvm.dx.lerp.f32(float %0, float %1, float %2)
// NO_HALF: ret float %dx.lerp
half test_lerp_half(half p0) { return lerp(p0, p0, p0); }

// NATIVE_HALF: %dx.lerp = call <2 x half> @llvm.dx.lerp.v2f16(<2 x half> %0, <2 x half> %1, <2 x half> %2)
// NATIVE_HALF: ret <2 x half> %dx.lerp
// NO_HALF: %dx.lerp = call <2 x float> @llvm.dx.lerp.v2f32(<2 x float> %0, <2 x float> %1, <2 x float> %2)
// NO_HALF: ret <2 x float> %dx.lerp
half2 test_lerp_half2(half2 p0, half2 p1) { return lerp(p0, p0, p0); }
half2 test_lerp_half2(half2 p0) { return lerp(p0, p0, p0); }

// NATIVE_HALF: %dx.lerp = call <3 x half> @llvm.dx.lerp.v3f16(<3 x half> %0, <3 x half> %1, <3 x half> %2)
// NATIVE_HALF: ret <3 x half> %dx.lerp
// NO_HALF: %dx.lerp = call <3 x float> @llvm.dx.lerp.v3f32(<3 x float> %0, <3 x float> %1, <3 x float> %2)
// NO_HALF: ret <3 x float> %dx.lerp
half3 test_lerp_half3(half3 p0, half3 p1) { return lerp(p0, p0, p0); }
half3 test_lerp_half3(half3 p0) { return lerp(p0, p0, p0); }

// NATIVE_HALF: %dx.lerp = call <4 x half> @llvm.dx.lerp.v4f16(<4 x half> %0, <4 x half> %1, <4 x half> %2)
// NATIVE_HALF: ret <4 x half> %dx.lerp
// NO_HALF: %dx.lerp = call <4 x float> @llvm.dx.lerp.v4f32(<4 x float> %0, <4 x float> %1, <4 x float> %2)
// NO_HALF: ret <4 x float> %dx.lerp
half4 test_lerp_half4(half4 p0, half4 p1) { return lerp(p0, p0, p0); }
half4 test_lerp_half4(half4 p0) { return lerp(p0, p0, p0); }

// CHECK: %3 = fsub float %1, %0
// CHECK: %4 = fmul float %2, %3
// CHECK: %dx.lerp = fadd float %0, %4
// CHECK: %dx.lerp = call float @llvm.dx.lerp.f32(float %0, float %1, float %2)
// CHECK: ret float %dx.lerp
float test_lerp_float(float p0, float p1) { return lerp(p0, p0, p0); }
float test_lerp_float(float p0) { return lerp(p0, p0, p0); }

// CHECK: %dx.lerp = call <2 x float> @llvm.dx.lerp.v2f32(<2 x float> %0, <2 x float> %1, <2 x float> %2)
// CHECK: ret <2 x float> %dx.lerp
float2 test_lerp_float2(float2 p0, float2 p1) { return lerp(p0, p0, p0); }
float2 test_lerp_float2(float2 p0) { return lerp(p0, p0, p0); }

// CHECK: %dx.lerp = call <3 x float> @llvm.dx.lerp.v3f32(<3 x float> %0, <3 x float> %1, <3 x float> %2)
// CHECK: ret <3 x float> %dx.lerp
float3 test_lerp_float3(float3 p0, float3 p1) { return lerp(p0, p0, p0); }
float3 test_lerp_float3(float3 p0) { return lerp(p0, p0, p0); }

// CHECK: %dx.lerp = call <4 x float> @llvm.dx.lerp.v4f32(<4 x float> %0, <4 x float> %1, <4 x float> %2)
// CHECK: ret <4 x float> %dx.lerp
float4 test_lerp_float4(float4 p0, float4 p1) { return lerp(p0, p0, p0); }
float4 test_lerp_float4(float4 p0) { return lerp(p0, p0, p0); }

// CHECK: %dx.lerp = call <2 x float> @llvm.dx.lerp.v2f32(<2 x float> %splat.splat, <2 x float> %1, <2 x float> %2)
// CHECK: ret <2 x float> %dx.lerp
Expand Down
4 changes: 2 additions & 2 deletions clang/test/Driver/apple-kext-mkernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
// CHECK-X86-2: "-fno-rtti"
// CHECK-X86-2-NOT: "-fno-common"

// RUN: not %clang -target x86_64-apple-darwin11 -arch armv7 -mkernel -mstrict-align -### -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-ARM %s
// RUN: not %clang -target x86_64-apple-darwin11 -arch armv7 -mkernel -mstrict-align -### -fsyntax-only -fbuiltin -fno-builtin -fcommon -fno-common %s 2>&1 | FileCheck --check-prefix=CHECK-ARM %s
// RUN: %clang --target=x86_64-apple-darwin11 -arch armv7 -mkernel -mstrict-align -### -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-ARM %s
// RUN: %clang --target=x86_64-apple-darwin11 -arch armv7 -mkernel -mstrict-align -### -fsyntax-only -fbuiltin -fno-builtin -fcommon -fno-common %s 2>&1 | FileCheck --check-prefix=CHECK-ARM %s

// CHECK-ARM: "-target-feature" "+long-calls"
// CHECK-ARM: "-target-feature" "+strict-align"
Expand Down
38 changes: 6 additions & 32 deletions clang/test/Driver/loongarch-munaligned-access.c
Original file line number Diff line number Diff line change
@@ -1,61 +1,35 @@
/// Test -m[no-]unaligned-access and -m[no-]strict-align options.

// RUN: %clang --target=loongarch64 -munaligned-access -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-UNALIGNED
// RUN: %clang --target=loongarch64 -mno-unaligned-access -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-NO-UNALIGNED
// RUN: %clang --target=loongarch64 -mstrict-align -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-NO-UNALIGNED
// RUN: %clang --target=loongarch64 -mno-strict-align -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-UNALIGNED
// RUN: %clang --target=loongarch64 -munaligned-access -mno-unaligned-access -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-NO-UNALIGNED
// RUN: %clang --target=loongarch64 -mno-unaligned-access -munaligned-access -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-UNALIGNED
// RUN: %clang --target=loongarch64 -mstrict-align -mno-strict-align -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-UNALIGNED
// RUN: %clang --target=loongarch64 -mno-strict-align -mstrict-align -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-NO-UNALIGNED
// RUN: %clang --target=loongarch64 -munaligned-access -mstrict-align -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-NO-UNALIGNED
// RUN: %clang --target=loongarch64 -mstrict-align -munaligned-access -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-UNALIGNED
// RUN: %clang --target=loongarch64 -mno-unaligned-access -mno-strict-align -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-UNALIGNED
// RUN: %clang --target=loongarch64 -mno-strict-align -mno-unaligned-access -fsyntax-only %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-NO-UNALIGNED

// RUN: %clang --target=loongarch64 -munaligned-access -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-UNALIGNED
// RUN: %clang --target=loongarch64 -mno-unaligned-access -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-NO-UNALIGNED
// RUN: %clang --target=loongarch64 -mstrict-align -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-NO-UNALIGNED
// RUN: %clang --target=loongarch64 -mno-strict-align -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-UNALIGNED
// RUN: %clang --target=loongarch64 -munaligned-access -mno-unaligned-access -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-NO-UNALIGNED
// RUN: %clang --target=loongarch64 -mno-unaligned-access -munaligned-access -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-UNALIGNED
// RUN: %clang --target=loongarch64 -mstrict-align -mno-strict-align -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-UNALIGNED
// RUN: %clang --target=loongarch64 -mno-strict-align -mstrict-align -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-NO-UNALIGNED
// RUN: %clang --target=loongarch64 -munaligned-access -mstrict-align -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-NO-UNALIGNED
// RUN: %clang --target=loongarch64 -mstrict-align -munaligned-access -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-UNALIGNED
// RUN: %clang --target=loongarch64 -mno-unaligned-access -mno-strict-align -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-UNALIGNED
// RUN: %clang --target=loongarch64 -mno-strict-align -mno-unaligned-access -S -emit-llvm %s -o - | \
// RUN: FileCheck %s --check-prefix=IR-NO-UNALIGNED

// RUN: not %clang -### --target=loongarch64 -mno-unaligned-access -munaligned-access %s 2>&1 | \
// RUN: FileCheck %s --check-prefix=ERR

// CC1-UNALIGNED: "-target-feature" "+ual"
// CC1-NO-UNALIGNED: "-target-feature" "-ual"

// IR-UNALIGNED: attributes #[[#]] ={{.*}}"target-features"="{{(.*,)?}}+ual{{(,.*)?}}"
// IR-NO-UNALIGNED: attributes #[[#]] ={{.*}}"target-features"="{{(.*,)?}}-ual{{(,.*)?}}"

// ERR: error: unsupported option '-mno-unaligned-access' for target 'loongarch64'
// ERR: error: unsupported option '-munaligned-access' for target 'loongarch64'

int foo(void) {
return 3;
}
7 changes: 4 additions & 3 deletions clang/test/Driver/munaligned-access-unused.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/// Check -m[no-]unaligned-access and -m[no-]strict-align are warned unused on a target that does not support them.
/// Check -m[no-]unaligned-access and -m[no-]strict-align are errored on a target that does not support them.

// RUN: not %clang --target=x86_64 -munaligned-access -fsyntax-only %s -### 2>&1 | FileCheck %s -DOPTION=unaligned-access
// RUN: not %clang --target=x86_64 -mno-unaligned-access -fsyntax-only %s -### 2>&1 | FileCheck %s -DOPTION=no-unaligned-access
// RUN: not %clang --target=x86_64 -mstrict-align -fsyntax-only %s -### 2>&1 | FileCheck %s -DOPTION=strict-align
// RUN: not %clang --target=x86_64 -mno-strict-align -fsyntax-only %s -### 2>&1 | FileCheck %s -DOPTION=no-strict-align
// RUN: not %clang --target=x86_64 -mno-strict-align -mstrict-align -fsyntax-only %s -### 2>&1 | FileCheck %s --check-prefix=ALIGN

// CHECK: error: unsupported option '-m{{(no-)?}}unaligned-access' for target '{{.*}}'
// ALIGN: error: unsupported option '-mno-strict-align' for target '{{.*}}'
// ALIGN: error: unsupported option '-mstrict-align' for target '{{.*}}'
2 changes: 0 additions & 2 deletions clang/test/Driver/riscv-features.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@
// NO-FORCE-SW-SCS: "-target-feature" "-forced-sw-shadow-stack"
// DEFAULT-NOT: "-target-feature" "+forced-sw-shadow-stack"

// RUN: %clang --target=riscv32-unknown-elf -### %s -munaligned-access 2>&1 | FileCheck %s -check-prefix=FAST-UNALIGNED-ACCESS
// RUN: %clang --target=riscv32-unknown-elf -### %s -mno-unaligned-access 2>&1 | FileCheck %s -check-prefix=NO-FAST-UNALIGNED-ACCESS
// RUN: %clang --target=riscv32-unknown-elf -### %s -mno-strict-align 2>&1 | FileCheck %s -check-prefix=FAST-UNALIGNED-ACCESS
// RUN: %clang --target=riscv32-unknown-elf -### %s -mstrict-align 2>&1 | FileCheck %s -check-prefix=NO-FAST-UNALIGNED-ACCESS

Expand Down
2 changes: 1 addition & 1 deletion clang/test/Driver/tls-dialect.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// RUN: %clang -### --target=riscv64-linux -mtls-dialect=trad %s 2>&1 | FileCheck --check-prefix=NODESC %s
// RUN: %clang -### --target=riscv64-linux %s 2>&1 | FileCheck --check-prefix=NODESC %s
// RUN: %clang -### --target=x86_64-linux -mtls-dialect=gnu %s 2>&1 | FileCheck --check-prefix=NODESC %s
// RUN: %clang -### --target=x86_64-linux -mtls-dialect=gnu2 %s 2>&1 | FileCheck --check-prefix=DESC %s

/// Android supports TLSDESC by default on RISC-V
/// TLSDESC is not on by default in Linux, even on RISC-V, and is covered above
Expand All @@ -18,7 +19,6 @@

/// Unsupported argument
// RUN: not %clang -### --target=riscv64-linux -mtls-dialect=gnu2 %s 2>&1 | FileCheck --check-prefix=UNSUPPORTED-ARG %s
// RUN: not %clang -### --target=x86_64-linux -mtls-dialect=gnu2 %s 2>&1 | FileCheck --check-prefix=UNSUPPORTED-ARG %s

// DESC: "-cc1" {{.*}}"-enable-tlsdesc"
// NODESC-NOT: "-enable-tlsdesc"
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Preprocessor/bpf-predefined-macros.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ int r;
#ifdef __BPF_FEATURE_ST
int s;
#endif
#ifdef __BPF_FEATURE_ARENA_CAST
#ifdef __BPF_FEATURE_ADDR_SPACE_CAST
int t;
#endif

Expand Down
10 changes: 10 additions & 0 deletions clang/test/Preprocessor/ptrauth_feature.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// RUN: %clang_cc1 %s -E -triple=arm64-- | FileCheck %s --check-prefixes=NOINTRIN
// RUN: %clang_cc1 %s -E -triple=arm64-- -fptrauth-intrinsics | FileCheck %s --check-prefixes=INTRIN

#if __has_feature(ptrauth_intrinsics)
// INTRIN: has_ptrauth_intrinsics
void has_ptrauth_intrinsics() {}
#else
// NOINTRIN: no_ptrauth_intrinsics
void no_ptrauth_intrinsics() {}
#endif
4 changes: 2 additions & 2 deletions clang/test/Preprocessor/riscv-target-features.c
Original file line number Diff line number Diff line change
Expand Up @@ -1666,9 +1666,9 @@
// CHECK-MISALIGNED-AVOID: __riscv_misaligned_avoid 1

// RUN: %clang --target=riscv32-unknown-linux-gnu -march=rv32i -E -dM %s \
// RUN: -munaligned-access -o - | FileCheck %s --check-prefix=CHECK-MISALIGNED-FAST
// RUN: -mno-strict-align -o - | FileCheck %s --check-prefix=CHECK-MISALIGNED-FAST
// RUN: %clang --target=riscv64-unknown-linux-gnu -march=rv64i -E -dM %s \
// RUN: -munaligned-access -o - | FileCheck %s --check-prefix=CHECK-MISALIGNED-FAST
// RUN: -mno-strict-align -o - | FileCheck %s --check-prefix=CHECK-MISALIGNED-FAST
// RUN: %clang --target=riscv64-unknown-linux-gnu -mcpu=sifive-p450 -E -dM %s \
// RUN: -o - | FileCheck %s --check-prefix=CHECK-MISALIGNED-FAST
// CHECK-MISALIGNED-FAST: __riscv_misaligned_fast 1
2 changes: 0 additions & 2 deletions clang/test/Sema/nullability.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,5 +248,3 @@ void arraysInBlocks(void) {
void (^withTypedefBad)(INTS _Nonnull [2]) = // expected-error {{nullability specifier '_Nonnull' cannot be applied to non-pointer type 'INTS' (aka 'int[4]')}}
^(INTS _Nonnull x[2]) {}; // expected-error {{nullability specifier '_Nonnull' cannot be applied to non-pointer type 'INTS' (aka 'int[4]')}}
}

struct _Nullable NotCplusplusClass {}; // expected-error {{'_Nullable' attribute only applies to classes}}
34 changes: 34 additions & 0 deletions clang/test/Sema/ptrauth-intrinsics-macro.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// RUN: %clang_cc1 -triple arm64-apple-ios -Wall -fsyntax-only -verify -fptrauth-intrinsics %s
// RUN: %clang_cc1 -triple arm64-apple-ios -Wall -fsyntax-only -verify %s

// expected-no-diagnostics

#include <ptrauth.h>

#define VALID_CODE_KEY 0
#define VALID_DATA_KEY 2

extern int dv;

void test(int *dp, int value) {
dp = ptrauth_strip(dp, VALID_DATA_KEY);
ptrauth_extra_data_t t0 = ptrauth_blend_discriminator(dp, value);
(void)t0;
dp = ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY, 0);
dp = ptrauth_auth_and_resign(dp, VALID_DATA_KEY, dp, VALID_DATA_KEY, dp);
dp = ptrauth_auth_data(dp, VALID_DATA_KEY, 0);
int pu0 = 0, pu1 = 0, pu2 = 0, pu3 = 0, pu4 = 0, pu5 = 0, pu6 = 0, pu7 = 0;
ptrauth_blend_discriminator(&pu0, value);
ptrauth_auth_and_resign(&pu1, VALID_DATA_KEY, dp, VALID_DATA_KEY, dp);
ptrauth_auth_and_resign(dp, VALID_DATA_KEY, &pu2, VALID_DATA_KEY, dp);
ptrauth_auth_and_resign(dp, VALID_DATA_KEY, dp, VALID_DATA_KEY, &pu3);
ptrauth_sign_generic_data(pu4, dp);
ptrauth_sign_generic_data(dp, pu5);
ptrauth_auth_data(&pu6, VALID_DATA_KEY, value);
ptrauth_auth_data(dp, VALID_DATA_KEY, pu7);



int t2 = ptrauth_sign_generic_data(dp, 0);
(void)t2;
}
126 changes: 126 additions & 0 deletions clang/test/Sema/ptrauth.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// RUN: %clang_cc1 -triple arm64-apple-ios -fsyntax-only -verify -fptrauth-intrinsics %s

#if __has_feature(ptrauth_intrinsics)
#warning Pointer authentication enabled!
// expected-warning@-1 {{Pointer authentication enabled!}}
#endif

#if __aarch64__
#define VALID_CODE_KEY 0
#define VALID_DATA_KEY 2
#define INVALID_KEY 200
#else
#error Provide these constants if you port this test
#endif

#define NULL ((void*) 0)
struct A { int x; } mismatched_type;

extern int dv;
extern int fv(int);

void test_strip(int *dp, int (*fp)(int)) {
__builtin_ptrauth_strip(dp); // expected-error {{too few arguments}}
__builtin_ptrauth_strip(dp, VALID_DATA_KEY, dp); // expected-error {{too many arguments}}
(void) __builtin_ptrauth_strip(NULL, VALID_DATA_KEY); // no warning

__builtin_ptrauth_strip(mismatched_type, VALID_DATA_KEY); // expected-error {{signed value must have pointer type; type here is 'struct A'}}
__builtin_ptrauth_strip(dp, mismatched_type); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}}

int *dr = __builtin_ptrauth_strip(dp, VALID_DATA_KEY);
dr = __builtin_ptrauth_strip(dp, INVALID_KEY); // expected-error {{does not identify a valid pointer authentication key for the current target}}

int (*fr)(int) = __builtin_ptrauth_strip(fp, VALID_CODE_KEY);
fr = __builtin_ptrauth_strip(fp, INVALID_KEY); // expected-error {{does not identify a valid pointer authentication key for the current target}}

float *mismatch = __builtin_ptrauth_strip(dp, VALID_DATA_KEY); // expected-warning {{incompatible pointer types initializing 'float *' with an expression of type 'int *'}}
}

void test_blend_discriminator(int *dp, int (*fp)(int), int value) {
__builtin_ptrauth_blend_discriminator(dp); // expected-error {{too few arguments}}
__builtin_ptrauth_blend_discriminator(dp, dp, dp); // expected-error {{too many arguments}}
(void) __builtin_ptrauth_blend_discriminator(dp, value); // no warning

__builtin_ptrauth_blend_discriminator(mismatched_type, value); // expected-error {{blended pointer must have pointer type; type here is 'struct A'}}
__builtin_ptrauth_blend_discriminator(dp, mismatched_type); // expected-error {{blended integer must have integer type; type here is 'struct A'}}

float *mismatch = __builtin_ptrauth_blend_discriminator(dp, value); // expected-error {{incompatible integer to pointer conversion initializing 'float *' with an expression of type}}
}

void test_sign_unauthenticated(int *dp, int (*fp)(int)) {
__builtin_ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY); // expected-error {{too few arguments}}
__builtin_ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY, dp, dp); // expected-error {{too many arguments}}

__builtin_ptrauth_sign_unauthenticated(mismatched_type, VALID_DATA_KEY, 0); // expected-error {{signed value must have pointer type; type here is 'struct A'}}
__builtin_ptrauth_sign_unauthenticated(dp, mismatched_type, 0); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}}
__builtin_ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY, mismatched_type); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}}

(void) __builtin_ptrauth_sign_unauthenticated(NULL, VALID_DATA_KEY, 0); // expected-warning {{signing a null pointer will yield a non-null pointer}}

int *dr = __builtin_ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY, 0);
dr = __builtin_ptrauth_sign_unauthenticated(dp, INVALID_KEY, 0); // expected-error {{does not identify a valid pointer authentication key for the current target}}

int (*fr)(int) = __builtin_ptrauth_sign_unauthenticated(fp, VALID_CODE_KEY, 0);
fr = __builtin_ptrauth_sign_unauthenticated(fp, INVALID_KEY, 0); // expected-error {{does not identify a valid pointer authentication key for the current target}}

float *mismatch = __builtin_ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY, 0); // expected-warning {{incompatible pointer types initializing 'float *' with an expression of type 'int *'}}
}

void test_auth(int *dp, int (*fp)(int)) {
__builtin_ptrauth_auth(dp, VALID_DATA_KEY); // expected-error {{too few arguments}}
__builtin_ptrauth_auth(dp, VALID_DATA_KEY, dp, dp); // expected-error {{too many arguments}}

__builtin_ptrauth_auth(mismatched_type, VALID_DATA_KEY, 0); // expected-error {{signed value must have pointer type; type here is 'struct A'}}
__builtin_ptrauth_auth(dp, mismatched_type, 0); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}}
__builtin_ptrauth_auth(dp, VALID_DATA_KEY, mismatched_type); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}}

(void) __builtin_ptrauth_auth(NULL, VALID_DATA_KEY, 0); // expected-warning {{authenticating a null pointer will almost certainly trap}}

int *dr = __builtin_ptrauth_auth(dp, VALID_DATA_KEY, 0);
dr = __builtin_ptrauth_auth(dp, INVALID_KEY, 0); // expected-error {{does not identify a valid pointer authentication key for the current target}}

int (*fr)(int) = __builtin_ptrauth_auth(fp, VALID_CODE_KEY, 0);
fr = __builtin_ptrauth_auth(fp, INVALID_KEY, 0); // expected-error {{does not identify a valid pointer authentication key for the current target}}

float *mismatch = __builtin_ptrauth_auth(dp, VALID_DATA_KEY, 0); // expected-warning {{incompatible pointer types initializing 'float *' with an expression of type 'int *'}}
}

void test_auth_and_resign(int *dp, int (*fp)(int)) {
__builtin_ptrauth_auth_and_resign(dp, VALID_DATA_KEY, 0, VALID_DATA_KEY); // expected-error {{too few arguments}}
__builtin_ptrauth_auth_and_resign(dp, VALID_DATA_KEY, dp, VALID_DATA_KEY, dp, 0); // expected-error {{too many arguments}}

__builtin_ptrauth_auth_and_resign(mismatched_type, VALID_DATA_KEY, 0, VALID_DATA_KEY, dp); // expected-error {{signed value must have pointer type; type here is 'struct A'}}
__builtin_ptrauth_auth_and_resign(dp, mismatched_type, 0, VALID_DATA_KEY, dp); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}}
__builtin_ptrauth_auth_and_resign(dp, VALID_DATA_KEY, mismatched_type, VALID_DATA_KEY, dp); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}}
__builtin_ptrauth_auth_and_resign(dp, VALID_DATA_KEY, 0, mismatched_type, dp); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}}
__builtin_ptrauth_auth_and_resign(dp, VALID_DATA_KEY, 0, VALID_DATA_KEY, mismatched_type); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}}

(void) __builtin_ptrauth_auth_and_resign(NULL, VALID_DATA_KEY, 0, VALID_DATA_KEY, dp); // expected-warning {{authenticating a null pointer will almost certainly trap}}

int *dr = __builtin_ptrauth_auth_and_resign(dp, VALID_DATA_KEY, 0, VALID_DATA_KEY, dp);
dr = __builtin_ptrauth_auth_and_resign(dp, INVALID_KEY, 0, VALID_DATA_KEY, dp); // expected-error {{does not identify a valid pointer authentication key for the current target}}
dr = __builtin_ptrauth_auth_and_resign(dp, VALID_DATA_KEY, 0, INVALID_KEY, dp); // expected-error {{does not identify a valid pointer authentication key for the current target}}

int (*fr)(int) = __builtin_ptrauth_auth_and_resign(fp, VALID_CODE_KEY, 0, VALID_CODE_KEY, dp);
fr = __builtin_ptrauth_auth_and_resign(fp, INVALID_KEY, 0, VALID_CODE_KEY, dp); // expected-error {{does not identify a valid pointer authentication key for the current target}}
fr = __builtin_ptrauth_auth_and_resign(fp, VALID_CODE_KEY, 0, INVALID_KEY, dp); // expected-error {{does not identify a valid pointer authentication key for the current target}}

float *mismatch = __builtin_ptrauth_auth_and_resign(dp, VALID_DATA_KEY, 0, VALID_DATA_KEY, dp); // expected-warning {{incompatible pointer types initializing 'float *' with an expression of type 'int *'}}
}

void test_sign_generic_data(int *dp) {
__builtin_ptrauth_sign_generic_data(dp); // expected-error {{too few arguments}}
__builtin_ptrauth_sign_generic_data(dp, 0, 0); // expected-error {{too many arguments}}

__builtin_ptrauth_sign_generic_data(mismatched_type, 0); // expected-error {{signed value must have pointer or integer type; type here is 'struct A'}}
__builtin_ptrauth_sign_generic_data(dp, mismatched_type); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}}

(void) __builtin_ptrauth_sign_generic_data(NULL, 0); // no warning

unsigned long dr = __builtin_ptrauth_sign_generic_data(dp, 0);
dr = __builtin_ptrauth_sign_generic_data(dp, &dv);
dr = __builtin_ptrauth_sign_generic_data(12314, 0);
dr = __builtin_ptrauth_sign_generic_data(12314, &dv);

int *mismatch = __builtin_ptrauth_sign_generic_data(dp, 0); // expected-error {{incompatible integer to pointer conversion initializing 'int *' with an expression of type}}
}
1 change: 1 addition & 0 deletions clang/test/SemaCXX/decomposed-condition.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++1z -Wno-binding-in-condition -verify %s
// RUN: %clang_cc1 -std=c++1z -Wno-binding-in-condition -verify %s -fexperimental-new-constant-interpreter

struct X {
bool flag;
Expand Down
62 changes: 2 additions & 60 deletions clang/test/SemaCXX/nullability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@
#else
# error nullability feature should be defined
#endif
#if __has_feature(nullability_on_classes)
#else
# error smart-pointer feature should be defined
#endif

#include "nullability-completeness.h"

Expand All @@ -31,7 +27,6 @@ template<typename T>
struct AddNonNull {
typedef _Nonnull T type; // expected-error{{nullability specifier '_Nonnull' cannot be applied to non-pointer type 'int'}}
// expected-error@-1{{nullability specifier '_Nonnull' cannot be applied to non-pointer type 'std::nullptr_t'}}
// expected-error@-2{{nullability specifier '_Nonnull' cannot be applied to non-pointer type 'NotPtr'}}
};

typedef AddNonNull<int *>::type nonnull_int_ptr_1;
Expand All @@ -40,33 +35,6 @@ typedef AddNonNull<nullptr_t>::type nonnull_int_ptr_3; // expected-note{{in inst

typedef AddNonNull<int>::type nonnull_non_pointer_1; // expected-note{{in instantiation of template class 'AddNonNull<int>' requested here}}

// Nullability on C++ class types (smart pointers).
struct NotPtr{};
typedef AddNonNull<NotPtr>::type nonnull_non_pointer_2; // expected-note{{in instantiation}}
struct _Nullable SmartPtr{
SmartPtr();
SmartPtr(nullptr_t);
SmartPtr(const SmartPtr&);
SmartPtr(SmartPtr&&);
SmartPtr &operator=(const SmartPtr&);
SmartPtr &operator=(SmartPtr&&);
};
typedef AddNonNull<SmartPtr>::type nonnull_smart_pointer_1;
template<class> struct _Nullable SmartPtrTemplate{};
typedef AddNonNull<SmartPtrTemplate<int>>::type nonnull_smart_pointer_2;
namespace std { inline namespace __1 {
template <class> class unique_ptr {};
template <class> class function;
template <class Ret, class... Args> class function<Ret(Args...)> {};
} }
typedef AddNonNull<std::unique_ptr<int>>::type nonnull_smart_pointer_3;
typedef AddNonNull<std::function<int()>>::type nonnull_smart_pointer_4;

class Derived : public SmartPtr {};
Derived _Nullable x; // expected-error {{'_Nullable' cannot be applied}}
class DerivedPrivate : private SmartPtr {};
DerivedPrivate _Nullable y; // expected-error {{'_Nullable' cannot be applied}}

// Non-null checking within a template.
template<typename T>
struct AddNonNull2 {
Expand All @@ -86,16 +54,13 @@ void (*& accepts_nonnull_2)(_Nonnull int *ptr) = accepts_nonnull_1;
void (X::* accepts_nonnull_3)(_Nonnull int *ptr);
void accepts_nonnull_4(_Nonnull int *ptr);
void (&accepts_nonnull_5)(_Nonnull int *ptr) = accepts_nonnull_4;
void accepts_nonnull_6(SmartPtr _Nonnull);

void test_accepts_nonnull_null_pointer_literal(X *x) {
accepts_nonnull_1(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
accepts_nonnull_2(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
(x->*accepts_nonnull_3)(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
accepts_nonnull_4(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
accepts_nonnull_5(0); // expected-warning{{null passed to a callee that requires a non-null argument}}

accepts_nonnull_6(nullptr); // expected-warning{{null passed to a callee that requires a non-null argument}}
}

template<void FP(_Nonnull int*)>
Expand All @@ -106,7 +71,6 @@ void test_accepts_nonnull_null_pointer_literal_template() {
template void test_accepts_nonnull_null_pointer_literal_template<&accepts_nonnull_4>(); // expected-note{{instantiation of function template specialization}}

void TakeNonnull(void *_Nonnull);
void TakeSmartNonnull(SmartPtr _Nonnull);
// Check different forms of assignment to a nonull type from a nullable one.
void AssignAndInitNonNull() {
void *_Nullable nullable;
Expand All @@ -117,26 +81,12 @@ void AssignAndInitNonNull() {
void *_Nonnull nonnull;
nonnull = nullable; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}}
nonnull = {nullable}; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}}

TakeNonnull(nullable); //expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull}}
TakeNonnull(nonnull); // OK
nonnull = (void *_Nonnull)nullable; // explicit cast OK

SmartPtr _Nullable s_nullable;
SmartPtr _Nonnull s(s_nullable); // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}}
SmartPtr _Nonnull s2{s_nullable}; // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}}
SmartPtr _Nonnull s3 = {s_nullable}; // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}}
SmartPtr _Nonnull s4 = s_nullable; // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}}
SmartPtr _Nonnull s_nonnull;
s_nonnull = s_nullable; // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}}
s_nonnull = {s_nullable}; // no warning here - might be nice?
TakeSmartNonnull(s_nullable); //expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull}}
TakeSmartNonnull(s_nonnull); // OK
s_nonnull = (SmartPtr _Nonnull)s_nullable; // explicit cast OK
s_nonnull = static_cast<SmartPtr _Nonnull>(s_nullable); // explicit cast OK
}

void *_Nullable ReturnNullable();
SmartPtr _Nullable ReturnSmartNullable();

void AssignAndInitNonNullFromFn() {
void *_Nonnull p(ReturnNullable()); // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}}
Expand All @@ -146,16 +96,8 @@ void AssignAndInitNonNullFromFn() {
void *_Nonnull nonnull;
nonnull = ReturnNullable(); // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}}
nonnull = {ReturnNullable()}; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}}
TakeNonnull(ReturnNullable()); //expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull}}

SmartPtr _Nonnull s(ReturnSmartNullable()); // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}}
SmartPtr _Nonnull s2{ReturnSmartNullable()}; // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}}
SmartPtr _Nonnull s3 = {ReturnSmartNullable()}; // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}}
SmartPtr _Nonnull s4 = ReturnSmartNullable(); // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}}
SmartPtr _Nonnull s_nonnull;
s_nonnull = ReturnSmartNullable(); // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}}
s_nonnull = {ReturnSmartNullable()};
TakeSmartNonnull(ReturnSmartNullable()); // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}}
TakeNonnull(ReturnNullable()); //expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull}}
}

void ConditionalExpr(bool c) {
Expand Down
12 changes: 12 additions & 0 deletions clang/test/SemaHLSL/BuiltIns/frac-errors.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,15 @@ float2 builtin_frac_int2_to_float2_promotion(int2 p1) {
return __builtin_hlsl_elementwise_frac(p1);
// expected-error@-1 {{passing 'int2' (aka 'vector<int, 2>') to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(float)))) float' (vector of 2 'float' values)}}
}

// builtins are variadic functions and so are subject to DefaultVariadicArgumentPromotion
half builtin_frac_half_scalar (half p0) {
return __builtin_hlsl_elementwise_frac (p0);
// expected-error@-1 {{passing 'double' to parameter of incompatible type 'float'}}
}

float builtin_frac_float_scalar ( float p0) {
return __builtin_hlsl_elementwise_frac (p0);
// expected-error@-1 {{passing 'double' to parameter of incompatible type 'float'}}
}

11 changes: 11 additions & 0 deletions clang/test/SemaHLSL/BuiltIns/isinf-errors.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,14 @@ bool2 builtin_isinf_int2_to_float2_promotion(int2 p1) {
return __builtin_hlsl_elementwise_isinf(p1);
// expected-error@-1 {{passing 'int2' (aka 'vector<int, 2>') to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(float)))) float' (vector of 2 'float' values)}}
}

// builtins are variadic functions and so are subject to DefaultVariadicArgumentPromotion
half builtin_isinf_half_scalar (half p0) {
return __builtin_hlsl_elementwise_isinf (p0);
// expected-error@-1 {{passing 'double' to parameter of incompatible type 'float'}}
}

float builtin_isinf_float_scalar ( float p0) {
return __builtin_hlsl_elementwise_isinf (p0);
// expected-error@-1 {{passing 'double' to parameter of incompatible type 'float'}}
}
17 changes: 15 additions & 2 deletions clang/test/SemaHLSL/BuiltIns/lerp-errors.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,18 @@ float builtin_lerp_int_to_float_promotion(float p0, int p1) {

float4 test_lerp_int4(int4 p0, int4 p1, int4 p2) {
return __builtin_hlsl_lerp(p0, p1, p2);
// expected-error@-1 {{1st argument must be a floating point type (was 'int4' (aka 'vector<int, 4>'))}}
}
// expected-error@-1 {{1st argument must be a floating point type (was 'int4' (aka 'vector<int, 4>'))}}
}

// note: DefaultVariadicArgumentPromotion --> DefaultArgumentPromotion has already promoted to double
// we don't know anymore that the input was half when __builtin_hlsl_lerp is called so we default to float
// for expected type
half builtin_lerp_half_scalar (half p0) {
return __builtin_hlsl_lerp ( p0, p0, p0 );
// expected-error@-1 {{passing 'double' to parameter of incompatible type 'float'}}
}

float builtin_lerp_float_scalar ( float p0) {
return __builtin_hlsl_lerp ( p0, p0, p0 );
// expected-error@-1 {{passing 'double' to parameter of incompatible type 'float'}}
}
11 changes: 11 additions & 0 deletions clang/test/SemaHLSL/BuiltIns/rsqrt-errors.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,14 @@ float2 builtin_rsqrt_int2_to_float2_promotion(int2 p1) {
return __builtin_hlsl_elementwise_rsqrt(p1);
// expected-error@-1 {{passing 'int2' (aka 'vector<int, 2>') to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(float)))) float' (vector of 2 'float' values)}}
}

// builtins are variadic functions and so are subject to DefaultVariadicArgumentPromotion
half builtin_rsqrt_half_scalar (half p0) {
return __builtin_hlsl_elementwise_rsqrt (p0);
// expected-error@-1 {{passing 'double' to parameter of incompatible type 'float'}}
}

float builtin_rsqrt_float_scalar ( float p0) {
return __builtin_hlsl_elementwise_rsqrt (p0);
// expected-error@-1 {{passing 'double' to parameter of incompatible type 'float'}}
}
1 change: 1 addition & 0 deletions clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,7 @@ Expected<StringRef> linkDevice(ArrayRef<StringRef> InputFiles,
case Triple::aarch64_be:
case Triple::ppc64:
case Triple::ppc64le:
case Triple::systemz:
return generic::clang(InputFiles, Args);
default:
return createStringError(inconvertibleErrorCode(),
Expand Down
13 changes: 13 additions & 0 deletions clang/unittests/Format/TokenAnnotatorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1776,9 +1776,22 @@ TEST_F(TokenAnnotatorTest, UnderstandsFunctionDeclarationNames) {
auto Style = getLLVMStyle();
Style.TypeNames.push_back("MyType");
Tokens = annotate("int iso_time(MyType);", Style);
ASSERT_TRUE(IsCpp);
ASSERT_EQ(Tokens.size(), 7u) << Tokens;
EXPECT_TOKEN(Tokens[1], tok::identifier, TT_FunctionDeclarationName);
EXPECT_TOKEN(Tokens[3], tok::identifier, TT_TypeName);

Style.Language = FormatStyle::LK_CSharp;
Tokens = annotate("int iso_time(time_t);", Style);
ASSERT_FALSE(IsCpp);
ASSERT_EQ(Tokens.size(), 7u) << Tokens;
EXPECT_TOKEN(Tokens[1], tok::identifier, TT_StartOfName);

Style.Language = FormatStyle::LK_ObjC;
Tokens = annotate("int iso_time(time_t);", Style);
ASSERT_TRUE(IsCpp);
ASSERT_EQ(Tokens.size(), 7u) << Tokens;
EXPECT_TOKEN(Tokens[1], tok::identifier, TT_FunctionDeclarationName);
}

TEST_F(TokenAnnotatorTest, UnderstandsCtorAndDtorDeclNames) {
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/msan/msan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ void __msan_init() {
__msan_clear_on_return();
if (__msan_get_track_origins())
VPrintf(1, "msan_track_origins\n");
if (!InitShadow(__msan_get_track_origins())) {
if (!InitShadowWithReExec(__msan_get_track_origins())) {
Printf("FATAL: MemorySanitizer can not mmap the shadow memory.\n");
Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");
Printf("FATAL: Disabling ASLR is known to cause this error.\n");
Expand Down
35 changes: 24 additions & 11 deletions compiler-rt/lib/msan/msan.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,18 @@ struct MappingDesc {
uptr start;
uptr end;
enum Type {
INVALID, APP, SHADOW, ORIGIN
INVALID = 1,
ALLOCATOR = 2,
APP = 4,
SHADOW = 8,
ORIGIN = 16,
} type;
const char *name;
};


// Note: MappingDesc::ALLOCATOR entries are only used to check for memory
// layout compatibility. The actual allocation settings are in
// msan_allocator.cpp, which need to be kept in sync.
#if SANITIZER_LINUX && defined(__mips64)

// MIPS64 maps:
Expand Down Expand Up @@ -84,7 +90,8 @@ const MappingDesc kMemoryLayout[] = {
{0X0B00000000000, 0X0C00000000000, MappingDesc::SHADOW, "shadow-10-13"},
{0X0C00000000000, 0X0D00000000000, MappingDesc::INVALID, "invalid"},
{0X0D00000000000, 0X0E00000000000, MappingDesc::ORIGIN, "origin-10-13"},
{0X0E00000000000, 0X1000000000000, MappingDesc::APP, "app-15"},
{0x0E00000000000, 0x0E40000000000, MappingDesc::ALLOCATOR, "allocator"},
{0X0E40000000000, 0X1000000000000, MappingDesc::APP, "app-15"},
};
# define MEM_TO_SHADOW(mem) ((uptr)mem ^ 0xB00000000000ULL)
# define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x200000000000ULL)
Expand All @@ -106,7 +113,8 @@ const MappingDesc kMemoryLayout[] = {
{0x510000000000ULL, 0x600000000000ULL, MappingDesc::APP, "app-2"},
{0x600000000000ULL, 0x610000000000ULL, MappingDesc::ORIGIN, "origin-1"},
{0x610000000000ULL, 0x700000000000ULL, MappingDesc::INVALID, "invalid"},
{0x700000000000ULL, 0x800000000000ULL, MappingDesc::APP, "app-3"}};
{0x700000000000ULL, 0x740000000000ULL, MappingDesc::ALLOCATOR, "allocator"},
{0x740000000000ULL, 0x800000000000ULL, MappingDesc::APP, "app-3"}};
# define MEM_TO_SHADOW(mem) (((uptr)(mem)) ^ 0x500000000000ULL)
# define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x100000000000ULL)

Expand All @@ -118,7 +126,8 @@ const MappingDesc kMemoryLayout[] = {
{0x180200000000ULL, 0x1C0000000000ULL, MappingDesc::INVALID, "invalid"},
{0x1C0000000000ULL, 0x2C0200000000ULL, MappingDesc::ORIGIN, "origin"},
{0x2C0200000000ULL, 0x300000000000ULL, MappingDesc::INVALID, "invalid"},
{0x300000000000ULL, 0x800000000000ULL, MappingDesc::APP, "high memory"}};
{0x300000000000ULL, 0x320000000000ULL, MappingDesc::ALLOCATOR, "allocator"},
{0x320000000000ULL, 0x800000000000ULL, MappingDesc::APP, "high memory"}};

// Various kernels use different low end ranges but we can combine them into one
// big range. They also use different high end ranges but we can map them all to
Expand All @@ -141,7 +150,8 @@ const MappingDesc kMemoryLayout[] = {
{0x180000000000ULL, 0x1C0000000000ULL, MappingDesc::INVALID, "invalid"},
{0x1C0000000000ULL, 0x2C0000000000ULL, MappingDesc::ORIGIN, "origin"},
{0x2C0000000000ULL, 0x440000000000ULL, MappingDesc::INVALID, "invalid"},
{0x440000000000ULL, 0x500000000000ULL, MappingDesc::APP, "high memory"}};
{0x440000000000ULL, 0x460000000000ULL, MappingDesc::ALLOCATOR, "allocator"},
{0x460000000000ULL, 0x500000000000ULL, MappingDesc::APP, "high memory"}};

#define MEM_TO_SHADOW(mem) \
((((uptr)(mem)) & ~0xC00000000000ULL) + 0x080000000000ULL)
Expand Down Expand Up @@ -208,7 +218,8 @@ const MappingDesc kMemoryLayout[] = {
{0x510000000000ULL, 0x600000000000ULL, MappingDesc::APP, "app-2"},
{0x600000000000ULL, 0x610000000000ULL, MappingDesc::ORIGIN, "origin-1"},
{0x610000000000ULL, 0x700000000000ULL, MappingDesc::INVALID, "invalid"},
{0x700000000000ULL, 0x800000000000ULL, MappingDesc::APP, "app-3"}};
{0x700000000000ULL, 0x740000000000ULL, MappingDesc::ALLOCATOR, "allocator"},
{0x740000000000ULL, 0x800000000000ULL, MappingDesc::APP, "app-3"}};
#define MEM_TO_SHADOW(mem) (((uptr)(mem)) ^ 0x500000000000ULL)
#define SHADOW_TO_ORIGIN(mem) (((uptr)(mem)) + 0x100000000000ULL)

Expand All @@ -223,20 +234,22 @@ const uptr kMemoryLayoutSize = sizeof(kMemoryLayout) / sizeof(kMemoryLayout[0]);
#ifndef __clang__
__attribute__((optimize("unroll-loops")))
#endif
inline bool addr_is_type(uptr addr, MappingDesc::Type mapping_type) {
inline bool
addr_is_type(uptr addr, int mapping_types) {
// It is critical for performance that this loop is unrolled (because then it is
// simplified into just a few constant comparisons).
#ifdef __clang__
#pragma unroll
#endif
for (unsigned i = 0; i < kMemoryLayoutSize; ++i)
if (kMemoryLayout[i].type == mapping_type &&
if ((kMemoryLayout[i].type & mapping_types) &&
addr >= kMemoryLayout[i].start && addr < kMemoryLayout[i].end)
return true;
return false;
}

#define MEM_IS_APP(mem) addr_is_type((uptr)(mem), MappingDesc::APP)
#define MEM_IS_APP(mem) \
(addr_is_type((uptr)(mem), MappingDesc::APP | MappingDesc::ALLOCATOR))
#define MEM_IS_SHADOW(mem) addr_is_type((uptr)(mem), MappingDesc::SHADOW)
#define MEM_IS_ORIGIN(mem) addr_is_type((uptr)(mem), MappingDesc::ORIGIN)

Expand All @@ -250,7 +263,7 @@ extern bool msan_init_is_running;
extern int msan_report_count;

bool ProtectRange(uptr beg, uptr end);
bool InitShadow(bool init_origins);
bool InitShadowWithReExec(bool init_origins);
char *GetProcSelfMaps();
void InitializeInterceptors();

Expand Down
3 changes: 3 additions & 0 deletions compiler-rt/lib/msan/msan_allocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ struct MsanMapUnmapCallback {
}
};

// Note: to ensure that the allocator is compatible with the application memory
// layout (especially with high-entropy ASLR), kSpaceBeg and kSpaceSize must be
// duplicated as MappingDesc::ALLOCATOR in msan.h.
#if defined(__mips64)
static const uptr kMaxAllowedMallocSize = 2UL << 30;

Expand Down
Loading