49 changes: 26 additions & 23 deletions clang/include/clang/InstallAPI/FrontendRecords.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ class FrontendRecordsSlice : public llvm::MachO::RecordsSlice {
/// \param Flags The flags that describe attributes of the symbol.
/// \param Inlined Whether declaration is inlined, only applicable to
/// functions.
/// \return The non-owning pointer to added record in slice.
GlobalRecord *addGlobal(StringRef Name, RecordLinkage Linkage,
GlobalRecord::Kind GV,
const clang::AvailabilityInfo Avail, const Decl *D,
const HeaderType Access,
SymbolFlags Flags = SymbolFlags::None,
bool Inlined = false);
/// \return The non-owning pointer to added record in slice with it's frontend
/// attributes.
std::pair<GlobalRecord *, FrontendAttrs *>
addGlobal(StringRef Name, RecordLinkage Linkage, GlobalRecord::Kind GV,
const clang::AvailabilityInfo Avail, const Decl *D,
const HeaderType Access, SymbolFlags Flags = SymbolFlags::None,
bool Inlined = false);

/// Add ObjC Class record with attributes from AST.
///
Expand All @@ -60,11 +60,12 @@ class FrontendRecordsSlice : public llvm::MachO::RecordsSlice {
/// \param D The pointer to the declaration from traversing AST.
/// \param Access The intended access level of symbol.
/// \param IsEHType Whether declaration has an exception attribute.
/// \return The non-owning pointer to added record in slice.
ObjCInterfaceRecord *addObjCInterface(StringRef Name, RecordLinkage Linkage,
const clang::AvailabilityInfo Avail,
const Decl *D, HeaderType Access,
bool IsEHType);
/// \return The non-owning pointer to added record in slice with it's frontend
/// attributes.
std::pair<ObjCInterfaceRecord *, FrontendAttrs *>
addObjCInterface(StringRef Name, RecordLinkage Linkage,
const clang::AvailabilityInfo Avail, const Decl *D,
HeaderType Access, bool IsEHType);

/// Add ObjC Category record with attributes from AST.
///
Expand All @@ -75,11 +76,12 @@ class FrontendRecordsSlice : public llvm::MachO::RecordsSlice {
/// to the active target triple.
/// \param D The pointer to the declaration from traversing AST.
/// \param Access The intended access level of symbol.
/// \return The non-owning pointer to added record in slice.
ObjCCategoryRecord *addObjCCategory(StringRef ClassToExtend,
StringRef CategoryName,
const clang::AvailabilityInfo Avail,
const Decl *D, HeaderType Access);
/// \return The non-owning pointer to added record in slice with it's frontend
/// attributes.
std::pair<ObjCCategoryRecord *, FrontendAttrs *>
addObjCCategory(StringRef ClassToExtend, StringRef CategoryName,
const clang::AvailabilityInfo Avail, const Decl *D,
HeaderType Access);

/// Add ObjC IVar record with attributes from AST.
///
Expand All @@ -91,12 +93,13 @@ class FrontendRecordsSlice : public llvm::MachO::RecordsSlice {
/// \param D The pointer to the declaration from traversing AST.
/// \param Access The intended access level of symbol.
/// \param AC The access control tied to the ivar declaration.
/// \return The non-owning pointer to added record in slice.
ObjCIVarRecord *addObjCIVar(ObjCContainerRecord *Container,
StringRef IvarName, RecordLinkage Linkage,
const clang::AvailabilityInfo Avail,
const Decl *D, HeaderType Access,
const clang::ObjCIvarDecl::AccessControl AC);
/// \return The non-owning pointer to added record in slice with it's frontend
/// attributes.
std::pair<ObjCIVarRecord *, FrontendAttrs *>
addObjCIVar(ObjCContainerRecord *Container, StringRef IvarName,
RecordLinkage Linkage, const clang::AvailabilityInfo Avail,
const Decl *D, HeaderType Access,
const clang::ObjCIvarDecl::AccessControl AC);

private:
/// Mapping of records stored in slice to their frontend attributes.
Expand Down
14 changes: 14 additions & 0 deletions clang/include/clang/InstallAPI/InstallAPIDiagnostic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//===--- InstallAPIDiagnostic.h - Diagnostics for InstallAPI ----*- 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_INSTALLAPI_INSTALLAPIDIAGNOSTIC_H
#define LLVM_CLANG_INSTALLAPI_INSTALLAPIDIAGNOSTIC_H

#include "clang/Basic/DiagnosticInstallAPI.h"

#endif
3 changes: 3 additions & 0 deletions clang/include/clang/InstallAPI/MachO.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "llvm/TextAPI/PackedVersion.h"
#include "llvm/TextAPI/Platform.h"
#include "llvm/TextAPI/RecordVisitor.h"
#include "llvm/TextAPI/Symbol.h"
#include "llvm/TextAPI/Target.h"
#include "llvm/TextAPI/TextAPIWriter.h"
#include "llvm/TextAPI/Utils.h"
Expand All @@ -33,8 +34,10 @@ using ObjCIVarRecord = llvm::MachO::ObjCIVarRecord;
using Records = llvm::MachO::Records;
using BinaryAttrs = llvm::MachO::RecordsSlice::BinaryAttrs;
using SymbolSet = llvm::MachO::SymbolSet;
using SimpleSymbol = llvm::MachO::SimpleSymbol;
using FileType = llvm::MachO::FileType;
using PackedVersion = llvm::MachO::PackedVersion;
using Target = llvm::MachO::Target;
using TargetList = llvm::MachO::TargetList;

#endif // LLVM_CLANG_INSTALLAPI_MACHO_H
7 changes: 3 additions & 4 deletions clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1567,10 +1567,9 @@ bool CXXRecordDecl::isGenericLambda() const {

#ifndef NDEBUG
static bool allLookupResultsAreTheSame(const DeclContext::lookup_result &R) {
for (auto *D : R)
if (!declaresSameEntity(D, R.front()))
return false;
return true;
return llvm::all_of(R, [&](NamedDecl *D) {
return D->isInvalidDecl() || declaresSameEntity(D, R.front());
});
}
#endif

Expand Down
13 changes: 11 additions & 2 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4604,8 +4604,17 @@ SourceRange DesignatedInitExpr::getDesignatorsSourceRange() const {
SourceLocation DesignatedInitExpr::getBeginLoc() const {
auto *DIE = const_cast<DesignatedInitExpr *>(this);
Designator &First = *DIE->getDesignator(0);
if (First.isFieldDesignator())
return GNUSyntax ? First.getFieldLoc() : First.getDotLoc();
if (First.isFieldDesignator()) {
// Skip past implicit designators for anonymous structs/unions, since
// these do not have valid source locations.
for (unsigned int i = 0; i < DIE->size(); i++) {
Designator &Des = *DIE->getDesignator(i);
SourceLocation retval = GNUSyntax ? Des.getFieldLoc() : Des.getDotLoc();
if (!retval.isValid())
continue;
return retval;
}
}
return First.getLBracketLoc();
}

Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5594,6 +5594,9 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
if (Assumption->isValueDependent())
return ESR_Failed;

if (Assumption->HasSideEffects(Info.getCtx()))
continue;

bool Value;
if (!EvaluateAsBooleanCondition(Assumption, Value, Info))
return ESR_Failed;
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1755,6 +1755,14 @@ bool ByteCodeExprGen<Emitter>::VisitTypeTraitExpr(const TypeTraitExpr *E) {
return this->emitConst(E->getValue(), E);
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitArrayTypeTraitExpr(
const ArrayTypeTraitExpr *E) {
if (DiscardResult)
return true;
return this->emitConst(E->getValue(), E);
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitLambdaExpr(const LambdaExpr *E) {
if (DiscardResult)
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E);
bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
bool VisitTypeTraitExpr(const TypeTraitExpr *E);
bool VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E);
bool VisitLambdaExpr(const LambdaExpr *E);
bool VisitPredefinedExpr(const PredefinedExpr *E);
bool VisitCXXThrowExpr(const CXXThrowExpr *E);
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/AST/MicrosoftMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ class MicrosoftCXXNameMangler {
const FunctionDecl *D = nullptr,
bool ForceThisQuals = false,
bool MangleExceptionSpec = true);
void mangleSourceName(StringRef Name);
void mangleNestedName(GlobalDecl GD);

private:
Expand All @@ -408,7 +409,6 @@ class MicrosoftCXXNameMangler {
mangleUnqualifiedName(GD, cast<NamedDecl>(GD.getDecl())->getDeclName());
}
void mangleUnqualifiedName(GlobalDecl GD, DeclarationName Name);
void mangleSourceName(StringRef Name);
void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc);
void mangleCXXDtorType(CXXDtorType T);
void mangleQualifiers(Qualifiers Quals, bool IsMember);
Expand Down Expand Up @@ -3920,7 +3920,8 @@ void MicrosoftMangleContextImpl::mangleThreadSafeStaticGuardVariable(
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);

Mangler.getStream() << "?$TSS" << GuardNum << '@';
Mangler.getStream() << "?";
Mangler.mangleSourceName("$TSS" + llvm::utostr(GuardNum));
Mangler.mangleNestedName(VD);
Mangler.getStream() << "@4HA";
}
Expand Down
10 changes: 8 additions & 2 deletions clang/lib/Basic/DiagnosticIDs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ struct StaticDiagInfoDescriptionStringTable {
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#include "clang/Basic/DiagnosticRefactoringKinds.inc"
#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
// clang-format on
#undef DIAG
};
Expand All @@ -70,7 +71,8 @@ const StaticDiagInfoDescriptionStringTable StaticDiagInfoDescriptions = {
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#include "clang/Basic/DiagnosticRefactoringKinds.inc"
// clang-format on
#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
// clang-format on
#undef DIAG
};

Expand All @@ -95,7 +97,8 @@ const uint32_t StaticDiagInfoDescriptionOffsets[] = {
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#include "clang/Basic/DiagnosticRefactoringKinds.inc"
// clang-format on
#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
// clang-format on
#undef DIAG
};

Expand Down Expand Up @@ -173,6 +176,7 @@ VALIDATE_DIAG_SIZE(CROSSTU)
VALIDATE_DIAG_SIZE(SEMA)
VALIDATE_DIAG_SIZE(ANALYSIS)
VALIDATE_DIAG_SIZE(REFACTORING)
VALIDATE_DIAG_SIZE(INSTALLAPI)
#undef VALIDATE_DIAG_SIZE
#undef STRINGIFY_NAME

Expand Down Expand Up @@ -204,6 +208,7 @@ const StaticDiagInfoRec StaticDiagInfo[] = {
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#include "clang/Basic/DiagnosticRefactoringKinds.inc"
#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
// clang-format on
#undef DIAG
};
Expand Down Expand Up @@ -246,6 +251,7 @@ CATEGORY(CROSSTU, COMMENT)
CATEGORY(SEMA, CROSSTU)
CATEGORY(ANALYSIS, SEMA)
CATEGORY(REFACTORING, ANALYSIS)
CATEGORY(INSTALLAPI, REFACTORING)
#undef CATEGORY

// Avoid out of bounds reads.
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18048,6 +18048,21 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
/*ReturnType=*/llvm::Type::getInt1Ty(getLLVMContext()),
Intrinsic::dx_any, ArrayRef<Value *>{Op0}, nullptr, "dx.any");
}
case Builtin::BI__builtin_hlsl_elementwise_clamp: {
Value *OpX = EmitScalarExpr(E->getArg(0));
Value *OpMin = EmitScalarExpr(E->getArg(1));
Value *OpMax = EmitScalarExpr(E->getArg(2));

QualType Ty = E->getArg(0)->getType();
bool IsUnsigned = false;
if (auto *VecTy = Ty->getAs<VectorType>())
Ty = VecTy->getElementType();
IsUnsigned = Ty->isUnsignedIntegerType();
return Builder.CreateIntrinsic(
/*ReturnType=*/OpX->getType(),
IsUnsigned ? Intrinsic::dx_uclamp : Intrinsic::dx_clamp,
ArrayRef<Value *>{OpX, OpMin, OpMax}, nullptr, "dx.clamp");
}
case Builtin::BI__builtin_hlsl_dot: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
Value *Op1 = EmitScalarExpr(E->getArg(1));
Expand Down
129 changes: 129 additions & 0 deletions clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/RISCVISAInfo.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/raw_ostream.h"
Expand Down Expand Up @@ -6677,3 +6678,131 @@ llvm::Error driver::expandResponseFiles(SmallVectorImpl<const char *> &Args,

return llvm::Error::success();
}

static const char *GetStableCStr(llvm::StringSet<> &SavedStrings, StringRef S) {
return SavedStrings.insert(S).first->getKeyData();
}

/// Apply a list of edits to the input argument lists.
///
/// The input string is a space separated list of edits to perform,
/// they are applied in order to the input argument lists. Edits
/// should be one of the following forms:
///
/// '#': Silence information about the changes to the command line arguments.
///
/// '^': Add FOO as a new argument at the beginning of the command line.
///
/// '+': Add FOO as a new argument at the end of the command line.
///
/// 's/XXX/YYY/': Substitute the regular expression XXX with YYY in the command
/// line.
///
/// 'xOPTION': Removes all instances of the literal argument OPTION.
///
/// 'XOPTION': Removes all instances of the literal argument OPTION,
/// and the following argument.
///
/// 'Ox': Removes all flags matching 'O' or 'O[sz0-9]' and adds 'Ox'
/// at the end of the command line.
///
/// \param OS - The stream to write edit information to.
/// \param Args - The vector of command line arguments.
/// \param Edit - The override command to perform.
/// \param SavedStrings - Set to use for storing string representations.
static void applyOneOverrideOption(raw_ostream &OS,
SmallVectorImpl<const char *> &Args,
StringRef Edit,
llvm::StringSet<> &SavedStrings) {
// This does not need to be efficient.

if (Edit[0] == '^') {
const char *Str = GetStableCStr(SavedStrings, Edit.substr(1));
OS << "### Adding argument " << Str << " at beginning\n";
Args.insert(Args.begin() + 1, Str);
} else if (Edit[0] == '+') {
const char *Str = GetStableCStr(SavedStrings, Edit.substr(1));
OS << "### Adding argument " << Str << " at end\n";
Args.push_back(Str);
} else if (Edit[0] == 's' && Edit[1] == '/' && Edit.ends_with("/") &&
Edit.slice(2, Edit.size() - 1).contains('/')) {
StringRef MatchPattern = Edit.substr(2).split('/').first;
StringRef ReplPattern = Edit.substr(2).split('/').second;
ReplPattern = ReplPattern.slice(0, ReplPattern.size() - 1);

for (unsigned i = 1, e = Args.size(); i != e; ++i) {
// Ignore end-of-line response file markers
if (Args[i] == nullptr)
continue;
std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]);

if (Repl != Args[i]) {
OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n";
Args[i] = GetStableCStr(SavedStrings, Repl);
}
}
} else if (Edit[0] == 'x' || Edit[0] == 'X') {
auto Option = Edit.substr(1);
for (unsigned i = 1; i < Args.size();) {
if (Option == Args[i]) {
OS << "### Deleting argument " << Args[i] << '\n';
Args.erase(Args.begin() + i);
if (Edit[0] == 'X') {
if (i < Args.size()) {
OS << "### Deleting argument " << Args[i] << '\n';
Args.erase(Args.begin() + i);
} else
OS << "### Invalid X edit, end of command line!\n";
}
} else
++i;
}
} else if (Edit[0] == 'O') {
for (unsigned i = 1; i < Args.size();) {
const char *A = Args[i];
// Ignore end-of-line response file markers
if (A == nullptr)
continue;
if (A[0] == '-' && A[1] == 'O' &&
(A[2] == '\0' || (A[3] == '\0' && (A[2] == 's' || A[2] == 'z' ||
('0' <= A[2] && A[2] <= '9'))))) {
OS << "### Deleting argument " << Args[i] << '\n';
Args.erase(Args.begin() + i);
} else
++i;
}
OS << "### Adding argument " << Edit << " at end\n";
Args.push_back(GetStableCStr(SavedStrings, '-' + Edit.str()));
} else {
OS << "### Unrecognized edit: " << Edit << "\n";
}
}

void driver::applyOverrideOptions(SmallVectorImpl<const char *> &Args,
const char *OverrideStr,
llvm::StringSet<> &SavedStrings,
raw_ostream *OS) {
if (!OS)
OS = &llvm::nulls();

if (OverrideStr[0] == '#') {
++OverrideStr;
OS = &llvm::nulls();
}

*OS << "### CCC_OVERRIDE_OPTIONS: " << OverrideStr << "\n";

// This does not need to be efficient.

const char *S = OverrideStr;
while (*S) {
const char *End = ::strchr(S, ' ');
if (!End)
End = S + strlen(S);
if (End != S)
applyOneOverrideOption(*OS, Args, std::string(S, End), SavedStrings);
S = End;
if (*S != '\0')
++S;
}
}
7 changes: 1 addition & 6 deletions clang/lib/Format/.clang-format
Original file line number Diff line number Diff line change
@@ -1,6 +1 @@
BasedOnStyle: LLVM
InsertBraces: true
InsertNewlineAtEOF: true
LineEnding: LF
RemoveBracesLLVM: true
RemoveParentheses: ReturnStatement
BasedOnStyle: clang-format
3 changes: 0 additions & 3 deletions clang/lib/Format/BreakableToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,8 @@
#define LLVM_CLANG_LIB_FORMAT_BREAKABLETOKEN_H

#include "Encoding.h"
#include "TokenAnnotator.h"
#include "WhitespaceManager.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Regex.h"
#include <utility>

namespace clang {
namespace format {
Expand Down
5 changes: 0 additions & 5 deletions clang/lib/Format/ContinuationIndenter.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,6 @@

#include "Encoding.h"
#include "FormatToken.h"
#include "clang/Format/Format.h"
#include "llvm/Support/Regex.h"
#include <map>
#include <optional>
#include <tuple>

namespace clang {
class SourceManager;
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Format/Encoding.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#define LLVM_CLANG_LIB_FORMAT_ENCODING_H

#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Unicode.h"

Expand Down
28 changes: 0 additions & 28 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,44 +13,16 @@
//===----------------------------------------------------------------------===//

#include "clang/Format/Format.h"
#include "AffectedRangeManager.h"
#include "BreakableToken.h"
#include "ContinuationIndenter.h"
#include "DefinitionBlockSeparator.h"
#include "FormatInternal.h"
#include "FormatToken.h"
#include "FormatTokenLexer.h"
#include "IntegerLiteralSeparatorFixer.h"
#include "NamespaceEndCommentsFixer.h"
#include "ObjCPropertyAttributeOrderFixer.h"
#include "QualifierAlignmentFixer.h"
#include "SortJavaScriptImports.h"
#include "TokenAnalyzer.h"
#include "TokenAnnotator.h"
#include "UnwrappedLineFormatter.h"
#include "UnwrappedLineParser.h"
#include "UsingDeclarationsSorter.h"
#include "WhitespaceManager.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
#include "clang/Tooling/Inclusions/HeaderIncludes.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/YAMLTraits.h"
#include <algorithm>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <unordered_map>

#define DEBUG_TYPE "format-formatter"

Expand Down
3 changes: 0 additions & 3 deletions clang/lib/Format/FormatInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@
#ifndef LLVM_CLANG_LIB_FORMAT_FORMATINTERNAL_H
#define LLVM_CLANG_LIB_FORMAT_FORMATINTERNAL_H

#include "BreakableToken.h"
#include <utility>

namespace clang {
namespace format {
namespace internal {
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/Format/FormatToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
#include "clang/Basic/OperatorPrecedence.h"
#include "clang/Format/Format.h"
#include "clang/Lex/Lexer.h"
#include <memory>
#include <optional>
#include <unordered_set>

namespace clang {
Expand Down
5 changes: 0 additions & 5 deletions clang/lib/Format/FormatTokenLexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,9 @@

#include "Encoding.h"
#include "FormatToken.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Format/Format.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Regex.h"

#include <stack>

Expand Down
3 changes: 0 additions & 3 deletions clang/lib/Format/FormatTokenSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@
#ifndef LLVM_CLANG_LIB_FORMAT_FORMATTOKENSOURCE_H
#define LLVM_CLANG_LIB_FORMAT_FORMATTOKENSOURCE_H

#include "FormatToken.h"
#include "UnwrappedLineParser.h"
#include "llvm/ADT/DenseMap.h"
#include <cstddef>

#define DEBUG_TYPE "format-token-source"

Expand Down
6 changes: 0 additions & 6 deletions clang/lib/Format/Macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,9 @@
#define CLANG_LIB_FORMAT_MACROS_H

#include <list>
#include <map>
#include <string>
#include <vector>

#include "FormatToken.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"

namespace clang {
namespace format {
Expand Down
3 changes: 0 additions & 3 deletions clang/lib/Format/SortJavaScriptImports.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@
#ifndef LLVM_CLANG_LIB_FORMAT_SORTJAVASCRIPTIMPORTS_H
#define LLVM_CLANG_LIB_FORMAT_SORTJAVASCRIPTIMPORTS_H

#include "clang/Basic/LLVM.h"
#include "clang/Format/Format.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"

namespace clang {
namespace format {
Expand Down
11 changes: 0 additions & 11 deletions clang/lib/Format/TokenAnalyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,8 @@
#define LLVM_CLANG_LIB_FORMAT_TOKENANALYZER_H

#include "AffectedRangeManager.h"
#include "Encoding.h"
#include "FormatToken.h"
#include "FormatTokenLexer.h"
#include "TokenAnnotator.h"
#include "UnwrappedLineParser.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Format/Format.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
#include <memory>

namespace clang {
namespace format {
Expand Down
22 changes: 14 additions & 8 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3595,6 +3595,13 @@ static bool isFunctionDeclarationName(const FormatToken &Current,
if (!Current.Tok.getIdentifierInfo())
return false;

const auto &Previous = *Current.Previous;

if (const auto *PrevPrev = Previous.Previous;
PrevPrev && PrevPrev->is(TT_ObjCDecl)) {
return false;
}

auto skipOperatorName = [](const FormatToken *Next) -> const FormatToken * {
for (; Next; Next = Next->Next) {
if (Next->is(TT_OverloadedOperatorLParen))
Expand Down Expand Up @@ -3633,18 +3640,17 @@ static bool isFunctionDeclarationName(const FormatToken &Current,
// Find parentheses of parameter list.
const FormatToken *Next = Current.Next;
if (Current.is(tok::kw_operator)) {
const auto *Previous = Current.Previous;
if (Previous->Tok.getIdentifierInfo() &&
!Previous->isOneOf(tok::kw_return, tok::kw_co_return)) {
if (Previous.Tok.getIdentifierInfo() &&
!Previous.isOneOf(tok::kw_return, tok::kw_co_return)) {
return true;
}
if (Previous->is(tok::r_paren) && Previous->is(TT_TypeDeclarationParen)) {
assert(Previous->MatchingParen);
assert(Previous->MatchingParen->is(tok::l_paren));
assert(Previous->MatchingParen->is(TT_TypeDeclarationParen));
if (Previous.is(tok::r_paren) && Previous.is(TT_TypeDeclarationParen)) {
assert(Previous.MatchingParen);
assert(Previous.MatchingParen->is(tok::l_paren));
assert(Previous.MatchingParen->is(TT_TypeDeclarationParen));
return true;
}
if (!Previous->isPointerOrReference() && Previous->isNot(TT_TemplateCloser))
if (!Previous.isPointerOrReference() && Previous.isNot(TT_TemplateCloser))
return false;
Next = skipOperatorName(Next);
} else {
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Format/TokenAnnotator.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#define LLVM_CLANG_LIB_FORMAT_TOKENANNOTATOR_H

#include "UnwrappedLineParser.h"
#include "clang/Format/Format.h"

namespace clang {
namespace format {
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/Format/UnwrappedLineFormatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
#define LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H

#include "ContinuationIndenter.h"
#include "clang/Format/Format.h"
#include <map>

namespace clang {
namespace format {
Expand Down
15 changes: 9 additions & 6 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1224,7 +1224,6 @@ void UnwrappedLineParser::parsePPUnknown() {
static bool tokenCanStartNewLine(const FormatToken &Tok) {
// Semicolon can be a null-statement, l_square can be a start of a macro or
// a C++11 attribute, but this doesn't seem to be common.
assert(Tok.isNot(TT_AttributeSquare));
return !Tok.isOneOf(tok::semi, tok::l_brace,
// Tokens that can only be used as binary operators and a
// part of overloaded operator names.
Expand Down Expand Up @@ -3712,14 +3711,19 @@ bool UnwrappedLineParser::parseEnum() {
if (Style.Language == FormatStyle::LK_Proto && FormatTok->is(tok::equal))
return false;

// Eat up enum class ...
if (FormatTok->isOneOf(tok::kw_class, tok::kw_struct))
nextToken();
if (IsCpp) {
// Eat up enum class ...
if (FormatTok->isOneOf(tok::kw_class, tok::kw_struct))
nextToken();
while (FormatTok->is(tok::l_square))
if (!handleCppAttributes())
return false;
}

while (FormatTok->Tok.getIdentifierInfo() ||
FormatTok->isOneOf(tok::colon, tok::coloncolon, tok::less,
tok::greater, tok::comma, tok::question,
tok::l_square, tok::r_square)) {
tok::l_square)) {
if (Style.isVerilog()) {
FormatTok->setFinalizedType(TT_VerilogDimensionedTypeName);
nextToken();
Expand All @@ -3732,7 +3736,6 @@ bool UnwrappedLineParser::parseEnum() {
// We can have macros or attributes in between 'enum' and the enum name.
if (FormatTok->is(tok::l_paren))
parseParens();
assert(FormatTok->isNot(TT_AttributeSquare));
if (FormatTok->is(tok::identifier)) {
nextToken();
// If there are two identifiers in a row, this is likely an elaborate
Expand Down
9 changes: 0 additions & 9 deletions clang/lib/Format/UnwrappedLineParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,8 @@
#ifndef LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEPARSER_H
#define LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEPARSER_H

#include "Encoding.h"
#include "FormatToken.h"
#include "Macros.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Format/Format.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/Support/Regex.h"
#include <list>
#include <stack>
#include <vector>

namespace clang {
namespace format {
Expand Down
5 changes: 0 additions & 5 deletions clang/lib/Format/WhitespaceManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,6 @@

#include "TokenAnnotator.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Format/Format.h"
#include "llvm/ADT/SmallVector.h"
#include <algorithm>
#include <string>
#include <tuple>

namespace clang {
namespace format {
Expand Down
110 changes: 110 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,116 @@ double3 ceil(double3);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_ceil)
double4 ceil(double4);

//===----------------------------------------------------------------------===//
// clamp builtins
//===----------------------------------------------------------------------===//

/// \fn T clamp(T X, T Min, T Max)
/// \brief Clamps the specified value \a X to the specified
/// minimum ( \a Min) and maximum ( \a Max) range.
/// \param X A value to clamp.
/// \param Min The specified minimum range.
/// \param Max The specified maximum range.
///
/// Returns The clamped value for the \a X parameter.
/// For values of -INF or INF, clamp will behave as expected.
/// However for values of NaN, the results are undefined.

_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
half clamp(half, half, half);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
half2 clamp(half2, half2, half2);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
half3 clamp(half3, half3, half3);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
half4 clamp(half4, half4, half4);

#ifdef __HLSL_ENABLE_16_BIT
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
int16_t clamp(int16_t, int16_t, int16_t);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
int16_t2 clamp(int16_t2, int16_t2, int16_t2);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
int16_t3 clamp(int16_t3, int16_t3, int16_t3);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
int16_t4 clamp(int16_t4, int16_t4, int16_t4);

_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
uint16_t clamp(uint16_t, uint16_t, uint16_t);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
uint16_t2 clamp(uint16_t2, uint16_t2, uint16_t2);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
uint16_t3 clamp(uint16_t3, uint16_t3, uint16_t3);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
uint16_t4 clamp(uint16_t4, uint16_t4, uint16_t4);
#endif

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
int clamp(int, int, int);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
int2 clamp(int2, int2, int2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
int3 clamp(int3, int3, int3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
int4 clamp(int4, int4, int4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
uint clamp(uint, uint, uint);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
uint2 clamp(uint2, uint2, uint2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
uint3 clamp(uint3, uint3, uint3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
uint4 clamp(uint4, uint4, uint4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
int64_t clamp(int64_t, int64_t, int64_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
int64_t2 clamp(int64_t2, int64_t2, int64_t2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
int64_t3 clamp(int64_t3, int64_t3, int64_t3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
int64_t4 clamp(int64_t4, int64_t4, int64_t4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
uint64_t clamp(uint64_t, uint64_t, uint64_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
uint64_t2 clamp(uint64_t2, uint64_t2, uint64_t2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
uint64_t3 clamp(uint64_t3, uint64_t3, uint64_t3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
uint64_t4 clamp(uint64_t4, uint64_t4, uint64_t4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
float clamp(float, float, float);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
float2 clamp(float2, float2, float2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
float3 clamp(float3, float3, float3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
float4 clamp(float4, float4, float4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
double clamp(double, double, double);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
double2 clamp(double2, double2, double2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
double3 clamp(double3, double3, double3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
double4 clamp(double4, double4, double4);

//===----------------------------------------------------------------------===//
// cos builtins
//===----------------------------------------------------------------------===//
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/InstallAPI/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
set(LLVM_LINK_COMPONENTS
Support
TextAPI
Demangle
Core
)

add_clang_library(clangInstallAPI
DylibVerifier.cpp
FileList.cpp
Frontend.cpp
HeaderFile.cpp
Expand Down
212 changes: 212 additions & 0 deletions clang/lib/InstallAPI/DylibVerifier.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
#include "clang/InstallAPI/DylibVerifier.h"
#include "clang/InstallAPI/FrontendRecords.h"
#include "llvm/Demangle/Demangle.h"

using namespace llvm::MachO;

namespace clang {
namespace installapi {

/// Metadata stored about a mapping of a declaration to a symbol.
struct DylibVerifier::SymbolContext {
// Name to use for printing in diagnostics.
std::string PrettyPrintName{""};

// Name to use for all querying and verification
// purposes.
std::string SymbolName{""};

// Kind to map symbol type against record.
EncodeKind Kind = EncodeKind::GlobalSymbol;

// Frontend Attributes tied to the AST.
const FrontendAttrs *FA = nullptr;

// The ObjCInterface symbol type, if applicable.
ObjCIFSymbolKind ObjCIFKind = ObjCIFSymbolKind::None;
};

static std::string
getAnnotatedName(const Record *R, EncodeKind Kind, StringRef Name,
bool ValidSourceLoc = true,
ObjCIFSymbolKind ObjCIF = ObjCIFSymbolKind::None) {
assert(!Name.empty() && "Need symbol name for printing");

std::string Annotation;
if (R->isWeakDefined())
Annotation += "(weak-def) ";
if (R->isWeakReferenced())
Annotation += "(weak-ref) ";
if (R->isThreadLocalValue())
Annotation += "(tlv) ";

// Check if symbol represents only part of a @interface declaration.
const bool IsAnnotatedObjCClass = ((ObjCIF != ObjCIFSymbolKind::None) &&
(ObjCIF <= ObjCIFSymbolKind::EHType));

if (IsAnnotatedObjCClass) {
if (ObjCIF == ObjCIFSymbolKind::EHType)
Annotation += "Exception Type of ";
if (ObjCIF == ObjCIFSymbolKind::MetaClass)
Annotation += "Metaclass of ";
if (ObjCIF == ObjCIFSymbolKind::Class)
Annotation += "Class of ";
}

// Only print symbol type prefix or leading "_" if there is no source location
// tied to it. This can only ever happen when the location has to come from
// debug info.
if (ValidSourceLoc) {
if ((Kind == EncodeKind::GlobalSymbol) && Name.starts_with("_"))
return Annotation + Name.drop_front(1).str();
return Annotation + Name.str();
}

if (IsAnnotatedObjCClass)
return Annotation + Name.str();

switch (Kind) {
case EncodeKind::GlobalSymbol:
return Annotation + Name.str();
case EncodeKind::ObjectiveCInstanceVariable:
return Annotation + "(ObjC IVar) " + Name.str();
case EncodeKind::ObjectiveCClass:
return Annotation + "(ObjC Class) " + Name.str();
case EncodeKind::ObjectiveCClassEHType:
return Annotation + "(ObjC Class EH) " + Name.str();
}

llvm_unreachable("unexpected case for EncodeKind");
}

static std::string demangle(StringRef Name) {
// Itanium encoding requires 1 or 3 leading underscores, followed by 'Z'.
if (!(Name.starts_with("_Z") || Name.starts_with("___Z")))
return Name.str();
char *Result = llvm::itaniumDemangle(Name.data());
if (!Result)
return Name.str();

std::string Demangled(Result);
free(Result);
return Demangled;
}

static DylibVerifier::Result updateResult(const DylibVerifier::Result Prev,
const DylibVerifier::Result Curr) {
if (Prev == Curr)
return Prev;

// Never update from invalid or noverify state.
if ((Prev == DylibVerifier::Result::Invalid) ||
(Prev == DylibVerifier::Result::NoVerify))
return Prev;

// Don't let an ignored verification remove a valid one.
if (Prev == DylibVerifier::Result::Valid &&
Curr == DylibVerifier::Result::Ignore)
return Prev;

return Curr;
}

void DylibVerifier::updateState(Result State) {
Ctx.FrontendState = updateResult(Ctx.FrontendState, State);
}

void DylibVerifier::addSymbol(const Record *R, SymbolContext &SymCtx,
TargetList &&Targets) {
if (Targets.empty())
Targets = {Ctx.Target};

Exports->addGlobal(SymCtx.Kind, SymCtx.SymbolName, R->getFlags(), Targets);
}

DylibVerifier::Result DylibVerifier::verifyImpl(Record *R,
SymbolContext &SymCtx) {
R->setVerify();
if (!canVerify()) {
// Accumulate symbols when not in verifying against dylib.
if (R->isExported() && !SymCtx.FA->Avail.isUnconditionallyUnavailable() &&
!SymCtx.FA->Avail.isObsoleted()) {
addSymbol(R, SymCtx);
}
return Ctx.FrontendState;
}
return Ctx.FrontendState;
}

bool DylibVerifier::canVerify() {
return Ctx.FrontendState != Result::NoVerify;
}

void DylibVerifier::setTarget(const Target &T) {
Ctx.Target = T;
Ctx.DiscoveredFirstError = false;
updateState(Dylib.empty() ? Result::NoVerify : Result::Ignore);
}

DylibVerifier::Result DylibVerifier::verify(ObjCIVarRecord *R,
const FrontendAttrs *FA,
const StringRef SuperClass) {
if (R->isVerified())
return getState();

std::string FullName =
ObjCIVarRecord::createScopedName(SuperClass, R->getName());
SymbolContext SymCtx{
getAnnotatedName(R, EncodeKind::ObjectiveCInstanceVariable,
Demangle ? demangle(FullName) : FullName),
FullName, EncodeKind::ObjectiveCInstanceVariable, FA};
return verifyImpl(R, SymCtx);
}

static ObjCIFSymbolKind assignObjCIFSymbolKind(const ObjCInterfaceRecord *R) {
ObjCIFSymbolKind Result = ObjCIFSymbolKind::None;
if (R->getLinkageForSymbol(ObjCIFSymbolKind::Class) != RecordLinkage::Unknown)
Result |= ObjCIFSymbolKind::Class;
if (R->getLinkageForSymbol(ObjCIFSymbolKind::MetaClass) !=
RecordLinkage::Unknown)
Result |= ObjCIFSymbolKind::MetaClass;
if (R->getLinkageForSymbol(ObjCIFSymbolKind::EHType) !=
RecordLinkage::Unknown)
Result |= ObjCIFSymbolKind::EHType;
return Result;
}

DylibVerifier::Result DylibVerifier::verify(ObjCInterfaceRecord *R,
const FrontendAttrs *FA) {
if (R->isVerified())
return getState();
SymbolContext SymCtx;
SymCtx.SymbolName = R->getName();
SymCtx.ObjCIFKind = assignObjCIFSymbolKind(R);

std::string DisplayName =
Demangle ? demangle(SymCtx.SymbolName) : SymCtx.SymbolName;
SymCtx.Kind = R->hasExceptionAttribute() ? EncodeKind::ObjectiveCClassEHType
: EncodeKind::ObjectiveCClass;
SymCtx.PrettyPrintName = getAnnotatedName(R, SymCtx.Kind, DisplayName);
SymCtx.FA = FA;

return verifyImpl(R, SymCtx);
}

DylibVerifier::Result DylibVerifier::verify(GlobalRecord *R,
const FrontendAttrs *FA) {
if (R->isVerified())
return getState();

// Global classifications could be obfusciated with `asm`.
SimpleSymbol Sym = parseSymbol(R->getName());
SymbolContext SymCtx;
SymCtx.SymbolName = Sym.Name;
SymCtx.PrettyPrintName =
getAnnotatedName(R, Sym.Kind, Demangle ? demangle(Sym.Name) : Sym.Name);
SymCtx.Kind = Sym.Kind;
SymCtx.FA = FA;
return verifyImpl(R, SymCtx);
}

} // namespace installapi
} // namespace clang
49 changes: 28 additions & 21 deletions clang/lib/InstallAPI/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,41 +16,47 @@ using namespace llvm;
using namespace llvm::MachO;

namespace clang::installapi {

GlobalRecord *FrontendRecordsSlice::addGlobal(
std::pair<GlobalRecord *, FrontendAttrs *> FrontendRecordsSlice::addGlobal(
StringRef Name, RecordLinkage Linkage, GlobalRecord::Kind GV,
const clang::AvailabilityInfo Avail, const Decl *D, const HeaderType Access,
SymbolFlags Flags, bool Inlined) {

auto *GR =
GlobalRecord *GR =
llvm::MachO::RecordsSlice::addGlobal(Name, Linkage, GV, Flags, Inlined);
FrontendRecords.insert({GR, FrontendAttrs{Avail, D, Access}});
return GR;
auto Result = FrontendRecords.insert({GR, FrontendAttrs{Avail, D, Access}});
return {GR, &(Result.first->second)};
}

ObjCInterfaceRecord *FrontendRecordsSlice::addObjCInterface(
StringRef Name, RecordLinkage Linkage, const clang::AvailabilityInfo Avail,
const Decl *D, HeaderType Access, bool IsEHType) {
std::pair<ObjCInterfaceRecord *, FrontendAttrs *>
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 =

ObjCInterfaceRecord *ObjCR =
llvm::MachO::RecordsSlice::addObjCInterface(Name, Linkage, SymType);
FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}});
return ObjCR;
auto Result =
FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}});
return {ObjCR, &(Result.first->second)};
}

ObjCCategoryRecord *FrontendRecordsSlice::addObjCCategory(
StringRef ClassToExtend, StringRef CategoryName,
const clang::AvailabilityInfo Avail, const Decl *D, HeaderType Access) {
auto *ObjCR =
std::pair<ObjCCategoryRecord *, FrontendAttrs *>
FrontendRecordsSlice::addObjCCategory(StringRef ClassToExtend,
StringRef CategoryName,
const clang::AvailabilityInfo Avail,
const Decl *D, HeaderType Access) {
ObjCCategoryRecord *ObjCR =
llvm::MachO::RecordsSlice::addObjCCategory(ClassToExtend, CategoryName);
FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}});
return ObjCR;
auto Result =
FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}});
return {ObjCR, &(Result.first->second)};
}

ObjCIVarRecord *FrontendRecordsSlice::addObjCIVar(
std::pair<ObjCIVarRecord *, FrontendAttrs *> FrontendRecordsSlice::addObjCIVar(
ObjCContainerRecord *Container, StringRef IvarName, RecordLinkage Linkage,
const clang::AvailabilityInfo Avail, const Decl *D, HeaderType Access,
const clang::ObjCIvarDecl::AccessControl AC) {
Expand All @@ -59,11 +65,12 @@ ObjCIVarRecord *FrontendRecordsSlice::addObjCIVar(
if ((Linkage == RecordLinkage::Exported) &&
((AC == ObjCIvarDecl::Private) || (AC == ObjCIvarDecl::Package)))
Linkage = RecordLinkage::Internal;
auto *ObjCR =
ObjCIVarRecord *ObjCR =
llvm::MachO::RecordsSlice::addObjCIVar(Container, IvarName, Linkage);
FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}});
auto Result =
FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}});

return nullptr;
return {ObjCR, &(Result.first->second)};
}

std::optional<HeaderType>
Expand Down
101 changes: 61 additions & 40 deletions clang/lib/InstallAPI/Visitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "clang/AST/ParentMapContext.h"
#include "clang/AST/VTableBuilder.h"
#include "clang/Basic/Linkage.h"
#include "clang/InstallAPI/DylibVerifier.h"
#include "clang/InstallAPI/FrontendRecords.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
Expand Down Expand Up @@ -156,7 +157,9 @@ void InstallAPIVisitor::recordObjCInstanceVariables(
StringRef Name = IV->getName();
const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(IV);
auto AC = IV->getCanonicalAccessControl();
Ctx.Slice->addObjCIVar(Record, Name, Linkage, Avail, IV, *Access, AC);
auto [ObjCIVR, FA] =
Ctx.Slice->addObjCIVar(Record, Name, Linkage, Avail, IV, *Access, AC);
Ctx.Verifier->verify(ObjCIVR, FA, SuperClass);
}
}

Expand All @@ -178,15 +181,16 @@ bool InstallAPIVisitor::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
(!D->getASTContext().getLangOpts().ObjCRuntime.isFragile() &&
hasObjCExceptionAttribute(D));

ObjCInterfaceRecord *Class =
auto [Class, FA] =
Ctx.Slice->addObjCInterface(Name, Linkage, Avail, D, *Access, IsEHType);
Ctx.Verifier->verify(Class, FA);

// Get base class.
StringRef SuperClassName;
if (const auto *SuperClass = D->getSuperClass())
SuperClassName = SuperClass->getObjCRuntimeNameAsString();

recordObjCInstanceVariables(D->getASTContext(), Class, SuperClassName,
recordObjCInstanceVariables(D->getASTContext(), Class, Class->getName(),
D->ivars());
return true;
}
Expand All @@ -201,8 +205,8 @@ bool InstallAPIVisitor::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
const ObjCInterfaceDecl *InterfaceD = D->getClassInterface();
const StringRef InterfaceName = InterfaceD->getName();

ObjCCategoryRecord *Category = Ctx.Slice->addObjCCategory(
InterfaceName, CategoryName, Avail, D, *Access);
auto [Category, FA] = Ctx.Slice->addObjCCategory(InterfaceName, CategoryName,
Avail, D, *Access);
recordObjCInstanceVariables(D->getASTContext(), Category, InterfaceName,
D->ivars());
return true;
Expand Down Expand Up @@ -236,8 +240,10 @@ bool InstallAPIVisitor::VisitVarDecl(const VarDecl *D) {
const bool WeakDef = D->hasAttr<WeakAttr>();
const bool ThreadLocal = D->getTLSKind() != VarDecl::TLS_None;
const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
Ctx.Slice->addGlobal(getMangledName(D), Linkage, GlobalRecord::Kind::Variable,
Avail, D, *Access, getFlags(WeakDef, ThreadLocal));
auto [GR, FA] = Ctx.Slice->addGlobal(getMangledName(D), Linkage,
GlobalRecord::Kind::Variable, Avail, D,
*Access, getFlags(WeakDef, ThreadLocal));
Ctx.Verifier->verify(GR, FA);
return true;
}

Expand Down Expand Up @@ -287,8 +293,10 @@ bool InstallAPIVisitor::VisitFunctionDecl(const FunctionDecl *D) {
const RecordLinkage Linkage = (Inlined || !isExported(D))
? RecordLinkage::Internal
: RecordLinkage::Exported;
Ctx.Slice->addGlobal(Name, Linkage, GlobalRecord::Kind::Function, Avail, D,
*Access, getFlags(WeakDef), Inlined);
auto [GR, FA] =
Ctx.Slice->addGlobal(Name, Linkage, GlobalRecord::Kind::Function, Avail,
D, *Access, getFlags(WeakDef), Inlined);
Ctx.Verifier->verify(GR, FA);
return true;
}

Expand Down Expand Up @@ -478,9 +486,10 @@ void InstallAPIVisitor::emitVTableSymbols(const CXXRecordDecl *D,
VTableLinkage == CXXLinkage::WeakODRLinkage) {
const std::string Name = getMangledCXXVTableName(D);
const bool WeakDef = VTableLinkage == CXXLinkage::WeakODRLinkage;
Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
GlobalRecord::Kind::Variable, Avail, D, Access,
getFlags(WeakDef));
auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
GlobalRecord::Kind::Variable, Avail,
D, Access, getFlags(WeakDef));
Ctx.Verifier->verify(GR, FA);
if (!D->getDescribedClassTemplate() && !D->isInvalidDecl()) {
VTableContextBase *VTable = D->getASTContext().getVTableContext();
auto AddThunk = [&](GlobalDecl GD) {
Expand All @@ -491,9 +500,10 @@ void InstallAPIVisitor::emitVTableSymbols(const CXXRecordDecl *D,

for (const auto &Thunk : *Thunks) {
const std::string Name = getMangledCXXThunk(GD, Thunk);
Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
GlobalRecord::Kind::Function, Avail,
GD.getDecl(), Access);
auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
GlobalRecord::Kind::Function,
Avail, GD.getDecl(), Access);
Ctx.Verifier->verify(GR, FA);
}
};

Expand All @@ -519,12 +529,16 @@ void InstallAPIVisitor::emitVTableSymbols(const CXXRecordDecl *D,

if (hasRTTI(D)) {
std::string Name = getMangledCXXRTTI(D);
Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
GlobalRecord::Kind::Variable, Avail, D, Access);
auto [GR, FA] =
Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
GlobalRecord::Kind::Variable, Avail, D, Access);
Ctx.Verifier->verify(GR, FA);

Name = getMangledCXXRTTIName(D);
Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
GlobalRecord::Kind::Variable, Avail, D, Access);
auto [NamedGR, NamedFA] =
Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
GlobalRecord::Kind::Variable, Avail, D, Access);
Ctx.Verifier->verify(NamedGR, NamedFA);
}

for (const auto &It : D->bases()) {
Expand Down Expand Up @@ -615,15 +629,17 @@ bool InstallAPIVisitor::VisitCXXRecordDecl(const CXXRecordDecl *D) {
continue;

std::string Name = getMangledCtorDtor(M, Ctor_Base);
Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
GlobalRecord::Kind::Function, Avail, D, *Access,
getFlags(WeakDef));
auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
GlobalRecord::Kind::Function, Avail,
D, *Access, getFlags(WeakDef));
Ctx.Verifier->verify(GR, FA);

if (!D->isAbstract()) {
std::string Name = getMangledCtorDtor(M, Ctor_Complete);
Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
GlobalRecord::Kind::Function, Avail, D, *Access,
getFlags(WeakDef));
auto [GR, FA] = Ctx.Slice->addGlobal(
Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail,
D, *Access, getFlags(WeakDef));
Ctx.Verifier->verify(GR, FA);
}

continue;
Expand All @@ -635,20 +651,23 @@ bool InstallAPIVisitor::VisitCXXRecordDecl(const CXXRecordDecl *D) {
continue;

std::string Name = getMangledCtorDtor(M, Dtor_Base);
Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
GlobalRecord::Kind::Function, Avail, D, *Access,
getFlags(WeakDef));
auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
GlobalRecord::Kind::Function, Avail,
D, *Access, getFlags(WeakDef));
Ctx.Verifier->verify(GR, FA);

Name = getMangledCtorDtor(M, Dtor_Complete);
Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
GlobalRecord::Kind::Function, Avail, D, *Access,
getFlags(WeakDef));
auto [CompleteGR, CompleteFA] = Ctx.Slice->addGlobal(
Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail, D,
*Access, getFlags(WeakDef));
Ctx.Verifier->verify(CompleteGR, CompleteFA);

if (Dtor->isVirtual()) {
Name = getMangledCtorDtor(M, Dtor_Deleting);
Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
GlobalRecord::Kind::Function, Avail, D, *Access,
getFlags(WeakDef));
auto [VirtualGR, VirtualFA] = Ctx.Slice->addGlobal(
Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail,
D, *Access, getFlags(WeakDef));
Ctx.Verifier->verify(VirtualGR, VirtualFA);
}

continue;
Expand All @@ -661,9 +680,10 @@ bool InstallAPIVisitor::VisitCXXRecordDecl(const CXXRecordDecl *D) {
continue;

std::string Name = getMangledName(M);
Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
GlobalRecord::Kind::Function, Avail, D, *Access,
getFlags(WeakDef));
auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
GlobalRecord::Kind::Function, Avail, D,
*Access, getFlags(WeakDef));
Ctx.Verifier->verify(GR, FA);
}

if (auto *Templ = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
Expand Down Expand Up @@ -694,9 +714,10 @@ bool InstallAPIVisitor::VisitCXXRecordDecl(const CXXRecordDecl *D) {
const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(Var);
const bool WeakDef = Var->hasAttr<WeakAttr>() || KeepInlineAsWeak;

Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
GlobalRecord::Kind::Variable, Avail, D, *Access,
getFlags(WeakDef));
auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
GlobalRecord::Kind::Variable, Avail, D,
*Access, getFlags(WeakDef));
Ctx.Verifier->verify(GR, FA);
}

return true;
Expand Down
15 changes: 14 additions & 1 deletion clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5499,6 +5499,17 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return true;
break;
}
case Builtin::BI__builtin_hlsl_elementwise_clamp: {
if (checkArgCount(*this, TheCall, 3))
return true;
if (CheckVectorElementCallArgs(this, TheCall))
return true;
if (SemaBuiltinElementwiseTernaryMath(
TheCall, /*CheckForFloatArgs*/
TheCall->getArg(0)->getType()->hasFloatingRepresentation()))
return true;
break;
}
case Builtin::BI__builtin_hlsl_dot: {
if (checkArgCount(*this, TheCall, 2))
return true;
Expand Down Expand Up @@ -5547,7 +5558,9 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return true;
if (CheckVectorElementCallArgs(this, TheCall))
return true;
if (SemaBuiltinElementwiseTernaryMath(TheCall, /*CheckForFloatArgs*/ false))
if (SemaBuiltinElementwiseTernaryMath(
TheCall, /*CheckForFloatArgs*/
TheCall->getArg(0)->getType()->hasFloatingRepresentation()))
return true;
}
}
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Sema/SemaConcept.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -692,11 +692,15 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
// A lambda conversion operator has the same constraints as the call operator
// and constraints checking relies on whether we are in a lambda call operator
// (and may refer to its parameters), so check the call operator instead.
// Note that the declarations outside of the lambda should also be
// considered. Turning on the 'ForOverloadResolution' flag results in the
// LocalInstantiationScope not looking into its parents, but we can still
// access Decls from the parents while building a lambda RAII scope later.
if (const auto *MD = dyn_cast<CXXConversionDecl>(FD);
MD && isLambdaConversionOperator(const_cast<CXXConversionDecl *>(MD)))
return CheckFunctionConstraints(MD->getParent()->getLambdaCallOperator(),
Satisfaction, UsageLoc,
ForOverloadResolution);
/*ShouldAddDeclsFromParentScope=*/true);

DeclContext *CtxToSave = const_cast<FunctionDecl *>(FD);

Expand Down
2 changes: 2 additions & 0 deletions clang/test/AST/Interp/builtin-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,9 @@ namespace bswap {
#define CFSTR __builtin___CFStringMakeConstantString
void test7(void) {
const void *X;
#if !defined(_AIX)
X = CFSTR("\242"); // both-warning {{input conversion stopped}}
#endif
X = CFSTR("\0"); // no-warning
X = CFSTR(242); // both-error {{cannot initialize a parameter of type 'const char *' with an rvalue of type 'int'}}
X = CFSTR("foo", "bar"); // both-error {{too many arguments to function call}}
Expand Down
12 changes: 12 additions & 0 deletions clang/test/AST/Interp/literals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,18 @@ namespace TypeTraits {
struct U {};
static_assert(S3<U>{}.foo(), "");
static_assert(!S3<T>{}.foo(), "");

typedef int Int;
typedef Int IntAr[10];
typedef const IntAr ConstIntAr;
typedef ConstIntAr ConstIntArAr[4];

static_assert(__array_rank(IntAr) == 1, "");
static_assert(__array_rank(ConstIntArAr) == 2, "");

static_assert(__array_extent(IntAr, 0) == 10, "");
static_assert(__array_extent(ConstIntArAr, 0) == 4, "");
static_assert(__array_extent(ConstIntArAr, 1) == 10, "");
}

#if __cplusplus >= 201402L
Expand Down
17 changes: 17 additions & 0 deletions clang/test/CodeGenCXX/mangle-ms-back-references.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,20 @@ class H;

void ManyParams(T01 &, T02 &, T03 &, T04 &, T05 &, T06 &, T07 &, T08 &, T09 &, T10 &, H<T11> &, H<T11> &) {}
// CHECK: "?ManyParams@@YAXAAVT01@@AAVT02@@AAVT03@@AAVT04@@AAVT05@@AAVT06@@AAVT07@@AAVT08@@AAVT09@@AAVT10@@AAV?$H@VT11@@@@AAV?$H@VT11@@@@@Z"

namespace NS {
// The name "TSS0" for the name of the class below has been specifically
// chosen to ensure that back reference lookup does not match against the
// implicitly generated "$TSS0" name of the thread safe static initialization
// variable.
struct __declspec(dllexport) TSS0 {
static TSS0& get();
__forceinline static TSS0& singleton() {
static TSS0& lsv = get();
return lsv;
}
};
}
// CHECK: "?singleton@TSS0@NS@@SAAAU12@XZ"
// CHECK: "?lsv@?1??singleton@TSS0@NS@@SAAAU23@XZ@4AAU23@A"
// CHECK: "?$TSS0@?1??singleton@TSS0@NS@@SAAAU23@XZ@4HA"
8 changes: 8 additions & 0 deletions clang/test/CodeGenHLSL/builtins/clamp-builtin.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -o - | FileCheck %s

// CHECK-LABEL: builtin_test_clamp_int4
// CHECK: %dx.clamp = call <4 x i32> @llvm.dx.clamp.v4i32(<4 x i32> %0, <4 x i32> %1, <4 x i32> %2)
// CHECK: ret <4 x i32> %dx.clamp
int4 builtin_test_clamp_int4(int4 p0, int4 p1, int4 p2) {
return __builtin_hlsl_elementwise_clamp(p0, p1, p2);
}
134 changes: 134 additions & 0 deletions clang/test/CodeGenHLSL/builtins/clamp.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// RUN: %clang_cc1 -std=hlsl2021 -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 -std=hlsl2021 -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

#ifdef __HLSL_ENABLE_16_BIT
// NATIVE_HALF: define noundef i16 @
// NATIVE_HALF: call i16 @llvm.dx.clamp.i16(
int16_t test_clamp_short(int16_t p0, int16_t p1) { return clamp(p0, p1,p1); }
// NATIVE_HALF: define noundef <2 x i16> @
// NATIVE_HALF: call <2 x i16> @llvm.dx.clamp.v2i16(
int16_t2 test_clamp_short2(int16_t2 p0, int16_t2 p1) { return clamp(p0, p1,p1); }
// NATIVE_HALF: define noundef <3 x i16> @
// NATIVE_HALF: call <3 x i16> @llvm.dx.clamp.v3i16
int16_t3 test_clamp_short3(int16_t3 p0, int16_t3 p1) { return clamp(p0, p1,p1); }
// NATIVE_HALF: define noundef <4 x i16> @
// NATIVE_HALF: call <4 x i16> @llvm.dx.clamp.v4i16
int16_t4 test_clamp_short4(int16_t4 p0, int16_t4 p1) { return clamp(p0, p1,p1); }

// NATIVE_HALF: define noundef i16 @
// NATIVE_HALF: call i16 @llvm.dx.uclamp.i16(
uint16_t test_clamp_ushort(uint16_t p0, uint16_t p1) { return clamp(p0, p1,p1); }
// NATIVE_HALF: define noundef <2 x i16> @
// NATIVE_HALF: call <2 x i16> @llvm.dx.uclamp.v2i16
uint16_t2 test_clamp_ushort2(uint16_t2 p0, uint16_t2 p1) { return clamp(p0, p1,p1); }
// NATIVE_HALF: define noundef <3 x i16> @
// NATIVE_HALF: call <3 x i16> @llvm.dx.uclamp.v3i16
uint16_t3 test_clamp_ushort3(uint16_t3 p0, uint16_t3 p1) { return clamp(p0, p1,p1); }
// NATIVE_HALF: define noundef <4 x i16> @
// NATIVE_HALF: call <4 x i16> @llvm.dx.uclamp.v4i16
uint16_t4 test_clamp_ushort4(uint16_t4 p0, uint16_t4 p1) { return clamp(p0, p1,p1); }
#endif

// CHECK: define noundef i32 @
// CHECK: call i32 @llvm.dx.clamp.i32(
int test_clamp_int(int p0, int p1) { return clamp(p0, p1,p1); }
// CHECK: define noundef <2 x i32> @
// CHECK: call <2 x i32> @llvm.dx.clamp.v2i32
int2 test_clamp_int2(int2 p0, int2 p1) { return clamp(p0, p1,p1); }
// CHECK: define noundef <3 x i32> @
// CHECK: call <3 x i32> @llvm.dx.clamp.v3i32
int3 test_clamp_int3(int3 p0, int3 p1) { return clamp(p0, p1,p1); }
// CHECK: define noundef <4 x i32> @
// CHECK: call <4 x i32> @llvm.dx.clamp.v4i32
int4 test_clamp_int4(int4 p0, int4 p1) { return clamp(p0, p1,p1); }

// CHECK: define noundef i32 @
// CHECK: call i32 @llvm.dx.uclamp.i32(
int test_clamp_uint(uint p0, uint p1) { return clamp(p0, p1,p1); }
// CHECK: define noundef <2 x i32> @
// CHECK: call <2 x i32> @llvm.dx.uclamp.v2i32
uint2 test_clamp_uint2(uint2 p0, uint2 p1) { return clamp(p0, p1,p1); }
// CHECK: define noundef <3 x i32> @
// CHECK: call <3 x i32> @llvm.dx.uclamp.v3i32
uint3 test_clamp_uint3(uint3 p0, uint3 p1) { return clamp(p0, p1,p1); }
// CHECK: define noundef <4 x i32> @
// CHECK: call <4 x i32> @llvm.dx.uclamp.v4i32
uint4 test_clamp_uint4(uint4 p0, uint4 p1) { return clamp(p0, p1,p1); }

// CHECK: define noundef i64 @
// CHECK: call i64 @llvm.dx.clamp.i64(
int64_t test_clamp_long(int64_t p0, int64_t p1) { return clamp(p0, p1,p1); }
// CHECK: define noundef <2 x i64> @
// CHECK: call <2 x i64> @llvm.dx.clamp.v2i64
int64_t2 test_clamp_long2(int64_t2 p0, int64_t2 p1) { return clamp(p0, p1,p1); }
// CHECK: define noundef <3 x i64> @
// CHECK: call <3 x i64> @llvm.dx.clamp.v3i64
int64_t3 test_clamp_long3(int64_t3 p0, int64_t3 p1) { return clamp(p0, p1,p1); }
// CHECK: define noundef <4 x i64> @
// CHECK: call <4 x i64> @llvm.dx.clamp.v4i64
int64_t4 test_clamp_long4(int64_t4 p0, int64_t4 p1) { return clamp(p0, p1,p1); }

// CHECK: define noundef i64 @
// CHECK: call i64 @llvm.dx.uclamp.i64(
uint64_t test_clamp_long(uint64_t p0, uint64_t p1) { return clamp(p0, p1,p1); }
// CHECK: define noundef <2 x i64> @
// CHECK: call <2 x i64> @llvm.dx.uclamp.v2i64
uint64_t2 test_clamp_long2(uint64_t2 p0, uint64_t2 p1) { return clamp(p0, p1,p1); }
// CHECK: define noundef <3 x i64> @
// CHECK: call <3 x i64> @llvm.dx.uclamp.v3i64
uint64_t3 test_clamp_long3(uint64_t3 p0, uint64_t3 p1) { return clamp(p0, p1,p1); }
// CHECK: define noundef <4 x i64> @
// CHECK: call <4 x i64> @llvm.dx.uclamp.v4i64
uint64_t4 test_clamp_long4(uint64_t4 p0, uint64_t4 p1) { return clamp(p0, p1,p1); }

// NATIVE_HALF: define noundef half @
// NATIVE_HALF: call half @llvm.dx.clamp.f16(
// NO_HALF: define noundef float @"?test_clamp_half
// NO_HALF: call float @llvm.dx.clamp.f32(
half test_clamp_half(half p0, half p1) { return clamp(p0, p1,p1); }
// NATIVE_HALF: define noundef <2 x half> @
// NATIVE_HALF: call <2 x half> @llvm.dx.clamp.v2f16
// NO_HALF: define noundef <2 x float> @"?test_clamp_half2
// NO_HALF: call <2 x float> @llvm.dx.clamp.v2f32(
half2 test_clamp_half2(half2 p0, half2 p1) { return clamp(p0, p1,p1); }
// NATIVE_HALF: define noundef <3 x half> @
// NATIVE_HALF: call <3 x half> @llvm.dx.clamp.v3f16
// NO_HALF: define noundef <3 x float> @"?test_clamp_half3
// NO_HALF: call <3 x float> @llvm.dx.clamp.v3f32(
half3 test_clamp_half3(half3 p0, half3 p1) { return clamp(p0, p1,p1); }
// NATIVE_HALF: define noundef <4 x half> @
// NATIVE_HALF: call <4 x half> @llvm.dx.clamp.v4f16
// NO_HALF: define noundef <4 x float> @"?test_clamp_half4
// NO_HALF: call <4 x float> @llvm.dx.clamp.v4f32(
half4 test_clamp_half4(half4 p0, half4 p1) { return clamp(p0, p1,p1); }

// CHECK: define noundef float @"?test_clamp_float
// CHECK: call float @llvm.dx.clamp.f32(
float test_clamp_float(float p0, float p1) { return clamp(p0, p1,p1); }
// CHECK: define noundef <2 x float> @"?test_clamp_float2
// CHECK: call <2 x float> @llvm.dx.clamp.v2f32
float2 test_clamp_float2(float2 p0, float2 p1) { return clamp(p0, p1,p1); }
// CHECK: define noundef <3 x float> @"?test_clamp_float3
// CHECK: call <3 x float> @llvm.dx.clamp.v3f32
float3 test_clamp_float3(float3 p0, float3 p1) { return clamp(p0, p1,p1); }
// CHECK: define noundef <4 x float> @"?test_clamp_float4
// CHECK: call <4 x float> @llvm.dx.clamp.v4f32
float4 test_clamp_float4(float4 p0, float4 p1) { return clamp(p0, p1,p1); }

// CHECK: define noundef double @
// CHECK: call double @llvm.dx.clamp.f64(
double test_clamp_double(double p0, double p1) { return clamp(p0, p1,p1); }
// CHECK: define noundef <2 x double> @
// CHECK: call <2 x double> @llvm.dx.clamp.v2f64
double2 test_clamp_double2(double2 p0, double2 p1) { return clamp(p0, p1,p1); }
// CHECK: define noundef <3 x double> @
// CHECK: call <3 x double> @llvm.dx.clamp.v3f64
double3 test_clamp_double3(double3 p0, double3 p1) { return clamp(p0, p1,p1); }
// CHECK: define noundef <4 x double> @
// CHECK: call <4 x double> @llvm.dx.clamp.v4f64
double4 test_clamp_double4(double4 p0, double4 p1) { return clamp(p0, p1,p1); }
90 changes: 90 additions & 0 deletions clang/test/InstallAPI/asm.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// 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: -I%t/usr/include \
// RUN: -install_name @rpath/lib/libasm.dylib \
// RUN: %t/inputs.json -o %t/output.tbd 2>&1 | FileCheck %s --allow-empty
// RUN: llvm-readtapi -compare %t/output.tbd %t/expected.tbd 2>&1 | FileCheck %s --allow-empty

// CHECK-NOT: error:
// CHECK-NOT: warning:

//--- usr/include/asm.h
#ifndef ASM_H
#define ASM_H

extern int ivar __asm("_OBJC_IVAR_$_SomeClass._ivar1");
extern int objcClass1 __asm("_OBJC_CLASS_$_SomeClass");
extern int objcClass2 __asm("_OBJC_METACLASS_$_SomeClass");
extern int objcClass3 __asm("_OBJC_EHTYPE_$_SomeClass");
extern int objcClass4 __asm(".objc_class_name_SomeClass");

__attribute__((visibility("hidden")))
@interface NSString {
}
@end

extern int ivarExtra __asm("_OBJC_IVAR_$_NSString._ivar1");
#endif // ASM_H

//--- inputs.json.in
{
"headers": [ {
"path" : "DSTROOT/usr/include/asm.h",
"type" : "public"
}],
"version": "3"
}

//--- expected.tbd
{
"main_library": {
"compatibility_versions": [
{
"version": "0"
}
],
"current_versions": [
{
"version": "0"
}
],
"exported_symbols": [
{
"data": {
"objc_class": [
"SomeClass"
],
"objc_eh_type": [
"SomeClass"
],
"objc_ivar": [
"NSString._ivar1",
"SomeClass._ivar1"
]
}
}
],
"flags": [
{
"attributes": [
"not_app_extension_safe"
]
}
],
"install_names": [
{
"name": "@rpath/lib/libasm.dylib"
}
],
"target_info": [
{
"min_deployment": "13.1",
"target": "arm64-macos"
}
]
},
"tapi_tbd_version": 5
}
7 changes: 6 additions & 1 deletion clang/test/InstallAPI/driver-invalid-options.test
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
/// Check non-darwin triple is rejected.
// RUN: not clang-installapi -target x86_64-unknown-unknown %s 2> %t
// RUN: not clang-installapi -target x86_64-unknown-unknown %s -o tmp.tbd 2> %t
// RUN: FileCheck --check-prefix INVALID_INSTALLAPI -input-file %t %s
// INVALID_INSTALLAPI: error: unsupported option 'installapi' for target 'x86_64-unknown-unknown'

/// Check that missing install_name is reported.
// RUN: not clang-installapi -target x86_64-apple-ios-simulator %s -o tmp.tbd 2> %t
// RUN: FileCheck --check-prefix INVALID_INSTALL_NAME -input-file %t %s
// INVALID_INSTALL_NAME: error: no install name specified: add -install_name <path>
2 changes: 1 addition & 1 deletion clang/test/InstallAPI/functions.test
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

// RUN: clang-installapi -target arm64-apple-macos13.1 \
// RUN: -I%t/usr/include -I%t/usr/local/include \
// RUN: -install_name @rpath/lib/libfunctions.dylib \
// RUN: -install_name @rpath/lib/libfunctions.dylib --filetype=tbd-v4 \
// RUN: %t/inputs.json -o %t/outputs.tbd 2>&1 | FileCheck %s --allow-empty
// RUN: llvm-readtapi -compare %t/outputs.tbd %t/expected.tbd 2>&1 | FileCheck %s --allow-empty

Expand Down
10 changes: 10 additions & 0 deletions clang/test/SemaCXX/cxx23-assume.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,13 @@ static_assert(f5<D>() == 1); // expected-note 3 {{while checking constraint sati
static_assert(f5<double>() == 2);
static_assert(f5<E>() == 1); // expected-note {{while checking constraint satisfaction}} expected-note {{in instantiation of}}
static_assert(f5<F>() == 2); // expected-note {{while checking constraint satisfaction}} expected-note {{in instantiation of}}

// Do not validate assumptions whose evaluation would have side-effects.
constexpr int foo() {
int a = 0;
[[assume(a++)]] [[assume(++a)]]; // expected-warning 2 {{has side effects that will be discarded}} ext-warning 2 {{C++23 extension}}
[[assume((a+=1))]]; // expected-warning {{has side effects that will be discarded}} ext-warning {{C++23 extension}}
return a;
}

static_assert(foo() == 0);
21 changes: 13 additions & 8 deletions clang/test/SemaCXX/lambda-expressions.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// RUN: %clang_cc1 -std=c++11 -Wno-unused-value -fsyntax-only -verify=expected,expected-cxx14,cxx11 -fblocks %s
// RUN: %clang_cc1 -std=c++14 -Wno-unused-value -fsyntax-only -verify -verify=expected-cxx14 -fblocks %s
// RUN: %clang_cc1 -std=c++17 -Wno-unused-value -verify -ast-dump -fblocks %s | FileCheck %s

Expand Down Expand Up @@ -558,8 +559,8 @@ struct B {
int x;
A a = [&] { int y = x; };
A b = [&] { [&] { [&] { int y = x; }; }; };
A d = [&](auto param) { int y = x; };
A e = [&](auto param) { [&] { [&](auto param2) { int y = x; }; }; };
A d = [&](auto param) { int y = x; }; // cxx11-error {{'auto' not allowed in lambda parameter}}
A e = [&](auto param) { [&] { [&](auto param2) { int y = x; }; }; }; // cxx11-error 2 {{'auto' not allowed in lambda parameter}}
};

B<int> b;
Expand Down Expand Up @@ -589,6 +590,7 @@ struct S1 {
void foo1() {
auto s0 = S1{[name=]() {}}; // expected-error 2 {{expected expression}}
auto s1 = S1{[name=name]() {}}; // expected-error {{use of undeclared identifier 'name'; did you mean 'name1'?}}
// cxx11-warning@-1 {{initialized lambda captures are a C++14 extension}}
}
}

Expand All @@ -604,7 +606,7 @@ namespace PR25627_dont_odr_use_local_consts {

namespace ConversionOperatorDoesNotHaveDeducedReturnType {
auto x = [](int){};
auto y = [](auto &v) -> void { v.n = 0; };
auto y = [](auto &v) -> void { v.n = 0; }; // cxx11-error {{'auto' not allowed in lambda parameter}} cxx11-note {{candidate function not viable}} cxx11-note {{conversion candidate}}
using T = decltype(x);
using U = decltype(y);
using ExpectedTypeT = void (*)(int);
Expand All @@ -624,22 +626,22 @@ namespace ConversionOperatorDoesNotHaveDeducedReturnType {
template<typename T>
friend constexpr U::operator ExpectedTypeU<T>() const noexcept;
#else
friend auto T::operator()(int) const;
friend auto T::operator()(int) const; // cxx11-error {{'auto' return without trailing return type; deduced return types are a C++14 extension}}
friend T::operator ExpectedTypeT() const;

template<typename T>
friend void U::operator()(T&) const;
friend void U::operator()(T&) const; // cxx11-error {{friend declaration of 'operator()' does not match any declaration}}
// FIXME: This should not match, as above.
template<typename T>
friend U::operator ExpectedTypeU<T>() const;
friend U::operator ExpectedTypeU<T>() const; // cxx11-error {{friend declaration of 'operator void (*)(type-parameter-0-0 &)' does not match any declaration}}
#endif

private:
int n;
};

// Should be OK: lambda's call operator is a friend.
void use(X &x) { y(x); }
// Should be OK in C++14 and later: lambda's call operator is a friend.
void use(X &x) { y(x); } // cxx11-error {{no matching function for call to object}}

// This used to crash in return type deduction for the conversion opreator.
struct A { int n; void f() { +[](decltype(n)) {}; } };
Expand Down Expand Up @@ -733,6 +735,8 @@ void GH67492() {
auto lambda = (test, []() noexcept(true) {});
}

// FIXME: This currently causes clang to crash in C++11 mode.
#if __cplusplus >= 201402L
namespace GH83267 {
auto l = [](auto a) { return 1; };
using type = decltype(l);
Expand All @@ -747,3 +751,4 @@ using t = decltype(ll);
template auto t::operator()<int>(int a) const; // expected-note {{in instantiation}}

}
#endif
91 changes: 91 additions & 0 deletions clang/test/SemaHLSL/BuiltIns/clamp-errors.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// 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

float2 test_no_second_arg(float2 p0) {
return __builtin_hlsl_elementwise_clamp(p0);
// expected-error@-1 {{too few arguments to function call, expected 3, have 1}}
}

float2 test_no_third_arg(float2 p0) {
return __builtin_hlsl_elementwise_clamp(p0, p0);
// expected-error@-1 {{too few arguments to function call, expected 3, have 2}}
}

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

float2 test_clamp_no_second_arg(float2 p0) {
return clamp(p0);
// expected-error@-1 {{no matching function for call to 'clamp'}}
}

float2 test_clamp_vector_size_mismatch(float3 p0, float2 p1) {
return clamp(p0, p0, p1);
// expected-warning@-1 {{implicit conversion truncates vector: 'float3' (aka 'vector<float, 3>') to 'float __attribute__((ext_vector_type(2)))' (vector of 2 'float' values)}}
}

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

float test_clamp_scalar_mismatch(float p0, half p1) {
return clamp(p1, p0, p1);
// expected-error@-1 {{call to 'clamp' is ambiguous}}
}

float2 test_clamp_element_type_mismatch(half2 p0, float2 p1) {
return clamp(p1, p0, p1);
// expected-error@-1 {{call to 'clamp' is ambiguous}}
}

float2 test_builtin_clamp_float2_splat(float p0, float2 p1) {
return __builtin_hlsl_elementwise_clamp(p0, p1, p1);
// expected-error@-1 {{all arguments to '__builtin_hlsl_elementwise_clamp' must be vectors}}
}

float3 test_builtin_clamp_float3_splat(float p0, float3 p1) {
return __builtin_hlsl_elementwise_clamp(p0, p1, p1);
// expected-error@-1 {{all arguments to '__builtin_hlsl_elementwise_clamp' must be vectors}}
}

float4 test_builtin_clamp_float4_splat(float p0, float4 p1) {
return __builtin_hlsl_elementwise_clamp(p0, p1, p1);
// expected-error@-1 {{all arguments to '__builtin_hlsl_elementwise_clamp' must be vectors}}
}

float2 test_clamp_float2_int_splat(float2 p0, int p1) {
return __builtin_hlsl_elementwise_clamp(p0, p1, p1);
// expected-error@-1 {{all arguments to '__builtin_hlsl_elementwise_clamp' must be vectors}}
}

float3 test_clamp_float3_int_splat(float3 p0, int p1) {
return __builtin_hlsl_elementwise_clamp(p0, p1, p1);
// expected-error@-1 {{all arguments to '__builtin_hlsl_elementwise_clamp' must be vectors}}
}

float2 test_builtin_clamp_int_vect_to_float_vec_promotion(int2 p0, float p1) {
return __builtin_hlsl_elementwise_clamp(p0, p1, p1);
// expected-error@-1 {{all arguments to '__builtin_hlsl_elementwise_clamp' must be vectors}}
}

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

float builtin_bool_to_float_type_promotion(float p0, bool p1) {
return __builtin_hlsl_elementwise_clamp(p0, p0, p1);
// expected-error@-1 {{3rd argument must be a floating point type (was 'bool')}}
}

float builtin_bool_to_float_type_promotion2(bool p0, float p1) {
return __builtin_hlsl_elementwise_clamp(p1, p0, p1);
// expected-error@-1 {{2nd argument must be a floating point type (was 'bool')}}
}

float builtin_clamp_int_to_float_promotion(float p0, int p1) {
return __builtin_hlsl_elementwise_clamp(p0, p0, p1);
// expected-error@-1 {{3rd argument must be a floating point type (was 'int')}}
}
6 changes: 3 additions & 3 deletions clang/test/SemaHLSL/BuiltIns/mad-errors.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,15 @@ float2 test_builtin_mad_int_vect_to_float_vec_promotion(int2 p0, float p1) {

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

float builtin_bool_to_float_type_promotion2(bool p0, float p1) {
return __builtin_hlsl_mad(p1, p0, p1);
// expected-error@-1 {{2nd argument must be a vector, integer or floating point type (was 'bool')}}
// expected-error@-1 {{2nd argument must be a floating point type (was 'bool')}}
}

float builtin_mad_int_to_float_promotion(float p0, int p1) {
return __builtin_hlsl_mad(p0, p0, p1);
// expected-error@-1 {{arguments are of different types ('double' vs 'int')}}
// expected-error@-1 {{3rd argument must be a floating point type (was 'int')}}
}
29 changes: 29 additions & 0 deletions clang/test/SemaTemplate/concepts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1085,3 +1085,32 @@ template void Struct<void>::bar<>();
template int Struct<void>::field<1, 2>;

}

namespace GH64808 {

template <class T> struct basic_sender {
T func;
basic_sender(T) : func(T()) {}
};

auto a = basic_sender{[](auto... __captures) {
return []() // #note-a-1
requires((__captures, ...), false) // #note-a-2
{};
}()};

auto b = basic_sender{[](auto... __captures) {
return []()
requires([](int, double) { return true; }(decltype(__captures)()...))
{};
}(1, 2.33)};

void foo() {
a.func();
// expected-error@-1{{no matching function for call}}
// expected-note@#note-a-1{{constraints not satisfied}}
// expected-note@#note-a-2{{evaluated to false}}
b.func();
}

} // namespace GH64808
7 changes: 1 addition & 6 deletions clang/tools/clang-format/.clang-format
Original file line number Diff line number Diff line change
@@ -1,6 +1 @@
BasedOnStyle: LLVM
InsertBraces: true
InsertNewlineAtEOF: true
LineEnding: LF
RemoveBracesLLVM: true
RemoveParentheses: ReturnStatement
BasedOnStyle: clang-format
8 changes: 8 additions & 0 deletions clang/tools/clang-installapi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@ set(LLVM_LINK_COMPONENTS
Support
TargetParser
TextAPI
TextAPIBinaryReader
Option
)

set(LLVM_TARGET_DEFINITIONS InstallAPIOpts.td)
tablegen(LLVM InstallAPIOpts.inc -gen-opt-parser-defs)
add_public_tablegen_target(InstallAPIDriverOptions)

add_clang_tool(clang-installapi
ClangInstallAPI.cpp
Options.cpp

DEPENDS
InstallAPIDriverOptions
GENERATE_DRIVER
)

Expand All @@ -22,3 +29,4 @@ clang_target_link_libraries(clang-installapi
clangTooling
clangSerialization
)

35 changes: 10 additions & 25 deletions clang/tools/clang-installapi/ClangInstallAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
#include "Options.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Tool.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/InstallAPI/Frontend.h"
#include "clang/InstallAPI/FrontendRecords.h"
#include "clang/InstallAPI/InstallAPIDiagnostic.h"
#include "clang/InstallAPI/MachO.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/ArrayRef.h"
Expand Down Expand Up @@ -92,22 +92,8 @@ static bool run(ArrayRef<const char *> Args, const char *ProgName) {
IntrusiveRefCntPtr<clang::FileManager> FM(
new FileManager(clang::FileSystemOptions(), OverlayFileSystem));

// Set up driver to parse input arguments.
auto DriverArgs = llvm::ArrayRef(Args).slice(1);
clang::driver::Driver Driver(ProgName, llvm::sys::getDefaultTargetTriple(),
*Diag, "clang installapi tool");
auto TargetAndMode =
clang::driver::ToolChain::getTargetAndModeFromProgramName(ProgName);
Driver.setTargetAndMode(TargetAndMode);
bool HasError = false;
llvm::opt::InputArgList ArgList =
Driver.ParseArgStrings(DriverArgs, /*UseDriverMode=*/true, HasError);
if (HasError)
return EXIT_FAILURE;
Driver.setCheckInputsExist(false);

// Capture InstallAPI specific options and diagnose any option errors.
Options Opts(*Diag, FM.get(), ArgList);
// Capture all options and diagnose any errors.
Options Opts(*Diag, FM.get(), Args, ProgName);
if (Diag->hasErrorOccurred())
return EXIT_FAILURE;

Expand All @@ -130,6 +116,7 @@ static bool run(ArrayRef<const char *> Args, const char *ProgName) {
for (const HeaderType Type :
{HeaderType::Public, HeaderType::Private, HeaderType::Project}) {
Ctx.Slice = std::make_shared<FrontendRecordsSlice>(Trip);
Ctx.Verifier->setTarget(Targ);
Ctx.Type = Type;
if (!runFrontend(ProgName, Opts.DriverOpts.Verbose, Ctx,
InMemoryFileSystem.get(), Opts.getClangFrontendArgs()))
Expand All @@ -138,6 +125,9 @@ static bool run(ArrayRef<const char *> Args, const char *ProgName) {
}
}

if (Ctx.Verifier->getState() == DylibVerifier::Result::Invalid)
return EXIT_FAILURE;

// After symbols have been collected, prepare to write output.
auto Out = CI->createOutputFile(Ctx.OutputLoc, /*Binary=*/false,
/*RemoveFileOnSignal=*/false,
Expand All @@ -147,21 +137,16 @@ static bool run(ArrayRef<const char *> Args, const char *ProgName) {
return EXIT_FAILURE;

// Assign attributes for serialization.
auto Symbols = std::make_unique<SymbolSet>();
for (const auto &FR : FrontendResults) {
SymbolConverter Converter(Symbols.get(), FR->getTarget());
FR->visit(Converter);
}

InterfaceFile IF(std::move(Symbols));
InterfaceFile IF(Ctx.Verifier->getExports());
for (const auto &TargetInfo : Opts.DriverOpts.Targets) {
IF.addTarget(TargetInfo.first);
IF.setFromBinaryAttrs(Ctx.BA, TargetInfo.first);
}

// Write output file and perform CI cleanup.
if (auto Err = TextAPIWriter::writeToStream(*Out, IF, Ctx.FT)) {
Diag->Report(diag::err_cannot_open_file) << Ctx.OutputLoc;
Diag->Report(diag::err_cannot_write_file)
<< Ctx.OutputLoc << std::move(Err);
CI->clearOutputFiles(/*EraseFiles=*/true);
return EXIT_FAILURE;
}
Expand Down
31 changes: 31 additions & 0 deletions clang/tools/clang-installapi/InstallAPIOpts.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//===--- InstallAPIOpts.td ------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file defines the specific options for InstallAPI.
//
//===----------------------------------------------------------------------===//

// Include the common option parsing interfaces.
include "llvm/Option/OptParser.td"


/////////
// Options

// TextAPI options.
def filetype : Joined<["--"], "filetype=">,
HelpText<"Specify the output file type (tbd-v4 or tbd-v5)">;

// Verification options.
def verify_against : Separate<["-"], "verify-against">,
HelpText<"Verify the specified dynamic library/framework against the headers">;
def verify_against_EQ : Joined<["--"], "verify-against=">, Alias<verify_against>;
def verify_mode_EQ : Joined<["--"], "verify-mode=">,
HelpText<"Specify the severity and extend of the validation. Valid modes are ErrorsOnly, ErrorsAndWarnings, and Pedantic.">;
def demangle : Flag<["--", "-"], "demangle">,
HelpText<"Demangle symbols when printing warnings and errors">;
197 changes: 170 additions & 27 deletions clang/tools/clang-installapi/Options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,43 +10,93 @@
#include "clang/Driver/Driver.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/InstallAPI/FileList.h"
#include "clang/InstallAPI/InstallAPIDiagnostic.h"
#include "llvm/Support/Program.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/TextAPI/DylibReader.h"
#include "llvm/TextAPI/TextAPIWriter.h"

using namespace clang::driver;
using namespace clang::driver::options;
using namespace llvm;
using namespace llvm::opt;
using namespace llvm::MachO;

namespace drv = clang::driver::options;

namespace clang {
namespace installapi {

/// Create prefix string literals used in InstallAPIOpts.td.
#define PREFIX(NAME, VALUE) \
static constexpr llvm::StringLiteral NAME##_init[] = VALUE; \
static constexpr llvm::ArrayRef<llvm::StringLiteral> NAME( \
NAME##_init, std::size(NAME##_init) - 1);
#include "InstallAPIOpts.inc"
#undef PREFIX

static constexpr const llvm::StringLiteral PrefixTable_init[] =
#define PREFIX_UNION(VALUES) VALUES
#include "InstallAPIOpts.inc"
#undef PREFIX_UNION
;
static constexpr const ArrayRef<StringLiteral>
PrefixTable(PrefixTable_init, std::size(PrefixTable_init) - 1);

/// Create table mapping all options defined in InstallAPIOpts.td.
static constexpr OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \
VISIBILITY, PARAM, HELPTEXT, METAVAR, VALUES) \
{PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, \
PARAM, FLAGS, VISIBILITY, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, \
VALUES},
#include "InstallAPIOpts.inc"
#undef OPTION
};

namespace {

/// \brief Create OptTable class for parsing actual command line arguments.
class DriverOptTable : public opt::PrecomputedOptTable {
public:
DriverOptTable() : PrecomputedOptTable(InfoTable, PrefixTable) {}
};

} // end anonymous namespace.

static llvm::opt::OptTable *createDriverOptTable() {
return new DriverOptTable();
}

bool Options::processDriverOptions(InputArgList &Args) {
// Handle inputs.
llvm::append_range(DriverOpts.FileLists, Args.getAllArgValues(OPT_INPUT));
llvm::append_range(DriverOpts.FileLists,
Args.getAllArgValues(drv::OPT_INPUT));

// Handle output.
SmallString<PATH_MAX> OutputPath;
if (auto *Arg = Args.getLastArg(OPT_o)) {
if (auto *Arg = Args.getLastArg(drv::OPT_o)) {
OutputPath = Arg->getValue();
if (OutputPath != "-")
FM->makeAbsolutePath(OutputPath);
DriverOpts.OutputPath = std::string(OutputPath);
}
if (DriverOpts.OutputPath.empty()) {
Diags->Report(diag::err_no_output_file);
return false;
}

// Do basic error checking first for mixing -target and -arch options.
auto *ArgArch = Args.getLastArgNoClaim(OPT_arch);
auto *ArgTarget = Args.getLastArgNoClaim(OPT_target);
auto *ArgArch = Args.getLastArgNoClaim(drv::OPT_arch);
auto *ArgTarget = Args.getLastArgNoClaim(drv::OPT_target);
auto *ArgTargetVariant =
Args.getLastArgNoClaim(OPT_darwin_target_variant_triple);
Args.getLastArgNoClaim(drv::OPT_darwin_target_variant_triple);
if (ArgArch && (ArgTarget || ArgTargetVariant)) {
Diags->Report(clang::diag::err_drv_argument_not_allowed_with)
<< ArgArch->getAsString(Args)
<< (ArgTarget ? ArgTarget : ArgTargetVariant)->getAsString(Args);
return false;
}

auto *ArgMinTargetOS = Args.getLastArgNoClaim(OPT_mtargetos_EQ);
auto *ArgMinTargetOS = Args.getLastArgNoClaim(drv::OPT_mtargetos_EQ);
if ((ArgTarget || ArgTargetVariant) && ArgMinTargetOS) {
Diags->Report(clang::diag::err_drv_cannot_mix_options)
<< ArgTarget->getAsString(Args) << ArgMinTargetOS->getAsString(Args);
Expand All @@ -55,7 +105,7 @@ bool Options::processDriverOptions(InputArgList &Args) {

// Capture target triples first.
if (ArgTarget) {
for (const Arg *A : Args.filtered(OPT_target)) {
for (const Arg *A : Args.filtered(drv::OPT_target)) {
A->claim();
llvm::Triple TargetTriple(A->getValue());
Target TAPITarget = Target(TargetTriple);
Expand All @@ -69,30 +119,32 @@ bool Options::processDriverOptions(InputArgList &Args) {
}
}

DriverOpts.Verbose = Args.hasArgNoClaim(OPT_v);
DriverOpts.Verbose = Args.hasArgNoClaim(drv::OPT_v);

return true;
}

bool Options::processLinkerOptions(InputArgList &Args) {
// TODO: add error handling.

// Required arguments.
if (const Arg *A = Args.getLastArg(options::OPT_install__name))
// Handle required arguments.
if (const Arg *A = Args.getLastArg(drv::OPT_install__name))
LinkerOpts.InstallName = A->getValue();
if (LinkerOpts.InstallName.empty()) {
Diags->Report(diag::err_no_install_name);
return false;
}

// Defaulted or optional arguments.
if (auto *Arg = Args.getLastArg(OPT_current__version))
if (auto *Arg = Args.getLastArg(drv::OPT_current__version))
LinkerOpts.CurrentVersion.parse64(Arg->getValue());

if (auto *Arg = Args.getLastArg(OPT_compatibility__version))
if (auto *Arg = Args.getLastArg(drv::OPT_compatibility__version))
LinkerOpts.CompatVersion.parse64(Arg->getValue());

LinkerOpts.IsDylib = Args.hasArg(OPT_dynamiclib);
LinkerOpts.IsDylib = Args.hasArg(drv::OPT_dynamiclib);

LinkerOpts.AppExtensionSafe =
Args.hasFlag(OPT_fapplication_extension, OPT_fno_application_extension,
/*Default=*/LinkerOpts.AppExtensionSafe);
LinkerOpts.AppExtensionSafe = Args.hasFlag(
drv::OPT_fapplication_extension, drv::OPT_fno_application_extension,
/*Default=*/LinkerOpts.AppExtensionSafe);

if (::getenv("LD_NO_ENCRYPT") != nullptr)
LinkerOpts.AppExtensionSafe = true;
Expand All @@ -105,7 +157,7 @@ bool Options::processLinkerOptions(InputArgList &Args) {
bool Options::processFrontendOptions(InputArgList &Args) {
// Do not claim any arguments, as they will be passed along for CC1
// invocations.
if (auto *A = Args.getLastArgNoClaim(OPT_x)) {
if (auto *A = Args.getLastArgNoClaim(drv::OPT_x)) {
FEOpts.LangMode = llvm::StringSwitch<clang::Language>(A->getValue())
.Case("c", clang::Language::C)
.Case("c++", clang::Language::CXX)
Expand All @@ -119,8 +171,8 @@ bool Options::processFrontendOptions(InputArgList &Args) {
return false;
}
}
for (auto *A : Args.filtered(OPT_ObjC, OPT_ObjCXX)) {
if (A->getOption().matches(OPT_ObjC))
for (auto *A : Args.filtered(drv::OPT_ObjC, drv::OPT_ObjCXX)) {
if (A->getOption().matches(drv::OPT_ObjC))
FEOpts.LangMode = clang::Language::ObjC;
else
FEOpts.LangMode = clang::Language::ObjCXX;
Expand All @@ -129,9 +181,77 @@ bool Options::processFrontendOptions(InputArgList &Args) {
return true;
}

std::vector<const char *>
Options::processAndFilterOutInstallAPIOptions(ArrayRef<const char *> Args) {
std::unique_ptr<llvm::opt::OptTable> Table;
Table.reset(createDriverOptTable());

unsigned MissingArgIndex, MissingArgCount;
auto ParsedArgs = Table->ParseArgs(Args.slice(1), MissingArgIndex,
MissingArgCount, Visibility());

// Capture InstallAPI only driver options.
DriverOpts.Demangle = ParsedArgs.hasArg(OPT_demangle);

if (auto *A = ParsedArgs.getLastArg(OPT_filetype)) {
DriverOpts.OutFT = TextAPIWriter::parseFileType(A->getValue());
if (DriverOpts.OutFT == FileType::Invalid) {
Diags->Report(clang::diag::err_drv_invalid_value)
<< A->getAsString(ParsedArgs) << A->getValue();
return {};
}
}

if (const Arg *A = ParsedArgs.getLastArg(OPT_verify_mode_EQ)) {
DriverOpts.VerifyMode =
StringSwitch<VerificationMode>(A->getValue())
.Case("ErrorsOnly", VerificationMode::ErrorsOnly)
.Case("ErrorsAndWarnings", VerificationMode::ErrorsAndWarnings)
.Case("Pedantic", VerificationMode::Pedantic)
.Default(VerificationMode::Invalid);

if (DriverOpts.VerifyMode == VerificationMode::Invalid) {
Diags->Report(clang::diag::err_drv_invalid_value)
<< A->getAsString(ParsedArgs) << A->getValue();
return {};
}
}

if (const Arg *A = ParsedArgs.getLastArg(OPT_verify_against))
DriverOpts.DylibToVerify = A->getValue();

/// Any unclaimed arguments should be forwarded to the clang driver.
std::vector<const char *> ClangDriverArgs(ParsedArgs.size());
for (const Arg *A : ParsedArgs) {
if (A->isClaimed())
continue;
llvm::copy(A->getValues(), std::back_inserter(ClangDriverArgs));
}
return ClangDriverArgs;
}

Options::Options(DiagnosticsEngine &Diag, FileManager *FM,
InputArgList &ArgList)
ArrayRef<const char *> Args, const StringRef ProgName)
: Diags(&Diag), FM(FM) {

// First process InstallAPI specific options.
auto DriverArgs = processAndFilterOutInstallAPIOptions(Args);
if (Diags->hasErrorOccurred())
return;

// Set up driver to parse remaining input arguments.
clang::driver::Driver Driver(ProgName, llvm::sys::getDefaultTargetTriple(),
*Diags, "clang installapi tool");
auto TargetAndMode =
clang::driver::ToolChain::getTargetAndModeFromProgramName(ProgName);
Driver.setTargetAndMode(TargetAndMode);
bool HasError = false;
llvm::opt::InputArgList ArgList =
Driver.ParseArgStrings(DriverArgs, /*UseDriverMode=*/true, HasError);
if (HasError)
return;
Driver.setCheckInputsExist(false);

if (!processDriverOptions(ArgList))
return;

Expand All @@ -145,7 +265,6 @@ Options::Options(DiagnosticsEngine &Diag, FileManager *FM,
for (const Arg *A : ArgList) {
if (A->isClaimed())
continue;

FrontendArgs.emplace_back(A->getSpelling());
llvm::copy(A->getValues(), std::back_inserter(FrontendArgs));
}
Expand All @@ -172,16 +291,40 @@ InstallAPIContext Options::createContext() {
for (const std::string &ListPath : DriverOpts.FileLists) {
auto Buffer = FM->getBufferForFile(ListPath);
if (auto Err = Buffer.getError()) {
Diags->Report(diag::err_cannot_open_file) << ListPath;
Diags->Report(diag::err_cannot_open_file) << ListPath << Err.message();
return Ctx;
}
if (auto Err = FileListReader::loadHeaders(std::move(Buffer.get()),
Ctx.InputHeaders)) {
Diags->Report(diag::err_cannot_open_file) << ListPath;
Diags->Report(diag::err_cannot_open_file) << ListPath << std::move(Err);
return Ctx;
}
}

// Parse binary dylib and initialize verifier.
if (DriverOpts.DylibToVerify.empty()) {
Ctx.Verifier = std::make_unique<DylibVerifier>();
return Ctx;
}

auto Buffer = FM->getBufferForFile(DriverOpts.DylibToVerify);
if (auto Err = Buffer.getError()) {
Diags->Report(diag::err_cannot_open_file)
<< DriverOpts.DylibToVerify << Err.message();
return Ctx;
}

DylibReader::ParseOption PO;
PO.Undefineds = false;
Expected<Records> Slices =
DylibReader::readFile((*Buffer)->getMemBufferRef(), PO);
if (auto Err = Slices.takeError()) {
Diags->Report(diag::err_cannot_open_file) << DriverOpts.DylibToVerify;
return Ctx;
}

Ctx.Verifier = std::make_unique<DylibVerifier>(
std::move(*Slices), Diags, DriverOpts.VerifyMode, DriverOpts.Demangle);
return Ctx;
}

Expand Down
25 changes: 24 additions & 1 deletion clang/tools/clang-installapi/Options.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@

#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Driver/Driver.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/InstallAPI/Context.h"
#include "clang/InstallAPI/DylibVerifier.h"
#include "clang/InstallAPI/MachO.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
Expand All @@ -32,12 +34,21 @@ struct DriverOptions {
/// \brief Mappings of target triples & tapi targets to build for.
std::map<llvm::MachO::Target, llvm::Triple> Targets;

/// \brief Path to binary dylib for comparing.
std::string DylibToVerify;

/// \brief Output path.
std::string OutputPath;

/// \brief File encoding to print.
FileType OutFT = FileType::TBD_V5;

/// \brief Verification mode for comparing symbols.
VerificationMode VerifyMode = VerificationMode::Pedantic;

/// \brief Print demangled symbols when reporting errors.
bool Demangle = false;

/// \brief Print verbose output.
bool Verbose = false;
};
Expand Down Expand Up @@ -69,6 +80,8 @@ class Options {
bool processDriverOptions(llvm::opt::InputArgList &Args);
bool processLinkerOptions(llvm::opt::InputArgList &Args);
bool processFrontendOptions(llvm::opt::InputArgList &Args);
std::vector<const char *>
processAndFilterOutInstallAPIOptions(ArrayRef<const char *> Args);

public:
/// The various options grouped together.
Expand All @@ -83,7 +96,7 @@ class Options {

/// \brief Constructor for options.
Options(clang::DiagnosticsEngine &Diag, FileManager *FM,
llvm::opt::InputArgList &Args);
ArrayRef<const char *> Args, const StringRef ProgName);

/// \brief Get CC1 arguments after extracting out the irrelevant
/// ones.
Expand All @@ -95,6 +108,16 @@ class Options {
std::vector<std::string> FrontendArgs;
};

enum ID {
OPT_INVALID = 0, // This is not an option ID.
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \
VISIBILITY, PARAM, HELPTEXT, METAVAR, VALUES) \
OPT_##ID,
#include "InstallAPIOpts.inc"
LastOption
#undef OPTION
};

} // namespace installapi
} // namespace clang
#endif
Loading