39 changes: 18 additions & 21 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class AnnotatingParser {
const AdditionalKeywords &Keywords,
SmallVector<ScopeType> &Scopes)
: Style(Style), Line(Line), CurrentToken(Line.First), AutoFound(false),
Keywords(Keywords), Scopes(Scopes) {
IsCpp(Style.isCpp()), Keywords(Keywords), Scopes(Scopes) {
Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false));
resetTokenMetadata();
}
Expand Down Expand Up @@ -676,26 +676,25 @@ class AnnotatingParser {
// In C++, this can happen either in array of templates (foo<int>[10])
// or when array is a nested template type (unique_ptr<type1<type2>[]>).
bool CppArrayTemplates =
Style.isCpp() && Parent && Parent->is(TT_TemplateCloser) &&
IsCpp && Parent && Parent->is(TT_TemplateCloser) &&
(Contexts.back().CanBeExpression || Contexts.back().IsExpression ||
Contexts.back().ContextType == Context::TemplateArgument);

const bool IsInnerSquare = Contexts.back().InCpp11AttributeSpecifier;
const bool IsCpp11AttributeSpecifier =
isCppAttribute(Style.isCpp(), *Left) || IsInnerSquare;
isCppAttribute(IsCpp, *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(Style);
bool IsCppStructuredBinding = Left->isCppStructuredBinding(IsCpp);
bool StartsObjCMethodExpr =
!IsCppStructuredBinding && !InsideInlineASM && !CppArrayTemplates &&
Style.isCpp() && !IsCpp11AttributeSpecifier &&
!IsCSharpAttributeSpecifier && Contexts.back().CanBeExpression &&
Left->isNot(TT_LambdaLSquare) &&
IsCpp && !IsCpp11AttributeSpecifier && !IsCSharpAttributeSpecifier &&
Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) &&
!CurrentToken->isOneOf(tok::l_brace, tok::r_square) &&
(!Parent ||
Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren,
Expand Down Expand Up @@ -723,7 +722,7 @@ class AnnotatingParser {
Contexts.back().ContextKind == tok::l_brace &&
Parent->isOneOf(tok::l_brace, tok::comma)) {
Left->setType(TT_JsComputedPropertyName);
} else if (Style.isCpp() && Contexts.back().ContextKind == tok::l_brace &&
} else if (IsCpp && Contexts.back().ContextKind == tok::l_brace &&
Parent && Parent->isOneOf(tok::l_brace, tok::comma)) {
Left->setType(TT_DesignatedInitializerLSquare);
} else if (IsCSharpAttributeSpecifier) {
Expand Down Expand Up @@ -1161,7 +1160,7 @@ class AnnotatingParser {
if (Previous->is(TT_JsTypeOptionalQuestion))
Previous = Previous->getPreviousNonComment();
if ((CurrentToken->is(tok::colon) && !Style.isTableGen() &&
(!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) ||
(!Contexts.back().ColonIsDictLiteral || !IsCpp)) ||
Style.isProto()) {
OpeningBrace.setType(TT_DictLiteral);
if (Previous->Tok.getIdentifierInfo() ||
Expand Down Expand Up @@ -1230,7 +1229,7 @@ class AnnotatingParser {
}

bool consumeToken() {
if (Style.isCpp()) {
if (IsCpp) {
const auto *Prev = CurrentToken->getPreviousNonComment();
if (Prev && Prev->is(tok::r_square) && Prev->is(TT_AttributeSquare) &&
CurrentToken->isOneOf(tok::kw_if, tok::kw_switch, tok::kw_case,
Expand Down Expand Up @@ -1424,7 +1423,7 @@ class AnnotatingParser {
if (CurrentToken && CurrentToken->is(Keywords.kw_await))
next();
}
if (Style.isCpp() && CurrentToken && CurrentToken->is(tok::kw_co_await))
if (IsCpp && CurrentToken && CurrentToken->is(tok::kw_co_await))
next();
Contexts.back().ColonIsForRangeExpr = true;
if (!CurrentToken || CurrentToken->isNot(tok::l_paren))
Expand Down Expand Up @@ -2590,7 +2589,7 @@ class AnnotatingParser {
/// Determine whether '(' is starting a C++ cast.
bool lParenStartsCppCast(const FormatToken &Tok) {
// C-style casts are only used in C++.
if (!Style.isCpp())
if (!IsCpp)
return false;

FormatToken *LeftOfParens = Tok.getPreviousNonComment();
Expand All @@ -2611,10 +2610,8 @@ class AnnotatingParser {
/// Determine whether ')' is ending a cast.
bool rParenEndsCast(const FormatToken &Tok) {
// C-style casts are only used in C++, C# and Java.
if (!Style.isCSharp() && !Style.isCpp() &&
Style.Language != FormatStyle::LK_Java) {
if (!Style.isCSharp() && !IsCpp && Style.Language != FormatStyle::LK_Java)
return false;
}

// Empty parens aren't casts and there are no casts at the end of the line.
if (Tok.Previous == Tok.MatchingParen || !Tok.Next || !Tok.MatchingParen)
Expand Down Expand Up @@ -2691,7 +2688,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(Style.isCpp(), *Tok.Next)) {
isCppAttribute(IsCpp, *Tok.Next)) {
return false;
}

Expand Down Expand Up @@ -3012,6 +3009,7 @@ class AnnotatingParser {
AnnotatedLine &Line;
FormatToken *CurrentToken;
bool AutoFound;
bool IsCpp;
const AdditionalKeywords &Keywords;

SmallVector<ScopeType> &Scopes;
Expand Down Expand Up @@ -3559,7 +3557,7 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) {
ExpressionParser ExprParser(Style, Keywords, Line);
ExprParser.parse();

if (Style.isCpp()) {
if (IsCpp) {
auto *Tok = getFunctionName(Line);
if (Tok && ((!Scopes.empty() && Scopes.back() == ST_Class) ||
Line.endsWith(TT_FunctionLBrace) || isCtorOrDtorName(Tok))) {
Expand Down Expand Up @@ -3766,7 +3764,6 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
if (AlignArrayOfStructures)
calculateArrayInitializerColumnList(Line);

const bool IsCpp = Style.isCpp();
bool SeenName = false;
bool LineIsFunctionDeclaration = false;
FormatToken *ClosingParen = nullptr;
Expand All @@ -3779,7 +3776,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
AfterLastAttribute = Tok;
if (const bool IsCtorOrDtor = Tok->is(TT_CtorDtorDeclName);
IsCtorOrDtor ||
isFunctionDeclarationName(Style.isCpp(), *Tok, Line, ClosingParen)) {
isFunctionDeclarationName(IsCpp, *Tok, Line, ClosingParen)) {
if (!IsCtorOrDtor)
Tok->setFinalizedType(TT_FunctionDeclarationName);
LineIsFunctionDeclaration = true;
Expand Down Expand Up @@ -4717,7 +4714,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
if (Left.is(tok::star) && Right.is(tok::comment))
return true;

if (Style.isCpp()) {
if (IsCpp) {
if (Left.is(TT_OverloadedOperator) &&
Right.isOneOf(TT_TemplateOpener, TT_TemplateCloser)) {
return true;
Expand Down Expand Up @@ -5425,7 +5422,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
if (!Keywords.isVerilogBegin(Right) && Keywords.isVerilogEndOfLabel(Left))
return true;
} else if (Style.BreakAdjacentStringLiterals &&
(Style.isCpp() || Style.isProto() ||
(IsCpp || Style.isProto() ||
Style.Language == FormatStyle::LK_TableGen)) {
if (Left.isStringLiteral() && Right.isStringLiteral())
return true;
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Format/TokenAnnotator.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ class AnnotatedLine {
class TokenAnnotator {
public:
TokenAnnotator(const FormatStyle &Style, const AdditionalKeywords &Keywords)
: Style(Style), Keywords(Keywords) {}
: Style(Style), IsCpp(Style.isCpp()), Keywords(Keywords) {}

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

const FormatStyle &Style;

bool IsCpp;

const AdditionalKeywords &Keywords;

SmallVector<ScopeType> Scopes;
Expand Down
43 changes: 21 additions & 22 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,9 @@ UnwrappedLineParser::UnwrappedLineParser(
llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator,
IdentifierTable &IdentTable)
: Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
CurrentLines(&Lines), Style(Style), Keywords(Keywords),
CommentPragmasRegex(Style.CommentPragmas), Tokens(nullptr),
Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1),
CurrentLines(&Lines), Style(Style), IsCpp(Style.isCpp()),
Keywords(Keywords), CommentPragmasRegex(Style.CommentPragmas),
Tokens(nullptr), Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1),
IncludeGuard(Style.IndentPPDirectives == FormatStyle::PPDIS_None
? IG_Rejected
: IG_Inited),
Expand Down Expand Up @@ -572,8 +572,8 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
(Style.isJavaScript() &&
NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in,
Keywords.kw_as));
ProbablyBracedList = ProbablyBracedList ||
(Style.isCpp() && NextTok->is(tok::l_paren));
ProbablyBracedList =
ProbablyBracedList || (IsCpp && NextTok->is(tok::l_paren));

// If there is a comma, semicolon or right paren after the closing
// brace, we assume this is a braced initializer list.
Expand Down Expand Up @@ -1428,7 +1428,7 @@ void UnwrappedLineParser::parseStructuralElement(
return;
}

if (Style.isCpp()) {
if (IsCpp) {
while (FormatTok->is(tok::l_square) && handleCppAttributes()) {
}
} else if (Style.isVerilog()) {
Expand Down Expand Up @@ -1602,7 +1602,7 @@ void UnwrappedLineParser::parseStructuralElement(
parseJavaScriptEs6ImportExport();
return;
}
if (Style.isCpp()) {
if (IsCpp) {
nextToken();
if (FormatTok->is(tok::kw_namespace)) {
parseNamespace();
Expand Down Expand Up @@ -1646,24 +1646,23 @@ void UnwrappedLineParser::parseStructuralElement(
addUnwrappedLine();
return;
}
if (Style.isCpp() && parseModuleImport())
if (IsCpp && parseModuleImport())
return;
}
if (Style.isCpp() &&
FormatTok->isOneOf(Keywords.kw_signals, Keywords.kw_qsignals,
Keywords.kw_slots, Keywords.kw_qslots)) {
if (IsCpp && FormatTok->isOneOf(Keywords.kw_signals, Keywords.kw_qsignals,
Keywords.kw_slots, Keywords.kw_qslots)) {
nextToken();
if (FormatTok->is(tok::colon)) {
nextToken();
addUnwrappedLine();
return;
}
}
if (Style.isCpp() && FormatTok->is(TT_StatementMacro)) {
if (IsCpp && FormatTok->is(TT_StatementMacro)) {
parseStatementMacro();
return;
}
if (Style.isCpp() && FormatTok->is(TT_NamespaceMacro)) {
if (IsCpp && FormatTok->is(TT_NamespaceMacro)) {
parseNamespace();
return;
}
Expand Down Expand Up @@ -1759,7 +1758,7 @@ void UnwrappedLineParser::parseStructuralElement(
}
break;
case tok::kw_requires: {
if (Style.isCpp()) {
if (IsCpp) {
bool ParsedClause = parseRequires();
if (ParsedClause)
return;
Expand All @@ -1780,7 +1779,7 @@ void UnwrappedLineParser::parseStructuralElement(
if (!parseEnum())
break;
// This only applies to C++ and Verilog.
if (!Style.isCpp() && !Style.isVerilog()) {
if (!IsCpp && !Style.isVerilog()) {
addUnwrappedLine();
return;
}
Expand Down Expand Up @@ -1848,7 +1847,7 @@ void UnwrappedLineParser::parseStructuralElement(
parseParens();
// Break the unwrapped line if a K&R C function definition has a parameter
// declaration.
if (OpeningBrace || !Style.isCpp() || !Previous || eof())
if (OpeningBrace || !IsCpp || !Previous || eof())
break;
if (isC78ParameterDecl(FormatTok,
Tokens->peekNextToken(/*SkipComment=*/true),
Expand Down Expand Up @@ -1977,13 +1976,13 @@ void UnwrappedLineParser::parseStructuralElement(
}
}

if (!Style.isCpp() && FormatTok->is(Keywords.kw_interface)) {
if (!IsCpp && FormatTok->is(Keywords.kw_interface)) {
if (parseStructLike())
return;
break;
}

if (Style.isCpp() && FormatTok->is(TT_StatementMacro)) {
if (IsCpp && FormatTok->is(TT_StatementMacro)) {
parseStatementMacro();
return;
}
Expand Down Expand Up @@ -2211,7 +2210,7 @@ bool UnwrappedLineParser::tryToParsePropertyAccessor() {

bool UnwrappedLineParser::tryToParseLambda() {
assert(FormatTok->is(tok::l_square));
if (!Style.isCpp()) {
if (!IsCpp) {
nextToken();
return false;
}
Expand Down Expand Up @@ -2340,7 +2339,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(Style)) {
LeftSquare->isCppStructuredBinding(IsCpp)) {
return false;
}
if (FormatTok->is(tok::l_square) || tok::isLiteral(FormatTok->Tok.getKind()))
Expand Down Expand Up @@ -3153,7 +3152,7 @@ void UnwrappedLineParser::parseForOrWhileLoop(bool HasParens) {
// JS' for await ( ...
if (Style.isJavaScript() && FormatTok->is(Keywords.kw_await))
nextToken();
if (Style.isCpp() && FormatTok->is(tok::kw_co_await))
if (IsCpp && FormatTok->is(tok::kw_co_await))
nextToken();
if (HasParens && FormatTok->is(tok::l_paren)) {
// The type is only set for Verilog basically because we were afraid to
Expand Down Expand Up @@ -3737,7 +3736,7 @@ bool UnwrappedLineParser::parseEnum() {
nextToken();
// If there are two identifiers in a row, this is likely an elaborate
// return type. In Java, this can be "implements", etc.
if (Style.isCpp() && FormatTok->is(tok::identifier))
if (IsCpp && FormatTok->is(tok::identifier))
return false;
}
}
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/UnwrappedLineParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ class UnwrappedLineParser {
llvm::BitVector DeclarationScopeStack;

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

llvm::Regex CommentPragmasRegex;
Expand Down
55 changes: 31 additions & 24 deletions clang/lib/Frontend/CompilerInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1061,30 +1061,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
}
}

if (getDiagnosticOpts().ShowCarets) {
// We can have multiple diagnostics sharing one diagnostic client.
// Get the total number of warnings/errors from the client.
unsigned NumWarnings = getDiagnostics().getClient()->getNumWarnings();
unsigned NumErrors = getDiagnostics().getClient()->getNumErrors();

if (NumWarnings)
OS << NumWarnings << " warning" << (NumWarnings == 1 ? "" : "s");
if (NumWarnings && NumErrors)
OS << " and ";
if (NumErrors)
OS << NumErrors << " error" << (NumErrors == 1 ? "" : "s");
if (NumWarnings || NumErrors) {
OS << " generated";
if (getLangOpts().CUDA) {
if (!getLangOpts().CUDAIsDevice) {
OS << " when compiling for host";
} else {
OS << " when compiling for " << getTargetOpts().CPU;
}
}
OS << ".\n";
}
}
printDiagnosticStats();

if (getFrontendOpts().ShowStats) {
if (hasFileManager()) {
Expand Down Expand Up @@ -1112,6 +1089,36 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
return !getDiagnostics().getClient()->getNumErrors();
}

void CompilerInstance::printDiagnosticStats() {
if (!getDiagnosticOpts().ShowCarets)
return;

raw_ostream &OS = getVerboseOutputStream();

// We can have multiple diagnostics sharing one diagnostic client.
// Get the total number of warnings/errors from the client.
unsigned NumWarnings = getDiagnostics().getClient()->getNumWarnings();
unsigned NumErrors = getDiagnostics().getClient()->getNumErrors();

if (NumWarnings)
OS << NumWarnings << " warning" << (NumWarnings == 1 ? "" : "s");
if (NumWarnings && NumErrors)
OS << " and ";
if (NumErrors)
OS << NumErrors << " error" << (NumErrors == 1 ? "" : "s");
if (NumWarnings || NumErrors) {
OS << " generated";
if (getLangOpts().CUDA) {
if (!getLangOpts().CUDAIsDevice) {
OS << " when compiling for host";
} else {
OS << " when compiling for " << getTargetOpts().CPU;
}
}
OS << ".\n";
}
}

void CompilerInstance::LoadRequestedPlugins() {
// Load any requested plugins.
for (const std::string &Path : getFrontendOpts().Plugins) {
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,17 @@ CompilerInvocationBase::shallow_copy_assign(const CompilerInvocationBase &X) {
return *this;
}

CompilerInvocation::CompilerInvocation(const CowCompilerInvocation &X)
: CompilerInvocationBase(EmptyConstructor{}) {
CompilerInvocationBase::deep_copy_assign(X);
}

CompilerInvocation &
CompilerInvocation::operator=(const CowCompilerInvocation &X) {
CompilerInvocationBase::deep_copy_assign(X);
return *this;
}

namespace {
template <typename T>
T &ensureOwned(std::shared_ptr<T> &Storage) {
Expand Down
34 changes: 34 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,40 @@ uint64_t3 reversebits(uint64_t3);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse)
uint64_t4 reversebits(uint64_t4);

//===----------------------------------------------------------------------===//
// round builtins
//===----------------------------------------------------------------------===//

/// \fn T round(T x)
/// \brief Rounds the specified value \a x to the nearest integer.
/// \param x The specified input value.
///
/// The return value is the \a x parameter, rounded to the nearest integer
/// within a floating-point type. Halfway cases are
/// rounded to the nearest even value.

_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round)
half round(half);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round)
half2 round(half2);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round)
half3 round(half3);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round)
half4 round(half4);

_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round)
float round(float);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round)
float2 round(float2);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round)
float3 round(float3);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round)
float4 round(float4);

//===----------------------------------------------------------------------===//
// sin builtins
//===----------------------------------------------------------------------===//
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Index/IndexSymbol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -552,8 +552,7 @@ StringRef index::getSymbolSubKindString(SymbolSubKind K) {
case SymbolSubKind::AccessorSetter: return "acc-set";
case SymbolSubKind::UsingTypename: return "using-typename";
case SymbolSubKind::UsingValue: return "using-value";
case SymbolSubKind::UsingEnum:
return "using-enum";
case SymbolSubKind::UsingEnum: return "using-enum";
}
llvm_unreachable("invalid symbol subkind");
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Index/IndexingAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ index::createIndexingAction(std::shared_ptr<IndexDataConsumer> DataConsumer,
}

static bool topLevelDeclVisitor(void *context, const Decl *D) {
IndexingContext &IndexCtx = *static_cast<IndexingContext*>(context);
IndexingContext &IndexCtx = *static_cast<IndexingContext *>(context);
return IndexCtx.indexTopLevelDecl(D);
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/InstallAPI/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ add_clang_library(clangInstallAPI
LINK_LIBS
clangAST
clangBasic
clangLex
)
71 changes: 70 additions & 1 deletion clang/lib/InstallAPI/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,73 @@ using namespace llvm::MachO;

namespace clang::installapi {

GlobalRecord *FrontendRecordsSlice::addGlobal(
StringRef Name, RecordLinkage Linkage, GlobalRecord::Kind GV,
const clang::AvailabilityInfo Avail, const Decl *D, const HeaderType Access,
SymbolFlags Flags) {

auto *GR = llvm::MachO::RecordsSlice::addGlobal(Name, Linkage, GV, Flags);
FrontendRecords.insert({GR, FrontendAttrs{Avail, D, Access}});
return GR;
}

ObjCInterfaceRecord *FrontendRecordsSlice::addObjCInterface(
StringRef Name, RecordLinkage Linkage, const clang::AvailabilityInfo Avail,
const Decl *D, HeaderType Access, bool IsEHType) {
ObjCIFSymbolKind SymType =
ObjCIFSymbolKind::Class | ObjCIFSymbolKind::MetaClass;
if (IsEHType)
SymType |= ObjCIFSymbolKind::EHType;
auto *ObjCR =
llvm::MachO::RecordsSlice::addObjCInterface(Name, Linkage, SymType);
FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}});
return ObjCR;
}

std::optional<HeaderType>
InstallAPIContext::findAndRecordFile(const FileEntry *FE,
const Preprocessor &PP) {
if (!FE)
return std::nullopt;

// Check if header has been looked up already and whether it is something
// installapi should use.
auto It = KnownFiles.find(FE);
if (It != KnownFiles.end()) {
if (It->second != HeaderType::Unknown)
return It->second;
else
return std::nullopt;
}

// If file was not found, search by how the header was
// included. This is primarily to resolve headers found
// in a different location than what passed directly as input.
StringRef IncludeName = PP.getHeaderSearchInfo().getIncludeNameForHeader(FE);
auto BackupIt = KnownIncludes.find(IncludeName.str());
if (BackupIt != KnownIncludes.end()) {
KnownFiles[FE] = BackupIt->second;
return BackupIt->second;
}

// Record that the file was found to avoid future string searches for the
// same file.
KnownFiles.insert({FE, HeaderType::Unknown});
return std::nullopt;
}

void InstallAPIContext::addKnownHeader(const HeaderFile &H) {
auto FE = FM->getFile(H.getPath());
if (!FE)
return; // File does not exist.
KnownFiles[*FE] = H.getType();

if (!H.useIncludeName())
return;

KnownIncludes[H.getIncludeName()] = H.getType();
}

static StringRef getFileExtension(clang::Language Lang) {
switch (Lang) {
default:
Expand All @@ -31,7 +98,7 @@ static StringRef getFileExtension(clang::Language Lang) {
}
}

std::unique_ptr<MemoryBuffer> createInputBuffer(const InstallAPIContext &Ctx) {
std::unique_ptr<MemoryBuffer> createInputBuffer(InstallAPIContext &Ctx) {
assert(Ctx.Type != HeaderType::Unknown &&
"unexpected access level for parsing");
SmallString<4096> Contents;
Expand All @@ -47,6 +114,8 @@ std::unique_ptr<MemoryBuffer> createInputBuffer(const InstallAPIContext &Ctx) {
OS << "<" << H.getIncludeName() << ">";
else
OS << "\"" << H.getPath() << "\"";

Ctx.addKnownHeader(H);
}
if (Contents.empty())
return nullptr;
Expand Down
74 changes: 69 additions & 5 deletions clang/lib/InstallAPI/Visitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
//===----------------------------------------------------------------------===//

#include "clang/InstallAPI/Visitor.h"
#include "clang/AST/Availability.h"
#include "clang/Basic/Linkage.h"
#include "clang/InstallAPI/Frontend.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/DataLayout.h"
Expand Down Expand Up @@ -62,7 +62,66 @@ std::string InstallAPIVisitor::getBackendMangledName(Twine Name) const {
return std::string(FinalName);
}

/// Collect all global variables.
std::optional<HeaderType>
InstallAPIVisitor::getAccessForDecl(const NamedDecl *D) const {
SourceLocation Loc = D->getLocation();
if (Loc.isInvalid())
return std::nullopt;

// If the loc refers to a macro expansion, InstallAPI needs to first get the
// file location of the expansion.
auto FileLoc = SrcMgr.getFileLoc(Loc);
FileID ID = SrcMgr.getFileID(FileLoc);
if (ID.isInvalid())
return std::nullopt;

const FileEntry *FE = SrcMgr.getFileEntryForID(ID);
if (!FE)
return std::nullopt;

auto Header = Ctx.findAndRecordFile(FE, PP);
if (!Header.has_value())
return std::nullopt;

HeaderType Access = Header.value();
assert(Access != HeaderType::Unknown && "unexpected access level for global");
return Access;
}

/// Check if the interface itself or any of its super classes have an
/// exception attribute. InstallAPI needs to export an additional symbol
/// ("OBJC_EHTYPE_$CLASS_NAME") if any of the classes have the exception
/// attribute.
static bool hasObjCExceptionAttribute(const ObjCInterfaceDecl *D) {
for (; D != nullptr; D = D->getSuperClass())
if (D->hasAttr<ObjCExceptionAttr>())
return true;

return false;
}

bool InstallAPIVisitor::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
// Skip forward declaration for classes (@class)
if (!D->isThisDeclarationADefinition())
return true;

// Skip over declarations that access could not be collected for.
auto Access = getAccessForDecl(D);
if (!Access)
return true;

StringRef Name = D->getObjCRuntimeNameAsString();
const RecordLinkage Linkage =
isExported(D) ? RecordLinkage::Exported : RecordLinkage::Internal;
const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
const bool IsEHType =
(!D->getASTContext().getLangOpts().ObjCRuntime.isFragile() &&
hasObjCExceptionAttribute(D));

Ctx.Slice->addObjCInterface(Name, Linkage, Avail, D, *Access, IsEHType);
return true;
}

bool InstallAPIVisitor::VisitVarDecl(const VarDecl *D) {
// Skip function parameters.
if (isa<ParmVarDecl>(D))
Expand All @@ -81,13 +140,18 @@ bool InstallAPIVisitor::VisitVarDecl(const VarDecl *D) {
D->getTemplateSpecializationKind() == TSK_Undeclared)
return true;

// TODO: Capture SourceLocation & Availability for Decls.
// Skip over declarations that access could not collected for.
auto Access = getAccessForDecl(D);
if (!Access)
return true;

const RecordLinkage Linkage =
isExported(D) ? RecordLinkage::Exported : RecordLinkage::Internal;
const bool WeakDef = D->hasAttr<WeakAttr>();
const bool ThreadLocal = D->getTLSKind() != VarDecl::TLS_None;
Slice.addGlobal(getMangledName(D), Linkage, GlobalRecord::Kind::Variable,
getFlags(WeakDef, ThreadLocal));
const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
Ctx.Slice->addGlobal(getMangledName(D), Linkage, GlobalRecord::Kind::Variable,
Avail, D, *Access, getFlags(WeakDef, ThreadLocal));
return true;
}

Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/Scope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ void Scope::setFlags(Scope *parent, unsigned flags) {
FnParent = parent->FnParent;
BlockParent = parent->BlockParent;
TemplateParamParent = parent->TemplateParamParent;
DeclParent = parent->DeclParent;
MSLastManglingParent = parent->MSLastManglingParent;
MSCurManglingNumber = getMSLastManglingNumber();
if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope |
Expand All @@ -52,6 +53,7 @@ void Scope::setFlags(Scope *parent, unsigned flags) {
PrototypeIndex = 0;
MSLastManglingParent = FnParent = BlockParent = nullptr;
TemplateParamParent = nullptr;
DeclParent = nullptr;
MSLastManglingNumber = 1;
MSCurManglingNumber = 1;
}
Expand All @@ -76,6 +78,7 @@ void Scope::setFlags(Scope *parent, unsigned flags) {
PrototypeDepth++;

if (flags & DeclScope) {
DeclParent = this;
if (flags & FunctionPrototypeScope)
; // Prototype scopes are uninteresting.
else if ((flags & ClassScope) && getParent()->isClassScope())
Expand Down
41 changes: 24 additions & 17 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5218,15 +5218,17 @@ bool CheckVectorElementCallArgs(Sema *S, CallExpr *TheCall) {
// Note: type promotion is intended to be handeled via the intrinsics
// and not the builtin itself.
S->Diag(TheCall->getBeginLoc(),
diag::err_vec_builtin_incompatible_vector_all)
<< TheCall->getDirectCallee()
diag::err_vec_builtin_incompatible_vector)
<< TheCall->getDirectCallee() << /*useAllTerminology*/ true
<< SourceRange(A.get()->getBeginLoc(), B.get()->getEndLoc());
retValue = true;
}
if (VecTyA->getNumElements() != VecTyB->getNumElements()) {
// if we get here a HLSLVectorTruncation is needed.
S->Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector_all)
<< TheCall->getDirectCallee()
// You should only be hitting this case if you are calling the builtin
// directly. HLSL intrinsics should avoid this case via a
// HLSLVectorTruncation.
S->Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector)
<< TheCall->getDirectCallee() << /*useAllTerminology*/ true
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
TheCall->getArg(1)->getEndLoc());
retValue = true;
Expand All @@ -5241,8 +5243,8 @@ bool CheckVectorElementCallArgs(Sema *S, CallExpr *TheCall) {

// Note: if we get here one of the args is a scalar which
// requires a VectorSplat on Arg0 or Arg1
S->Diag(BuiltinLoc, diag::err_vec_builtin_non_vector_all)
<< TheCall->getDirectCallee()
S->Diag(BuiltinLoc, diag::err_vec_builtin_non_vector)
<< TheCall->getDirectCallee() << /*useAllTerminology*/ true
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
TheCall->getArg(1)->getEndLoc());
return true;
Expand Down Expand Up @@ -9472,15 +9474,15 @@ bool Sema::SemaBuiltinVSX(CallExpr *TheCall) {
if ((!Arg1Ty->isVectorType() && !Arg1Ty->isDependentType()) ||
(!Arg2Ty->isVectorType() && !Arg2Ty->isDependentType())) {
return Diag(BuiltinLoc, diag::err_vec_builtin_non_vector)
<< TheCall->getDirectCallee()
<< TheCall->getDirectCallee() << /*isMorethantwoArgs*/ false
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
TheCall->getArg(1)->getEndLoc());
}

// Check the first two arguments are the same type.
if (!Context.hasSameUnqualifiedType(Arg1Ty, Arg2Ty)) {
return Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector)
<< TheCall->getDirectCallee()
<< TheCall->getDirectCallee() << /*isMorethantwoArgs*/ false
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
TheCall->getArg(1)->getEndLoc());
}
Expand Down Expand Up @@ -9516,7 +9518,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
if (!LHSType->isVectorType() || !RHSType->isVectorType())
return ExprError(
Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_non_vector)
<< TheCall->getDirectCallee()
<< TheCall->getDirectCallee() << /*isMorethantwoArgs*/ false
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
TheCall->getArg(1)->getEndLoc()));

Expand All @@ -9532,12 +9534,14 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
return ExprError(Diag(TheCall->getBeginLoc(),
diag::err_vec_builtin_incompatible_vector)
<< TheCall->getDirectCallee()
<< /*isMorethantwoArgs*/ false
<< SourceRange(TheCall->getArg(1)->getBeginLoc(),
TheCall->getArg(1)->getEndLoc()));
} else if (!Context.hasSameUnqualifiedType(LHSType, RHSType)) {
return ExprError(Diag(TheCall->getBeginLoc(),
diag::err_vec_builtin_incompatible_vector)
<< TheCall->getDirectCallee()
<< /*isMorethantwoArgs*/ false
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
TheCall->getArg(1)->getEndLoc()));
} else if (numElements != numResElements) {
Expand Down Expand Up @@ -16588,13 +16592,16 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
}

// Complain if we are converting a lambda expression to a boolean value
if (const auto *MCallExpr = dyn_cast<CXXMemberCallExpr>(E)) {
if (const auto *MRecordDecl = MCallExpr->getRecordDecl();
MRecordDecl && MRecordDecl->isLambda()) {
Diag(E->getExprLoc(), diag::warn_impcast_pointer_to_bool)
<< /*LambdaPointerConversionOperatorType=*/3
<< MRecordDecl->getSourceRange() << Range << IsEqual;
return;
// outside of instantiation.
if (!inTemplateInstantiation()) {
if (const auto *MCallExpr = dyn_cast<CXXMemberCallExpr>(E)) {
if (const auto *MRecordDecl = MCallExpr->getRecordDecl();
MRecordDecl && MRecordDecl->isLambda()) {
Diag(E->getExprLoc(), diag::warn_impcast_pointer_to_bool)
<< /*LambdaPointerConversionOperatorType=*/3
<< MRecordDecl->getSourceRange() << Range << IsEqual;
return;
}
}
}

Expand Down
31 changes: 19 additions & 12 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6353,12 +6353,6 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
} else if (DiagnoseUnexpandedParameterPack(NameInfo, UPPC_DeclarationType))
return nullptr;

// The scope passed in may not be a decl scope. Zip up the scope tree until
// we find one that is.
while ((S->getFlags() & Scope::DeclScope) == 0 ||
(S->getFlags() & Scope::TemplateParamScope) != 0)
S = S->getParent();

DeclContext *DC = CurContext;
if (D.getCXXScopeSpec().isInvalid())
D.setInvalidType();
Expand Down Expand Up @@ -6486,12 +6480,22 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
RemoveUsingDecls(Previous);
}

if (Previous.isSingleResult() &&
Previous.getFoundDecl()->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
if (!D.isInvalidType())
DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
Previous.getFoundDecl());
if (auto *TPD = Previous.getAsSingle<NamedDecl>();
TPD && TPD->isTemplateParameter()) {
// Older versions of clang allowed the names of function/variable templates
// to shadow the names of their template parameters. For the compatibility
// purposes we detect such cases and issue a default-to-error warning that
// can be disabled with -Wno-strict-primary-template-shadow.
if (!D.isInvalidType()) {
bool AllowForCompatibility = false;
if (Scope *DeclParent = S->getDeclParent();
Scope *TemplateParamParent = S->getTemplateParamParent()) {
AllowForCompatibility = DeclParent->Contains(*TemplateParamParent) &&
TemplateParamParent->isDeclScope(TPD);
}
DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), TPD,
AllowForCompatibility);
}

// Just pretend that we didn't see the previous declaration.
Previous.clear();
Expand All @@ -6515,6 +6519,9 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
if (getLangOpts().CPlusPlus)
CheckExtraCXXDefaultArguments(D);

/// Get the innermost enclosing declaration scope.
S = S->getDeclParent();

NamedDecl *New;

bool AddToScope = true;
Expand Down
15 changes: 5 additions & 10 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7294,7 +7294,7 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
bool CanPass = canPassInRegisters(*this, Record, CCK);

// Do not change ArgPassingRestrictions if it has already been set to
// ArgPassingKind::CanNeverPassInRegs.
// RecordArgPassingKind::CanNeverPassInRegs.
if (Record->getArgPassingRestrictions() !=
RecordArgPassingKind::CanNeverPassInRegs)
Record->setArgPassingRestrictions(
Expand Down Expand Up @@ -12203,10 +12203,8 @@ Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc,
assert(NamespcName && "Invalid NamespcName.");
assert(IdentLoc.isValid() && "Invalid NamespceName location.");

// This can only happen along a recovery path.
while (S->isTemplateParamScope())
S = S->getParent();
assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
// Get the innermost enclosing declaration scope.
S = S->getDeclParent();

UsingDirectiveDecl *UDir = nullptr;
NestedNameSpecifier *Qualifier = nullptr;
Expand Down Expand Up @@ -13516,11 +13514,8 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc, UnqualifiedId &Name,
const ParsedAttributesView &AttrList,
TypeResult Type, Decl *DeclFromDeclSpec) {
// Skip up to the relevant declaration scope.
while (S->isTemplateParamScope())
S = S->getParent();
assert((S->getFlags() & Scope::DeclScope) &&
"got alias-declaration outside of declaration scope");
// Get the innermost enclosing declaration scope.
S = S->getDeclParent();

if (Type.isInvalid())
return nullptr;
Expand Down
8 changes: 6 additions & 2 deletions clang/lib/Sema/SemaDeclObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2233,12 +2233,16 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
Diag(IVI->getLocation(), diag::err_inconsistent_ivar_count);
}

static bool shouldWarnUndefinedMethod(const ObjCMethodDecl *M) {
// No point warning no definition of method which is 'unavailable'.
return M->getAvailability() != AR_Unavailable;
}

static void WarnUndefinedMethod(Sema &S, ObjCImplDecl *Impl,
ObjCMethodDecl *method, bool &IncompleteImpl,
unsigned DiagID,
NamedDecl *NeededFor = nullptr) {
// No point warning no definition of method which is 'unavailable'.
if (method->getAvailability() == AR_Unavailable)
if (!shouldWarnUndefinedMethod(method))
return;

// FIXME: For now ignore 'IncompleteImpl'.
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17772,7 +17772,6 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
if (lhq.getAddressSpace() != rhq.getAddressSpace()) {
DiagKind = diag::err_typecheck_incompatible_address_space;
break;

} else if (lhq.getObjCLifetime() != rhq.getObjCLifetime()) {
DiagKind = diag::err_typecheck_incompatible_ownership;
break;
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,12 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,
if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope())
Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw";

// Exceptions that escape a compute construct are ill-formed.
if (getLangOpts().OpenACC && getCurScope() &&
getCurScope()->isInOpenACCComputeConstructScope(Scope::TryScope))
Diag(OpLoc, diag::err_acc_branch_in_out_compute_construct)
<< /*throw*/ 2 << /*out of*/ 0;

if (Ex && !Ex->isTypeDependent()) {
// Initialize the exception result. This implicitly weeds out
// abstract types or types with inaccessible copy constructors.
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, ExprResult LHSVal,
}

if (LangOpts.OpenACC &&
getCurScope()->isInOpenACCComputeConstructBeforeSwitch()) {
getCurScope()->isInOpenACCComputeConstructScope(Scope::SwitchScope)) {
Diag(CaseLoc, diag::err_acc_branch_in_out_compute_construct)
<< /*branch*/ 0 << /*into*/ 1;
return StmtError();
Expand All @@ -554,7 +554,7 @@ Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc,
}

if (LangOpts.OpenACC &&
getCurScope()->isInOpenACCComputeConstructBeforeSwitch()) {
getCurScope()->isInOpenACCComputeConstructScope(Scope::SwitchScope)) {
Diag(DefaultLoc, diag::err_acc_branch_in_out_compute_construct)
<< /*branch*/ 0 << /*into*/ 1;
return StmtError();
Expand Down
36 changes: 17 additions & 19 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -881,20 +881,23 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
return true;
}

/// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining
/// that the template parameter 'PrevDecl' is being shadowed by a new
/// declaration at location Loc. Returns true to indicate that this is
/// an error, and false otherwise.
void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) {
void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl,
bool SupportedForCompatibility) {
assert(PrevDecl->isTemplateParameter() && "Not a template parameter");

// C++ [temp.local]p4:
// A template-parameter shall not be redeclared within its
// scope (including nested scopes).
// C++23 [temp.local]p6:
// The name of a template-parameter shall not be bound to any following.
// declaration whose locus is contained by the scope to which the
// template-parameter belongs.
//
// Make this a warning when MSVC compatibility is requested.
unsigned DiagId = getLangOpts().MSVCCompat ? diag::ext_template_param_shadow
: diag::err_template_param_shadow;
// When MSVC compatibility is enabled, the diagnostic is always a warning
// by default. Otherwise, it an error unless SupportedForCompatibility is
// true, in which case it is a default-to-error warning.
unsigned DiagId =
getLangOpts().MSVCCompat
? diag::ext_template_param_shadow
: (SupportedForCompatibility ? diag::ext_compat_template_param_shadow
: diag::err_template_param_shadow);
const auto *ND = cast<NamedDecl>(PrevDecl);
Diag(Loc, DiagId) << ND->getDeclName();
NoteTemplateParameterLocation(*ND);
Expand Down Expand Up @@ -8502,9 +8505,7 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) {
return false;

// Find the nearest enclosing declaration scope.
while ((S->getFlags() & Scope::DeclScope) == 0 ||
(S->getFlags() & Scope::TemplateParamScope) != 0)
S = S->getParent();
S = S->getDeclParent();

// C++ [temp.pre]p6: [P2096]
// A template, explicit specialization, or partial specialization shall not
Expand Down Expand Up @@ -10619,11 +10620,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
return true;
}

// The scope passed in may not be a decl scope. Zip up the scope tree until
// we find one that is.
while ((S->getFlags() & Scope::DeclScope) == 0 ||
(S->getFlags() & Scope::TemplateParamScope) != 0)
S = S->getParent();
// Get the innermost enclosing declaration scope.
S = S->getDeclParent();

// Determine the type of the declaration.
TypeSourceInfo *T = GetTypeForDeclarator(D);
Expand Down
16 changes: 11 additions & 5 deletions clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,21 +301,27 @@ compareValueToThreshold(ProgramStateRef State, NonLoc Value, NonLoc Threshold,
// calling `evalBinOpNN`:
if (isNegative(SVB, State, Value) && isUnsigned(SVB, Threshold)) {
if (CheckEquality) {
// negative_value == unsigned_value is always false
// negative_value == unsigned_threshold is always false
return {nullptr, State};
}
// negative_value < unsigned_value is always false
// negative_value < unsigned_threshold is always true
return {State, nullptr};
}
if (isUnsigned(SVB, Value) && isNegative(SVB, State, Threshold)) {
// unsigned_value == negative_value and unsigned_value < negative_value are
// both always false
// unsigned_value == negative_threshold and
// unsigned_value < negative_threshold are both always false
return {nullptr, State};
}
// FIXME: these special cases are sufficient for handling real-world
// FIXME: These special cases are sufficient for handling real-world
// comparisons, but in theory there could be contrived situations where
// automatic conversion of a symbolic value (which can be negative and can be
// positive) leads to incorrect results.
// NOTE: We NEED to use the `evalBinOpNN` call in the "common" case, because
// we want to ensure that assumptions coming from this precondition and
// assumptions coming from regular C/C++ operator calls are represented by
// constraints on the same symbolic expression. A solution that would
// evaluate these "mathematical" compariosns through a separate pathway would
// be a step backwards in this sense.

const BinaryOperatorKind OpKind = CheckEquality ? BO_EQ : BO_LT;
auto BelowThreshold =
Expand Down
65 changes: 32 additions & 33 deletions clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,48 +124,47 @@ class CStringChecker : public Checker< eval::Call,
const CallEvent &)>;

CallDescriptionMap<FnCheck> Callbacks = {
{{CDF_MaybeBuiltin, {"memcpy"}, 3},
{{CDM::CLibrary, {"memcpy"}, 3},
std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, CK_Regular)},
{{CDF_MaybeBuiltin, {"wmemcpy"}, 3},
{{CDM::CLibrary, {"wmemcpy"}, 3},
std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, CK_Wide)},
{{CDF_MaybeBuiltin, {"mempcpy"}, 3},
{{CDM::CLibrary, {"mempcpy"}, 3},
std::bind(&CStringChecker::evalMempcpy, _1, _2, _3, CK_Regular)},
{{CDF_None, {"wmempcpy"}, 3},
{{CDM::Unspecified, {"wmempcpy"}, 3},
std::bind(&CStringChecker::evalMempcpy, _1, _2, _3, CK_Wide)},
{{CDF_MaybeBuiltin, {"memcmp"}, 3},
{{CDM::CLibrary, {"memcmp"}, 3},
std::bind(&CStringChecker::evalMemcmp, _1, _2, _3, CK_Regular)},
{{CDF_MaybeBuiltin, {"wmemcmp"}, 3},
{{CDM::CLibrary, {"wmemcmp"}, 3},
std::bind(&CStringChecker::evalMemcmp, _1, _2, _3, CK_Wide)},
{{CDF_MaybeBuiltin, {"memmove"}, 3},
{{CDM::CLibrary, {"memmove"}, 3},
std::bind(&CStringChecker::evalMemmove, _1, _2, _3, CK_Regular)},
{{CDF_MaybeBuiltin, {"wmemmove"}, 3},
{{CDM::CLibrary, {"wmemmove"}, 3},
std::bind(&CStringChecker::evalMemmove, _1, _2, _3, CK_Wide)},
{{CDF_MaybeBuiltin, {"memset"}, 3}, &CStringChecker::evalMemset},
{{CDF_MaybeBuiltin, {"explicit_memset"}, 3}, &CStringChecker::evalMemset},
{{CDF_MaybeBuiltin, {"strcpy"}, 2}, &CStringChecker::evalStrcpy},
{{CDF_MaybeBuiltin, {"strncpy"}, 3}, &CStringChecker::evalStrncpy},
{{CDF_MaybeBuiltin, {"stpcpy"}, 2}, &CStringChecker::evalStpcpy},
{{CDF_MaybeBuiltin, {"strlcpy"}, 3}, &CStringChecker::evalStrlcpy},
{{CDF_MaybeBuiltin, {"strcat"}, 2}, &CStringChecker::evalStrcat},
{{CDF_MaybeBuiltin, {"strncat"}, 3}, &CStringChecker::evalStrncat},
{{CDF_MaybeBuiltin, {"strlcat"}, 3}, &CStringChecker::evalStrlcat},
{{CDF_MaybeBuiltin, {"strlen"}, 1}, &CStringChecker::evalstrLength},
{{CDF_MaybeBuiltin, {"wcslen"}, 1}, &CStringChecker::evalstrLength},
{{CDF_MaybeBuiltin, {"strnlen"}, 2}, &CStringChecker::evalstrnLength},
{{CDF_MaybeBuiltin, {"wcsnlen"}, 2}, &CStringChecker::evalstrnLength},
{{CDF_MaybeBuiltin, {"strcmp"}, 2}, &CStringChecker::evalStrcmp},
{{CDF_MaybeBuiltin, {"strncmp"}, 3}, &CStringChecker::evalStrncmp},
{{CDF_MaybeBuiltin, {"strcasecmp"}, 2}, &CStringChecker::evalStrcasecmp},
{{CDF_MaybeBuiltin, {"strncasecmp"}, 3},
&CStringChecker::evalStrncasecmp},
{{CDF_MaybeBuiltin, {"strsep"}, 2}, &CStringChecker::evalStrsep},
{{CDF_MaybeBuiltin, {"bcopy"}, 3}, &CStringChecker::evalBcopy},
{{CDF_MaybeBuiltin, {"bcmp"}, 3},
{{CDM::CLibrary, {"memset"}, 3}, &CStringChecker::evalMemset},
{{CDM::CLibrary, {"explicit_memset"}, 3}, &CStringChecker::evalMemset},
{{CDM::CLibrary, {"strcpy"}, 2}, &CStringChecker::evalStrcpy},
{{CDM::CLibrary, {"strncpy"}, 3}, &CStringChecker::evalStrncpy},
{{CDM::CLibrary, {"stpcpy"}, 2}, &CStringChecker::evalStpcpy},
{{CDM::CLibrary, {"strlcpy"}, 3}, &CStringChecker::evalStrlcpy},
{{CDM::CLibrary, {"strcat"}, 2}, &CStringChecker::evalStrcat},
{{CDM::CLibrary, {"strncat"}, 3}, &CStringChecker::evalStrncat},
{{CDM::CLibrary, {"strlcat"}, 3}, &CStringChecker::evalStrlcat},
{{CDM::CLibrary, {"strlen"}, 1}, &CStringChecker::evalstrLength},
{{CDM::CLibrary, {"wcslen"}, 1}, &CStringChecker::evalstrLength},
{{CDM::CLibrary, {"strnlen"}, 2}, &CStringChecker::evalstrnLength},
{{CDM::CLibrary, {"wcsnlen"}, 2}, &CStringChecker::evalstrnLength},
{{CDM::CLibrary, {"strcmp"}, 2}, &CStringChecker::evalStrcmp},
{{CDM::CLibrary, {"strncmp"}, 3}, &CStringChecker::evalStrncmp},
{{CDM::CLibrary, {"strcasecmp"}, 2}, &CStringChecker::evalStrcasecmp},
{{CDM::CLibrary, {"strncasecmp"}, 3}, &CStringChecker::evalStrncasecmp},
{{CDM::CLibrary, {"strsep"}, 2}, &CStringChecker::evalStrsep},
{{CDM::CLibrary, {"bcopy"}, 3}, &CStringChecker::evalBcopy},
{{CDM::CLibrary, {"bcmp"}, 3},
std::bind(&CStringChecker::evalMemcmp, _1, _2, _3, CK_Regular)},
{{CDF_MaybeBuiltin, {"bzero"}, 2}, &CStringChecker::evalBzero},
{{CDF_MaybeBuiltin, {"explicit_bzero"}, 2}, &CStringChecker::evalBzero},
{{CDF_MaybeBuiltin, {"sprintf"}, 2}, &CStringChecker::evalSprintf},
{{CDF_MaybeBuiltin, {"snprintf"}, 2}, &CStringChecker::evalSnprintf},
{{CDM::CLibrary, {"bzero"}, 2}, &CStringChecker::evalBzero},
{{CDM::CLibrary, {"explicit_bzero"}, 2}, &CStringChecker::evalBzero},
{{CDM::CLibrary, {"sprintf"}, 2}, &CStringChecker::evalSprintf},
{{CDM::CLibrary, {"snprintf"}, 2}, &CStringChecker::evalSnprintf},
};

// These require a bit of special handling.
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ class CheckerDocumentation : public Checker< check::PreStmt<ReturnStmt>,
/// first one wins.
///
/// eval::Call
bool evalCall(const CallExpr *CE, CheckerContext &C) const { return true; }
bool evalCall(const CallEvent &Call, CheckerContext &C) const { return true; }

/// Handles assumptions on symbolic values.
///
Expand Down
50 changes: 22 additions & 28 deletions clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -718,28 +718,24 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
{{{"isupper"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
{{{"isxdigit"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},

{{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrncat)}},
{{CDM::CLibrary, {BI.getName(Builtin::BIstrncat)}},
TR::Prop({{1, 2}}, {{0, ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrlcpy)}},
{{CDM::CLibrary, {BI.getName(Builtin::BIstrlcpy)}},
TR::Prop({{1, 2}}, {{0}})},
{{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrlcat)}},
{{CDM::CLibrary, {BI.getName(Builtin::BIstrlcat)}},
TR::Prop({{1, 2}}, {{0}})},
{{CDF_MaybeBuiltin, {{"snprintf"}}},
{{CDM::CLibrary, {{"snprintf"}}},
TR::Prop({{1}, 3}, {{0, ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {{"sprintf"}}},
{{CDM::CLibrary, {{"sprintf"}}},
TR::Prop({{1}, 2}, {{0, ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {{"strcpy"}}},
{{CDM::CLibrary, {{"strcpy"}}}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
{{CDM::CLibrary, {{"stpcpy"}}}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
{{CDM::CLibrary, {{"strcat"}}}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
{{CDM::CLibrary, {{"wcsncat"}}},
TR::Prop({{1}}, {{0, ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {{"stpcpy"}}},
TR::Prop({{1}}, {{0, ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {{"strcat"}}},
TR::Prop({{1}}, {{0, ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {{"wcsncat"}}},
TR::Prop({{1}}, {{0, ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {{"strdup"}}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {{"strdupa"}}},
TR::Prop({{0}}, {{ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {{"wcsdup"}}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
{{CDM::CLibrary, {{"strdup"}}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
{{CDM::CLibrary, {{"strdupa"}}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
{{CDM::CLibrary, {{"wcsdup"}}}, TR::Prop({{0}}, {{ReturnValueIndex}})},

// Sinks
{{{"system"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
Expand All @@ -753,31 +749,29 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
{{{"execvp"}}, TR::Sink({{0, 1}}, MsgSanitizeSystemArgs)},
{{{"execvpe"}}, TR::Sink({{0, 1, 2}}, MsgSanitizeSystemArgs)},
{{{"dlopen"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
{{CDF_MaybeBuiltin, {{"malloc"}}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
{{CDF_MaybeBuiltin, {{"calloc"}}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
{{CDF_MaybeBuiltin, {{"alloca"}}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
{{CDF_MaybeBuiltin, {{"memccpy"}}},
TR::Sink({{3}}, MsgTaintedBufferSize)},
{{CDF_MaybeBuiltin, {{"realloc"}}},
TR::Sink({{1}}, MsgTaintedBufferSize)},
{{CDM::CLibrary, {{"malloc"}}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
{{CDM::CLibrary, {{"calloc"}}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
{{CDM::CLibrary, {{"alloca"}}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
{{CDM::CLibrary, {{"memccpy"}}}, TR::Sink({{3}}, MsgTaintedBufferSize)},
{{CDM::CLibrary, {{"realloc"}}}, TR::Sink({{1}}, MsgTaintedBufferSize)},
{{{{"setproctitle"}}}, TR::Sink({{0}, 1}, MsgUncontrolledFormatString)},
{{{{"setproctitle_fast"}}},
TR::Sink({{0}, 1}, MsgUncontrolledFormatString)},

// SinkProps
{{CDF_MaybeBuiltin, BI.getName(Builtin::BImemcpy)},
{{CDM::CLibrary, BI.getName(Builtin::BImemcpy)},
TR::SinkProp({{2}}, {{1, 2}}, {{0, ReturnValueIndex}},
MsgTaintedBufferSize)},
{{CDF_MaybeBuiltin, {BI.getName(Builtin::BImemmove)}},
{{CDM::CLibrary, {BI.getName(Builtin::BImemmove)}},
TR::SinkProp({{2}}, {{1, 2}}, {{0, ReturnValueIndex}},
MsgTaintedBufferSize)},
{{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrncpy)}},
{{CDM::CLibrary, {BI.getName(Builtin::BIstrncpy)}},
TR::SinkProp({{2}}, {{1, 2}}, {{0, ReturnValueIndex}},
MsgTaintedBufferSize)},
{{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrndup)}},
{{CDM::CLibrary, {BI.getName(Builtin::BIstrndup)}},
TR::SinkProp({{1}}, {{0, 1}}, {{ReturnValueIndex}},
MsgTaintedBufferSize)},
{{CDF_MaybeBuiltin, {{"bcopy"}}},
{{CDM::CLibrary, {{"bcopy"}}},
TR::SinkProp({{2}}, {{0, 2}}, {{1}}, MsgTaintedBufferSize)}};

// `getenv` returns taint only in untrusted environments.
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,13 +410,13 @@ class MallocChecker
{{{"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
{{{"calloc"}, 2}, &MallocChecker::checkCalloc},
{{{"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
{{CDF_MaybeBuiltin, {"strndup"}, 2}, &MallocChecker::checkStrdup},
{{CDF_MaybeBuiltin, {"strdup"}, 1}, &MallocChecker::checkStrdup},
{{CDM::CLibrary, {"strndup"}, 2}, &MallocChecker::checkStrdup},
{{CDM::CLibrary, {"strdup"}, 1}, &MallocChecker::checkStrdup},
{{{"_strdup"}, 1}, &MallocChecker::checkStrdup},
{{{"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
{{{"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
{{CDF_MaybeBuiltin, {"wcsdup"}, 1}, &MallocChecker::checkStrdup},
{{CDF_MaybeBuiltin, {"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
{{CDM::CLibrary, {"wcsdup"}, 1}, &MallocChecker::checkStrdup},
{{CDM::CLibrary, {"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
{{{"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
{{{"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
{{{"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
Expand Down
21 changes: 14 additions & 7 deletions clang/lib/StaticAnalyzer/Core/CallDescription.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ static MaybeCount readRequiredParams(MaybeCount RequiredArgs,
return std::nullopt;
}

ento::CallDescription::CallDescription(CallDescriptionFlags Flags,
ento::CallDescription::CallDescription(Mode MatchAs,
ArrayRef<StringRef> QualifiedName,
MaybeCount RequiredArgs /*= None*/,
MaybeCount RequiredParams /*= None*/)
: RequiredArgs(RequiredArgs),
RequiredParams(readRequiredParams(RequiredArgs, RequiredParams)),
Flags(Flags) {
MatchAs(MatchAs) {
assert(!QualifiedName.empty());
this->QualifiedName.reserve(QualifiedName.size());
llvm::transform(QualifiedName, std::back_inserter(this->QualifiedName),
Expand All @@ -52,7 +52,8 @@ ento::CallDescription::CallDescription(CallDescriptionFlags Flags,
ento::CallDescription::CallDescription(ArrayRef<StringRef> QualifiedName,
MaybeCount RequiredArgs /*= None*/,
MaybeCount RequiredParams /*= None*/)
: CallDescription(CDF_None, QualifiedName, RequiredArgs, RequiredParams) {}
: CallDescription(Mode::Unspecified, QualifiedName, RequiredArgs,
RequiredParams) {}

bool ento::CallDescription::matches(const CallEvent &Call) const {
// FIXME: Add ObjC Message support.
Expand All @@ -74,14 +75,20 @@ bool ento::CallDescription::matchesAsWritten(const CallExpr &CE) const {
return matchesImpl(FD, CE.getNumArgs(), FD->param_size());
}

bool ento::CallDescription::matchesImpl(const FunctionDecl *Callee,
size_t ArgCount,
bool ento::CallDescription::matchesImpl(const FunctionDecl *FD, size_t ArgCount,
size_t ParamCount) const {
const auto *FD = Callee;
if (!FD)
return false;

if (Flags & CDF_MaybeBuiltin) {
const bool isMethod = isa<CXXMethodDecl>(FD);

if (MatchAs == Mode::SimpleFunc && isMethod)
return false;

if (MatchAs == Mode::CXXMethod && !isMethod)
return false;

if (MatchAs == Mode::CLibrary) {
return CheckerContext::isCLibraryFunction(FD, getFunctionName()) &&
(!RequiredArgs || *RequiredArgs <= ArgCount) &&
(!RequiredParams || *RequiredParams <= ParamCount);
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Tooling/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,5 @@ add_clang_library(clangTooling
clangRewrite
clangSerialization
clangToolingCore
${LLVM_PTHREAD_LIB}
)
2 changes: 2 additions & 0 deletions clang/test/AST/Interp/arrays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ constexpr int dependent[4] = {
static_assert(dependent[2] == dependent[0], "");
static_assert(dependent[3] == dependent[1], "");

union { char x[]; } r = {0};

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wc99-extensions"
#pragma clang diagnostic ignored "-Winitializer-overrides"
Expand Down
8 changes: 8 additions & 0 deletions clang/test/AST/Interp/builtin-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ namespace strcmp {
static_assert(__builtin_strcmp(kFoobar, kFoobazfoobar + 6) == 0, ""); // both-error {{not an integral constant}} \
// both-note {{dereferenced one-past-the-end}} \
// expected-note {{in call to}}

/// Used to assert because we're passing a dummy pointer to
/// __builtin_strcmp() when evaluating the return statement.
constexpr bool char_memchr_mutable() {
char buffer[] = "mutable";
return __builtin_strcmp(buffer, "mutable") == 0;
}
static_assert(char_memchr_mutable(), "");
}

/// Copied from constant-expression-cxx11.cpp
Expand Down
13 changes: 13 additions & 0 deletions clang/test/AST/Interp/lambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,3 +235,16 @@ namespace LambdaToAPValue {
static_assert(g() == f(), "");
}
}

namespace ns2_capture_this_byval {
struct S {
int s;
constexpr S(int s) : s{s} { }
constexpr auto f(S o) {
return [*this,o] (auto a) { return s + o.s + a.s; };
}
};

constexpr auto L = S{5}.f(S{10});
static_assert(L(S{100}) == 115, "");
} // end test_captures_1::ns2_capture_this_byval
7 changes: 7 additions & 0 deletions clang/test/AST/Interp/literals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1168,3 +1168,10 @@ namespace incdecbool {


}

#if __cplusplus >= 201402L
constexpr int externvar1() { // both-error {{never produces a constant expression}}
extern char arr[]; // both-note {{declared here}}
return arr[0]; // both-note {{read of non-constexpr variable 'arr'}}
}
#endif
2 changes: 1 addition & 1 deletion clang/test/Analysis/analyzer-config.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
// CHECK-NEXT: unix.DynamicMemoryModeling:Optimistic = false
// CHECK-NEXT: unix.Errno:AllowErrnoReadOutsideConditionExpressions = true
// CHECK-NEXT: unix.StdCLibraryFunctions:DisplayLoadedSummaries = false
// CHECK-NEXT: unix.StdCLibraryFunctions:ModelPOSIX = false
// CHECK-NEXT: unix.StdCLibraryFunctions:ModelPOSIX = true
// CHECK-NEXT: unroll-loops = false
// CHECK-NEXT: verbose-report-filename = false
// CHECK-NEXT: widen-loops = false
5 changes: 5 additions & 0 deletions clang/test/Analysis/std-c-library-functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// RUN: -analyzer-checker=unix.StdCLibraryFunctions \
// RUN: -analyzer-checker=debug.ExprInspection \
// RUN: -analyzer-config eagerly-assume=false \
// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=false \
// RUN: -triple i686-unknown-linux \
// RUN: -verify

Expand All @@ -11,6 +12,7 @@
// RUN: -analyzer-checker=unix.StdCLibraryFunctions \
// RUN: -analyzer-checker=debug.ExprInspection \
// RUN: -analyzer-config eagerly-assume=false \
// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=false \
// RUN: -triple x86_64-unknown-linux \
// RUN: -verify

Expand All @@ -19,6 +21,7 @@
// RUN: -analyzer-checker=unix.StdCLibraryFunctions \
// RUN: -analyzer-checker=debug.ExprInspection \
// RUN: -analyzer-config eagerly-assume=false \
// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=false \
// RUN: -triple armv7-a15-linux \
// RUN: -verify

Expand All @@ -27,6 +30,7 @@
// RUN: -analyzer-checker=unix.StdCLibraryFunctions \
// RUN: -analyzer-checker=debug.ExprInspection \
// RUN: -analyzer-config eagerly-assume=false \
// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=false \
// RUN: -triple thumbv7-a15-linux \
// RUN: -verify

Expand All @@ -36,6 +40,7 @@
// RUN: -analyzer-config unix.StdCLibraryFunctions:DisplayLoadedSummaries=true \
// RUN: -analyzer-checker=debug.ExprInspection \
// RUN: -analyzer-config eagerly-assume=false \
// RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=false \
// RUN: -triple i686-unknown-linux 2>&1 | FileCheck %s

// CHECK: Loaded summary for: int isalnum(int)
Expand Down
22 changes: 18 additions & 4 deletions clang/test/CXX/temp/temp.res/temp.local/p6.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -verify %s -fcxx-exceptions -std=c++1y
// RUN: %clang_cc1 -verify %s -fcxx-exceptions -std=c++1y -Wno-error=strict-primary-template-shadow

namespace N {}

Expand Down Expand Up @@ -127,16 +127,30 @@ template<int T> struct Z { // expected-note 16{{declared here}}
template<typename T> // expected-note {{declared here}}
void f(int T) {} // expected-error {{declaration of 'T' shadows template parameter}}

// FIXME: These are ill-formed: a template-parameter shall not have the same name as the template name.
namespace A {
template<typename T> struct T {}; // expected-error{{declaration of 'T' shadows template parameter}}
// expected-note@-1{{template parameter is declared here}}
template<typename T> struct U {
template<typename V> struct V {}; // expected-error{{declaration of 'V' shadows template parameter}}
// expected-note@-1{{template parameter is declared here}}
};
}
namespace B {
template<typename T> void T() {}
template<typename T> void T() {} // expected-warning{{declaration of 'T' shadows template parameter}}
// expected-note@-1{{template parameter is declared here}}

template<typename T> struct U {
template<typename V> void V(); // expected-warning{{declaration of 'V' shadows template parameter}}
// expected-note@-1{{template parameter is declared here}}
};
}
namespace C {
template<typename T> int T;
template<typename T> int T; // expected-warning{{declaration of 'T' shadows template parameter}}
// expected-note@-1{{template parameter is declared here}}
template<typename T> struct U {
template<typename V> static int V; // expected-warning{{declaration of 'V' shadows template parameter}}
// expected-note@-1{{template parameter is declared here}}
};
}

namespace PR28023 {
Expand Down
24 changes: 8 additions & 16 deletions clang/test/CodeGen/PowerPC/builtins-ppc-xlcompat-rotate.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,8 @@ void test_builtin_ppc_rldimi() {
// CHECK: %res = alloca i64, align 8
// CHECK-NEXT: [[RA:%[0-9]+]] = load i64, ptr @ull, align 8
// CHECK-NEXT: [[RB:%[0-9]+]] = load i64, ptr @ull, align 8
// CHECK-NEXT: [[RC:%[0-9]+]] = call i64 @llvm.fshl.i64(i64 [[RA]], i64 [[RA]], i64 63)
// CHECK-NEXT: [[RD:%[0-9]+]] = and i64 [[RC]], 72057593769492480
// CHECK-NEXT: [[RE:%[0-9]+]] = and i64 [[RB]], -72057593769492481
// CHECK-NEXT: [[RF:%[0-9]+]] = or i64 [[RD]], [[RE]]
// CHECK-NEXT: store i64 [[RF]], ptr %res, align 8
// CHECK-NEXT: [[RC:%[0-9]+]] = call i64 @llvm.ppc.rldimi(i64 [[RA]], i64 [[RB]], i32 63, i64 72057593769492480)
// CHECK-NEXT: store i64 [[RC]], ptr %res, align 8
// CHECK-NEXT: ret void

/*shift = 63, mask = 0x00FFFFFFF0000000 = 72057593769492480, ~mask = 0xFF0000000FFFFFFF = -72057593769492481*/
Expand All @@ -32,11 +29,8 @@ void test_builtin_ppc_rlwimi() {
// CHECK: %res = alloca i32, align 4
// CHECK-NEXT: [[RA:%[0-9]+]] = load i32, ptr @ui, align 4
// CHECK-NEXT: [[RB:%[0-9]+]] = load i32, ptr @ui, align 4
// CHECK-NEXT: [[RC:%[0-9]+]] = call i32 @llvm.fshl.i32(i32 [[RA]], i32 [[RA]], i32 31)
// CHECK-NEXT: [[RD:%[0-9]+]] = and i32 [[RC]], 16776960
// CHECK-NEXT: [[RE:%[0-9]+]] = and i32 [[RB]], -16776961
// CHECK-NEXT: [[RF:%[0-9]+]] = or i32 [[RD]], [[RE]]
// CHECK-NEXT: store i32 [[RF]], ptr %res, align 4
// CHECK-NEXT: [[RC:%[0-9]+]] = call i32 @llvm.ppc.rlwimi(i32 [[RA]], i32 [[RB]], i32 31, i32 16776960)
// CHECK-NEXT: store i32 [[RC]], ptr %res, align 4
// CHECK-NEXT: ret void

/*shift = 31, mask = 0xFFFF00 = 16776960, ~mask = 0xFFFFFFFFFF0000FF = -16776961*/
Expand All @@ -47,9 +41,8 @@ void test_builtin_ppc_rlwnm() {
// CHECK-LABEL: test_builtin_ppc_rlwnm
// CHECK: %res = alloca i32, align 4
// CHECK-NEXT: [[RA:%[0-9]+]] = load i32, ptr @ui, align 4
// CHECK-NEXT: [[RB:%[0-9]+]] = call i32 @llvm.fshl.i32(i32 [[RA]], i32 [[RA]], i32 31)
// CHECK-NEXT: [[RC:%[0-9]+]] = and i32 [[RB]], 511
// CHECK-NEXT: store i32 [[RC]], ptr %res, align 4
// CHECK-NEXT: [[RB:%[0-9]+]] = call i32 @llvm.ppc.rlwnm(i32 [[RA]], i32 31, i32 511)
// CHECK-NEXT: store i32 [[RB]], ptr %res, align 4
// CHECK-NEXT: ret void

/*shift = 31, mask = 0x1FF = 511*/
Expand All @@ -63,9 +56,8 @@ void test_builtin_ppc_rlwnm2(unsigned int shift) {
// CHECK-NEXT: store i32 %shift, ptr %shift.addr, align 4
// CHECK-NEXT: [[RA:%[0-9]+]] = load i32, ptr @ui, align 4
// CHECK-NEXT: [[RB:%[0-9]+]] = load i32, ptr %shift.addr, align 4
// CHECK-NEXT: [[RC:%[0-9]+]] = call i32 @llvm.fshl.i32(i32 [[RA]], i32 [[RA]], i32 [[RB]])
// CHECK-NEXT: [[RD:%[0-9]+]] = and i32 [[RC]], 511
// CHECK-NEXT: store i32 [[RD]], ptr %res, align 4
// CHECK-NEXT: [[RC:%[0-9]+]] = call i32 @llvm.ppc.rlwnm(i32 [[RA]], i32 [[RB]], i32 511)
// CHECK-NEXT: store i32 [[RC]], ptr %res, align 4
// CHECK-NEXT: ret void

/*mask = 0x1FF = 511*/
Expand Down
12 changes: 6 additions & 6 deletions clang/test/CodeGen/attr-target-version.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ int foo() {
}

inline int __attribute__((target_version("sha1+pmull+f64mm"))) fmv_inline(void) { return 1; }
inline int __attribute__((target_version("fp16+fcma+sme+ fp16 "))) fmv_inline(void) { return 2; }
inline int __attribute__((target_version("fp16+fcma+rdma+sme+ fp16 "))) fmv_inline(void) { return 2; }
inline int __attribute__((target_version("sha3+i8mm+f32mm"))) fmv_inline(void) { return 12; }
inline int __attribute__((target_version("dit+sve-ebf16"))) fmv_inline(void) { return 8; }
inline int __attribute__((target_version("dpb+rcpc2 "))) fmv_inline(void) { return 6; }
Expand Down Expand Up @@ -261,12 +261,12 @@ int hoo(void) {
// CHECK-NEXT: resolver_entry:
// CHECK-NEXT: call void @__init_cpu_features_resolver()
// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8
// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 4398048608256
// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 4398048608256
// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 4398048608320
// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 4398048608320
// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]]
// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]]
// CHECK: resolver_return:
// CHECK-NEXT: ret ptr @fmv_inline._MfcmaMfp16Mfp16Msme
// CHECK-NEXT: ret ptr @fmv_inline._MfcmaMfp16Mfp16MrdmMsme
// CHECK: resolver_else:
// CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8
// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 864726312827224064
Expand Down Expand Up @@ -575,7 +575,7 @@ int hoo(void) {
//
//
// CHECK: Function Attrs: noinline nounwind optnone
// CHECK-LABEL: define {{[^@]+}}@fmv_inline._MfcmaMfp16Mfp16Msme
// CHECK-LABEL: define {{[^@]+}}@fmv_inline._MfcmaMfp16Mfp16MrdmMsme
// CHECK-SAME: () #[[ATTR13:[0-9]+]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: ret i32 2
Expand Down Expand Up @@ -829,7 +829,7 @@ int hoo(void) {
// CHECK: attributes #[[ATTR10]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+fullfp16,+ls64,+sme,+sme2" }
// CHECK: attributes #[[ATTR11]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+ccpp,+fullfp16,+ls64" }
// CHECK: attributes #[[ATTR12]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+aes,+f64mm,+fp-armv8,+fullfp16,+ls64,+neon,+sve" }
// CHECK: attributes #[[ATTR13]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+complxnum,+fp-armv8,+fullfp16,+ls64,+neon,+sme" }
// CHECK: attributes #[[ATTR13]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+complxnum,+fp-armv8,+fullfp16,+ls64,+neon,+rdm,+sme" }
// CHECK: attributes #[[ATTR14]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+f32mm,+fp-armv8,+fullfp16,+i8mm,+ls64,+neon,+sha2,+sha3,+sve" }
// CHECK: attributes #[[ATTR15]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+dit,+fp-armv8,+fullfp16,+ls64,+neon,+sve" }
// CHECK: attributes #[[ATTR16]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+ccpp,+fullfp16,+ls64,+rcpc" }
Expand Down
53 changes: 53 additions & 0 deletions clang/test/CodeGenHLSL/builtins/round.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
// RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \
// RUN: --check-prefixes=CHECK,NATIVE_HALF
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
// RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \
// RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF

// NATIVE_HALF: define noundef half @
// NATIVE_HALF: %elt.round = call half @llvm.round.f16(
// NATIVE_HALF: ret half %elt.round
// NO_HALF: define noundef float @"?test_round_half@@YA$halff@$halff@@Z"(
// NO_HALF: %elt.round = call float @llvm.round.f32(
// NO_HALF: ret float %elt.round
half test_round_half(half p0) { return round(p0); }
// NATIVE_HALF: define noundef <2 x half> @
// NATIVE_HALF: %elt.round = call <2 x half> @llvm.round.v2f16
// NATIVE_HALF: ret <2 x half> %elt.round
// NO_HALF: define noundef <2 x float> @
// NO_HALF: %elt.round = call <2 x float> @llvm.round.v2f32(
// NO_HALF: ret <2 x float> %elt.round
half2 test_round_half2(half2 p0) { return round(p0); }
// NATIVE_HALF: define noundef <3 x half> @
// NATIVE_HALF: %elt.round = call <3 x half> @llvm.round.v3f16
// NATIVE_HALF: ret <3 x half> %elt.round
// NO_HALF: define noundef <3 x float> @
// NO_HALF: %elt.round = call <3 x float> @llvm.round.v3f32(
// NO_HALF: ret <3 x float> %elt.round
half3 test_round_half3(half3 p0) { return round(p0); }
// NATIVE_HALF: define noundef <4 x half> @
// NATIVE_HALF: %elt.round = call <4 x half> @llvm.round.v4f16
// NATIVE_HALF: ret <4 x half> %elt.round
// NO_HALF: define noundef <4 x float> @
// NO_HALF: %elt.round = call <4 x float> @llvm.round.v4f32(
// NO_HALF: ret <4 x float> %elt.round
half4 test_round_half4(half4 p0) { return round(p0); }

// CHECK: define noundef float @
// CHECK: %elt.round = call float @llvm.round.f32(
// CHECK: ret float %elt.round
float test_round_float(float p0) { return round(p0); }
// CHECK: define noundef <2 x float> @
// CHECK: %elt.round = call <2 x float> @llvm.round.v2f32
// CHECK: ret <2 x float> %elt.round
float2 test_round_float2(float2 p0) { return round(p0); }
// CHECK: define noundef <3 x float> @
// CHECK: %elt.round = call <3 x float> @llvm.round.v3f32
// CHECK: ret <3 x float> %elt.round
float3 test_round_float3(float3 p0) { return round(p0); }
// CHECK: define noundef <4 x float> @
// CHECK: %elt.round = call <4 x float> @llvm.round.v4f32
// CHECK: ret <4 x float> %elt.round
float4 test_round_float4(float4 p0) { return round(p0); }
3 changes: 3 additions & 0 deletions clang/test/Driver/aarch64-rdm.c
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
// RUN: %clang --target=aarch64-none-elf -march=armv8a+rdm -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-RDM %s
// RUN: %clang --target=aarch64-none-elf -march=armv8a+rdma -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-RDM %s
// RUN: %clang --target=aarch64-none-elf -mcpu=generic+rdm -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-RDM %s
// RUN: %clang --target=aarch64-none-elf -mcpu=falkor -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-RDM %s
// RUN: %clang --target=aarch64-none-elf -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-RDM %s
// CHECK-RDM: "-target-feature" "+rdm"

// RUN: %clang --target=aarch64-none-elf -march=armv8a+nordm -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-NORDM %s
// RUN: %clang --target=aarch64-none-elf -march=armv8a+nordma -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-NORDM %s
// RUN: %clang --target=aarch64-none-elf -mcpu=generic+nordm -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-NORDM %s
// CHECK-NORDM-NOT: "-target-feature" "+rdm"
//
// RUN: %clang --target=aarch64-none-elf -march=armv8.1a -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-RDM %s
// RUN: %clang --target=aarch64-none-elf -march=armv8.1a+nordm -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-NORDM-DEFAULT %s
// RUN: %clang --target=aarch64-none-elf -march=armv8.1a+nordma -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-NORDM-DEFAULT %s
// CHECK-NORDM-DEFAULT: "-target-feature" "-rdm"
40 changes: 40 additions & 0 deletions clang/test/Driver/modules-print-library-module-manifest-path.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Test that -print-library-module-manifest-path finds the correct file.

// FIXME: Enable on all platforms.

// REQUIRES: x86-registered-target

// RUN: rm -rf %t && split-file %s %t && cd %t
// RUN: mkdir -p %t/Inputs/usr/lib/x86_64-linux-gnu
// RUN: touch %t/Inputs/usr/lib/x86_64-linux-gnu/libc++.so

// RUN: %clang -print-library-module-manifest-path \
// RUN: -stdlib=libc++ \
// RUN: --sysroot=%t/Inputs \
// RUN: --target=x86_64-linux-gnu 2>&1 \
// RUN: | FileCheck libcxx-no-module-json.cpp

// RUN: touch %t/Inputs/usr/lib/x86_64-linux-gnu/modules.json
// RUN: %clang -print-library-module-manifest-path \
// RUN: -stdlib=libc++ \
// RUN: --sysroot=%t/Inputs \
// RUN: --target=x86_64-linux-gnu 2>&1 \
// RUN: | FileCheck libcxx.cpp

// RUN: %clang -print-library-module-manifest-path \
// RUN: -stdlib=libstdc++ \
// RUN: --sysroot=%t/Inputs \
// RUN: --target=x86_64-linux-gnu 2>&1 \
// RUN: | FileCheck libstdcxx.cpp

//--- libcxx-no-module-json.cpp

// CHECK: <NOT PRESENT>

//--- libcxx.cpp

// CHECK: {{.*}}/Inputs/usr/lib/x86_64-linux-gnu{{/|\\}}modules.json

//--- libstdcxx.cpp

// CHECK: <NOT PRESENT>
11 changes: 0 additions & 11 deletions clang/test/Driver/openmp-offload-gpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,17 +101,6 @@

/// ###########################################################################

/// Check that the warning is thrown when the libomptarget bitcode library is not found.
/// Libomptarget requires sm_52 or newer so an sm_52 bitcode library should never exist.
// RUN: not %clang -### -fopenmp=libomp -fopenmp-targets=nvptx64-nvidia-cuda \
// RUN: -Xopenmp-target -march=sm_52 --cuda-path=%S/Inputs/CUDA_102/usr/local/cuda \
// RUN: -fopenmp-relocatable-target -save-temps %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHK-BCLIB-WARN %s

// CHK-BCLIB-WARN: no library 'libomptarget-nvptx-sm_52.bc' found in the default clang lib directory or in LIBRARY_PATH; use '--libomptarget-nvptx-bc-path' to specify nvptx bitcode library

/// ###########################################################################

/// Check that the error is thrown when the libomptarget bitcode library does not exist.
// RUN: not %clang -### -fopenmp=libomp -fopenmp-targets=nvptx64-nvidia-cuda \
// RUN: -Xopenmp-target -march=sm_52 --cuda-path=%S/Inputs/CUDA_102/usr/local/cuda \
Expand Down
85 changes: 85 additions & 0 deletions clang/test/InstallAPI/objcclasses.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// RUN: rm -rf %t
// RUN: split-file %s %t
// RUN: sed -e "s|DSTROOT|%/t|g" %t/inputs.json.in > %t/inputs.json

// RUN: clang-installapi -target arm64-apple-macos13.1 \
// RUN: -F%t -install_name /System/Library/Frameworks/Foo.framework/Foo \
// RUN: %t/inputs.json -o %t/outputs.tbd -v 2>&1 | FileCheck %s --check-prefix=VERBOSE
// RUN: llvm-readtapi -compare %t/outputs.tbd %t/expected.tbd 2>&1 | FileCheck %s --allow-empty

// VERBOSE: Public Headers:
// VERBOSE-NEXT: #import <Foo/Foo.h>
// CHECK-NOT: error:
// CHECK-NOT: warning:

//--- Foo.framework/Headers/Foo.h
// Ignore forward declaration.
@class NSObject;

@interface Visible
@end

__attribute__((visibility("hidden")))
@interface Hidden
@end

__attribute__((objc_exception))
@interface Exception
@end

//--- inputs.json.in
{
"headers": [ {
"path" : "DSTROOT/Foo.framework/Headers/Foo.h",
"type" : "public"
}],
"version": "3"
}

//--- expected.tbd
{
"main_library": {
"compatibility_versions": [
{
"version": "0"
}
],
"current_versions": [
{
"version": "0"
}
],
"exported_symbols": [
{
"data": {
"objc_class": [
"Exception",
"Visible"
],
"objc_eh_type": [
"Exception"
]
}
}
],
"flags": [
{
"attributes": [
"not_app_extension_safe"
]
}
],
"install_names": [
{
"name": "/System/Library/Frameworks/Foo.framework/Foo"
}
],
"target_info": [
{
"min_deployment": "13.1",
"target": "arm64-macos"
}
]
},
"tapi_tbd_version": 5
}
6 changes: 6 additions & 0 deletions clang/test/Layout/dump-complete-invalid.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// RUN: %clang_cc1 -verify -fsyntax-only -fdump-record-layouts-complete %s

struct Incomplete; // expected-note {{forward declaration}}

// Check we don't crash on trying to print out an invalid declaration.
struct Invalid : Incomplete {}; // expected-error {{base class has incomplete type}}
57 changes: 56 additions & 1 deletion clang/test/Layout/dump-complete.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -emit-llvm-only -fdump-record-layouts-complete %s | FileCheck %s
// RUN: %clang_cc1 -fsyntax-only -fdump-record-layouts-complete %s | FileCheck %s

struct a {
int x;
Expand All @@ -12,7 +12,62 @@ class c {};

class d;

template <typename>
struct s {
int x;
};

template <typename T>
struct ts {
T x;
};

template <>
struct ts<void> {
float f;
};

void f() {
ts<int> a;
ts<double> b;
ts<void> c;
}

namespace gh83671 {
template <class _Tp, _Tp __v>
struct integral_constant {
static constexpr const _Tp value = __v;
typedef integral_constant type;
};

template <bool _Val>
using _BoolConstant = integral_constant<bool, _Val>;

template <class _Tp, class _Up>
struct is_same : _BoolConstant<__is_same(_Tp, _Up)> {};

template < class _Tp >
class numeric_limits {};

template < class _Tp >
class numeric_limits< const _Tp > : public numeric_limits< _Tp > {};
}

namespace gh83684 {
template <class Pointer>
struct AllocationResult {
Pointer ptr = nullptr;
int count = 0;
};
}

// CHECK: 0 | struct a
// CHECK: 0 | struct b
// CHECK: 0 | class c
// CHECK: 0 | struct ts<void>
// CHECK-NEXT: 0 | float
// CHECK: 0 | struct ts<int>
// CHECK: 0 | struct ts<double>
// CHECK-NOT: 0 | class d
// CHECK-NOT: 0 | struct s
// CHECK-NOT: 0 | struct AllocationResult
2 changes: 1 addition & 1 deletion clang/test/Sema/attr-target-clones-aarch64.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -triple aarch64-linux-gnu -fsyntax-only -verify %s

void __attribute__((target_clones("fp16+sve2-aes", "sb+sve2-sha3+rcpc3+mops"))) no_def(void);
void __attribute__((target_clones("fp16+sve2-aes", "sb+sve2-sha3+rcpc3+mops", "rdma"))) no_def(void);

// expected-warning@+1 {{unsupported 'default' in the 'target_clones' attribute string; 'target_clones' attribute ignored}}
void __attribute__((target_clones("default+sha3"))) warn1(void);
Expand Down
1 change: 1 addition & 0 deletions clang/test/SemaCXX/attr-target-version.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ void __attribute__((target_version("dotprod"))) no_def(void);
void __attribute__((target_version("rdm+fp"))) no_def(void);
void __attribute__((target_version("rcpc3"))) no_def(void);
void __attribute__((target_version("mops"))) no_def(void);
void __attribute__((target_version("rdma"))) no_def(void);

// expected-error@+1 {{no matching function for call to 'no_def'}}
void foo(void) { no_def(); }
Expand Down
15 changes: 15 additions & 0 deletions clang/test/SemaCXX/warn-bool-conversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,21 @@ void foo() {
bool is_true = [](){ return true; };
// expected-warning@-1{{address of lambda function pointer conversion operator will always evaluate to 'true'}}
}

template <typename... Ts>
static bool IsFalse(const Ts&...) { return false; }
template <typename T>
static bool IsFalse(const T& p) {
bool b;
b = f7; // expected-warning {{address of lambda function pointer conversion operator will always evaluate to 'true'}}
// Intentionally not warned on because p could be a lambda type in one
// instantiation, but a pointer type in another.
return p ? false : true;
}

bool use_instantiation() {
return IsFalse([]() { return 0; });
}
#endif

void bar() {
Expand Down
16 changes: 8 additions & 8 deletions clang/test/SemaHLSL/BuiltIns/dot-errors.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ float test_dot_vector_size_mismatch(float3 p0, float2 p1) {

float test_dot_builtin_vector_size_mismatch(float3 p0, float2 p1) {
return __builtin_hlsl_dot(p0, p1);
// expected-error@-1 {{all arguments to '__builtin_hlsl_dot' must have vectors of the same type}}
// expected-error@-1 {{all arguments to '__builtin_hlsl_dot' must have the same type}}
}

float test_dot_scalar_mismatch(float p0, int p1) {
Expand All @@ -38,39 +38,39 @@ float test_dot_element_type_mismatch(int2 p0, float2 p1) {
//NOTE: for all the *_promotion we are intentionally not handling type promotion in builtins
float test_builtin_dot_vec_int_to_float_promotion(int2 p0, float2 p1) {
return __builtin_hlsl_dot(p0, p1);
// expected-error@-1 {{all arguments to '__builtin_hlsl_dot' must have vectors of the same type}}
// expected-error@-1 {{all arguments to '__builtin_hlsl_dot' must have the same type}}
}

int64_t test_builtin_dot_vec_int_to_int64_promotion(int64_t2 p0, int2 p1) {
return __builtin_hlsl_dot(p0, p1);
// expected-error@-1 {{all arguments to '__builtin_hlsl_dot' must have vectors of the same type}}
// expected-error@-1 {{all arguments to '__builtin_hlsl_dot' must have the same type}}
}

float test_builtin_dot_vec_half_to_float_promotion(float2 p0, half2 p1) {
return __builtin_hlsl_dot(p0, p1);
// expected-error@-1 {{all arguments to '__builtin_hlsl_dot' must have vectors of the same type}}
// expected-error@-1 {{all arguments to '__builtin_hlsl_dot' must have the same type}}
}

#ifdef __HLSL_ENABLE_16_BIT
float test_builtin_dot_vec_int16_to_float_promotion(float2 p0, int16_t2 p1) {
return __builtin_hlsl_dot(p0, p1);
// expected-error@-1 {{all arguments to '__builtin_hlsl_dot' must have vectors of the same type}}
// expected-error@-1 {{all arguments to '__builtin_hlsl_dot' must have the same type}}
}

half test_builtin_dot_vec_int16_to_half_promotion(half2 p0, int16_t2 p1) {
return __builtin_hlsl_dot(p0, p1);
// expected-error@-1 {{all arguments to '__builtin_hlsl_dot' must have vectors of the same type}}
// expected-error@-1 {{all arguments to '__builtin_hlsl_dot' must have the same type}}
}

int test_builtin_dot_vec_int16_to_int_promotion(int2 p0, int16_t2 p1) {
return __builtin_hlsl_dot(p0, p1);
// expected-error@-1 {{all arguments to '__builtin_hlsl_dot' must have vectors of the same type}}
// expected-error@-1 {{all arguments to '__builtin_hlsl_dot' must have the same type}}
}

int64_t test_builtin_dot_vec_int16_to_int64_promotion(int64_t2 p0,
int16_t2 p1) {
return __builtin_hlsl_dot(p0, p1);
// expected-error@-1 {{all arguments to '__builtin_hlsl_dot' must have vectors of the same type}}
// expected-error@-1 {{all arguments to '__builtin_hlsl_dot' must have the same type}}
}
#endif

Expand Down
2 changes: 1 addition & 1 deletion clang/test/SemaHLSL/BuiltIns/lerp-errors.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ float2 test_lerp_vector_size_mismatch(float3 p0, float2 p1) {

float2 test_lerp_builtin_vector_size_mismatch(float3 p0, float2 p1) {
return __builtin_hlsl_lerp(p0, p1, p1);
// expected-error@-1 {{all arguments to '__builtin_hlsl_lerp' must have vectors of the same type}}
// expected-error@-1 {{all arguments to '__builtin_hlsl_lerp' must have the same type}}
}

float test_lerp_scalar_mismatch(float p0, half p1) {
Expand Down
27 changes: 27 additions & 0 deletions clang/test/SemaHLSL/BuiltIns/round-errors.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -verify -verify-ignore-unexpected

float test_too_few_arg() {
return __builtin_elementwise_round();
// expected-error@-1 {{too few arguments to function call, expected 1, have 0}}
}

float2 test_too_many_arg(float2 p0) {
return __builtin_elementwise_round(p0, p0);
// expected-error@-1 {{too many arguments to function call, expected 1, have 2}}
}

float builtin_bool_to_float_type_promotion(bool p1) {
return __builtin_elementwise_round(p1);
// expected-error@-1 {{1st argument must be a vector, integer or floating point type (was 'bool')}}
}

float builtin_round_int_to_float_promotion(int p1) {
return __builtin_elementwise_round(p1);
// expected-error@-1 {{1st argument must be a floating point type (was 'int')}}
}

float2 builtin_round_int2_to_float2_promotion(int2 p1) {
return __builtin_elementwise_round(p1);
// expected-error@-1 {{1st argument must be a floating point type (was 'int2' (aka 'vector<int, 2>'))}}
}
60 changes: 60 additions & 0 deletions clang/test/SemaOpenACC/no-branch-in-out.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,66 @@ void DuffsDevice() {
}
}

void Exceptions() {
#pragma acc parallel
for(int i = 0; i < 5; ++i) {
throw 5; // expected-error{{invalid throw out of OpenACC Compute Construct}}
}

#pragma acc parallel
for(int i = 0; i < 5; ++i) {
throw; // expected-error{{invalid throw out of OpenACC Compute Construct}}
}

#pragma acc parallel
for(int i = 0; i < 5; ++i) {
try {
throw 5;
} catch(float f) {
}
}

#pragma acc parallel
for(int i = 0; i < 5; ++i) {
try {
throw 5;
} catch(int f) {
}
}

#pragma acc parallel
for(int i = 0; i < 5; ++i) {
try {
throw 5;
} catch(...) {
}
}
#pragma acc parallel
for(int i = 0; i < 5; ++i) {
try {
throw;
} catch(...) {
}
}

#pragma acc parallel
for(int i = 0; i < 5; ++i) {
try {
throw;
} catch(...) {
throw; // expected-error{{invalid throw out of OpenACC Compute Construct}}
}
}
#pragma acc parallel
for(int i = 0; i < 5; ++i) {
try {
throw;
} catch(int f) {
throw; // expected-error{{invalid throw out of OpenACC Compute Construct}}
}
}
}

void Instantiate() {
BreakContinue<int>();
DuffsDevice<int>();
Expand Down
8 changes: 5 additions & 3 deletions clang/tools/clang-installapi/ClangInstallAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ using namespace llvm::opt;
using namespace llvm::MachO;

static bool runFrontend(StringRef ProgName, bool Verbose,
const InstallAPIContext &Ctx,
InstallAPIContext &Ctx,
llvm::vfs::InMemoryFileSystem *FS,
const ArrayRef<std::string> InitialArgs) {

Expand All @@ -64,7 +64,7 @@ static bool runFrontend(StringRef ProgName, bool Verbose,

// Create & run invocation.
clang::tooling::ToolInvocation Invocation(
std::move(Args), std::make_unique<InstallAPIAction>(*Ctx.Slice), Ctx.FM);
std::move(Args), std::make_unique<InstallAPIAction>(Ctx), Ctx.FM);

return Invocation.run();
}
Expand Down Expand Up @@ -123,11 +123,13 @@ static bool run(ArrayRef<const char *> Args, const char *ProgName) {
return EXIT_FAILURE;

// Execute and gather AST results.
// An invocation is ran for each unique target triple and for each header
// access level.
llvm::MachO::Records FrontendResults;
for (const auto &[Targ, Trip] : Opts.DriverOpts.Targets) {
for (const HeaderType Type :
{HeaderType::Public, HeaderType::Private, HeaderType::Project}) {
Ctx.Slice = std::make_shared<RecordsSlice>(Trip);
Ctx.Slice = std::make_shared<FrontendRecordsSlice>(Trip);
Ctx.Type = Type;
if (!runFrontend(ProgName, Opts.DriverOpts.Verbose, Ctx,
InMemoryFileSystem.get(), Opts.getClangFrontendArgs()))
Expand Down
23 changes: 9 additions & 14 deletions clang/unittests/Format/FormatTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11159,10 +11159,8 @@ TEST_F(FormatTest, UnderstandsOverloadedOperators) {
verifyFormat("void f() { a.operator*(b & b); }");
verifyFormat("void f() { a->operator&(a * b); }");
verifyFormat("void f() { NS::a.operator+(*b * *b); }");
// TODO: Calling an operator as a non-member function is hard to distinguish.
// https://llvm.org/PR50629
// verifyFormat("void f() { operator*(a & a); }");
// verifyFormat("void f() { operator&(a, b * b); }");
verifyFormat("void f() { operator*(a & a); }");
verifyFormat("void f() { operator&(a, b * b); }");

verifyFormat("void f() { return operator()(x) * b; }");
verifyFormat("void f() { return operator[](x) * b; }");
Expand Down Expand Up @@ -16551,9 +16549,8 @@ TEST_F(FormatTest, ConfigurableSpaceBeforeParens) {
verifyFormat("static_assert (sizeof (char) == 1, \"Impossible!\");", Space);
verifyFormat("int f () throw (Deprecated);", Space);
verifyFormat("typedef void (*cb) (int);", Space);
// FIXME these tests regressed behaviour.
// verifyFormat("T A::operator() ();", Space);
// verifyFormat("X A::operator++ (T);", Space);
verifyFormat("T A::operator() ();", Space);
verifyFormat("X A::operator++ (T);", Space);
verifyFormat("auto lambda = [] () { return 0; };", Space);
verifyFormat("int x = int (y);", Space);
verifyFormat("#define F(...) __VA_OPT__ (__VA_ARGS__)", Space);
Expand Down Expand Up @@ -16612,8 +16609,7 @@ TEST_F(FormatTest, ConfigurableSpaceBeforeParens) {
verifyFormat("int f() throw (Deprecated);", SomeSpace);
verifyFormat("typedef void (*cb) (int);", SomeSpace);
verifyFormat("T A::operator()();", SomeSpace);
// FIXME these tests regressed behaviour.
// verifyFormat("X A::operator++ (T);", SomeSpace);
verifyFormat("X A::operator++ (T);", SomeSpace);
verifyFormat("int x = int (y);", SomeSpace);
verifyFormat("auto lambda = []() { return 0; };", SomeSpace);

Expand Down Expand Up @@ -16671,9 +16667,8 @@ TEST_F(FormatTest, ConfigurableSpaceBeforeParens) {
SpaceFuncDecl);
verifyFormat("int f () throw(Deprecated);", SpaceFuncDecl);
verifyFormat("typedef void (*cb)(int);", SpaceFuncDecl);
// FIXME these tests regressed behaviour.
// verifyFormat("T A::operator() ();", SpaceFuncDecl);
// verifyFormat("X A::operator++ (T);", SpaceFuncDecl);
verifyFormat("T A::operator()();", SpaceFuncDecl);
verifyFormat("X A::operator++(T);", SpaceFuncDecl);
verifyFormat("T A::operator()() {}", SpaceFuncDecl);
verifyFormat("auto lambda = []() { return 0; };", SpaceFuncDecl);
verifyFormat("int x = int(y);", SpaceFuncDecl);
Expand Down Expand Up @@ -16710,7 +16705,7 @@ TEST_F(FormatTest, ConfigurableSpaceBeforeParens) {
verifyFormat("typedef void (*cb)(int);", SpaceFuncDef);
verifyFormat("T A::operator()();", SpaceFuncDef);
verifyFormat("X A::operator++(T);", SpaceFuncDef);
// verifyFormat("T A::operator() () {}", SpaceFuncDef);
verifyFormat("T A::operator()() {}", SpaceFuncDef);
verifyFormat("auto lambda = [] () { return 0; };", SpaceFuncDef);
verifyFormat("int x = int(y);", SpaceFuncDef);
verifyFormat("M(std::size_t R, std::size_t C) : C(C), data(R) {}",
Expand Down Expand Up @@ -16797,7 +16792,7 @@ TEST_F(FormatTest, ConfigurableSpaceBeforeParens) {
verifyFormat("int f() throw (Deprecated);", SomeSpace2);
verifyFormat("typedef void (*cb) (int);", SomeSpace2);
verifyFormat("T A::operator()();", SomeSpace2);
// verifyFormat("X A::operator++ (T);", SomeSpace2);
verifyFormat("X A::operator++ (T);", SomeSpace2);
verifyFormat("int x = int (y);", SomeSpace2);
verifyFormat("auto lambda = []() { return 0; };", SomeSpace2);

Expand Down
21 changes: 10 additions & 11 deletions clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,11 +488,10 @@ TEST(CallDescription, NegativeMatchQualifiedNames) {
}

TEST(CallDescription, MatchBuiltins) {
// Test CDF_MaybeBuiltin - a flag that allows matching weird builtins.
// Test CDM::CLibrary - a flag that allows matching weird builtins.
EXPECT_TRUE(tooling::runToolOnCode(
std::unique_ptr<FrontendAction>(new CallDescriptionAction<>(
{{{{"memset"}, 3}, false},
{{CDF_MaybeBuiltin, {"memset"}, 3}, true}})),
{{{{"memset"}, 3}, false}, {{CDM::CLibrary, {"memset"}, 3}, true}})),
"void foo() {"
" int x;"
" __builtin___memset_chk(&x, 0, sizeof(x),"
Expand All @@ -503,8 +502,8 @@ TEST(CallDescription, MatchBuiltins) {
SCOPED_TRACE("multiple similar builtins");
EXPECT_TRUE(tooling::runToolOnCode(
std::unique_ptr<FrontendAction>(new CallDescriptionAction<>(
{{{CDF_MaybeBuiltin, {"memcpy"}, 3}, false},
{{CDF_MaybeBuiltin, {"wmemcpy"}, 3}, true}})),
{{{CDM::CLibrary, {"memcpy"}, 3}, false},
{{CDM::CLibrary, {"wmemcpy"}, 3}, true}})),
R"(void foo(wchar_t *x, wchar_t *y) {
__builtin_wmemcpy(x, y, sizeof(wchar_t));
})"));
Expand All @@ -513,17 +512,17 @@ TEST(CallDescription, MatchBuiltins) {
SCOPED_TRACE("multiple similar builtins reversed order");
EXPECT_TRUE(tooling::runToolOnCode(
std::unique_ptr<FrontendAction>(new CallDescriptionAction<>(
{{{CDF_MaybeBuiltin, {"wmemcpy"}, 3}, true},
{{CDF_MaybeBuiltin, {"memcpy"}, 3}, false}})),
{{{CDM::CLibrary, {"wmemcpy"}, 3}, true},
{{CDM::CLibrary, {"memcpy"}, 3}, false}})),
R"(void foo(wchar_t *x, wchar_t *y) {
__builtin_wmemcpy(x, y, sizeof(wchar_t));
})"));
}
{
SCOPED_TRACE("lookbehind and lookahead mismatches");
EXPECT_TRUE(tooling::runToolOnCode(
std::unique_ptr<FrontendAction>(new CallDescriptionAction<>(
{{{CDF_MaybeBuiltin, {"func"}}, false}})),
std::unique_ptr<FrontendAction>(
new CallDescriptionAction<>({{{CDM::CLibrary, {"func"}}, false}})),
R"(
void funcXXX();
void XXXfunc();
Expand All @@ -537,8 +536,8 @@ TEST(CallDescription, MatchBuiltins) {
{
SCOPED_TRACE("lookbehind and lookahead matches");
EXPECT_TRUE(tooling::runToolOnCode(
std::unique_ptr<FrontendAction>(new CallDescriptionAction<>(
{{{CDF_MaybeBuiltin, {"func"}}, true}})),
std::unique_ptr<FrontendAction>(
new CallDescriptionAction<>({{{CDM::CLibrary, {"func"}}, true}})),
R"(
void func();
void func_XXX();
Expand Down
9 changes: 7 additions & 2 deletions compiler-rt/cmake/Modules/CompilerRTCompile.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,14 @@ function(clang_compile object_file source)
if (TARGET CompilerRTUnitTestCheckCxx)
list(APPEND SOURCE_DEPS CompilerRTUnitTestCheckCxx)
endif()
string(REGEX MATCH "[.](cc|cpp)$" is_cxx ${source_rpath})
if (is_cxx)
set(compiler ${COMPILER_RT_TEST_COMPILER})
else()
set(compiler ${COMPILER_RT_TEST_CXX_COMPILER})
endif()
if(COMPILER_RT_STANDALONE_BUILD)
# Only add global flags in standalone build.
string(REGEX MATCH "[.](cc|cpp)$" is_cxx ${source_rpath})
if(is_cxx)
string(REPLACE " " ";" global_flags "${CMAKE_CXX_FLAGS}")
else()
Expand Down Expand Up @@ -102,7 +107,7 @@ function(clang_compile object_file source)

add_custom_command(
OUTPUT ${object_file}
COMMAND ${COMPILER_RT_TEST_COMPILER} ${compile_flags} -c
COMMAND ${compiler} ${compile_flags} -c
-o "${object_file}"
${source_rpath}
MAIN_DEPENDENCY ${source}
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/builtins/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ set(GENERIC_SOURCES

# We only build BF16 files when "__bf16" is available.
set(BF16_SOURCES
extendbfsf2.c
truncdfbf2.c
truncsfbf2.c
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
//===-- Implementation of the GPU lround function -------------------------===//
//===-- lib/extendbfsf2.c - bfloat -> single conversion -----------*- C -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#include "src/math/lround.h"
#include "src/__support/common.h"
#define SRC_BFLOAT16
#define DST_SINGLE
#include "fp_extend_impl.inc"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(long, lround, (double x)) { return __builtin_lround(x); }

} // namespace LIBC_NAMESPACE
COMPILER_RT_ABI float __extendbfsf2(src_t a) { return __extendXfYf2__(a); }
15 changes: 15 additions & 0 deletions compiler-rt/lib/builtins/fp_extend.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,21 @@ static inline int src_rep_t_clz_impl(src_rep_t a) {

#define src_rep_t_clz src_rep_t_clz_impl

#elif defined SRC_BFLOAT16
#ifdef COMPILER_RT_HAS_BFLOAT16
typedef __bf16 src_t;
#else
typedef uint16_t src_t;
#endif
typedef uint16_t src_rep_t;
#define SRC_REP_C UINT16_C
static const int srcBits = sizeof(src_t) * CHAR_BIT;
static const int srcSigFracBits = 7;
// -1 accounts for the sign bit.
// srcBits - srcSigFracBits - 1
static const int srcExpBits = 8;
#define src_rep_t_clz __builtin_clz

#else
#error Source should be half, single, or double precision!
#endif // end source precision
Expand Down
4 changes: 2 additions & 2 deletions compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,12 @@ static rlim_t getlim(int res) {

static void setlim(int res, rlim_t lim) {
struct rlimit rlim;
if (getrlimit(res, const_cast<struct rlimit *>(&rlim))) {
if (getrlimit(res, &rlim)) {
Report("ERROR: %s getrlimit() failed %d\n", SanitizerToolName, errno);
Die();
}
rlim.rlim_cur = lim;
if (setrlimit(res, const_cast<struct rlimit *>(&rlim))) {
if (setrlimit(res, &rlim)) {
Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno);
Die();
}
Expand Down
16 changes: 16 additions & 0 deletions compiler-rt/lib/scudo/standalone/checksum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#else
#include <sys/auxv.h>
#endif
#elif defined(__loongarch__)
#include <sys/auxv.h>
#endif

namespace scudo {
Expand Down Expand Up @@ -75,6 +77,20 @@ bool hasHardwareCRC32() {
return !!(getauxval(AT_HWCAP) & HWCAP_CRC32);
#endif // SCUDO_FUCHSIA
}
#elif defined(__loongarch__)
// The definition is only pulled in by <sys/auxv.h> since glibc 2.38, so
// supply it if missing.
#ifndef HWCAP_LOONGARCH_CRC32
#define HWCAP_LOONGARCH_CRC32 (1 << 6)
#endif
// Query HWCAP for platform capability, according to *Software Development and
// Build Convention for LoongArch Architectures* v0.1, Section 9.1.
//
// Link:
// https://github.com/loongson/la-softdev-convention/blob/v0.1/la-softdev-convention.adoc#kernel-development
bool hasHardwareCRC32() {
return !!(getauxval(AT_HWCAP) & HWCAP_LOONGARCH_CRC32);
}
#else
// No hardware CRC32 implemented in Scudo for other architectures.
bool hasHardwareCRC32() { return false; }
Expand Down
4 changes: 4 additions & 0 deletions compiler-rt/lib/scudo/standalone/checksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
#include <arm_acle.h>
#define CRC32_INTRINSIC FIRST_32_SECOND_64(__crc32cw, __crc32cd)
#endif
#ifdef __loongarch__
#include <larchintrin.h>
#define CRC32_INTRINSIC FIRST_32_SECOND_64(__crcc_w_w_w, __crcc_w_d_w)
#endif

namespace scudo {

Expand Down
9 changes: 9 additions & 0 deletions compiler-rt/lib/scudo/standalone/crc32_hw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,13 @@ u32 computeHardwareCRC32(u32 Crc, uptr Data) {
#endif // defined(__CRC32__) || defined(__SSE4_2__) ||
// defined(__ARM_FEATURE_CRC32)

#if defined(__loongarch__)
u32 computeHardwareCRC32(u32 Crc, uptr Data) {
// The LoongArch CRC intrinsics have the two input arguments swapped, and
// expect them to be signed.
return static_cast<u32>(
CRC32_INTRINSIC(static_cast<long>(Data), static_cast<int>(Crc)));
}
#endif // defined(__loongarch__)

} // namespace scudo
12 changes: 6 additions & 6 deletions compiler-rt/test/dfsan/reaches_function.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ void my_dfsan_reaches_function_callback(dfsan_label label, dfsan_origin origin,
__attribute__((noinline)) uint64_t add(uint64_t *a, uint64_t *b) {

return *a + *b;
// CHECK: {{.*}}compiler-rt/test/dfsan/reaches_function.c:[[# @LINE - 1]] add.dfsan
// CHECK: reaches_function.c:[[# @LINE - 1]] add.dfsan
// CHECK-ORIGIN-TRACKING: Origin value: 0x10000002, Taint value was stored to memory at
// CHECK-ORIGIN-TRACKING: #0 {{.*}} in add.dfsan {{.*}}compiler-rt/test/dfsan/reaches_function.c:[[# @LINE - 3]]:{{.*}}
// CHECK-ORIGIN-TRACKING: #0 {{.*}} in add.dfsan {{.*}}reaches_function.c:[[# @LINE - 3]]:{{.*}}
// CHECK-ORIGIN-TRACKING: Origin value: 0x1, Taint value was created at
// CHECK-ORIGIN-TRACKING: #0 {{.*}} in main {{.*}}compiler-rt/test/dfsan/reaches_function.c:{{.*}}
// CHECK-ORIGIN-TRACKING: #0 {{.*}} in main {{.*}}reaches_function.c:{{.*}}
}

extern void my_dfsan_reaches_function_callback(dfsan_label label,
Expand All @@ -54,11 +54,11 @@ int main(int argc, char *argv[]) {

dfsan_set_label(8, &a, sizeof(a));
uint64_t c = add(&a, &b);
// CHECK: {{.*}}compiler-rt/test/dfsan/reaches_function.c:[[# @LINE - 1]] main
// CHECK: reaches_function.c:[[# @LINE - 1]] main
// CHECK-ORIGIN-TRACKING: Origin value: 0x10000002, Taint value was stored to memory at
// CHECK-ORIGIN-TRACKING: #0 {{.*}} in add.dfsan {{.*}}compiler-rt/test/dfsan/reaches_function.c:{{.*}}
// CHECK-ORIGIN-TRACKING: #0 {{.*}} in add.dfsan {{.*}}reaches_function.c:{{.*}}
// CHECK-ORIGIN-TRACKING: Origin value: 0x1, Taint value was created at
// CHECK-ORIGIN-TRACKING: #0 {{.*}} in main {{.*}}compiler-rt/test/dfsan/reaches_function.c:[[# @LINE - 6]]:{{.*}}
// CHECK-ORIGIN-TRACKING: #0 {{.*}} in main {{.*}}reaches_function.c:[[# @LINE - 6]]:{{.*}}
return c;
}

Expand Down
Loading