37 changes: 35 additions & 2 deletions clang/include/clang/ExtractAPI/API.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/TargetParser/Triple.h"
#include <cstddef>
#include <iterator>
Expand Down Expand Up @@ -615,7 +616,24 @@ struct TagRecord : APIRecord, RecordContext {
return classofKind(Record->getKind());
}
static bool classofKind(RecordKind K) {
return K == RK_Struct || K == RK_Union || K == RK_Enum;
switch (K) {
case RK_Enum:
LLVM_FALLTHROUGH;
case RK_Struct:
LLVM_FALLTHROUGH;
case RK_Union:
LLVM_FALLTHROUGH;
case RK_CXXClass:
LLVM_FALLTHROUGH;
case RK_ClassTemplate:
LLVM_FALLTHROUGH;
case RK_ClassTemplateSpecialization:
LLVM_FALLTHROUGH;
case RK_ClassTemplatePartialSpecialization:
return true;
default:
return false;
}
}

bool IsEmbeddedInVarDeclarator;
Expand Down Expand Up @@ -684,7 +702,22 @@ struct RecordRecord : TagRecord {
return classofKind(Record->getKind());
}
static bool classofKind(RecordKind K) {
return K == RK_Struct || K == RK_Union;
switch (K) {
case RK_Struct:
LLVM_FALLTHROUGH;
case RK_Union:
LLVM_FALLTHROUGH;
case RK_CXXClass:
LLVM_FALLTHROUGH;
case RK_ClassTemplate:
LLVM_FALLTHROUGH;
case RK_ClassTemplateSpecialization:
LLVM_FALLTHROUGH;
case RK_ClassTemplatePartialSpecialization:
return true;
default:
return false;
}
}

bool isAnonymousWithNoTypedef() { return Name.empty(); }
Expand Down
13 changes: 6 additions & 7 deletions clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -299,13 +299,12 @@ ANALYZER_OPTION(

ANALYZER_OPTION(
bool, ShouldEagerlyAssume, "eagerly-assume",
"Whether we should eagerly assume evaluations of conditionals, thus, "
"bifurcating the path. This indicates how the engine should handle "
"expressions such as: 'x = (y != 0)'. When this is true then the "
"subexpression 'y != 0' will be eagerly assumed to be true or false, thus "
"evaluating it to the integers 0 or 1 respectively. The upside is that "
"this can increase analysis precision until we have a better way to lazily "
"evaluate such logic. The downside is that it eagerly bifurcates paths.",
"If this is enabled (the default behavior), when the analyzer encounters "
"a comparison operator or logical negation, it immediately splits the "
"state to separate the case when the expression is true and the case when "
"it's false. The upside is that this can increase analysis precision until "
"we have a better way to lazily evaluate such logic; the downside is that "
"it eagerly bifurcates paths.",
true)

ANALYZER_OPTION(
Expand Down
8 changes: 3 additions & 5 deletions clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,6 @@ class AnalyzerOptions : public RefCountedBase<AnalyzerOptions> {
unsigned AnalyzerDisplayProgress : 1;
unsigned AnalyzerNoteAnalysisEntryPoints : 1;

unsigned eagerlyAssumeBinOpBifurcation : 1;

unsigned TrimGraph : 1;
unsigned visualizeExplodedGraphWithGraphViz : 1;
unsigned UnoptimizedCFG : 1;
Expand Down Expand Up @@ -293,9 +291,9 @@ class AnalyzerOptions : public RefCountedBase<AnalyzerOptions> {
ShowConfigOptionsList(false),
ShouldEmitErrorsOnInvalidConfigValue(false), AnalyzeAll(false),
AnalyzerDisplayProgress(false), AnalyzerNoteAnalysisEntryPoints(false),
eagerlyAssumeBinOpBifurcation(false), TrimGraph(false),
visualizeExplodedGraphWithGraphViz(false), UnoptimizedCFG(false),
PrintStats(false), NoRetryExhausted(false), AnalyzerWerror(false) {}
TrimGraph(false), visualizeExplodedGraphWithGraphViz(false),
UnoptimizedCFG(false), PrintStats(false), NoRetryExhausted(false),
AnalyzerWerror(false) {}

/// Interprets an option's string value as a boolean. The "true" string is
/// interpreted as true and the "false" string is interpreted as false.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -583,14 +583,13 @@ class ExprEngine {
ExplodedNode *Pred,
ExplodedNodeSet &Dst);

/// evalEagerlyAssumeBinOpBifurcation - Given the nodes in 'Src', eagerly assume symbolic
/// expressions of the form 'x != 0' and generate new nodes (stored in Dst)
/// with those assumptions.
void evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
const Expr *Ex);
/// evalEagerlyAssumeBifurcation - Given the nodes in 'Src', eagerly assume
/// concrete boolean values for 'Ex', storing the resulting nodes in 'Dst'.
void evalEagerlyAssumeBifurcation(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
const Expr *Ex);

static std::pair<const ProgramPointTag *, const ProgramPointTag *>
geteagerlyAssumeBinOpBifurcationTags();
getEagerlyAssumeBifurcationTags();

ProgramStateRef handleLValueBitCast(ProgramStateRef state, const Expr *Ex,
const LocationContext *LCtx, QualType T,
Expand Down
28 changes: 28 additions & 0 deletions clang/lib/AST/DeclTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1185,6 +1185,20 @@ SourceRange ClassTemplatePartialSpecializationDecl::getSourceRange() const {
return Range;
}

ArrayRef<TemplateArgument>
ClassTemplatePartialSpecializationDecl::getInjectedTemplateArgs() {
TemplateParameterList *Params = getTemplateParameters();
auto *First = cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
if (!First->InjectedArgs) {
auto &Context = getASTContext();
SmallVector<TemplateArgument, 16> TemplateArgs;
Context.getInjectedTemplateArgs(Params, TemplateArgs);
First->InjectedArgs = new (Context) TemplateArgument[TemplateArgs.size()];
std::copy(TemplateArgs.begin(), TemplateArgs.end(), First->InjectedArgs);
}
return llvm::ArrayRef(First->InjectedArgs, Params->size());
}

//===----------------------------------------------------------------------===//
// FriendTemplateDecl Implementation
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1535,6 +1549,20 @@ SourceRange VarTemplatePartialSpecializationDecl::getSourceRange() const {
return Range;
}

ArrayRef<TemplateArgument>
VarTemplatePartialSpecializationDecl::getInjectedTemplateArgs() {
TemplateParameterList *Params = getTemplateParameters();
auto *First = cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
if (!First->InjectedArgs) {
auto &Context = getASTContext();
SmallVector<TemplateArgument, 16> TemplateArgs;
Context.getInjectedTemplateArgs(Params, TemplateArgs);
First->InjectedArgs = new (Context) TemplateArgument[TemplateArgs.size()];
std::copy(TemplateArgs.begin(), TemplateArgs.end(), First->InjectedArgs);
}
return llvm::ArrayRef(First->InjectedArgs, Params->size());
}

static TemplateParameterList *
createMakeIntegerSeqParameterList(const ASTContext &C, DeclContext *DC) {
// typename T
Expand Down
43 changes: 43 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7237,6 +7237,7 @@ class APValueToBufferConverter {

case APValue::ComplexInt:
case APValue::ComplexFloat:
return visitComplex(Val, Ty, Offset);
case APValue::FixedPoint:
// FIXME: We should support these.

Expand Down Expand Up @@ -7323,6 +7324,31 @@ class APValueToBufferConverter {
return true;
}

bool visitComplex(const APValue &Val, QualType Ty, CharUnits Offset) {
const ComplexType *ComplexTy = Ty->castAs<ComplexType>();
QualType EltTy = ComplexTy->getElementType();
CharUnits EltSizeChars = Info.Ctx.getTypeSizeInChars(EltTy);
bool IsInt = Val.isComplexInt();

if (IsInt) {
if (!visitInt(Val.getComplexIntReal(), EltTy,
Offset + (0 * EltSizeChars)))
return false;
if (!visitInt(Val.getComplexIntImag(), EltTy,
Offset + (1 * EltSizeChars)))
return false;
} else {
if (!visitFloat(Val.getComplexFloatReal(), EltTy,
Offset + (0 * EltSizeChars)))
return false;
if (!visitFloat(Val.getComplexFloatImag(), EltTy,
Offset + (1 * EltSizeChars)))
return false;
}

return true;
}

bool visitVector(const APValue &Val, QualType Ty, CharUnits Offset) {
const VectorType *VTy = Ty->castAs<VectorType>();
QualType EltTy = VTy->getElementType();
Expand Down Expand Up @@ -7595,6 +7621,23 @@ class BufferToAPValueConverter {
return ArrayValue;
}

std::optional<APValue> visit(const ComplexType *Ty, CharUnits Offset) {
QualType ElementType = Ty->getElementType();
CharUnits ElementWidth = Info.Ctx.getTypeSizeInChars(ElementType);
bool IsInt = ElementType->isIntegerType();

std::optional<APValue> Values[2];
for (unsigned I = 0; I != 2; ++I) {
Values[I] = visitType(Ty->getElementType(), Offset + I * ElementWidth);
if (!Values[I])
return std::nullopt;
}

if (IsInt)
return APValue(Values[0]->getInt(), Values[1]->getInt());
return APValue(Values[0]->getFloat(), Values[1]->getFloat());
}

std::optional<APValue> visit(const VectorType *VTy, CharUnits Offset) {
QualType EltTy = VTy->getElementType();
unsigned NElts = VTy->getNumElements();
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/Basic/Targets/OSTargets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,11 @@ static void addVisualCDefines(const LangOptions &Opts, MacroBuilder &Builder) {
Builder.defineMacro("_HAS_CHAR16_T_LANGUAGE_SUPPORT", Twine(1));

if (Opts.isCompatibleWithMSVC(LangOptions::MSVC2015)) {
if (Opts.CPlusPlus23)
if (Opts.CPlusPlus26)
// TODO update to the proper value.
Builder.defineMacro("_MSVC_LANG", "202004L");
Builder.defineMacro("_MSVC_LANG", "202400L");
else if (Opts.CPlusPlus23)
Builder.defineMacro("_MSVC_LANG", "202302L");
else if (Opts.CPlusPlus20)
Builder.defineMacro("_MSVC_LANG", "202002L");
else if (Opts.CPlusPlus17)
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5657,13 +5657,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
*Arg3 = EmitScalarExpr(E->getArg(3));
llvm::FunctionType *FTy = llvm::FunctionType::get(
Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), false);
Value *ACast = Builder.CreateAddrSpaceCast(Arg3, I8PTy);
// We know the third argument is an integer type, but we may need to cast
// it to i32.
if (Arg2->getType() != Int32Ty)
Arg2 = Builder.CreateZExtOrTrunc(Arg2, Int32Ty);
return RValue::get(
EmitRuntimeCall(CGM.CreateRuntimeFunction(FTy, Name),
{Arg0, Arg1, Arg2, Arg3, PacketSize, PacketAlign}));
{Arg0, Arg1, Arg2, ACast, PacketSize, PacketAlign}));
}
}
// OpenCL v2.0 s6.13.16 ,s9.17.3.5 - Built-in pipe reserve read and write
Expand Down
25 changes: 17 additions & 8 deletions clang/lib/CodeGen/CodeGenABITypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,23 @@ CodeGen::arrangeCXXMethodType(CodeGenModule &CGM,
return CGM.getTypes().arrangeCXXMethodType(RD, FTP, MD);
}

const CGFunctionInfo &
CodeGen::arrangeFreeFunctionCall(CodeGenModule &CGM,
CanQualType returnType,
ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info,
RequiredArgs args) {
return CGM.getTypes().arrangeLLVMFunctionInfo(returnType, FnInfoOpts::None,
argTypes, info, {}, args);
const CGFunctionInfo &CodeGen::arrangeCXXMethodCall(
CodeGenModule &CGM, CanQualType returnType, ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info,
ArrayRef<FunctionProtoType::ExtParameterInfo> paramInfos,
RequiredArgs args) {
return CGM.getTypes().arrangeLLVMFunctionInfo(
returnType, FnInfoOpts::IsInstanceMethod, argTypes, info, paramInfos,
args);
}

const CGFunctionInfo &CodeGen::arrangeFreeFunctionCall(
CodeGenModule &CGM, CanQualType returnType, ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info,
ArrayRef<FunctionProtoType::ExtParameterInfo> paramInfos,
RequiredArgs args) {
return CGM.getTypes().arrangeLLVMFunctionInfo(
returnType, FnInfoOpts::None, argTypes, info, paramInfos, args);
}

ImplicitCXXConstructorArgs
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ createTargetCodeGenInfo(CodeGenModule &CGM) {
return createCommonSPIRTargetCodeGenInfo(CGM);
case llvm::Triple::spirv32:
case llvm::Triple::spirv64:
case llvm::Triple::spirv:
return createSPIRVTargetCodeGenInfo(CGM);
case llvm::Triple::dxil:
return createDirectXTargetCodeGenInfo(CGM);
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/Targets/DirectX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
llvm_unreachable("dx.Sampler handles are not implemented yet");
break;
}
llvm_unreachable("Unknown llvm::dxil::ResourceClass enum");
}

} // namespace
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7225,6 +7225,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
.Case("c++17", "-std=c++17")
.Case("c++20", "-std=c++20")
// TODO add c++23 and c++26 when MSVC supports it.
.Case("c++23preview", "-std=c++23")
.Case("c++latest", "-std=c++26")
.Default("");
if (LanguageStandard.empty())
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1294,6 +1294,16 @@ void tools::addFortranRuntimeLibs(const ToolChain &TC, const ArgList &Args,
CmdArgs.push_back("-lFortranRuntime");
CmdArgs.push_back("-lFortranDecimal");
}

// libomp needs libatomic for atomic operations if using libgcc
if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
options::OPT_fno_openmp, false)) {
Driver::OpenMPRuntimeKind OMPRuntime =
TC.getDriver().getOpenMPRuntime(Args);
ToolChain::RuntimeLibType RuntimeLib = TC.GetRuntimeLibType(Args);
if (OMPRuntime == Driver::OMPRT_OMP && RuntimeLib == ToolChain::RLT_Libgcc)
CmdArgs.push_back("-latomic");
}
}

void tools::addFortranRuntimeLibraryPath(const ToolChain &TC,
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18273,7 +18273,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
}

// The return types aren't either both pointers or references to a class type.
if (NewClassTy.isNull()) {
if (NewClassTy.isNull() || !NewClassTy->isStructureOrClassType()) {
Diag(New->getLocation(),
diag::err_different_return_type_for_overriding_virtual_function)
<< New->getDeclName() << NewTy << OldTy
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2216,7 +2216,7 @@ ExprResult SemaOpenACC::CheckGangExpr(OpenACCGangKind GK, Expr *E) {
case OpenACCGangKind::Static:
return CheckGangStaticExpr(*this, E);
}
}
} break;
default:
llvm_unreachable("Non compute construct in active compute construct?");
}
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ struct TemplateInstantiationArgumentCollecter
if (Innermost)
AddInnermostTemplateArguments(VTPSD);
else if (ForConstraintInstantiation)
AddOuterTemplateArguments(VTPSD, VTPSD->getTemplateArgs().asArray(),
AddOuterTemplateArguments(VTPSD, VTPSD->getInjectedTemplateArgs(),
/*Final=*/false);

if (VTPSD->isMemberSpecialization())
Expand Down Expand Up @@ -274,7 +274,7 @@ struct TemplateInstantiationArgumentCollecter
if (Innermost)
AddInnermostTemplateArguments(CTPSD);
else if (ForConstraintInstantiation)
AddOuterTemplateArguments(CTPSD, CTPSD->getTemplateArgs().asArray(),
AddOuterTemplateArguments(CTPSD, CTPSD->getInjectedTemplateArgs(),
/*Final=*/false);

if (CTPSD->isMemberSpecialization())
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2695,7 +2695,7 @@ ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
PathSensitiveBugReport &BR) {
ProgramPoint ProgPoint = N->getLocation();
const std::pair<const ProgramPointTag *, const ProgramPointTag *> &Tags =
ExprEngine::geteagerlyAssumeBinOpBifurcationTags();
ExprEngine::getEagerlyAssumeBifurcationTags();

// If an assumption was made on a branch, it should be caught
// here by looking at the state transition.
Expand Down
41 changes: 18 additions & 23 deletions clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2129,7 +2129,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
(B->isRelationalOp() || B->isEqualityOp())) {
ExplodedNodeSet Tmp;
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp);
evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, cast<Expr>(S));
evalEagerlyAssumeBifurcation(Dst, Tmp, cast<Expr>(S));
}
else
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
Expand Down Expand Up @@ -2402,7 +2402,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
if (AMgr.options.ShouldEagerlyAssume && (U->getOpcode() == UO_LNot)) {
ExplodedNodeSet Tmp;
VisitUnaryOperator(U, Pred, Tmp);
evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, U);
evalEagerlyAssumeBifurcation(Dst, Tmp, U);
}
else
VisitUnaryOperator(U, Pred, Dst);
Expand Down Expand Up @@ -3742,23 +3742,20 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst,
BldrTop.addNodes(Tmp);
}

std::pair<const ProgramPointTag *, const ProgramPointTag*>
ExprEngine::geteagerlyAssumeBinOpBifurcationTags() {
static SimpleProgramPointTag
eagerlyAssumeBinOpBifurcationTrue(TagProviderName,
"Eagerly Assume True"),
eagerlyAssumeBinOpBifurcationFalse(TagProviderName,
"Eagerly Assume False");
return std::make_pair(&eagerlyAssumeBinOpBifurcationTrue,
&eagerlyAssumeBinOpBifurcationFalse);
std::pair<const ProgramPointTag *, const ProgramPointTag *>
ExprEngine::getEagerlyAssumeBifurcationTags() {
static SimpleProgramPointTag TrueTag(TagProviderName, "Eagerly Assume True"),
FalseTag(TagProviderName, "Eagerly Assume False");

return std::make_pair(&TrueTag, &FalseTag);
}

void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst,
ExplodedNodeSet &Src,
const Expr *Ex) {
void ExprEngine::evalEagerlyAssumeBifurcation(ExplodedNodeSet &Dst,
ExplodedNodeSet &Src,
const Expr *Ex) {
StmtNodeBuilder Bldr(Src, Dst, *currBldrCtx);

for (const auto Pred : Src) {
for (ExplodedNode *Pred : Src) {
// Test if the previous node was as the same expression. This can happen
// when the expression fails to evaluate to anything meaningful and
// (as an optimization) we don't generate a node.
Expand All @@ -3767,28 +3764,26 @@ void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst,
continue;
}

ProgramStateRef state = Pred->getState();
SVal V = state->getSVal(Ex, Pred->getLocationContext());
ProgramStateRef State = Pred->getState();
SVal V = State->getSVal(Ex, Pred->getLocationContext());
std::optional<nonloc::SymbolVal> SEV = V.getAs<nonloc::SymbolVal>();
if (SEV && SEV->isExpression()) {
const std::pair<const ProgramPointTag *, const ProgramPointTag*> &tags =
geteagerlyAssumeBinOpBifurcationTags();
const auto &[TrueTag, FalseTag] = getEagerlyAssumeBifurcationTags();

ProgramStateRef StateTrue, StateFalse;
std::tie(StateTrue, StateFalse) = state->assume(*SEV);
auto [StateTrue, StateFalse] = State->assume(*SEV);

// First assume that the condition is true.
if (StateTrue) {
SVal Val = svalBuilder.makeIntVal(1U, Ex->getType());
StateTrue = StateTrue->BindExpr(Ex, Pred->getLocationContext(), Val);
Bldr.generateNode(Ex, Pred, StateTrue, tags.first);
Bldr.generateNode(Ex, Pred, StateTrue, TrueTag);
}

// Next, assume that the condition is false.
if (StateFalse) {
SVal Val = svalBuilder.makeIntVal(0U, Ex->getType());
StateFalse = StateFalse->BindExpr(Ex, Pred->getLocationContext(), Val);
Bldr.generateNode(Ex, Pred, StateFalse, tags.second);
Bldr.generateNode(Ex, Pred, StateFalse, FalseTag);
}
}
}
Expand Down
46 changes: 40 additions & 6 deletions clang/test/Analysis/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,10 @@ void strcpy_fn_const(char *x) {
strcpy(x, (const char*)&strcpy_fn); // expected-warning{{Argument to string copy function is the address of the function 'strcpy_fn', which is not a null-terminated string}}
}

void strcpy_fn_dst(const char *x) {
strcpy((char*)&strcpy_fn, x); // expected-warning{{Argument to string copy function is the address of the function 'strcpy_fn', which is not a null-terminated string}}
}

extern int globalInt;
void strcpy_effects(char *x, char *y) {
char a = x[0];
Expand Down Expand Up @@ -469,8 +473,22 @@ void strcat_null_src(char *x) {
strcat(x, NULL); // expected-warning{{Null pointer passed as 2nd argument to string concatenation function}}
}

void strcat_fn(char *x) {
strcat(x, (char*)&strcat_fn); // expected-warning{{Argument to string concatenation function is the address of the function 'strcat_fn', which is not a null-terminated string}}
void strcat_fn_dst(const char *x) {
strcat((char*)&strcat_fn_dst, x); // expected-warning{{Argument to string concatenation function is the address of the function 'strcat_fn_dst', which is not a null-terminated string}}
}

void strcat_fn_src(char *x) {
strcat(x, (char*)&strcat_fn_src); // expected-warning{{Argument to string concatenation function is the address of the function 'strcat_fn_src', which is not a null-terminated string}}
}

void strcat_label_dst(const char *x) {
label:
strcat((char*)&&label, x); // expected-warning{{Argument to string concatenation function is the address of the label 'label', which is not a null-terminated string}}
}

void strcat_label_src(char *x) {
label:
strcat(x, (char*)&&label); // expected-warning{{Argument to string concatenation function is the address of the label 'label', which is not a null-terminated string}}
}

void strcat_effects(char *y) {
Expand Down Expand Up @@ -568,8 +586,12 @@ void strncpy_null_src(char *x) {
strncpy(x, NULL, 5); // expected-warning{{Null pointer passed as 2nd argument to string copy function}}
}

void strncpy_fn(char *x) {
strncpy(x, (char*)&strcpy_fn, 5); // expected-warning{{Argument to string copy function is the address of the function 'strcpy_fn', which is not a null-terminated string}}
void strncpy_fn_src(char *x) {
strncpy(x, (char*)&strncpy_fn_src, 5); // expected-warning{{Argument to string copy function is the address of the function 'strncpy_fn_src', which is not a null-terminated string}}
}

void strncpy_fn_dst(const char *x) {
strncpy((char*)&strncpy_fn_dst, x, 5); // expected-warning{{Argument to string copy function is the address of the function 'strncpy_fn_dst', which is not a null-terminated string}}
}

void strncpy_effects(char *x, char *y) {
Expand Down Expand Up @@ -680,8 +702,12 @@ void strncat_null_src(char *x) {
strncat(x, NULL, 4); // expected-warning{{Null pointer passed as 2nd argument to string concatenation function}}
}

void strncat_fn(char *x) {
strncat(x, (char*)&strncat_fn, 4); // expected-warning{{Argument to string concatenation function is the address of the function 'strncat_fn', which is not a null-terminated string}}
void strncat_fn_src(char *x) {
strncat(x, (char*)&strncat_fn_src, 4); // expected-warning{{Argument to string concatenation function is the address of the function 'strncat_fn_src', which is not a null-terminated string}}
}

void strncat_fn_dst(const char *x) {
strncat((char*)&strncat_fn_dst, x, 4); // expected-warning{{Argument to string concatenation function is the address of the function 'strncat_fn_dst', which is not a null-terminated string}}
}

void strncat_effects(char *y) {
Expand Down Expand Up @@ -921,6 +947,14 @@ int strcmp_null_argument(char *a) {
return strcmp(a, b); // expected-warning{{Null pointer passed as 2nd argument to string comparison function}}
}

void strcmp_fn_r(char *x) {
strcmp(x, (char*)&strcmp_null_argument); // expected-warning{{Argument to string comparison function is the address of the function 'strcmp_null_argument', which is not a null-terminated string}}
}

void strcmp_fn_l(char *x) {
strcmp((char*)&strcmp_null_argument, x); // expected-warning{{Argument to string comparison function is the address of the function 'strcmp_null_argument', which is not a null-terminated string}}
}

//===----------------------------------------------------------------------===
// strncmp()
//===----------------------------------------------------------------------===
Expand Down
10 changes: 9 additions & 1 deletion clang/test/Analysis/string.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix,debug.ExprInspection -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix,alpha.unix.cstring,debug.ExprInspection -verify %s

// Test functions that are called "memcpy" but aren't the memcpy
// we're looking for. Unfortunately, this test cannot be put into
// a namespace. The out-of-class weird memcpy needs to be recognized
// as a normal C function for the test to make sense.
typedef __typeof(sizeof(int)) size_t;
void *memcpy(void *, const void *, size_t);
size_t strlen(const char *s);

int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
Expand Down Expand Up @@ -45,3 +46,10 @@ void log(const char* fmt, const Args&... args) {
void test_gh_74269_no_crash() {
log("%d", 1);
}

struct TestNotNullTerm {
void test1() {
TestNotNullTerm * const &x = this;
strlen((char *)&x); // expected-warning{{Argument to string length function is not a null-terminated string}}
}
};
284 changes: 164 additions & 120 deletions clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
Original file line number Diff line number Diff line change
@@ -1,175 +1,219 @@
// RUN: %clang_cc1 -std=c++20 -verify %s
// expected-no-diagnostics

template<typename T>
concept D = true;
namespace Primary {
template<typename T>
concept D = true;

template<typename T>
struct A {
template<typename U, bool V>
void f() requires V;
template<typename T>
struct A {
template<typename U, bool V>
void f() requires V;

template<>
void f<short, true>();
template<>
void f<short, true>();

template<D U>
void g();

template<typename U, bool V> requires V
struct B;

template<typename U, bool V> requires V
struct B<U*, V>;

template<>
struct B<short, true>;

template<D U>
struct C;

template<D U>
struct C<U*>;

template<typename U, bool V> requires V
static int x;

template<typename U, bool V> requires V
static int x<U*, V>;

template<>
int x<short, true>;

template<D U>
static int y;

template<D U>
static int y<U*>;
};

template<typename T>
template<typename U, bool V>
void A<T>::f() requires V { }

template<typename T>
template<D U>
void g();
void A<T>::g() { }

template<typename T>
template<typename U, bool V> requires V
struct B;
struct A<T>::B { };

template<typename T>
template<typename U, bool V> requires V
struct B<U*, V>;
struct A<T>::B<U*, V> { };

template<>
struct B<short, true>;
template<typename T>
template<typename U, bool V> requires V
struct A<T>::B<U&, V> { };

template<typename T>
template<D U>
struct C;
struct A<T>::C { };

template<typename T>
template<D U>
struct C<U*>;
struct A<T>::C<U*> { };

template<typename T>
template<typename U, bool V> requires V
static int x;
int A<T>::x = 0;

template<typename T>
template<typename U, bool V> requires V
static int x<U*, V>;
int A<T>::x<U*, V> = 0;

template<>
int x<short, true>;
template<typename T>
template<typename U, bool V> requires V
int A<T>::x<U&, V> = 0;

template<typename T>
template<D U>
static int y;
int A<T>::y = 0;

template<typename T>
template<D U>
static int y<U*>;
};

template<typename T>
template<typename U, bool V>
void A<T>::f() requires V { }
int A<T>::y<U*> = 0;

template<typename T>
template<D U>
void A<T>::g() { }

template<typename T>
template<typename U, bool V> requires V
struct A<T>::B { };
template<>
template<typename U, bool V>
void A<short>::f() requires V;

template<typename T>
template<typename U, bool V> requires V
struct A<T>::B<U*, V> { };
template<>
template<>
void A<short>::f<int, true>();

template<typename T>
template<typename U, bool V> requires V
struct A<T>::B<U&, V> { };
template<>
template<>
void A<void>::f<int, true>();

template<typename T>
template<D U>
struct A<T>::C { };
template<>
template<D U>
void A<short>::g();

template<typename T>
template<D U>
struct A<T>::C<U*> { };
template<>
template<typename U, bool V> requires V
struct A<int>::B;

template<typename T>
template<typename U, bool V> requires V
int A<T>::x = 0;
template<>
template<>
struct A<int>::B<int, true>;

template<typename T>
template<typename U, bool V> requires V
int A<T>::x<U*, V> = 0;
template<>
template<>
struct A<void>::B<int, true>;

template<typename T>
template<typename U, bool V> requires V
int A<T>::x<U&, V> = 0;
template<>
template<typename U, bool V> requires V
struct A<int>::B<U*, V>;

template<typename T>
template<D U>
int A<T>::y = 0;
template<>
template<typename U, bool V> requires V
struct A<int>::B<U&, V>;

template<typename T>
template<D U>
int A<T>::y<U*> = 0;
template<>
template<D U>
struct A<int>::C;

template<>
template<typename U, bool V>
void A<short>::f() requires V;
template<>
template<D U>
struct A<int>::C<U*>;

template<>
template<>
void A<short>::f<int, true>();
template<>
template<D U>
struct A<int>::C<U&>;

template<>
template<>
void A<void>::f<int, true>();
template<>
template<typename U, bool V> requires V
int A<long>::x;

template<>
template<D U>
void A<short>::g();
template<>
template<>
int A<long>::x<int, true>;

template<>
template<typename U, bool V> requires V
struct A<int>::B;
template<>
template<>
int A<void>::x<int, true>;

template<>
template<>
struct A<int>::B<int, true>;
template<>
template<typename U, bool V> requires V
int A<long>::x<U*, V>;

template<>
template<>
struct A<void>::B<int, true>;
template<>
template<typename U, bool V> requires V
int A<long>::x<U&, V>;

template<>
template<typename U, bool V> requires V
struct A<int>::B<U*, V>;
template<>
template<D U>
int A<long>::y;

template<>
template<typename U, bool V> requires V
struct A<int>::B<U&, V>;
template<>
template<D U>
int A<long>::y<U*>;

template<>
template<D U>
struct A<int>::C;
template<>
template<D U>
int A<long>::y<U&>;
} // namespace Primary

template<>
template<D U>
struct A<int>::C<U*>;
namespace Partial {
template<typename T, bool B>
struct A;

template<>
template<D U>
struct A<int>::C<U&>;
template<bool U>
struct A<int, U>
{
template<typename V> requires U
void f();

template<>
template<typename U, bool V> requires V
int A<long>::x;
template<typename V> requires U
static const int x;

template<>
template<>
int A<long>::x<int, true>;
template<typename V> requires U
struct B;
};

template<>
template<>
int A<void>::x<int, true>;
template<bool U>
template<typename V> requires U
void A<int, U>::f() { }

template<>
template<typename U, bool V> requires V
int A<long>::x<U*, V>;
template<bool U>
template<typename V> requires U
constexpr int A<int, U>::x = 0;

template<>
template<typename U, bool V> requires V
int A<long>::x<U&, V>;
template<bool U>
template<typename V> requires U
struct A<int, U>::B { };

template<>
template<D U>
int A<long>::y;
template<>
template<typename V> requires true
void A<int, true>::f() { }

template<>
template<D U>
int A<long>::y<U*>;
template<>
template<typename V> requires true
constexpr int A<int, true>::x = 1;

template<>
template<D U>
int A<long>::y<U&>;
template<>
template<typename V> requires true
struct A<int, true>::B { };
} // namespace Partial
2 changes: 1 addition & 1 deletion clang/test/CodeGen/attr-counted-by-pr88931.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ void init(void * __attribute__((pass_dynamic_object_size(0))));
// CHECK-LABEL: define dso_local void @_ZN3foo3barC1Ev(
// CHECK-SAME: ptr noundef nonnull align 4 dereferenceable(1) [[THIS:%.*]]) unnamed_addr #[[ATTR0:[0-9]+]] align 2 {
// CHECK-NEXT: entry:
// CHECK-NEXT: tail call void @_Z4initPvU25pass_dynamic_object_size0(ptr noundef nonnull [[THIS]], i64 noundef -1) #[[ATTR2:[0-9]+]]
// CHECK-NEXT: tail call void @_Z4initPvU25pass_dynamic_object_size0(ptr noundef nonnull align 4 dereferenceable(1) [[THIS]], i64 noundef -1) #[[ATTR2:[0-9]+]]
// CHECK-NEXT: ret void
//
foo::bar::bar() {
Expand Down
20 changes: 10 additions & 10 deletions clang/test/CodeGenHLSL/builtins/WaveReadLaneAt.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -10,65 +10,65 @@
// CHECK-LABEL: test_int
int test_int(int expr, uint idx) {
// CHECK-SPIRV: %[[#entry_tok0:]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIRV: %[[RET:.*]] = call [[TY:.*]] @llvm.spv.wave.readlane.i32([[TY]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok0]]) ]
// CHECK-SPIRV: %[[RET:.*]] = call spir_func [[TY:.*]] @llvm.spv.wave.readlane.i32([[TY]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok0]]) ]
// CHECK-DXIL: %[[RET:.*]] = call [[TY:.*]] @llvm.dx.wave.readlane.i32([[TY]] %[[#]], i32 %[[#]])
// CHECK: ret [[TY]] %[[RET]]
return WaveReadLaneAt(expr, idx);
}

// CHECK-DXIL: declare [[TY]] @llvm.dx.wave.readlane.i32([[TY]], i32) #[[#attr:]]
// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.readlane.i32([[TY]], i32) #[[#attr:]]
// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.readlane.i32([[TY]], i32) #[[#attr:]]

#ifdef __HLSL_ENABLE_16_BIT
// CHECK-LABEL: test_int16
int16_t test_int16(int16_t expr, uint idx) {
// CHECK-SPIRV: %[[#entry_tok1:]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIRV: %[[RET:.*]] = call [[TY:.*]] @llvm.spv.wave.readlane.i16([[TY]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok1]]) ]
// CHECK-SPIRV: %[[RET:.*]] = call spir_func [[TY:.*]] @llvm.spv.wave.readlane.i16([[TY]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok1]]) ]
// CHECK-DXIL: %[[RET:.*]] = call [[TY:.*]] @llvm.dx.wave.readlane.i16([[TY]] %[[#]], i32 %[[#]])
// CHECK: ret [[TY]] %[[RET]]
return WaveReadLaneAt(expr, idx);
}

// CHECK-DXIL: declare [[TY]] @llvm.dx.wave.readlane.i16([[TY]], i32) #[[#attr:]]
// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.readlane.i16([[TY]], i32) #[[#attr:]]
// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.readlane.i16([[TY]], i32) #[[#attr:]]
#endif

// Test basic lowering to runtime function call with array and float values.

// CHECK-LABEL: test_half
half test_half(half expr, uint idx) {
// CHECK-SPIRV: %[[#entry_tok2:]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIRV: %[[RET:.*]] = call [[TY:.*]] @llvm.spv.wave.readlane.f16([[TY]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok2]]) ]
// CHECK-SPIRV: %[[RET:.*]] = call spir_func [[TY:.*]] @llvm.spv.wave.readlane.f16([[TY]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok2]]) ]
// CHECK-DXIL: %[[RET:.*]] = call [[TY:.*]] @llvm.dx.wave.readlane.f16([[TY]] %[[#]], i32 %[[#]])
// CHECK: ret [[TY]] %[[RET]]
return WaveReadLaneAt(expr, idx);
}

// CHECK-DXIL: declare [[TY]] @llvm.dx.wave.readlane.f16([[TY]], i32) #[[#attr:]]
// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.readlane.f16([[TY]], i32) #[[#attr:]]
// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.readlane.f16([[TY]], i32) #[[#attr:]]

// CHECK-LABEL: test_double
double test_double(double expr, uint idx) {
// CHECK-SPIRV: %[[#entry_tok3:]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIRV: %[[RET:.*]] = call [[TY:.*]] @llvm.spv.wave.readlane.f64([[TY]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok3]]) ]
// CHECK-SPIRV: %[[RET:.*]] = call spir_func [[TY:.*]] @llvm.spv.wave.readlane.f64([[TY]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok3]]) ]
// CHECK-DXIL: %[[RET:.*]] = call [[TY:.*]] @llvm.dx.wave.readlane.f64([[TY]] %[[#]], i32 %[[#]])
// CHECK: ret [[TY]] %[[RET]]
return WaveReadLaneAt(expr, idx);
}

// CHECK-DXIL: declare [[TY]] @llvm.dx.wave.readlane.f64([[TY]], i32) #[[#attr:]]
// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.readlane.f64([[TY]], i32) #[[#attr:]]
// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.readlane.f64([[TY]], i32) #[[#attr:]]

// CHECK-LABEL: test_floatv4
float4 test_floatv4(float4 expr, uint idx) {
// CHECK-SPIRV: %[[#entry_tok4:]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIRV: %[[RET1:.*]] = call [[TY1:.*]] @llvm.spv.wave.readlane.v4f32([[TY1]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok4]]) ]
// CHECK-SPIRV: %[[RET1:.*]] = call spir_func [[TY1:.*]] @llvm.spv.wave.readlane.v4f32([[TY1]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok4]]) ]
// CHECK-DXIL: %[[RET1:.*]] = call [[TY1:.*]] @llvm.dx.wave.readlane.v4f32([[TY1]] %[[#]], i32 %[[#]])
// CHECK: ret [[TY1]] %[[RET1]]
return WaveReadLaneAt(expr, idx);
}

// CHECK-DXIL: declare [[TY1]] @llvm.dx.wave.readlane.v4f32([[TY1]], i32) #[[#attr]]
// CHECK-SPIRV: declare [[TY1]] @llvm.spv.wave.readlane.v4f32([[TY1]], i32) #[[#attr]]
// CHECK-SPIRV: declare spir_func [[TY1]] @llvm.spv.wave.readlane.v4f32([[TY1]], i32) #[[#attr]]

// CHECK: attributes #[[#attr]] = {{{.*}} convergent {{.*}}}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ void main() {
// CHECK: br i1 {{%.+}}, label %[[LABEL_IF_THEN:.+]], label %[[LABEL_IF_END:.+]]

// CHECK: [[LABEL_IF_THEN]]:
// CHECK: call i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %[[CT_LOOP]]) ]
// CHECK: call spir_func i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %[[CT_LOOP]]) ]
// CHECK: br label %[[LABEL_WHILE_END:.+]]
if (cond == 2) {
uint index = WaveGetLaneIndex();
Expand All @@ -33,7 +33,7 @@ void main() {
// CHECK: ret void
}

// CHECK-DAG: declare i32 @__hlsl_wave_get_lane_index() [[A1:#[0-9]+]]
// CHECK-DAG: declare spir_func i32 @__hlsl_wave_get_lane_index() [[A1:#[0-9]+]]

// CHECK-DAG: attributes [[A0]] = {{{.*}}convergent{{.*}}}
// CHECK-DAG: attributes [[A1]] = {{{.*}}convergent{{.*}}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
// CHECK-SPIRV: define spir_func noundef i32 @{{.*test_1.*}}() [[A0:#[0-9]+]] {
// CHECK-DXIL: define noundef i32 @{{.*test_1.*}}() [[A0:#[0-9]+]] {
// CHECK-SPIRV: %[[CI:[0-9]+]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIRV: call i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %[[CI]]) ]
// CHECK-SPIRV: call spir_func i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %[[CI]]) ]
// CHECK-DXIL: call i32 @llvm.dx.wave.getlaneindex()
int test_1() {
return WaveGetLaneIndex();
}

// CHECK-SPIRV: declare i32 @__hlsl_wave_get_lane_index() [[A1:#[0-9]+]]
// CHECK-SPIRV: declare spir_func i32 @__hlsl_wave_get_lane_index() [[A1:#[0-9]+]]
// CHECK-DXIL: declare i32 @llvm.dx.wave.getlaneindex() [[A1:#[0-9]+]]

// CHECK-DAG: attributes [[A0]] = { {{.*}}convergent{{.*}} }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

// CHECK: define spir_func noundef i32 @_Z6test_1v() [[A0:#[0-9]+]] {
// CHECK: %[[C1:[0-9]+]] = call token @llvm.experimental.convergence.entry()
// CHECK: call i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %[[C1]]) ]
// CHECK: call spir_func i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %[[C1]]) ]
uint test_1() {
return WaveGetLaneIndex();
}

// CHECK-DAG: declare i32 @__hlsl_wave_get_lane_index() [[A1:#[0-9]+]]
// CHECK-DAG: declare spir_func i32 @__hlsl_wave_get_lane_index() [[A1:#[0-9]+]]

// CHECK: define spir_func noundef i32 @_Z6test_2v() [[A0]] {
// CHECK: %[[C2:[0-9]+]] = call token @llvm.experimental.convergence.entry()
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CodeGenHLSL/builtins/wave_is_first_lane.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ void main() {
while (true) {

// CHECK-DXIL: %[[#]] = call i1 @llvm.dx.wave.is.first.lane()
// CHECK-SPIRV: %[[#]] = call i1 @llvm.spv.wave.is.first.lane()
// CHECK-SPIRV: %[[#]] = call spir_func i1 @llvm.spv.wave.is.first.lane()
// CHECK-SPIRV-SAME: [ "convergencectrl"(token %[[#loop_tok]]) ]
if (WaveIsFirstLane()) {
break;
}
}

// CHECK-DXIL: %[[#]] = call i1 @llvm.dx.wave.is.first.lane()
// CHECK-SPIRV: %[[#]] = call i1 @llvm.spv.wave.is.first.lane()
// CHECK-SPIRV: %[[#]] = call spir_func i1 @llvm.spv.wave.is.first.lane()
// CHECK-SPIRV-SAME: [ "convergencectrl"(token %[[#entry_tok]]) ]
if (WaveIsFirstLane()) {
return;
Expand Down
21 changes: 21 additions & 0 deletions clang/test/CodeGenOpenCL/pipe_builtin.cl
Original file line number Diff line number Diff line change
@@ -1,69 +1,90 @@
// RUN: %clang_cc1 -triple spir-unknown-unknown -emit-llvm -cl-ext=+cl_khr_subgroups -O0 -cl-std=clc++ -o - %s | FileCheck --check-prefix=CHECK-SPIR %s
// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -cl-ext=+cl_khr_subgroups -O0 -cl-std=clc++ -o - %s | FileCheck %s
// FIXME: Add MS ABI manglings of OpenCL things and remove %itanium_abi_triple
// above to support OpenCL in the MS C++ ABI.

#pragma OPENCL EXTENSION cl_khr_subgroups : enable

void test1(read_only pipe int p, global int *ptr) {
// CHECK-SPIR: call spir_func i32 @__read_pipe_2(target("spirv.Pipe", 0) %{{.*}}, ptr addrspace(4) %{{.*}}, i32 4, i32 4)
// CHECK: call i32 @__read_pipe_2(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4)
read_pipe(p, ptr);
// CHECK-SPIR: call spir_func target("spirv.ReserveId") @__reserve_read_pipe(target("spirv.Pipe", 0) %{{.*}}, i32 {{.*}}, i32 4, i32 4)
// CHECK: call ptr @__reserve_read_pipe(ptr %{{.*}}, i32 {{.*}}, i32 4, i32 4)
reserve_id_t rid = reserve_read_pipe(p, 2);
// CHECK-SPIR: call spir_func i32 @__read_pipe_4(target("spirv.Pipe", 0) %{{.*}}, ptr addrspace(4) %{{.*}}, i32 4, i32 4)
// CHECK: call i32 @__read_pipe_4(ptr %{{.*}}, ptr %{{.*}}, i32 {{.*}}, ptr %{{.*}}, i32 4, i32 4)
read_pipe(p, rid, 2, ptr);
// CHECK-SPIR: call spir_func void @__commit_read_pipe(target("spirv.Pipe", 0) %{{.*}}, target("spirv.ReserveId") %{{.*}}, i32 4, i32 4)
// CHECK: call void @__commit_read_pipe(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4)
commit_read_pipe(p, rid);
}

void test2(write_only pipe int p, global int *ptr) {
// CHECK-SPIR: call spir_func i32 @__write_pipe_2(target("spirv.Pipe", 1) %{{.*}}, ptr addrspace(4) %{{.*}}, i32 4, i32 4)
// CHECK: call i32 @__write_pipe_2(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4)
write_pipe(p, ptr);
// CHECK-SPIR: call spir_func target("spirv.ReserveId") @__reserve_write_pipe(target("spirv.Pipe", 1) %{{.*}}, i32 {{.*}}, i32 4, i32 4)
// CHECK: call ptr @__reserve_write_pipe(ptr %{{.*}}, i32 {{.*}}, i32 4, i32 4)
reserve_id_t rid = reserve_write_pipe(p, 2);
// CHECK-SPIR: call spir_func i32 @__write_pipe_4(target("spirv.Pipe", 1) %{{.*}}, ptr addrspace(4) %{{.*}}, i32 4, i32 4)
// CHECK: call i32 @__write_pipe_4(ptr %{{.*}}, ptr %{{.*}}, i32 {{.*}}, ptr %{{.*}}, i32 4, i32 4)
write_pipe(p, rid, 2, ptr);
// CHECK-SPIR: call spir_func void @__commit_write_pipe(target("spirv.Pipe", 1) %{{.*}}, target("spirv.ReserveId") %{{.*}}, i32 4, i32 4)
// CHECK: call void @__commit_write_pipe(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4)
commit_write_pipe(p, rid);
}

void test3(read_only pipe int p, global int *ptr) {
// CHECK-SPIR: call spir_func target("spirv.ReserveId") @__work_group_reserve_read_pipe(target("spirv.Pipe", 0) %{{.*}}, i32 {{.*}}, i32 4, i32 4)
// CHECK: call ptr @__work_group_reserve_read_pipe(ptr %{{.*}}, i32 {{.*}}, i32 4, i32 4)
reserve_id_t rid = work_group_reserve_read_pipe(p, 2);
// CHECK-SPIR: call spir_func void @__work_group_commit_read_pipe(target("spirv.Pipe", 0) %{{.*}}, target("spirv.ReserveId") %{{.*}}, i32 4, i32 4)
// CHECK: call void @__work_group_commit_read_pipe(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4)
work_group_commit_read_pipe(p, rid);
}

void test4(write_only pipe int p, global int *ptr) {
// CHECK-SPIR: call spir_func target("spirv.ReserveId") @__work_group_reserve_write_pipe(target("spirv.Pipe", 1) %{{.*}}, i32 {{.*}}, i32 4, i32 4)
// CHECK: call ptr @__work_group_reserve_write_pipe(ptr %{{.*}}, i32 {{.*}}, i32 4, i32 4)
reserve_id_t rid = work_group_reserve_write_pipe(p, 2);
// CHECK-SPIR: call spir_func void @__work_group_commit_write_pipe(target("spirv.Pipe", 1) %{{.*}}, target("spirv.ReserveId") %{{.*}}, i32 4, i32 4)
// CHECK: call void @__work_group_commit_write_pipe(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4)
work_group_commit_write_pipe(p, rid);
}

void test5(read_only pipe int p, global int *ptr) {
// CHECK-SPIR: call spir_func target("spirv.ReserveId") @__sub_group_reserve_read_pipe(target("spirv.Pipe", 0) %{{.*}}, i32 {{.*}}, i32 4, i32 4)
// CHECK: call ptr @__sub_group_reserve_read_pipe(ptr %{{.*}}, i32 {{.*}}, i32 4, i32 4)
reserve_id_t rid = sub_group_reserve_read_pipe(p, 2);
// CHECK-SPIR: call spir_func void @__sub_group_commit_read_pipe(target("spirv.Pipe", 0) %{{.*}}, target("spirv.ReserveId") %{{.*}}, i32 4, i32 4)
// CHECK: call void @__sub_group_commit_read_pipe(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4)
sub_group_commit_read_pipe(p, rid);
}

void test6(write_only pipe int p, global int *ptr) {
// CHECK-SPIR: call spir_func target("spirv.ReserveId") @__sub_group_reserve_write_pipe(target("spirv.Pipe", 1) %{{.*}}, i32 {{.*}}, i32 4, i32 4)
// CHECK: call ptr @__sub_group_reserve_write_pipe(ptr %{{.*}}, i32 {{.*}}, i32 4, i32 4)
reserve_id_t rid = sub_group_reserve_write_pipe(p, 2);
// CHECK-SPIR: call spir_func void @__sub_group_commit_write_pipe(target("spirv.Pipe", 1) %{{.*}}, target("spirv.ReserveId") %{{.*}}, i32 4, i32 4)
// CHECK: call void @__sub_group_commit_write_pipe(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4)
sub_group_commit_write_pipe(p, rid);
}

void test7(read_only pipe int p, global int *ptr) {
// CHECK-SPIR: call spir_func i32 @__get_pipe_num_packets_ro(target("spirv.Pipe", 0) %{{.*}}, i32 4, i32 4)
// CHECK: call i32 @__get_pipe_num_packets_ro(ptr %{{.*}}, i32 4, i32 4)
*ptr = get_pipe_num_packets(p);
// CHECK-SPIR: call spir_func i32 @__get_pipe_max_packets_ro(target("spirv.Pipe", 0) %{{.*}}, i32 4, i32 4)
// CHECK: call i32 @__get_pipe_max_packets_ro(ptr %{{.*}}, i32 4, i32 4)
*ptr = get_pipe_max_packets(p);
}

void test8(write_only pipe int p, global int *ptr) {
// CHECK-SPIR: call spir_func i32 @__get_pipe_num_packets_wo(target("spirv.Pipe", 1) %{{.*}}, i32 4, i32 4)
// CHECK: call i32 @__get_pipe_num_packets_wo(ptr %{{.*}}, i32 4, i32 4)
*ptr = get_pipe_num_packets(p);
// CHECK-SPIR: call spir_func i32 @__get_pipe_max_packets_wo(target("spirv.Pipe", 1) %{{.*}}, i32 4, i32 4)
// CHECK: call i32 @__get_pipe_max_packets_wo(ptr %{{.*}}, i32 4, i32 4)
*ptr = get_pipe_max_packets(p);
}
3 changes: 3 additions & 0 deletions clang/test/Driver/cl-options.c
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,9 @@
// RUN: %clang_cl -fmsc-version=1900 -TP -std:c++20 -### -- %s 2>&1 | FileCheck -check-prefix=STDCXX20 %s
// STDCXX20: -std=c++20

// RUN: %clang_cl -fmsc-version=1900 -TP -std:c++23preview -### -- %s 2>&1 | FileCheck -check-prefix=STDCXX23PREVIEW %s
// STDCXX23PREVIEW: -std=c++23

// RUN: %clang_cl -fmsc-version=1900 -TP -std:c++latest -### -- %s 2>&1 | FileCheck -check-prefix=STDCXXLATEST %s
// STDCXXLATEST: -std=c++26

Expand Down
44 changes: 30 additions & 14 deletions clang/test/ExtractAPI/anonymous_record_no_typedef.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \
// RUN: -triple arm64-apple-macosx -isystem %S -fretain-comments-from-system-headers \
// RUN: -x c-header %s -o %t/output.symbols.json -verify
// RUN: -x c-header %s -o %t/output-c.symbols.json -verify
//
// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \
// RUN: -triple arm64-apple-macosx -isystem %S -fretain-comments-from-system-headers \
// RUN: -x c++-header %s -o %t/output-cxx.symbols.json -verify

// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix GLOBAL
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix PREFIX
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix CONTENT
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix GLOBAL
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix PREFIX
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix CONTENT
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix GLOBAL
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix PREFIX
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix CONTENT
/// A global variable with an anonymous struct type.
struct { char *prefix; char *content; } global;
// GLOBAL-LABEL: "!testLabel": "c:@global"
Expand All @@ -30,7 +37,7 @@ struct { char *prefix; char *content; } global;
// GLOBAL: "text": "A global variable with an anonymous struct type."
// GLOBAL: "kind": {
// GLOBAL-NEXT: "displayName": "Global Variable",
// GLOBAL-NEXT: "identifier": "c.var"
// GLOBAL-NEXT: "identifier": "c{{(\+\+)?}}.var"
// GLOBAL: "title": "global"
// GLOBAL: "pathComponents": [
// GLOBAL-NEXT: "global"
Expand All @@ -54,9 +61,12 @@ struct { char *prefix; char *content; } global;

/// A Vehicle
struct Vehicle {
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix TYPE
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix BICYCLE
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix CAR
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix TYPE
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix BICYCLE
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix CAR
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix TYPE
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix BICYCLE
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix CAR
/// The type of vehicle.
enum {
Bicycle,
Expand Down Expand Up @@ -96,9 +106,12 @@ struct Vehicle {
// CAR-NEXT: "Car"
// CAR-NEXT: ]

// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix INFORMATION
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix WHEELS
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix NAME
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix INFORMATION
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix WHEELS
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix NAME
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix INFORMATION
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix WHEELS
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix NAME
/// The information about the vehicle.
union {
int wheels;
Expand Down Expand Up @@ -145,8 +158,10 @@ struct Vehicle {
// NAME-NEXT: ]
};

// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix GLOBALCASE
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix GLOBALOTHERCASE
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix GLOBALCASE
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix GLOBALOTHERCASE
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix GLOBALCASE
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix GLOBALOTHERCASE
enum {
GlobalCase,
GlobalOtherCase
Expand All @@ -163,7 +178,8 @@ enum {
// GLOBALOTHERCASE-NEXT: "GlobalOtherCase"
// GLOBALOTHERCASE-NEXT: ]

// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix VEC
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix VEC
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix VEC
union Vector {
struct {
float X;
Expand Down
27 changes: 17 additions & 10 deletions clang/test/ExtractAPI/typedef_anonymous_record.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \
// RUN: --product-name=TypedefChain -triple arm64-apple-macosx -x c-header %s -o %t/typedefchain.symbols.json -verify
// RUN: --product-name=TypedefChain -triple arm64-apple-macosx -x c-header %s -o %t/typedefchain-c.symbols.json -verify
// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \
// RUN: --product-name=TypedefChain -triple arm64-apple-macosx -x c++-header %s -o %t/typedefchain-cxx.symbols.json -verify

// RUN: FileCheck %s --input-file %t/typedefchain.symbols.json --check-prefix MYSTRUCT
// RUN: FileCheck %s --input-file %t/typedefchain-c.symbols.json --check-prefix MYSTRUCT
// RUN: FileCheck %s --input-file %t/typedefchain-cxx.symbols.json --check-prefix MYSTRUCT
typedef struct { } MyStruct;
// MYSTRUCT-LABEL: "!testLabel": "c:@SA@MyStruct"
// MYSTRUCT: "accessLevel": "public",
Expand Down Expand Up @@ -34,7 +37,7 @@ typedef struct { } MyStruct;
// MYSTRUCT-NEXT: ]
// MYSTRUCT: "kind": {
// MYSTRUCT-NEXT: "displayName": "Structure",
// MYSTRUCT-NEXT: "identifier": "c.struct"
// MYSTRUCT-NEXT: "identifier": "c{{(\+\+)?}}.struct"
// MYSTRUCT: "names": {
// MYSTRUCT-NEXT: "navigator": [
// MYSTRUCT-NEXT: {
Expand All @@ -54,7 +57,8 @@ typedef struct { } MyStruct;
// MYSTRUCT-NEXT: "MyStruct"
// MYSTRUCT-NEXT: ]

// RUN: FileCheck %s --input-file %t/typedefchain.symbols.json --check-prefix MYSTRUCTSTRUCT
// RUN: FileCheck %s --input-file %t/typedefchain-c.symbols.json --check-prefix MYSTRUCTSTRUCT
// RUN: FileCheck %s --input-file %t/typedefchain-cxx.symbols.json --check-prefix MYSTRUCTSTRUCT
typedef MyStruct MyStructStruct;
// MYSTRUCTSTRUCT-LABEL: "!testLabel": "c:typedef_anonymous_record.c@T@MyStructStruct"
// MYSTRUCTSTRUCT: "accessLevel": "public",
Expand Down Expand Up @@ -87,10 +91,12 @@ typedef MyStruct MyStructStruct;
// MYSTRUCTSTRUCT-NEXT:],
// MYSTRUCTSTRUCT: "kind": {
// MYSTRUCTSTRUCT-NEXT: "displayName": "Type Alias",
// MYSTRUCTSTRUCT-NEXT: "identifier": "c.typealias"
// MYSTRUCTSTRUCT-NEXT: "identifier": "c{{(\+\+)?}}.typealias"

// RUN: FileCheck %s --input-file %t/typedefchain.symbols.json --check-prefix MYENUM
// RUN: FileCheck %s --input-file %t/typedefchain.symbols.json --check-prefix CASE
// RUN: FileCheck %s --input-file %t/typedefchain-c.symbols.json --check-prefix MYENUM
// RUN: FileCheck %s --input-file %t/typedefchain-c.symbols.json --check-prefix CASE
// RUN: FileCheck %s --input-file %t/typedefchain-cxx.symbols.json --check-prefix MYENUM
// RUN: FileCheck %s --input-file %t/typedefchain-cxx.symbols.json --check-prefix CASE
typedef enum { Case } MyEnum;
// MYENUM: "source": "c:@EA@MyEnum@Case",
// MYENUM-NEXT: "target": "c:@EA@MyEnum",
Expand Down Expand Up @@ -124,7 +130,7 @@ typedef enum { Case } MyEnum;
// MYENUM-NEXT:],
// MYENUM: "kind": {
// MYENUM-NEXT: "displayName": "Enumeration",
// MYENUM-NEXT: "identifier": "c.enum"
// MYENUM-NEXT: "identifier": "c{{(\+\+)?}}.enum"
// MYENUM: "names": {
// MYENUM-NEXT: "navigator": [
// MYENUM-NEXT: {
Expand All @@ -147,7 +153,8 @@ typedef enum { Case } MyEnum;
// CASE-NEXT: "Case"
// CASE-NEXT: ]

// RUN: FileCheck %s --input-file %t/typedefchain.symbols.json --check-prefix MYENUMENUM
// RUN: FileCheck %s --input-file %t/typedefchain-c.symbols.json --check-prefix MYENUMENUM
// RUN: FileCheck %s --input-file %t/typedefchain-cxx.symbols.json --check-prefix MYENUMENUM
typedef MyEnum MyEnumEnum;
// MYENUMENUM-LABEL: "!testLabel": "c:typedef_anonymous_record.c@T@MyEnumEnum"
// MYENUMENUM: "declarationFragments": [
Expand Down Expand Up @@ -179,7 +186,7 @@ typedef MyEnum MyEnumEnum;
// MYENUMENUM-NEXT: ],
// MYENUMENUM: "kind": {
// MYENUMENUM-NEXT: "displayName": "Type Alias",
// MYENUMENUM-NEXT: "identifier": "c.typealias"
// MYENUMENUM-NEXT: "identifier": "c{{(\+\+)?}}.typealias"
// MYENUMENUM-NEXT: },
// MYENUMENUM: "title": "MyEnumEnum"

Expand Down
59 changes: 40 additions & 19 deletions clang/test/Modules/friend-definition-2.cpp
Original file line number Diff line number Diff line change
@@ -1,32 +1,53 @@
// RUN: %clang_cc1 -std=c++14 -fmodules %s -verify
// RUN: %clang_cc1 -std=c++14 -fmodules %s -verify -triple i686-windows
// expected-no-diagnostics
#pragma clang module build A
module A {}
#pragma clang module contents
#pragma clang module begin A
// RUN: split-file %s %t

// RUN: %clang_cc1 -std=c++14 -x c++ -fmodules -fmodule-name=A -emit-module %t/a.modulemap -o %t/a.pcm
// RUN: %clang_cc1 -std=c++14 -x c++ -fmodules -fmodule-name=B -emit-module %t/b.modulemap -o %t/b.pcm
// RUN: %clang_cc1 -std=c++14 -x c++ -fmodules -fmodule-map-file=%t/a.modulemap -fmodule-map-file=%t/b.modulemap \
// RUN: -fmodule-file=%t/a.pcm -fmodule-file=%t/b.pcm \
// RUN: %t/use.cc -verify

// RUN: rm -f %t/*.pcm

// RUN: %clang_cc1 -std=c++14 -x c++ -fmodules -fmodule-name=A -emit-module %t/a.modulemap -o %t/a.pcm -triple i686-windows
// RUN: %clang_cc1 -std=c++14 -x c++ -fmodules -fmodule-name=B -emit-module %t/b.modulemap -o %t/b.pcm -triple i686-windows
// RUN: %clang_cc1 -std=c++14 -x c++ -fmodules -fmodule-map-file=%t/a.modulemap -fmodule-map-file=%t/b.modulemap \
// RUN: -fmodule-file=%t/a.pcm -fmodule-file=%t/b.pcm \
// RUN: %t/use.cc -verify -triple i686-windows

//--- a.modulemap
module A {
header "a.h"
}

//--- a.h
#ifndef A_H
#define A_H
template<typename T> struct ct { friend auto operator-(ct, ct) { struct X {}; return X(); } void x(); };
#endif

//--- b.modulemap
module B {
header "b.h"
}

//--- b.h
#ifndef B_H
#define B_H
template<typename T> struct ct { friend auto operator-(ct, ct) { struct X {}; return X(); } void x(); };
#pragma clang module end
#pragma clang module endbuild

#pragma clang module build B
module B {}
#pragma clang module contents
#pragma clang module begin B
template<typename T> struct ct { friend auto operator-(ct, ct) { struct X{}; return X(); } void x(); };
inline auto f() { return ct<float>() - ct<float>(); }
#pragma clang module end
#pragma clang module endbuild
#endif

//--- use.cc
// expected-no-diagnostics
// Force the definition of ct in module A to be the primary definition.
#pragma clang module import A
#include "a.h"
template<typename T> void ct<T>::x() {}

// Attempt to cause the definition of operator- in the ct primary template in
// module B to be the primary definition of that function. If that happens,
// we'll be left with a class template ct that appears to not contain a
// definition of the inline friend function.
#pragma clang module import B
#include "b.h"
auto v = f();

ct<int> make();
Expand Down
2 changes: 1 addition & 1 deletion clang/test/OpenMP/bug57757.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ void foo() {
// CHECK-NEXT: ]
// CHECK: .untied.jmp..i:
// CHECK-NEXT: store i32 1, ptr [[TMP2]], align 4, !tbaa [[TBAA16]], !alias.scope [[META13]], !noalias [[META17]]
// CHECK-NEXT: [[TMP4:%.*]] = tail call i32 @__kmpc_omp_task(ptr nonnull @[[GLOB1]], i32 [[TMP0]], ptr [[TMP1]]), !noalias [[META13]]
// CHECK-NEXT: [[TMP4:%.*]] = tail call i32 @__kmpc_omp_task(ptr nonnull @[[GLOB1]], i32 [[TMP0]], ptr nonnull [[TMP1]]), !noalias [[META13]]
// CHECK-NEXT: br label [[DOTOMP_OUTLINED__EXIT]]
// CHECK: .untied.next..i:
// CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP1]], i64 40
Expand Down
7 changes: 6 additions & 1 deletion clang/test/Preprocessor/predefined-win-macros.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@
// RUN: %clang_cc1 %s -x c++ -E -dM -triple i686-pc-win32 -fms-extensions -fms-compatibility \
// RUN: -fms-compatibility-version=19.00 -std=c++23 -o - | FileCheck -match-full-lines %s --check-prefix=CHECK-MS-CPP2B
// CHECK-MS-CPP2B: #define _MSC_VER 1900
// CHECK-MS-CPP2B: #define _MSVC_LANG 202004L
// CHECK-MS-CPP2B: #define _MSVC_LANG 202302L

// RUN: %clang_cc1 %s -x c++ -E -dM -triple i686-pc-win32 -fms-extensions -fms-compatibility \
// RUN: -fms-compatibility-version=19.00 -std=c++26 -o - | FileCheck -match-full-lines %s --check-prefix=CHECK-MS-CPP2C
// CHECK-MS-CPP2C: #define _MSC_VER 1900
// CHECK-MS-CPP2C: #define _MSVC_LANG 202400L

// RUN: %clang_cc1 -triple i386-windows %s -E -dM -o - \
// RUN: | FileCheck -match-full-lines %s --check-prefix=CHECK-X86-WIN
Expand Down
16 changes: 16 additions & 0 deletions clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -511,3 +511,19 @@ constexpr bool9 bad_short_to_bool9 = __builtin_bit_cast(bool9, static_cast<unsig
constexpr bool17 bad_int_to_bool17 = __builtin_bit_cast(bool17, 0x0001CAFEU);

}

namespace test_complex {
constexpr _Complex unsigned test_int_complex = { 0x0C05FEFE, 0xCAFEBABE };
static_assert(round_trip<_Complex unsigned>(0xCAFEBABE0C05FEFEULL), "");
static_assert(bit_cast<unsigned long long>(test_int_complex) == (LITTLE_END
? 0xCAFEBABE0C05FEFE
: 0x0C05FEFECAFEBABE), "");
static_assert(sizeof(double) == 2 * sizeof(float));
struct TwoFloats { float A; float B; };
constexpr _Complex float test_float_complex = {1.0f, 2.0f};
constexpr TwoFloats TF = __builtin_bit_cast(TwoFloats, test_float_complex);
static_assert(TF.A == 1.0f && TF.B == 2.0f);

constexpr double D = __builtin_bit_cast(double, test_float_complex);
constexpr int M = __builtin_bit_cast(int, test_int_complex); // expected-error {{__builtin_bit_cast source size does not equal destination size}}
}
6 changes: 6 additions & 0 deletions clang/test/SemaCXX/virtual-override.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ struct b { };

class A {
virtual a* f(); // expected-note{{overridden virtual function is here}}
virtual int *g(); // expected-note{{overridden virtual function is here}}
};

class B : A {
virtual b* f(); // expected-error{{return type of virtual function 'f' is not covariant with the return type of the function it overrides ('b *' is not derived from 'a *')}}
virtual char *g(); // expected-error{{virtual function 'g' has a different return type ('char *') than the function it overrides (which has return type 'int *')}}
};

}
Expand Down Expand Up @@ -83,11 +85,15 @@ struct a { };
class A {
virtual const a* f();
virtual a* g(); // expected-note{{overridden virtual function is here}}
virtual const int* h(); // expected-note{{overridden virtual function is here}}
virtual int* i(); // expected-note{{overridden virtual function is here}}
};

class B : A {
virtual a* f();
virtual const a* g(); // expected-error{{return type of virtual function 'g' is not covariant with the return type of the function it overrides (class type 'const a *' is more qualified than class type 'a *'}}
virtual int* h(); // expected-error{{virtual function 'h' has a different return type ('int *') than the function it overrides (which has return type 'const int *')}}
virtual const int* i(); // expected-error{{virtual function 'i' has a different return type ('const int *') than the function it overrides (which has return type 'int *')}}
};

}
Expand Down
1 change: 1 addition & 0 deletions clang/unittests/Analysis/FlowSensitive/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ add_clang_unittest(ClangAnalysisFlowSensitiveTests
ArenaTest.cpp
ASTOpsTest.cpp
CFGMatchSwitchTest.cpp
CachedConstAccessorsLatticeTest.cpp
ChromiumCheckModelTest.cpp
DataflowAnalysisContextTest.cpp
DataflowEnvironmentTest.cpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,305 @@
//===- unittests/Analysis/FlowSensitive/CachedConstAccessorsLatticeTest.cpp ==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "clang/Analysis/FlowSensitive/CachedConstAccessorsLattice.h"

#include <cassert>
#include <memory>

#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
#include "clang/Analysis/FlowSensitive/NoopLattice.h"
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
#include "clang/Analysis/FlowSensitive/Value.h"
#include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
#include "clang/Basic/LLVM.h"
#include "clang/Testing/TestAST.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"

namespace clang::dataflow {
namespace {

using ast_matchers::BoundNodes;
using ast_matchers::callee;
using ast_matchers::cxxMemberCallExpr;
using ast_matchers::functionDecl;
using ast_matchers::hasName;
using ast_matchers::match;
using ast_matchers::selectFirst;

using dataflow::DataflowAnalysisContext;
using dataflow::Environment;
using dataflow::LatticeJoinEffect;
using dataflow::RecordStorageLocation;
using dataflow::Value;
using dataflow::WatchedLiteralsSolver;

using testing::SizeIs;

NamedDecl *lookup(StringRef Name, const DeclContext &DC) {
auto Result = DC.lookup(&DC.getParentASTContext().Idents.get(Name));
EXPECT_TRUE(Result.isSingleResult()) << Name;
return Result.front();
}

class CachedConstAccessorsLatticeTest : public ::testing::Test {
protected:
using LatticeT = CachedConstAccessorsLattice<NoopLattice>;

DataflowAnalysisContext DACtx{std::make_unique<WatchedLiteralsSolver>()};
Environment Env{DACtx};
};

// Basic test AST with two const methods (return a value, and return a ref).
struct CommonTestInputs {
CommonTestInputs()
: AST(R"cpp(
struct S {
int *valProperty() const;
int &refProperty() const;
};
void target() {
S s;
s.valProperty();
S s2;
s2.refProperty();
}
)cpp") {
auto *SDecl = cast<CXXRecordDecl>(
lookup("S", *AST.context().getTranslationUnitDecl()));
SType = AST.context().getRecordType(SDecl);
CallVal = selectFirst<CallExpr>(
"call",
match(cxxMemberCallExpr(callee(functionDecl(hasName("valProperty"))))
.bind("call"),
AST.context()));
assert(CallVal != nullptr);

CallRef = selectFirst<CallExpr>(
"call",
match(cxxMemberCallExpr(callee(functionDecl(hasName("refProperty"))))
.bind("call"),
AST.context()));
assert(CallRef != nullptr);
}

TestAST AST;
QualType SType;
const CallExpr *CallVal;
const CallExpr *CallRef;
};

TEST_F(CachedConstAccessorsLatticeTest,
SamePrimitiveValBeforeClearOrDiffAfterClear) {
CommonTestInputs Inputs;
auto *CE = Inputs.CallVal;
RecordStorageLocation Loc(Inputs.SType, RecordStorageLocation::FieldToLoc(),
{});

LatticeT Lattice;
Value *Val1 = Lattice.getOrCreateConstMethodReturnValue(Loc, CE, Env);
Value *Val2 = Lattice.getOrCreateConstMethodReturnValue(Loc, CE, Env);

EXPECT_EQ(Val1, Val2);

Lattice.clearConstMethodReturnValues(Loc);
Value *Val3 = Lattice.getOrCreateConstMethodReturnValue(Loc, CE, Env);

EXPECT_NE(Val3, Val1);
EXPECT_NE(Val3, Val2);
}

TEST_F(CachedConstAccessorsLatticeTest, SameLocBeforeClearOrDiffAfterClear) {
CommonTestInputs Inputs;
auto *CE = Inputs.CallRef;
RecordStorageLocation Loc(Inputs.SType, RecordStorageLocation::FieldToLoc(),
{});

LatticeT Lattice;
auto NopInit = [](StorageLocation &) {};
StorageLocation *Loc1 = Lattice.getOrCreateConstMethodReturnStorageLocation(
Loc, CE, Env, NopInit);
auto NotCalled = [](StorageLocation &) {
ASSERT_TRUE(false) << "Not reached";
};
StorageLocation *Loc2 = Lattice.getOrCreateConstMethodReturnStorageLocation(
Loc, CE, Env, NotCalled);

EXPECT_EQ(Loc1, Loc2);

Lattice.clearConstMethodReturnStorageLocations(Loc);
StorageLocation *Loc3 = Lattice.getOrCreateConstMethodReturnStorageLocation(
Loc, CE, Env, NopInit);

EXPECT_NE(Loc3, Loc1);
EXPECT_NE(Loc3, Loc2);
}

TEST_F(CachedConstAccessorsLatticeTest,
SameStructValBeforeClearOrDiffAfterClear) {
TestAST AST(R"cpp(
struct S {
S structValProperty() const;
};
void target() {
S s;
s.structValProperty();
}
)cpp");
auto *SDecl =
cast<CXXRecordDecl>(lookup("S", *AST.context().getTranslationUnitDecl()));
QualType SType = AST.context().getRecordType(SDecl);
const CallExpr *CE = selectFirst<CallExpr>(
"call", match(cxxMemberCallExpr(
callee(functionDecl(hasName("structValProperty"))))
.bind("call"),
AST.context()));
ASSERT_NE(CE, nullptr);

RecordStorageLocation Loc(SType, RecordStorageLocation::FieldToLoc(), {});

LatticeT Lattice;
// Accessors that return a record by value are modeled by a record storage
// location (instead of a Value).
auto NopInit = [](StorageLocation &) {};
StorageLocation *Loc1 = Lattice.getOrCreateConstMethodReturnStorageLocation(
Loc, CE, Env, NopInit);
auto NotCalled = [](StorageLocation &) {
ASSERT_TRUE(false) << "Not reached";
};
StorageLocation *Loc2 = Lattice.getOrCreateConstMethodReturnStorageLocation(
Loc, CE, Env, NotCalled);

EXPECT_EQ(Loc1, Loc2);

Lattice.clearConstMethodReturnStorageLocations(Loc);
StorageLocation *Loc3 = Lattice.getOrCreateConstMethodReturnStorageLocation(
Loc, CE, Env, NopInit);

EXPECT_NE(Loc3, Loc1);
EXPECT_NE(Loc3, Loc1);
}

TEST_F(CachedConstAccessorsLatticeTest, ClearDifferentLocs) {
CommonTestInputs Inputs;
auto *CE = Inputs.CallRef;
RecordStorageLocation LocS1(Inputs.SType, RecordStorageLocation::FieldToLoc(),
{});
RecordStorageLocation LocS2(Inputs.SType, RecordStorageLocation::FieldToLoc(),
{});

LatticeT Lattice;
auto NopInit = [](StorageLocation &) {};
StorageLocation *RetLoc1 =
Lattice.getOrCreateConstMethodReturnStorageLocation(LocS1, CE, Env,
NopInit);
Lattice.clearConstMethodReturnStorageLocations(LocS2);
auto NotCalled = [](StorageLocation &) {
ASSERT_TRUE(false) << "Not reached";
};
StorageLocation *RetLoc2 =
Lattice.getOrCreateConstMethodReturnStorageLocation(LocS1, CE, Env,
NotCalled);

EXPECT_EQ(RetLoc1, RetLoc2);
}

TEST_F(CachedConstAccessorsLatticeTest, DifferentValsFromDifferentLocs) {
TestAST AST(R"cpp(
struct S {
int *valProperty() const;
};
void target() {
S s1;
s1.valProperty();
S s2;
s2.valProperty();
}
)cpp");
auto *SDecl =
cast<CXXRecordDecl>(lookup("S", *AST.context().getTranslationUnitDecl()));
QualType SType = AST.context().getRecordType(SDecl);
SmallVector<BoundNodes, 1> valPropertyCalls =
match(cxxMemberCallExpr(callee(functionDecl(hasName("valProperty"))))
.bind("call"),
AST.context());
ASSERT_THAT(valPropertyCalls, SizeIs(2));

const CallExpr *CE1 = selectFirst<CallExpr>("call", valPropertyCalls);
ASSERT_NE(CE1, nullptr);

valPropertyCalls.erase(valPropertyCalls.begin());
const CallExpr *CE2 = selectFirst<CallExpr>("call", valPropertyCalls);
ASSERT_NE(CE2, nullptr);
ASSERT_NE(CE1, CE2);

RecordStorageLocation LocS1(SType, RecordStorageLocation::FieldToLoc(), {});
RecordStorageLocation LocS2(SType, RecordStorageLocation::FieldToLoc(), {});

LatticeT Lattice;
Value *Val1 = Lattice.getOrCreateConstMethodReturnValue(LocS1, CE1, Env);
Value *Val2 = Lattice.getOrCreateConstMethodReturnValue(LocS2, CE2, Env);

EXPECT_NE(Val1, Val2);
}

TEST_F(CachedConstAccessorsLatticeTest, JoinSameNoop) {
CommonTestInputs Inputs;
auto *CE = Inputs.CallVal;
RecordStorageLocation Loc(Inputs.SType, RecordStorageLocation::FieldToLoc(),
{});

LatticeT EmptyLattice;
LatticeT EmptyLattice2;
EXPECT_EQ(EmptyLattice.join(EmptyLattice2), LatticeJoinEffect::Unchanged);

LatticeT Lattice1;
Lattice1.getOrCreateConstMethodReturnValue(Loc, CE, Env);
EXPECT_EQ(Lattice1.join(Lattice1), LatticeJoinEffect::Unchanged);
}

TEST_F(CachedConstAccessorsLatticeTest, ProducesNewValueAfterJoinDistinct) {
CommonTestInputs Inputs;
auto *CE = Inputs.CallVal;
RecordStorageLocation Loc(Inputs.SType, RecordStorageLocation::FieldToLoc(),
{});

// L1 w/ v vs L2 empty
LatticeT Lattice1;
Value *Val1 = Lattice1.getOrCreateConstMethodReturnValue(Loc, CE, Env);

LatticeT EmptyLattice;

EXPECT_EQ(Lattice1.join(EmptyLattice), LatticeJoinEffect::Changed);
Value *ValAfterJoin =
Lattice1.getOrCreateConstMethodReturnValue(Loc, CE, Env);

EXPECT_NE(ValAfterJoin, Val1);

// L1 w/ v1 vs L3 w/ v2
LatticeT Lattice3;
Value *Val3 = Lattice3.getOrCreateConstMethodReturnValue(Loc, CE, Env);

EXPECT_EQ(Lattice1.join(Lattice3), LatticeJoinEffect::Changed);
Value *ValAfterJoin2 =
Lattice1.getOrCreateConstMethodReturnValue(Loc, CE, Env);

EXPECT_NE(ValAfterJoin2, ValAfterJoin);
EXPECT_NE(ValAfterJoin2, Val3);
}

} // namespace
} // namespace clang::dataflow
51 changes: 26 additions & 25 deletions clang/utils/TableGen/MveEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1033,15 +1033,15 @@ class EmitterBase {
// to expand Tablegen classes like 'Vector' which mean something different in
// each member of a parametric family.
const Type *getType(const Record *R, const Type *Param);
const Type *getType(DagInit *D, const Type *Param);
const Type *getType(Init *I, const Type *Param);
const Type *getType(const DagInit *D, const Type *Param);
const Type *getType(const Init *I, const Type *Param);

// Functions that translate the Tablegen representation of an intrinsic's
// code generation into a collection of Value objects (which will then be
// reprocessed to read out the actual C++ code included by CGBuiltin.cpp).
Result::Ptr getCodeForDag(DagInit *D, const Result::Scope &Scope,
Result::Ptr getCodeForDag(const DagInit *D, const Result::Scope &Scope,
const Type *Param);
Result::Ptr getCodeForDagArg(DagInit *D, unsigned ArgNum,
Result::Ptr getCodeForDagArg(const DagInit *D, unsigned ArgNum,
const Result::Scope &Scope, const Type *Param);
Result::Ptr getCodeForArg(unsigned ArgNum, const Type *ArgType, bool Promote,
bool Immediate);
Expand All @@ -1060,10 +1060,10 @@ class EmitterBase {
void EmitBuiltinAliases(raw_ostream &OS);
};

const Type *EmitterBase::getType(Init *I, const Type *Param) {
if (auto Dag = dyn_cast<DagInit>(I))
const Type *EmitterBase::getType(const Init *I, const Type *Param) {
if (const auto *Dag = dyn_cast<DagInit>(I))
return getType(Dag, Param);
if (auto Def = dyn_cast<DefInit>(I))
if (const auto *Def = dyn_cast<DefInit>(I))
return getType(Def->getDef(), Param);

PrintFatalError("Could not convert this value into a type");
Expand All @@ -1088,7 +1088,7 @@ const Type *EmitterBase::getType(const Record *R, const Type *Param) {
PrintFatalError(R->getLoc(), "Could not convert this record into a type");
}

const Type *EmitterBase::getType(DagInit *D, const Type *Param) {
const Type *EmitterBase::getType(const DagInit *D, const Type *Param) {
// The meat of the getType system: types in the Tablegen are represented by a
// dag whose operators select sub-cases of this function.

Expand Down Expand Up @@ -1156,7 +1156,8 @@ const Type *EmitterBase::getType(DagInit *D, const Type *Param) {
PrintFatalError("Bad operator in type dag expression");
}

Result::Ptr EmitterBase::getCodeForDag(DagInit *D, const Result::Scope &Scope,
Result::Ptr EmitterBase::getCodeForDag(const DagInit *D,
const Result::Scope &Scope,
const Type *Param) {
const Record *Op = cast<DefInit>(D->getOperator())->getDef();

Expand Down Expand Up @@ -1199,14 +1200,14 @@ Result::Ptr EmitterBase::getCodeForDag(DagInit *D, const Result::Scope &Scope,
Result::Ptr Arg = getCodeForDagArg(D, 0, Scope, Param);

const Type *Ty = nullptr;
if (auto *DI = dyn_cast<DagInit>(D->getArg(0)))
if (const auto *DI = dyn_cast<DagInit>(D->getArg(0)))
if (auto *PTy = dyn_cast<PointerType>(getType(DI->getOperator(), Param)))
Ty = PTy->getPointeeType();
if (!Ty)
PrintFatalError("'address' pointer argument should be a pointer");

unsigned Alignment;
if (auto *II = dyn_cast<IntInit>(D->getArg(1))) {
if (const auto *II = dyn_cast<IntInit>(D->getArg(1))) {
Alignment = II->getValue();
} else {
PrintFatalError("'address' alignment argument should be an integer");
Expand Down Expand Up @@ -1267,10 +1268,10 @@ Result::Ptr EmitterBase::getCodeForDag(DagInit *D, const Result::Scope &Scope,
}
}

Result::Ptr EmitterBase::getCodeForDagArg(DagInit *D, unsigned ArgNum,
Result::Ptr EmitterBase::getCodeForDagArg(const DagInit *D, unsigned ArgNum,
const Result::Scope &Scope,
const Type *Param) {
Init *Arg = D->getArg(ArgNum);
const Init *Arg = D->getArg(ArgNum);
StringRef Name = D->getArgNameStr(ArgNum);

if (!Name.empty()) {
Expand All @@ -1286,18 +1287,18 @@ Result::Ptr EmitterBase::getCodeForDagArg(DagInit *D, unsigned ArgNum,
// Sometimes the Arg is a bit. Prior to multiclass template argument
// checking, integers would sneak through the bit declaration,
// but now they really are bits.
if (auto *BI = dyn_cast<BitInit>(Arg))
if (const auto *BI = dyn_cast<BitInit>(Arg))
return std::make_shared<IntLiteralResult>(getScalarType("u32"),
BI->getValue());

if (auto *II = dyn_cast<IntInit>(Arg))
if (const auto *II = dyn_cast<IntInit>(Arg))
return std::make_shared<IntLiteralResult>(getScalarType("u32"),
II->getValue());

if (auto *DI = dyn_cast<DagInit>(Arg))
if (const auto *DI = dyn_cast<DagInit>(Arg))
return getCodeForDag(DI, Scope, Param);

if (auto *DI = dyn_cast<DefInit>(Arg)) {
if (const auto *DI = dyn_cast<DefInit>(Arg)) {
const Record *Rec = DI->getDef();
if (Rec->isSubClassOf("Type")) {
const Type *T = getType(Rec, Param);
Expand All @@ -1307,7 +1308,7 @@ Result::Ptr EmitterBase::getCodeForDagArg(DagInit *D, unsigned ArgNum,

PrintError("bad DAG argument type for code generation");
PrintNote("DAG: " + D->getAsString());
if (TypedInit *Typed = dyn_cast<TypedInit>(Arg))
if (const auto *Typed = dyn_cast<TypedInit>(Arg))
PrintNote("argument type: " + Typed->getType()->getAsString());
PrintFatalNote("argument number " + Twine(ArgNum) + ": " + Arg->getAsString());
}
Expand Down Expand Up @@ -1379,13 +1380,13 @@ ACLEIntrinsic::ACLEIntrinsic(EmitterBase &ME, const Record *R,
HeaderOnly = R->getValueAsBit("headerOnly");

// Process the intrinsic's argument list.
DagInit *ArgsDag = R->getValueAsDag("args");
const DagInit *ArgsDag = R->getValueAsDag("args");
Result::Scope Scope;
for (unsigned i = 0, e = ArgsDag->getNumArgs(); i < e; ++i) {
Init *TypeInit = ArgsDag->getArg(i);
const Init *TypeInit = ArgsDag->getArg(i);

bool Promote = true;
if (auto TypeDI = dyn_cast<DefInit>(TypeInit))
if (const auto *TypeDI = dyn_cast<DefInit>(TypeInit))
if (TypeDI->getDef()->isSubClassOf("unpromoted"))
Promote = false;

Expand All @@ -1397,7 +1398,7 @@ ACLEIntrinsic::ACLEIntrinsic(EmitterBase &ME, const Record *R,
// If the argument is a subclass of Immediate, record the details about
// what values it can take, for Sema checking.
bool Immediate = false;
if (auto TypeDI = dyn_cast<DefInit>(TypeInit)) {
if (const auto *TypeDI = dyn_cast<DefInit>(TypeInit)) {
const Record *TypeRec = TypeDI->getDef();
if (TypeRec->isSubClassOf("Immediate")) {
Immediate = true;
Expand Down Expand Up @@ -1444,7 +1445,7 @@ ACLEIntrinsic::ACLEIntrinsic(EmitterBase &ME, const Record *R,

// Finally, go through the codegen dag and translate it into a Result object
// (with an arbitrary DAG of depended-on Results hanging off it).
DagInit *CodeDag = R->getValueAsDag("codegen");
const DagInit *CodeDag = R->getValueAsDag("codegen");
const Record *MainOp = cast<DefInit>(CodeDag->getOperator())->getDef();
if (MainOp->isSubClassOf("CustomCodegen")) {
// Or, if it's the special case of CustomCodegen, just accumulate
Expand All @@ -1456,9 +1457,9 @@ ACLEIntrinsic::ACLEIntrinsic(EmitterBase &ME, const Record *R,
StringRef Name = CodeDag->getArgNameStr(i);
if (Name.empty()) {
PrintFatalError("Operands to CustomCodegen should have names");
} else if (auto *II = dyn_cast<IntInit>(CodeDag->getArg(i))) {
} else if (const auto *II = dyn_cast<IntInit>(CodeDag->getArg(i))) {
CustomCodeGenArgs[std::string(Name)] = itostr(II->getValue());
} else if (auto *SI = dyn_cast<StringInit>(CodeDag->getArg(i))) {
} else if (const auto *SI = dyn_cast<StringInit>(CodeDag->getArg(i))) {
CustomCodeGenArgs[std::string(Name)] = std::string(SI->getValue());
} else {
PrintFatalError("Operands to CustomCodegen should be integers");
Expand Down
5 changes: 0 additions & 5 deletions cmake/Modules/CMakePolicy.cmake
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
# CMake policy settings shared between LLVM projects

# CMP0114: ExternalProject step targets fully adopt their steps.
# New in CMake 3.19: https://cmake.org/cmake/help/latest/policy/CMP0114.html
if(POLICY CMP0114)
cmake_policy(SET CMP0114 OLD)
endif()
# CMP0116: Ninja generators transform `DEPFILE`s from `add_custom_command()`
# New in CMake 3.20. https://cmake.org/cmake/help/latest/policy/CMP0116.html
if(POLICY CMP0116)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include <Foundation/Foundation.h>

@interface Foo : NSObject
@end

@implementation Foo
@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: %clang -c -o %t/EmptyClassFoo.o %S/Inputs/EmptyClassFoo.m
// RUN: ar r %t/libFooClass.a %t/EmptyClassFoo.o
// RUN: %clang -c -o %t/force-objc.o %s
// RUN: %llvm_jitlink -ObjC %t/force-objc.o -L%t -lFooClass
//
// REQUIRES: system-darwin && host-arch-compatible

id objc_getClass(const char *name);

int main(int argc, char *argv[]) {
// Return succeess if we find Foo, error otherwise.
return objc_getClass("Foo") ? 0 : 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
extern "C" int x;

namespace {

struct Init {
public:
Init() { x = 1; }
};

Init SetX;

} // namespace
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Check that the -all_load flag to llvm-jitlink causes all objects from
// archives to be loaded, regardless of whether or not they're referenced.
//
// RUN: rm -rf %t && mkdir -p %t
// RUN: %clangxx -c -o %t/SetX.o %S/Inputs/SetGlobalIntXInConstructor.cpp
// RUN: ar r %t/libSetX.a %t/SetX.o
// RUN: %clang -c -o %t/all_load.o %s
// RUN: %llvm_jitlink -all_load %t/all_load.o -L%t -lSetX
//
// REQUIRES: system-darwin && host-arch-compatible

int x = 0;

int main(int argc, char *argv[]) { return x == 1 ? 0 : 1; }
5 changes: 4 additions & 1 deletion compiler-rt/test/orc/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

if config.host_arch == "x86_64h" and config.target_arch == "x86_64":
host_arch_compatible = True
if host_arch_compatible:
config.available_features.add("host-arch-compatible")
config.test_target_is_host_executable = (
config.target_os == config.host_os and host_arch_compatible
)
Expand Down Expand Up @@ -71,9 +73,10 @@ def build_invocation(compile_flags):
(lli + " -jit-kind=orc -jit-linker=jitlink -orc-runtime=" + orc_rt_path),
)
)
config.substitutions.append(("%ar", "ar"))

# Default test suffixes.
config.suffixes = [".c", ".cpp", ".S", ".ll", ".test"]
config.suffixes = [".c", ".cpp", ".m", ".S", ".ll", ".test"]

# Exclude Inputs directories.
config.excludes = ["Inputs"]
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/test/profile/Posix/instrprof-visibility.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// XFAIL: target={{.*}}-aix{{.*}}
// RUN: %clangxx_profgen -fcoverage-mapping %S/Inputs/instrprof-visibility-helper.cpp -o %t %s
// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
// RUN: llvm-profdata merge %t.profraw -o %t.profdata
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/test/profile/coverage-inline.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// XFAIL: target={{.*}}-aix{{.*}}
// Test that the instrumentation puts the right linkage on the profile data for
// inline functions.
// RUN: %clang_profgen -g -fcoverage-mapping -c -o %t1.o %s -DOBJECT_1
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/test/profile/coverage_comments.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// XFAIL: target={{.*}}-aix{{.*}}
// RUN: %clangxx_profgen -fcoverage-mapping -Wno-comment -o %t %s
// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
// RUN: llvm-profdata merge -o %t.profdata %t.profraw
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/test/profile/coverage_emptylines.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// XFAIL: target={{.*}}-aix{{.*}}
// Remove comments first.
// RUN: sed 's/[ \t]*\/\/.*//' %s > %t.stripped.cpp
// RUN: %clangxx_profgen -fcoverage-mapping -o %t %t.stripped.cpp
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/test/profile/instrprof-merging.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// UNSUPPORTED: target={{.*windows.*}}
// XFAIL: target={{.*}}-aix{{.*}}
// 1) Compile shared code into different object files and into an executable.

// RUN: %clangxx_profgen -std=c++14 -fcoverage-mapping %s -c -o %t.v1.o \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ int main(int argc, const char *argv[]) {

return 0;
}
// XFAIL: target={{.*}}-aix{{.*}}
// CHECK: 10| |#include <stdio.h>
// CHECK: 11| |
// CHECK: 12| |extern void __llvm_profile_set_file_object(FILE *, int);
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/test/profile/instrprof-set-file-object.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ int main(int argc, const char *argv[]) {
__llvm_profile_set_file_object(F, 0);
return 0;
}
// XFAIL: target={{.*}}-aix{{.*}}
// CHECK: 8| |#include <stdio.h>
// CHECK: 9| |
// CHECK: 10| |extern void __llvm_profile_set_file_object(FILE *, int);
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/test/profile/instrprof-without-libc.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// XFAIL: target={{.*}}-aix{{.*}}
// RUN: %clang_profgen -DCHECK_SYMBOLS -O3 -o %t.symbols %s
// RUN: llvm-nm %t.symbols | FileCheck %s --check-prefix=CHECK-SYMBOLS
// RUN: %clang_profgen -O3 -o %t %s
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/test/profile/instrprof-write-file-only.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// XFAIL: target={{.*}}-aix{{.*}}
// RUN: %clang_profgen -o %t -O3 %s
// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
// RUN: llvm-profdata merge -o %t.profdata %t.profraw
Expand Down
8 changes: 2 additions & 6 deletions compiler-rt/test/profile/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,8 @@ def exclude_unsupported_files_for_aix(dirname):
f = open(source_path, "r")
try:
data = f.read()
# -fprofile-instr-generate and rpath are not supported on AIX, exclude all tests with them.
if (
"%clang_profgen" in data
or "%clangxx_profgen" in data
or "-rpath" in data
):
# rpath is not supported on AIX, exclude all tests with them.
if ( "-rpath" in data ):
config.excludes += [filename]
finally:
f.close()
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Evaluate/intrinsics-library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ template <> struct HostRuntimeLibrary<double, LibraryVersion::LibmExtensions> {
static_assert(map.Verify(), "map must be sorted");
};

#if HAS_FLOAT80 || HAS_LDBL128
#if defined(__GLIBC__) && (HAS_FLOAT80 || HAS_LDBL128)
template <>
struct HostRuntimeLibrary<long double, LibraryVersion::LibmExtensions> {
using F = FuncPointer<long double, long double>;
Expand Down
16 changes: 12 additions & 4 deletions flang/lib/Lower/OpenMP/OpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2070,7 +2070,9 @@ static void genStandaloneSimd(lower::AbstractConverter &converter,
loopNestClauseOps, iv);

EntryBlockArgs simdArgs;
// TODO: Add private, reduction syms and vars.
// TODO: Add private syms and vars.
simdArgs.reduction.syms = simdReductionSyms;
simdArgs.reduction.vars = simdClauseOps.reductionVars;
auto simdOp =
genWrapperOp<mlir::omp::SimdOp>(converter, loc, simdClauseOps, simdArgs);

Expand Down Expand Up @@ -2228,7 +2230,9 @@ static void genCompositeDistributeParallelDoSimd(
wsloopOp.setComposite(/*val=*/true);

EntryBlockArgs simdArgs;
// TODO: Add private, reduction syms and vars.
// TODO: Add private syms and vars.
simdArgs.reduction.syms = simdReductionSyms;
simdArgs.reduction.vars = simdClauseOps.reductionVars;
auto simdOp =
genWrapperOp<mlir::omp::SimdOp>(converter, loc, simdClauseOps, simdArgs);
simdOp.setComposite(/*val=*/true);
Expand Down Expand Up @@ -2285,7 +2289,9 @@ static void genCompositeDistributeSimd(lower::AbstractConverter &converter,
distributeOp.setComposite(/*val=*/true);

EntryBlockArgs simdArgs;
// TODO: Add private, reduction syms and vars.
// TODO: Add private syms and vars.
simdArgs.reduction.syms = simdReductionSyms;
simdArgs.reduction.vars = simdClauseOps.reductionVars;
auto simdOp =
genWrapperOp<mlir::omp::SimdOp>(converter, loc, simdClauseOps, simdArgs);
simdOp.setComposite(/*val=*/true);
Expand Down Expand Up @@ -2342,7 +2348,9 @@ static void genCompositeDoSimd(lower::AbstractConverter &converter,
wsloopOp.setComposite(/*val=*/true);

EntryBlockArgs simdArgs;
// TODO: Add private, reduction syms and vars.
// TODO: Add private syms and vars.
simdArgs.reduction.syms = simdReductionSyms;
simdArgs.reduction.vars = simdClauseOps.reductionVars;
auto simdOp =
genWrapperOp<mlir::omp::SimdOp>(converter, loc, simdClauseOps, simdArgs);
simdOp.setComposite(/*val=*/true);
Expand Down
9 changes: 6 additions & 3 deletions flang/runtime/Float128Math/math-entries.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,6 @@ DEFINE_SIMPLE_ALIAS(Hypot, std::hypot)
DEFINE_SIMPLE_ALIAS(Ilogb, std::ilogb)
DEFINE_SIMPLE_ALIAS(Isinf, std::isinf)
DEFINE_SIMPLE_ALIAS(Isnan, std::isnan)
DEFINE_SIMPLE_ALIAS(J0, j0l)
DEFINE_SIMPLE_ALIAS(J1, j1l)
DEFINE_SIMPLE_ALIAS(Jn, jnl)
DEFINE_SIMPLE_ALIAS(Ldexp, std::ldexp)
DEFINE_SIMPLE_ALIAS(Lgamma, std::lgamma)
DEFINE_SIMPLE_ALIAS(Llround, std::llround)
Expand All @@ -207,9 +204,15 @@ DEFINE_SIMPLE_ALIAS(Tan, std::tan)
DEFINE_SIMPLE_ALIAS(Tanh, std::tanh)
DEFINE_SIMPLE_ALIAS(Tgamma, std::tgamma)
DEFINE_SIMPLE_ALIAS(Trunc, std::trunc)

#if defined(__GLIBC__) && defined(_GNU_SOURCE)
DEFINE_SIMPLE_ALIAS(J0, j0l)
DEFINE_SIMPLE_ALIAS(J1, j1l)
DEFINE_SIMPLE_ALIAS(Jn, jnl)
DEFINE_SIMPLE_ALIAS(Y0, y0l)
DEFINE_SIMPLE_ALIAS(Y1, y1l)
DEFINE_SIMPLE_ALIAS(Yn, ynl)
#endif

// Use numeric_limits to produce infinity of the right type.
#define F128_RT_INFINITY \
Expand Down
5 changes: 5 additions & 0 deletions flang/test/Driver/atomic.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
!RUN: %flang --target=aarch64-unknown-linux-gnu -fuse-ld=ld -fopenmp -rtlib=libgcc -### %s 2>&1 | FileCheck --check-prefixes=GCC %s
!RUN: %flang --target=aarch64-unknown-linux-gnu -fuse-ld=ld -fopenmp -rtlib=compiler-rt -### %s 2>&1 | FileCheck --check-prefixes=CRT %s

!GCC: -latomic
!CRT-NOT: -latomic
Loading