129 changes: 74 additions & 55 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8517,6 +8517,53 @@ class LValueExprEvaluator
};
} // end anonymous namespace

/// Get an lvalue to a field of a lambda's closure type.
static bool HandleLambdaCapture(EvalInfo &Info, const Expr *E, LValue &Result,
const CXXMethodDecl *MD, const FieldDecl *FD,
bool LValueToRValueConversion) {
// Static lambda function call operators can't have captures. We already
// diagnosed this, so bail out here.
if (MD->isStatic()) {
assert(Info.CurrentCall->This == nullptr &&
"This should not be set for a static call operator");
return false;
}

// Start with 'Result' referring to the complete closure object...
if (MD->isExplicitObjectMemberFunction()) {
// Self may be passed by reference or by value.
const ParmVarDecl *Self = MD->getParamDecl(0);
if (Self->getType()->isReferenceType()) {
APValue *RefValue = Info.getParamSlot(Info.CurrentCall->Arguments, Self);
Result.setFrom(Info.Ctx, *RefValue);
} else {
const ParmVarDecl *VD = Info.CurrentCall->Arguments.getOrigParam(Self);
CallStackFrame *Frame =
Info.getCallFrameAndDepth(Info.CurrentCall->Arguments.CallIndex)
.first;
unsigned Version = Info.CurrentCall->Arguments.Version;
Result.set({VD, Frame->Index, Version});
}
} else
Result = *Info.CurrentCall->This;

// ... then update it to refer to the field of the closure object
// that represents the capture.
if (!HandleLValueMember(Info, E, Result, FD))
return false;

// And if the field is of reference type (or if we captured '*this' by
// reference), update 'Result' to refer to what
// the field refers to.
if (LValueToRValueConversion) {
APValue RVal;
if (!handleLValueToRValueConversion(Info, E, FD->getType(), Result, RVal))
return false;
Result.setFrom(Info.Ctx, RVal);
}
return true;
}

/// Evaluate an expression as an lvalue. This can be legitimately called on
/// expressions which are not glvalues, in three cases:
/// * function designators in C, and
Expand Down Expand Up @@ -8561,37 +8608,8 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {

if (auto *FD = Info.CurrentCall->LambdaCaptureFields.lookup(VD)) {
const auto *MD = cast<CXXMethodDecl>(Info.CurrentCall->Callee);

// Static lambda function call operators can't have captures. We already
// diagnosed this, so bail out here.
if (MD->isStatic()) {
assert(Info.CurrentCall->This == nullptr &&
"This should not be set for a static call operator");
return false;
}

// Start with 'Result' referring to the complete closure object...
if (MD->isExplicitObjectMemberFunction()) {
APValue *RefValue =
Info.getParamSlot(Info.CurrentCall->Arguments, MD->getParamDecl(0));
Result.setFrom(Info.Ctx, *RefValue);
} else
Result = *Info.CurrentCall->This;

// ... then update it to refer to the field of the closure object
// that represents the capture.
if (!HandleLValueMember(Info, E, Result, FD))
return false;
// And if the field is of reference type, update 'Result' to refer to what
// the field refers to.
if (FD->getType()->isReferenceType()) {
APValue RVal;
if (!handleLValueToRValueConversion(Info, E, FD->getType(), Result,
RVal))
return false;
Result.setFrom(Info.Ctx, RVal);
}
return true;
return HandleLambdaCapture(Info, E, Result, MD, FD,
FD->getType()->isReferenceType());
}
}

Expand Down Expand Up @@ -9069,45 +9087,46 @@ class PointerExprEvaluator
return Error(E);
}
bool VisitCXXThisExpr(const CXXThisExpr *E) {
// Can't look at 'this' when checking a potential constant expression.
if (Info.checkingPotentialConstantExpression())
return false;
if (!Info.CurrentCall->This) {
auto DiagnoseInvalidUseOfThis = [&] {
if (Info.getLangOpts().CPlusPlus11)
Info.FFDiag(E, diag::note_constexpr_this) << E->isImplicit();
else
Info.FFDiag(E);
};

// Can't look at 'this' when checking a potential constant expression.
if (Info.checkingPotentialConstantExpression())
return false;

bool IsExplicitLambda =
isLambdaCallWithExplicitObjectParameter(Info.CurrentCall->Callee);
if (!IsExplicitLambda) {
if (!Info.CurrentCall->This) {
DiagnoseInvalidUseOfThis();
return false;
}

Result = *Info.CurrentCall->This;
}
Result = *Info.CurrentCall->This;

if (isLambdaCallOperator(Info.CurrentCall->Callee)) {
// Ensure we actually have captured 'this'. If something was wrong with
// 'this' capture, the error would have been previously reported.
// Otherwise we can be inside of a default initialization of an object
// declared by lambda's body, so no need to return false.
if (!Info.CurrentCall->LambdaThisCaptureField)
return true;

// If we have captured 'this', the 'this' expression refers
// to the enclosing '*this' object (either by value or reference) which is
// either copied into the closure object's field that represents the
// '*this' or refers to '*this'.
// Update 'Result' to refer to the data member/field of the closure object
// that represents the '*this' capture.
if (!HandleLValueMember(Info, E, Result,
Info.CurrentCall->LambdaThisCaptureField))
return false;
// If we captured '*this' by reference, replace the field with its referent.
if (Info.CurrentCall->LambdaThisCaptureField->getType()
->isPointerType()) {
APValue RVal;
if (!handleLValueToRValueConversion(Info, E, E->getType(), Result,
RVal))
if (!Info.CurrentCall->LambdaThisCaptureField) {
if (IsExplicitLambda && !Info.CurrentCall->This) {
DiagnoseInvalidUseOfThis();
return false;
}

Result.setFrom(Info.Ctx, RVal);
return true;
}

const auto *MD = cast<CXXMethodDecl>(Info.CurrentCall->Callee);
return HandleLambdaCapture(
Info, E, Result, MD, Info.CurrentCall->LambdaThisCaptureField,
Info.CurrentCall->LambdaThisCaptureField->getType()->isPointerType());
}
return true;
}
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -846,8 +846,7 @@ bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
CmpInfo->getValueInfo(CmpInfo->makeWeakResult(CmpResult));
assert(CmpValueInfo);
assert(CmpValueInfo->hasValidIntValue());
const APSInt &IntValue = CmpValueInfo->getIntValue();
return SetThreeWayComparisonField(S, OpPC, P, IntValue);
return SetThreeWayComparisonField(S, OpPC, P, CmpValueInfo->getIntValue());
}

template <PrimType Name, class T = typename PrimConv<Name>::T>
Expand Down
7 changes: 3 additions & 4 deletions clang/lib/Basic/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,10 +301,9 @@ bool Module::directlyUses(const Module *Requested) {
if (Requested->isSubModuleOf(Use))
return true;

// Anyone is allowed to use our builtin stdarg.h and stddef.h and their
// accompanying modules.
if (Requested->getTopLevelModuleName() == "_Builtin_stdarg" ||
Requested->getTopLevelModuleName() == "_Builtin_stddef")
// Anyone is allowed to use our builtin stddef.h and its accompanying modules.
if (Requested->fullModuleNameIs({"_Builtin_stddef", "max_align_t"}) ||
Requested->fullModuleNameIs({"_Builtin_stddef_wint_t"}))
return true;

if (NoUndeclaredIncludes)
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl(
setTLSMode(GV, D);

setGVProperties(GV, &D);
getTargetCodeGenInfo().setTargetAttributes(cast<Decl>(&D), GV, *this);

// Make sure the result is of the correct type.
LangAS ExpectedAS = Ty.getAddressSpace();
Expand Down
26 changes: 26 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,26 @@ static bool checkAliasedGlobal(
return true;
}

// Emit a warning if toc-data attribute is requested for global variables that
// have aliases and remove the toc-data attribute.
static void checkAliasForTocData(llvm::GlobalVariable *GVar,
const CodeGenOptions &CodeGenOpts,
DiagnosticsEngine &Diags,
SourceLocation Location) {
if (GVar->hasAttribute("toc-data")) {
auto GVId = GVar->getName();
// Is this a global variable specified by the user as local?
if ((llvm::binary_search(CodeGenOpts.TocDataVarsUserSpecified, GVId))) {
Diags.Report(Location, diag::warn_toc_unsupported_type)
<< GVId << "the variable has an alias";
}
llvm::AttributeSet CurrAttributes = GVar->getAttributes();
llvm::AttributeSet NewAttributes =
CurrAttributes.removeAttribute(GVar->getContext(), "toc-data");
GVar->setAttributes(NewAttributes);
}
}

void CodeGenModule::checkAliases() {
// Check if the constructed aliases are well formed. It is really unfortunate
// that we have to do this in CodeGen, but we only construct mangled names
Expand All @@ -652,6 +672,12 @@ void CodeGenModule::checkAliases() {
continue;
}

if (getContext().getTargetInfo().getTriple().isOSAIX())
if (const llvm::GlobalVariable *GVar =
dyn_cast<const llvm::GlobalVariable>(GV))
checkAliasForTocData(const_cast<llvm::GlobalVariable *>(GVar),
getCodeGenOpts(), Diags, Location);

llvm::Constant *Aliasee =
IsIFunc ? cast<llvm::GlobalIFunc>(Alias)->getResolver()
: cast<llvm::GlobalAlias>(Alias)->getAliasee();
Expand Down
59 changes: 59 additions & 0 deletions clang/lib/CodeGen/Targets/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "ABIInfoImpl.h"
#include "TargetInfo.h"
#include "clang/Basic/DiagnosticFrontend.h"

using namespace clang;
using namespace clang::CodeGen;
Expand Down Expand Up @@ -145,6 +146,9 @@ class AIXTargetCodeGenInfo : public TargetCodeGenInfo {

bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const override;

void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
CodeGen::CodeGenModule &M) const override;
};
} // namespace

Expand Down Expand Up @@ -265,6 +269,61 @@ bool AIXTargetCodeGenInfo::initDwarfEHRegSizeTable(
return PPC_initDwarfEHRegSizeTable(CGF, Address, Is64Bit, /*IsAIX*/ true);
}

void AIXTargetCodeGenInfo::setTargetAttributes(
const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const {
if (!isa<llvm::GlobalVariable>(GV))
return;

auto *GVar = dyn_cast<llvm::GlobalVariable>(GV);
auto GVId = GV->getName();

// Is this a global variable specified by the user as toc-data?
bool UserSpecifiedTOC =
llvm::binary_search(M.getCodeGenOpts().TocDataVarsUserSpecified, GVId);
// Assumes the same variable cannot be in both TocVarsUserSpecified and
// NoTocVars.
if (UserSpecifiedTOC ||
((M.getCodeGenOpts().AllTocData) &&
!llvm::binary_search(M.getCodeGenOpts().NoTocDataVars, GVId))) {
const unsigned long PointerSize =
GV->getParent()->getDataLayout().getPointerSizeInBits() / 8;
auto *VarD = dyn_cast<VarDecl>(D);
assert(VarD && "Invalid declaration of global variable.");

ASTContext &Context = D->getASTContext();
unsigned Alignment = Context.toBits(Context.getDeclAlign(D)) / 8;
const auto *Ty = VarD->getType().getTypePtr();
const RecordDecl *RDecl =
Ty->isRecordType() ? Ty->getAs<RecordType>()->getDecl() : nullptr;

bool EmitDiagnostic = UserSpecifiedTOC && GV->hasExternalLinkage();
auto reportUnsupportedWarning = [&](bool ShouldEmitWarning, StringRef Msg) {
if (ShouldEmitWarning)
M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type)
<< GVId << Msg;
};
if (!Ty || Ty->isIncompleteType())
reportUnsupportedWarning(EmitDiagnostic, "of incomplete type");
else if (RDecl && RDecl->hasFlexibleArrayMember())
reportUnsupportedWarning(EmitDiagnostic,
"it contains a flexible array member");
else if (VarD->getTLSKind() != VarDecl::TLS_None)
reportUnsupportedWarning(EmitDiagnostic, "of thread local storage");
else if (PointerSize < Context.getTypeInfo(VarD->getType()).Width / 8)
reportUnsupportedWarning(EmitDiagnostic,
"variable is larger than a pointer");
else if (PointerSize < Alignment)
reportUnsupportedWarning(EmitDiagnostic,
"variable is aligned wider than a pointer");
else if (D->hasAttr<SectionAttr>())
reportUnsupportedWarning(EmitDiagnostic,
"variable has a section attribute");
else if (GV->hasExternalLinkage() ||
(M.getCodeGenOpts().AllTocData && !GV->hasLocalLinkage()))
GVar->addAttribute("toc-data");
}
}

// PowerPC-32
namespace {
/// PPC32_SVR4_ABIInfo - The 32-bit PowerPC ELF (SVR4) ABI information.
Expand Down
87 changes: 87 additions & 0 deletions clang/lib/Driver/ToolChains/AIX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,13 +433,100 @@ void AIX::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
llvm_unreachable("Unexpected C++ library type; only libc++ is supported.");
}

// This function processes all the mtocdata options to build the final
// simplified toc data options to pass to CC1.
static void addTocDataOptions(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CC1Args,
const Driver &D) {

// Check the global toc-data setting. The default is -mno-tocdata.
// To enable toc-data globally, -mtocdata must be specified.
// Additionally, it must be last to take effect.
const bool TOCDataGloballyinEffect = [&Args]() {
if (const Arg *LastArg =
Args.getLastArg(options::OPT_mtocdata, options::OPT_mno_tocdata))
return LastArg->getOption().matches(options::OPT_mtocdata);
else
return false;
}();

// Currently only supported for small code model.
if (TOCDataGloballyinEffect &&
(Args.getLastArgValue(options::OPT_mcmodel_EQ).equals("large") ||
Args.getLastArgValue(options::OPT_mcmodel_EQ).equals("medium"))) {
D.Diag(clang::diag::warn_drv_unsupported_tocdata);
return;
}

enum TOCDataSetting {
AddressInTOC = 0, // Address of the symbol stored in the TOC.
DataInTOC = 1 // Symbol defined in the TOC.
};

const TOCDataSetting DefaultTocDataSetting =
TOCDataGloballyinEffect ? DataInTOC : AddressInTOC;

// Process the list of variables in the explicitly specified options
// -mtocdata= and -mno-tocdata= to see which variables are opposite to
// the global setting of tocdata in TOCDataGloballyinEffect.
// Those that have the opposite setting to TOCDataGloballyinEffect, are added
// to ExplicitlySpecifiedGlobals.
llvm::StringSet<> ExplicitlySpecifiedGlobals;
for (const auto Arg :
Args.filtered(options::OPT_mtocdata_EQ, options::OPT_mno_tocdata_EQ)) {
TOCDataSetting ArgTocDataSetting =
Arg->getOption().matches(options::OPT_mtocdata_EQ) ? DataInTOC
: AddressInTOC;

if (ArgTocDataSetting != DefaultTocDataSetting)
for (const char *Val : Arg->getValues())
ExplicitlySpecifiedGlobals.insert(Val);
else
for (const char *Val : Arg->getValues())
ExplicitlySpecifiedGlobals.erase(Val);
}

auto buildExceptionList = [](const llvm::StringSet<> &ExplicitValues,
const char *OptionSpelling) {
std::string Option(OptionSpelling);
bool IsFirst = true;
for (const auto &E : ExplicitValues) {
if (!IsFirst)
Option += ",";

IsFirst = false;
Option += E.first();
}
return Option;
};

// Pass the final tocdata options to CC1 consisting of the default
// tocdata option (-mtocdata/-mno-tocdata) along with the list
// option (-mno-tocdata=/-mtocdata=) if there are any explicitly specified
// variables which would be exceptions to the default setting.
const char *TocDataGlobalOption =
TOCDataGloballyinEffect ? "-mtocdata" : "-mno-tocdata";
CC1Args.push_back(TocDataGlobalOption);

const char *TocDataListOption =
TOCDataGloballyinEffect ? "-mno-tocdata=" : "-mtocdata=";
if (!ExplicitlySpecifiedGlobals.empty())
CC1Args.push_back(Args.MakeArgString(llvm::Twine(
buildExceptionList(ExplicitlySpecifiedGlobals, TocDataListOption))));
}

void AIX::addClangTargetOptions(
const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1Args,
Action::OffloadKind DeviceOffloadingKind) const {
Args.AddLastArg(CC1Args, options::OPT_mignore_xcoff_visibility);
Args.AddLastArg(CC1Args, options::OPT_mdefault_visibility_export_mapping_EQ);
Args.addOptInFlag(CC1Args, options::OPT_mxcoff_roptr, options::OPT_mno_xcoff_roptr);

// Forward last mtocdata/mno_tocdata options to -cc1.
if (Args.hasArg(options::OPT_mtocdata_EQ, options::OPT_mno_tocdata_EQ,
options::OPT_mtocdata))
addTocDataOptions(Args, CC1Args, getDriver());

if (Args.hasFlag(options::OPT_fxl_pragma_pack,
options::OPT_fno_xl_pragma_pack, true))
CC1Args.push_back("-fxl-pragma-pack");
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Frontend/CompilerInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,11 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
if (getFrontendOpts().ShowStats || !getFrontendOpts().StatsFile.empty())
llvm::EnableStatistics(false);

// Sort vectors containing toc data and no toc data variables to facilitate
// binary search later.
llvm::sort(getCodeGenOpts().TocDataVarsUserSpecified);
llvm::sort(getCodeGenOpts().NoTocDataVars);

for (const FrontendInputFile &FIF : getFrontendOpts().Inputs) {
// Reset the ID tables if we are reusing the SourceManager and parsing
// regular files.
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Headers/__stddef_null.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*===-----------------------------------------------------------------------===
*/

#if !defined(NULL) || !__has_feature(modules)
#if !defined(NULL) || !__building_module(_Builtin_stddef)

/* linux/stddef.h will define NULL to 0. glibc (and other) headers then define
* __need_NULL and rely on stddef.h to redefine NULL to the correct value again.
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Headers/__stddef_nullptr_t.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
*===-----------------------------------------------------------------------===
*/

#ifndef _NULLPTR_T
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(_NULLPTR_T) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define _NULLPTR_T

#ifdef __cplusplus
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Headers/__stddef_offsetof.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
*===-----------------------------------------------------------------------===
*/

#ifndef offsetof
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(offsetof) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define offsetof(t, d) __builtin_offsetof(t, d)
#endif
7 changes: 6 additions & 1 deletion clang/lib/Headers/__stddef_ptrdiff_t.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
*===-----------------------------------------------------------------------===
*/

#ifndef _PTRDIFF_T
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(_PTRDIFF_T) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define _PTRDIFF_T

typedef __PTRDIFF_TYPE__ ptrdiff_t;
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Headers/__stddef_rsize_t.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
*===-----------------------------------------------------------------------===
*/

#ifndef _RSIZE_T
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(_RSIZE_T) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define _RSIZE_T

typedef __SIZE_TYPE__ rsize_t;
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Headers/__stddef_size_t.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
*===-----------------------------------------------------------------------===
*/

#ifndef _SIZE_T
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(_SIZE_T) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define _SIZE_T

typedef __SIZE_TYPE__ size_t;
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Headers/__stddef_unreachable.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
*===-----------------------------------------------------------------------===
*/

#ifndef unreachable
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(unreachable) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define unreachable() __builtin_unreachable()
#endif
7 changes: 6 additions & 1 deletion clang/lib/Headers/__stddef_wchar_t.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@

#if !defined(__cplusplus) || (defined(_MSC_VER) && !_NATIVE_WCHAR_T_DEFINED)

#ifndef _WCHAR_T
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(_WCHAR_T) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define _WCHAR_T

#ifdef _MSC_EXTENSIONS
Expand Down
20 changes: 9 additions & 11 deletions clang/lib/Headers/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,9 @@ module _Builtin_intrinsics [system] [extern_c] {

// Start -fbuiltin-headers-in-system-modules affected modules

// The following modules all ignore their top level headers
// when -fbuiltin-headers-in-system-modules is passed, and
// most of those headers join system modules when present.
// The following modules all ignore their headers when
// -fbuiltin-headers-in-system-modules is passed, and many of
// those headers join system modules when present.

// e.g. if -fbuiltin-headers-in-system-modules is passed, then
// float.h will not be in the _Builtin_float module (that module
Expand Down Expand Up @@ -190,11 +190,6 @@ module _Builtin_stdalign [system] {
export *
}

// When -fbuiltin-headers-in-system-modules is passed, only
// the top level headers are removed, the implementation headers
// will always be in their submodules. That means when stdarg.h
// is included, it will still import this module and make the
// appropriate submodules visible.
module _Builtin_stdarg [system] {
textual header "stdarg.h"

Expand Down Expand Up @@ -237,6 +232,8 @@ module _Builtin_stdbool [system] {
module _Builtin_stddef [system] {
textual header "stddef.h"

// __stddef_max_align_t.h is always in this module, even if
// -fbuiltin-headers-in-system-modules is passed.
explicit module max_align_t {
header "__stddef_max_align_t.h"
export *
Expand Down Expand Up @@ -283,9 +280,10 @@ module _Builtin_stddef [system] {
}
}

/* wint_t is provided by <wchar.h> and not <stddef.h>. It's here
* for compatibility, but must be explicitly requested. Therefore
* __stddef_wint_t.h is not part of _Builtin_stddef. */
// wint_t is provided by <wchar.h> and not <stddef.h>. It's here
// for compatibility, but must be explicitly requested. Therefore
// __stddef_wint_t.h is not part of _Builtin_stddef. It is always in
// this module even if -fbuiltin-headers-in-system-modules is passed.
module _Builtin_stddef_wint_t [system] {
header "__stddef_wint_t.h"
export *
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/Lex/ModuleMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2498,9 +2498,12 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
}

bool NeedsFramework = false;
// Don't add the top level headers to the builtin modules if the builtin headers
// belong to the system modules.
if (!Map.LangOpts.BuiltinHeadersInSystemModules || ActiveModule->isSubModule() || !isBuiltInModuleName(ActiveModule->Name))
// Don't add headers to the builtin modules if the builtin headers belong to
// the system modules, with the exception of __stddef_max_align_t.h which
// always had its own module.
if (!Map.LangOpts.BuiltinHeadersInSystemModules ||
!isBuiltInModuleName(ActiveModule->getTopLevelModuleName()) ||
ActiveModule->fullModuleNameIs({"_Builtin_stddef", "max_align_t"}))
Map.addUnresolvedHeader(ActiveModule, std::move(Header), NeedsFramework);

if (NeedsFramework)
Expand Down
30 changes: 16 additions & 14 deletions clang/lib/Parse/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result,
// FIXME: We need a better way to disambiguate C++ clang modules and
// standard C++ modules.
if (!getLangOpts().CPlusPlusModules || !Mod->isHeaderUnit())
Actions.ActOnModuleInclude(Loc, Mod);
Actions.ActOnAnnotModuleInclude(Loc, Mod);
else {
DeclResult Import =
Actions.ActOnModuleImport(Loc, SourceLocation(), Loc, Mod);
Expand All @@ -697,15 +697,17 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result,
}

case tok::annot_module_begin:
Actions.ActOnModuleBegin(Tok.getLocation(), reinterpret_cast<Module *>(
Tok.getAnnotationValue()));
Actions.ActOnAnnotModuleBegin(
Tok.getLocation(),
reinterpret_cast<Module *>(Tok.getAnnotationValue()));
ConsumeAnnotationToken();
ImportState = Sema::ModuleImportState::NotACXX20Module;
return false;

case tok::annot_module_end:
Actions.ActOnModuleEnd(Tok.getLocation(), reinterpret_cast<Module *>(
Tok.getAnnotationValue()));
Actions.ActOnAnnotModuleEnd(
Tok.getLocation(),
reinterpret_cast<Module *>(Tok.getAnnotationValue()));
ConsumeAnnotationToken();
ImportState = Sema::ModuleImportState::NotACXX20Module;
return false;
Expand Down Expand Up @@ -2708,9 +2710,9 @@ bool Parser::parseMisplacedModuleImport() {
// happens.
if (MisplacedModuleBeginCount) {
--MisplacedModuleBeginCount;
Actions.ActOnModuleEnd(Tok.getLocation(),
reinterpret_cast<Module *>(
Tok.getAnnotationValue()));
Actions.ActOnAnnotModuleEnd(
Tok.getLocation(),
reinterpret_cast<Module *>(Tok.getAnnotationValue()));
ConsumeAnnotationToken();
continue;
}
Expand All @@ -2720,18 +2722,18 @@ bool Parser::parseMisplacedModuleImport() {
return true;
case tok::annot_module_begin:
// Recover by entering the module (Sema will diagnose).
Actions.ActOnModuleBegin(Tok.getLocation(),
reinterpret_cast<Module *>(
Tok.getAnnotationValue()));
Actions.ActOnAnnotModuleBegin(
Tok.getLocation(),
reinterpret_cast<Module *>(Tok.getAnnotationValue()));
ConsumeAnnotationToken();
++MisplacedModuleBeginCount;
continue;
case tok::annot_module_include:
// Module import found where it should not be, for instance, inside a
// namespace. Recover by importing the module.
Actions.ActOnModuleInclude(Tok.getLocation(),
reinterpret_cast<Module *>(
Tok.getAnnotationValue()));
Actions.ActOnAnnotModuleInclude(
Tok.getLocation(),
reinterpret_cast<Module *>(Tok.getAnnotationValue()));
ConsumeAnnotationToken();
// If there is another module import, process it.
continue;
Expand Down
63 changes: 25 additions & 38 deletions clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1207,26 +1207,35 @@ void Sema::ActOnEndOfTranslationUnit() {
}

// A global-module-fragment is only permitted within a module unit.
bool DiagnosedMissingModuleDeclaration = false;
if (!ModuleScopes.empty() && ModuleScopes.back().Module->Kind ==
Module::ExplicitGlobalModuleFragment) {
Diag(ModuleScopes.back().BeginLoc,
diag::err_module_declaration_missing_after_global_module_introducer);
DiagnosedMissingModuleDeclaration = true;
}

if (TUKind == TU_Module) {
// If we are building a module interface unit, we need to have seen the
// module declaration by now.
if (getLangOpts().getCompilingModule() ==
LangOptions::CMK_ModuleInterface &&
!isCurrentModulePurview() && !DiagnosedMissingModuleDeclaration) {
// FIXME: Make a better guess as to where to put the module declaration.
Diag(getSourceManager().getLocForStartOfFile(
getSourceManager().getMainFileID()),
diag::err_module_declaration_missing);
}
}

// Now we can decide whether the modules we're building need an initializer.
if (Module *CurrentModule = getCurrentModule();
CurrentModule && CurrentModule->isInterfaceOrPartition()) {
auto DoesModNeedInit = [this](Module *M) {
if (!getASTContext().getModuleInitializers(M).empty())
return true;
for (auto [Exported, _] : M->Exports)
if (Exported->isNamedModuleInterfaceHasInit())
return true;
for (Module *I : M->Imports)
if (I->isNamedModuleInterfaceHasInit())
return true;

return false;
};

CurrentModule->NamedModuleHasInit =
DoesModNeedInit(CurrentModule) ||
llvm::any_of(CurrentModule->submodules(),
[&](auto *SubM) { return DoesModNeedInit(SubM); });
}

if (TUKind == TU_ClangModule) {
// If we are building a module, resolve all of the exported declarations
// now.
if (Module *CurrentModule = PP.getCurrentModule()) {
Expand All @@ -1251,28 +1260,6 @@ void Sema::ActOnEndOfTranslationUnit() {
}
}

// Now we can decide whether the modules we're building need an initializer.
if (Module *CurrentModule = getCurrentModule();
CurrentModule && CurrentModule->isInterfaceOrPartition()) {
auto DoesModNeedInit = [this](Module *M) {
if (!getASTContext().getModuleInitializers(M).empty())
return true;
for (auto [Exported, _] : M->Exports)
if (Exported->isNamedModuleInterfaceHasInit())
return true;
for (Module *I : M->Imports)
if (I->isNamedModuleInterfaceHasInit())
return true;

return false;
};

CurrentModule->NamedModuleHasInit =
DoesModNeedInit(CurrentModule) ||
llvm::any_of(CurrentModule->submodules(),
[&](auto *SubM) { return DoesModNeedInit(SubM); });
}

// Warnings emitted in ActOnEndOfTranslationUnit() should be emitted for
// modules when they are built, not every time they are used.
emitAndClearUnusedLocalTypedefWarnings();
Expand Down Expand Up @@ -1358,7 +1345,7 @@ void Sema::ActOnEndOfTranslationUnit() {
// noise. Don't warn for a use from a module: either we should warn on all
// file-scope declarations in modules or not at all, but whether the
// declaration is used is immaterial.
if (!Diags.hasErrorOccurred() && TUKind != TU_Module) {
if (!Diags.hasErrorOccurred() && TUKind != TU_ClangModule) {
// Output warning for unused file scoped decls.
for (UnusedFileScopedDeclsType::iterator
I = UnusedFileScopedDecls.begin(ExternalSource.get()),
Expand Down
24 changes: 24 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3787,6 +3787,30 @@ static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
<< NI.getName() << ParamTy << Ty;
return;
}
VarDecl *VD = cast<VarDecl>(D);
// Create a reference to the variable declaration. This is a fake/dummy
// reference.
DeclRefExpr *VariableReference = DeclRefExpr::Create(
S.Context, NestedNameSpecifierLoc{}, FD->getLocation(), VD, false,
DeclarationNameInfo{VD->getDeclName(), VD->getLocation()}, VD->getType(),
VK_LValue);

// Create a unary operator expression that represents taking the address of
// the variable. This is a fake/dummy expression.
Expr *AddressOfVariable = UnaryOperator::Create(
S.Context, VariableReference, UnaryOperatorKind::UO_AddrOf,
S.Context.getPointerType(VD->getType()), VK_PRValue, OK_Ordinary, Loc,
+false, FPOptionsOverride{});

// Create a function call expression. This is a fake/dummy call expression.
CallExpr *FunctionCallExpression =
CallExpr::Create(S.Context, E, ArrayRef{AddressOfVariable},
S.Context.VoidTy, VK_PRValue, Loc, FPOptionsOverride{});

if (S.CheckFunctionCall(FD, FunctionCallExpression,
FD->getType()->getAs<FunctionProtoType>())) {
return;
}

D->addAttr(::new (S.Context) CleanupAttr(S.Context, AL, FD));
}
Expand Down
15 changes: 7 additions & 8 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1099,12 +1099,13 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
return E;
}

/// Converts an integer to complex float type. Helper function of
/// Convert complex integers to complex floats and real integers to
/// real floats as required for complex arithmetic. Helper function of
/// UsualArithmeticConversions()
///
/// \return false if the integer expression is an integer type and is
/// successfully converted to the complex type.
static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr,
/// successfully converted to the (complex) float type.
static bool handleComplexIntegerToFloatConversion(Sema &S, ExprResult &IntExpr,
ExprResult &ComplexExpr,
QualType IntTy,
QualType ComplexTy,
Expand All @@ -1114,8 +1115,6 @@ static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr,
if (IntTy->isIntegerType()) {
QualType fpTy = ComplexTy->castAs<ComplexType>()->getElementType();
IntExpr = S.ImpCastExprToType(IntExpr.get(), fpTy, CK_IntegralToFloating);
IntExpr = S.ImpCastExprToType(IntExpr.get(), ComplexTy,
CK_FloatingRealToComplex);
} else {
assert(IntTy->isComplexIntegerType());
IntExpr = S.ImpCastExprToType(IntExpr.get(), ComplexTy,
Expand Down Expand Up @@ -1160,11 +1159,11 @@ static QualType handleComplexFloatConversion(Sema &S, ExprResult &Shorter,
static QualType handleComplexConversion(Sema &S, ExprResult &LHS,
ExprResult &RHS, QualType LHSType,
QualType RHSType, bool IsCompAssign) {
// if we have an integer operand, the result is the complex type.
if (!handleIntegerToComplexFloatConversion(S, RHS, LHS, RHSType, LHSType,
// Handle (complex) integer types.
if (!handleComplexIntegerToFloatConversion(S, RHS, LHS, RHSType, LHSType,
/*SkipCast=*/false))
return LHSType;
if (!handleIntegerToComplexFloatConversion(S, LHS, RHS, LHSType, RHSType,
if (!handleComplexIntegerToFloatConversion(S, LHS, RHS, LHSType, RHSType,
/*SkipCast=*/IsCompAssign))
return RHSType;

Expand Down
10 changes: 5 additions & 5 deletions clang/lib/Sema/SemaModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
return Import;
}

void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) {
void Sema::ActOnAnnotModuleInclude(SourceLocation DirectiveLoc, Module *Mod) {
checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext, true);
BuildModuleInclude(DirectiveLoc, Mod);
}
Expand All @@ -723,9 +723,9 @@ void Sema::BuildModuleInclude(SourceLocation DirectiveLoc, Module *Mod) {
// in that buffer do not qualify as module imports; they're just an
// implementation detail of us building the module.
//
// FIXME: Should we even get ActOnModuleInclude calls for those?
// FIXME: Should we even get ActOnAnnotModuleInclude calls for those?
bool IsInModuleIncludes =
TUKind == TU_Module &&
TUKind == TU_ClangModule &&
getSourceManager().isWrittenInMainFile(DirectiveLoc);

// If we are really importing a module (not just checking layering) due to an
Expand All @@ -752,7 +752,7 @@ void Sema::BuildModuleInclude(SourceLocation DirectiveLoc, Module *Mod) {
}
}

void Sema::ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod) {
void Sema::ActOnAnnotModuleBegin(SourceLocation DirectiveLoc, Module *Mod) {
checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext, true);

ModuleScopes.push_back({});
Expand All @@ -776,7 +776,7 @@ void Sema::ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod) {
}
}

void Sema::ActOnModuleEnd(SourceLocation EomLoc, Module *Mod) {
void Sema::ActOnAnnotModuleEnd(SourceLocation EomLoc, Module *Mod) {
if (getLangOpts().ModulesLocalVisibility) {
VisibleModules = std::move(ModuleScopes.back().OuterVisibleModules);
// Leaving a module hides namespace names, so our visible namespace cache
Expand Down
19 changes: 14 additions & 5 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2906,18 +2906,27 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
Context.getCanonicalTemplateArgument(
Context.getInjectedTemplateArg(NewParam));
}
// FIXME: implement the associated constraint per C++
// Substitute new template parameters into requires-clause if present.
Expr *RequiresClause = nullptr;
if (Expr *InnerRC = F->getTemplateParameters()->getRequiresClause()) {
MultiLevelTemplateArgumentList Args;
Args.setKind(TemplateSubstitutionKind::Rewrite);
Args.addOuterTemplateArguments(TemplateArgsForBuildingFPrime);
ExprResult E = SemaRef.SubstExpr(InnerRC, Args);
if (E.isInvalid())
return;
RequiresClause = E.getAs<Expr>();
}
// FIXME: implement the is_deducible constraint per C++
// [over.match.class.deduct]p3.3:
// The associated constraints ([temp.constr.decl]) are the
// conjunction of the associated constraints of g and a
// constraint that is satisfied if and only if the arguments
// ... and a constraint that is satisfied if and only if the arguments
// of A are deducible (see below) from the return type.
auto *FPrimeTemplateParamList = TemplateParameterList::Create(
Context, AliasTemplate->getTemplateParameters()->getTemplateLoc(),
AliasTemplate->getTemplateParameters()->getLAngleLoc(),
FPrimeTemplateParams,
AliasTemplate->getTemplateParameters()->getRAngleLoc(),
/*RequiresClause=*/nullptr);
/*RequiresClause=*/RequiresClause);

// To form a deduction guide f' from f, we leverage clang's instantiation
// mechanism, we construct a template argument list where the template
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ module A; // #module-decl
// expected-error@-2 {{missing 'export' specifier in module declaration while building module interface}}
#define INTERFACE
#endif
#else
#ifdef BUILT_AS_INTERFACE
// expected-error@1 {{missing 'export module' declaration in module interface unit}}
#endif
#endif

#ifndef INTERFACE
Expand Down
50 changes: 50 additions & 0 deletions clang/test/CodeGen/PowerPC/toc-data-attribute.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata=f,g,h,i,j,k,l,m,n,o,p -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=COMMON,CHECK32 --match-full-lines
// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=COMMON,CHECK32 --match-full-lines

// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata=f,g,h,i,j,k,l,m,n,o,p -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=COMMON,CHECK64 --match-full-lines
// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=COMMON,CHECK64 --match-full-lines

extern int f;
long long g = 5;
const char *h = "h";
int *i;
int __attribute__((aligned(128))) j = 0;
float k = 100.00;
double l = 2.5;
int m __attribute__((section("foo"))) = 10;
__thread int n;

extern int p[];

struct SomeStruct;
extern struct SomeStruct o;

static int func_a() {
return g+(int)h[0]+*i+j+k+l+m+n+p[0];
}

int func_b() {
f = 1;
return func_a();
}

struct SomeStruct* getAddress(void) {
return &o;
}

// CHECK32: @g = global i64 5, align 8
// CHECK64: @g = global i64 5, align 8 #0
// COMMON: {{.*}} = private unnamed_addr constant [2 x i8] c"h\00", align 1
// COMMON: @h = global {{...*}} #0
// COMMON: @j = global i32 0, align 128
// COMMON: @k = global float 1.000000e+02, align 4 #0
// CHECK32: @l = global double 2.500000e+00, align 8
// CHECK64: @l = global double 2.500000e+00, align 8 #0
// COMMON: @m = global i32 10, section "foo", align 4
// COMMON: @f = external global i32, align 4 #0
// COMMON: @o = external global %struct.SomeStruct, align 1
// CHECK32: @i = global ptr null, align 4 #0
// CHECK64: @i = global ptr null, align 8 #0
// COMMON: @n = thread_local global i32 0, align 4
// COMMON: @p = external global [0 x i32], align 4
// COMMON: attributes #0 = { "toc-data" }
39 changes: 39 additions & 0 deletions clang/test/CodeGen/PowerPC/toc-data-attribute.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=COMMON,ALLTOC
// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata=n,_ZN11MyNamespace10myVariableE,_ZL1s,_ZZ4testvE7counter -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=COMMON,TOCLIST
// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=COMMON,ALLTOC
// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata=n,_ZN11MyNamespace10myVariableE,_ZL1s,_ZZ4testvE7counter -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=COMMON,TOCLIST

extern int n;
static int s = 100;

inline int test() {
static int counter = 0;
counter++;
return counter;
}

int a () {
n = test();
return 0;
}

namespace MyNamespace {
int myVariable = 10;
}

int b(int x) {
using namespace MyNamespace;
return x + myVariable;
}

int c(int x) {
s += x;
return s;
}

// COMMON: @n = external global i32, align 4 #0
// COMMON: @_ZN11MyNamespace10myVariableE = global i32 10, align 4 #0
// COMMON-NOT: @_ZL1s = internal global i32 100, align 4 #0
// ALLTOC: @_ZZ4testvE7counter = linkonce_odr global i32 0, align 4 #0
// TOCLIST-NOT: @_ZZ4testvE7counter = linkonce_odr global i32 0, align 4 #0
// COMMON: attributes #0 = { "toc-data" }
68 changes: 68 additions & 0 deletions clang/test/CodeGen/PowerPC/toc-data-diagnostics.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// RUN: %clang_cc1 %s -triple=powerpc-ibm-aix-xcoff -S -mtocdata=h,g,f,e,d,c,b,a,globalOneWithAlias,globalTwoWithAlias,ll,t3 -verify -emit-llvm -o - | FileCheck %s -check-prefix=CHECK --match-full-lines
// RUN: %clang_cc1 %s -triple=powerpc-ibm-aix-xcoff -S -mtocdata -verify=none -emit-llvm -o - | FileCheck %s -check-prefix=CHECK --match-full-lines

// none-no-diagnostics

struct large_struct {
int x;
short y;
short z;
char c;
};

struct large_struct a; // expected-warning {{-mtocdata option is ignored for a because variable is larger than a pointer}}
long long b = 5; // expected-warning {{-mtocdata option is ignored for b because variable is larger than a pointer}}
int __attribute__((aligned(128))) c = 0; // expected-warning {{-mtocdata option is ignored for c because variable is aligned wider than a pointer}}
double d = 2.5; // expected-warning {{-mtocdata option is ignored for d because variable is larger than a pointer}}
int e __attribute__((section("foo"))) = 10; // expected-warning {{-mtocdata option is ignored for e because variable has a section attribute}}
__thread int f; // expected-warning {{-mtocdata option is ignored for f because of thread local storage}}

struct SomeStruct;
extern struct SomeStruct g; // expected-warning {{-mtocdata option is ignored for g because of incomplete type}}

extern int h[]; // expected-warning {{-mtocdata option is ignored for h because of incomplete type}}

struct ty3 {
int A;
char C[];
};
struct ty3 t3 = { 4, "fo" }; // expected-warning {{-mtocdata option is ignored for t3 because it contains a flexible array member}}

int globalOneWithAlias = 10;
__attribute__((__alias__("globalOneWithAlias"))) extern int aliasOne; // expected-warning {{-mtocdata option is ignored for globalOneWithAlias because the variable has an alias}}
__attribute__((__alias__("globalTwoWithAlias"))) extern int aliasTwo; // expected-warning {{-mtocdata option is ignored for globalTwoWithAlias because the variable has an alias}}
int globalTwoWithAlias = 20;


int func() {
return a.x+b+c+d+e+f+h[0];
}

struct SomeStruct* getAddress(void) {
return &g;
}

int test() {
return globalOneWithAlias + globalTwoWithAlias + aliasOne + aliasTwo;
}

long long test2() {
static long long ll = 5;
ll++;
return ll;
}

// CHECK: @b = global i64 5, align 8
// CHECK: @c = global i32 0, align 128
// CHECK: @d = global double 2.500000e+00, align 8
// CHECK: @e = global i32 10, section "foo", align 4
// CHECK: @globalOneWithAlias = global i32 10, align 4
// CHECK: @globalTwoWithAlias = global i32 20, align 4
// CHECK: @a = global %struct.large_struct zeroinitializer, align 4
// CHECK: @f = thread_local global i32 0, align 4
// CHECK: @h = external global [0 x i32], align 4
// CHECK: @g = external global %struct.SomeStruct, align 1
// CHECK: @test2.ll = internal global i64 5, align 8
// CHECK: @aliasOne = alias i32, ptr @globalOneWithAlias
// CHECK: @aliasTwo = alias i32, ptr @globalTwoWithAlias
// CHECK-NOT: attributes #0 = { "toc-data" }
65 changes: 65 additions & 0 deletions clang/test/CodeGen/PowerPC/toc-data-structs-arrays.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata=a4,a5,a8,a9,b,c,d,e,v -emit-llvm -o - 2>&1 \
// RUN: | FileCheck %s -check-prefixes=CHECK32 --match-full-lines
// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 \
// RUN: | FileCheck %s -check-prefixes=CHECK32 --match-full-lines

// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata=a4,a5,a8,a9,b,c,d,e,v -emit-llvm -o - 2>&1 \
// RUN: | FileCheck %s -check-prefixes=CHECK64 --match-full-lines
// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 \
// RUN: | FileCheck %s -check-prefixes=CHECK64 --match-full-lines

struct size4_struct {
int x;
};

struct size5_struct {
int x;
char c;
};

struct size8_struct {
int x;
short y;
short z;
};

struct size9_struct {
int x;
short y;
short z;
char c;
};

struct size4_struct a4;
struct size5_struct a5;
struct size8_struct a8;
struct size9_struct a9;

short b[2];
short c[3];
short d[4];
short e[5];

int func_a() {
return a4.x+a5.x+a8.x+a9.x+b[0]+c[0]+d[0]+e[0];
}

// CHECK32: @a4 = global %struct.size4_struct zeroinitializer, align 4 #0
// CHECK32: @a5 = global %struct.size5_struct zeroinitializer, align 4
// CHECK32: @a8 = global %struct.size8_struct zeroinitializer, align 4
// CHECK32: @a9 = global %struct.size9_struct zeroinitializer, align 4
// CHECK32: @b = global [2 x i16] zeroinitializer, align 2 #0
// CHECK32: @c = global [3 x i16] zeroinitializer, align 2
// CHECK32: @d = global [4 x i16] zeroinitializer, align 2
// CHECK32: @e = global [5 x i16] zeroinitializer, align 2
// CHECK32: attributes #0 = { "toc-data" }

// CHECK64: @a4 = global %struct.size4_struct zeroinitializer, align 4 #0
// CHECK64: @a5 = global %struct.size5_struct zeroinitializer, align 4 #0
// CHECK64: @a8 = global %struct.size8_struct zeroinitializer, align 4 #0
// CHECK64: @a9 = global %struct.size9_struct zeroinitializer, align 4
// CHECK64: @b = global [2 x i16] zeroinitializer, align 2 #0
// CHECK64: @c = global [3 x i16] zeroinitializer, align 2 #0
// CHECK64: @d = global [4 x i16] zeroinitializer, align 2 #0
// CHECK64: @e = global [5 x i16] zeroinitializer, align 2
// CHECK64: attributes #0 = { "toc-data" }
146 changes: 146 additions & 0 deletions clang/test/CodeGen/complex-math-mixed.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown -o - | FileCheck %s --check-prefix=X86
// RUN: %clang_cc1 %s -O0 -triple x86_64-unknown-unknown -fsyntax-only -ast-dump | FileCheck %s --check-prefix=AST

// Check that for 'F _Complex + int' (F = real floating-point type), we emit an
// implicit cast from 'int' to 'F', but NOT to 'F _Complex' (i.e. that we do
// 'F _Complex + F', NOT 'F _Complex + F _Complex'), and likewise for -/*.

// AST-NOT: FloatingRealToComplex

float _Complex add_float_ci(float _Complex a, int b) {
// X86-LABEL: @add_float_ci
// X86: [[I:%.*]] = sitofp i32 {{%.*}} to float
// X86: fadd float {{.*}}, [[I]]
// X86-NOT: fadd
return a + b;
}

float _Complex add_float_ic(int a, float _Complex b) {
// X86-LABEL: @add_float_ic
// X86: [[I:%.*]] = sitofp i32 {{%.*}} to float
// X86: fadd float [[I]]
// X86-NOT: fadd
return a + b;
}

float _Complex sub_float_ci(float _Complex a, int b) {
// X86-LABEL: @sub_float_ci
// X86: [[I:%.*]] = sitofp i32 {{%.*}} to float
// X86: fsub float {{.*}}, [[I]]
// X86-NOT: fsub
return a - b;
}

float _Complex sub_float_ic(int a, float _Complex b) {
// X86-LABEL: @sub_float_ic
// X86: [[I:%.*]] = sitofp i32 {{%.*}} to float
// X86: fsub float [[I]]
// X86: fneg
// X86-NOT: fsub
return a - b;
}

float _Complex mul_float_ci(float _Complex a, int b) {
// X86-LABEL: @mul_float_ci
// X86: [[I:%.*]] = sitofp i32 {{%.*}} to float
// X86: fmul float {{.*}}, [[I]]
// X86: fmul float {{.*}}, [[I]]
// X86-NOT: fmul
return a * b;
}

float _Complex mul_float_ic(int a, float _Complex b) {
// X86-LABEL: @mul_float_ic
// X86: [[I:%.*]] = sitofp i32 {{%.*}} to float
// X86: fmul float [[I]]
// X86: fmul float [[I]]
// X86-NOT: fmul
return a * b;
}

float _Complex div_float_ci(float _Complex a, int b) {
// X86-LABEL: @div_float_ci
// X86: [[I:%.*]] = sitofp i32 {{%.*}} to float
// X86: fdiv float {{.*}}, [[I]]
// X86: fdiv float {{.*}}, [[I]]
// X86-NOT: @__divsc3
return a / b;
}

// There is no good way of doing this w/o converting the 'int' to a complex
// number, so we expect complex division here.
float _Complex div_float_ic(int a, float _Complex b) {
// X86-LABEL: @div_float_ic
// X86: [[I:%.*]] = sitofp i32 {{%.*}} to float
// X86: call {{.*}} @__divsc3(float {{.*}} [[I]], float noundef 0.{{0+}}e+00, float {{.*}}, float {{.*}})
return a / b;
}

double _Complex add_double_ci(double _Complex a, int b) {
// X86-LABEL: @add_double_ci
// X86: [[I:%.*]] = sitofp i32 {{%.*}} to double
// X86: fadd double {{.*}}, [[I]]
// X86-NOT: fadd
return a + b;
}

double _Complex add_double_ic(int a, double _Complex b) {
// X86-LABEL: @add_double_ic
// X86: [[I:%.*]] = sitofp i32 {{%.*}} to double
// X86: fadd double [[I]]
// X86-NOT: fadd
return a + b;
}

double _Complex sub_double_ci(double _Complex a, int b) {
// X86-LABEL: @sub_double_ci
// X86: [[I:%.*]] = sitofp i32 {{%.*}} to double
// X86: fsub double {{.*}}, [[I]]
// X86-NOT: fsub
return a - b;
}

double _Complex sub_double_ic(int a, double _Complex b) {
// X86-LABEL: @sub_double_ic
// X86: [[I:%.*]] = sitofp i32 {{%.*}} to double
// X86: fsub double [[I]]
// X86: fneg
// X86-NOT: fsub
return a - b;
}

double _Complex mul_double_ci(double _Complex a, int b) {
// X86-LABEL: @mul_double_ci
// X86: [[I:%.*]] = sitofp i32 {{%.*}} to double
// X86: fmul double {{.*}}, [[I]]
// X86: fmul double {{.*}}, [[I]]
// X86-NOT: fmul
return a * b;
}

double _Complex mul_double_ic(int a, double _Complex b) {
// X86-LABEL: @mul_double_ic
// X86: [[I:%.*]] = sitofp i32 {{%.*}} to double
// X86: fmul double [[I]]
// X86: fmul double [[I]]
// X86-NOT: fmul
return a * b;
}

double _Complex div_double_ci(double _Complex a, int b) {
// X86-LABEL: @div_double_ci
// X86: [[I:%.*]] = sitofp i32 {{%.*}} to double
// X86: fdiv double {{.*}}, [[I]]
// X86: fdiv double {{.*}}, [[I]]
// X86-NOT: @__divdc3
return a / b;
}

// There is no good way of doing this w/o converting the 'int' to a complex
// number, so we expect complex division here.
double _Complex div_double_ic(int a, double _Complex b) {
// X86-LABEL: @div_double_ic
// X86: [[I:%.*]] = sitofp i32 {{%.*}} to double
// X86: call {{.*}} @__divdc3(double {{.*}} [[I]], double noundef 0.{{0+}}e+00, double {{.*}}, double {{.*}})
return a / b;
}
3 changes: 3 additions & 0 deletions clang/test/CodeGen/const-init.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,6 @@ int PR4517_x2 = PR4517_arrc[PR4517_idx];
// CHECK: @PR4517_x = global i32 42, align 4
// CHECK: @PR4517_idx = constant i32 1, align 4
// CHECK: @PR4517_x2 = global i32 42, align 4

// CHECK: @GH84784_inf = constant i8 1
_Bool const GH84784_inf = (1.0/0.0);
48 changes: 23 additions & 25 deletions clang/test/CodeGen/volatile.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -O2 -triple=x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK
// RUN: %clang_cc1 -O2 -triple=x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s
struct agg
{
int a ;
Expand All @@ -10,34 +10,32 @@ _Complex float cf;
int volatile vol =10;
void f0() {
const_cast<volatile _Complex float &>(cf) = const_cast<volatile _Complex float&>(cf) + 1;
// CHECK: %cf.real = load volatile float, ptr @cf
// CHECK: %cf.imag = load volatile float, ptr getelementptr
// CHECK: %add.r = fadd float %cf.real, 1.000000e+00
// CHECK: %add.i = fadd float %cf.imag, 0.000000e+00
// CHECK: store volatile float %add.r
// CHECK: store volatile float %add.i, ptr getelementptr
// CHECK: [[Re1:%.*]] = load volatile float, ptr @cf
// CHECK: [[Im1:%.*]] = load volatile float, ptr getelementptr
// CHECK: [[Add1:%.*]] = fadd float [[Re1]], 1.000000e+00
// CHECK: store volatile float [[Add1]], ptr @cf
// CHECK: store volatile float [[Im1]], ptr getelementptr
static_cast<volatile _Complex float &>(cf) = static_cast<volatile _Complex float&>(cf) + 1;
// CHECK: %cf.real1 = load volatile float, ptr @cf
// CHECK: %cf.imag2 = load volatile float, ptr getelementptr
// CHECK: %add.r3 = fadd float %cf.real1, 1.000000e+00
// CHECK: %add.i4 = fadd float %cf.imag2, 0.000000e+00
// CHECK: store volatile float %add.r3, ptr @cf
// CHECK: store volatile float %add.i4, ptr getelementptr
// CHECK: [[Re2:%.*]] = load volatile float, ptr @cf
// CHECK: [[Im2:%.*]] = load volatile float, ptr getelementptr
// CHECK: [[Add2:%.*]] = fadd float [[Re2]], 1.000000e+00
// CHECK: store volatile float [[Add2]], ptr @cf
// CHECK: store volatile float [[Im2]], ptr getelementptr
const_cast<volatile int &>(a.a) = const_cast<volatile int &>(t.a) ;
// CHECK: %0 = load volatile i32, ptr @t
// CHECK: store volatile i32 %0, ptr @a
// CHECK: [[I1:%.*]] = load volatile i32, ptr @t
// CHECK: store volatile i32 [[I1]], ptr @a
static_cast<volatile int &>(a.b) = static_cast<volatile int &>(t.a) ;
// CHECK: %1 = load volatile i32, ptr @t
// CHECK: store volatile i32 %1, ptr getelementptr
// CHECK: [[I2:%.*]] = load volatile i32, ptr @t
// CHECK: store volatile i32 [[I2]], ptr getelementptr
const_cast<volatile int&>(vt) = const_cast<volatile int&>(vt) + 1;
// CHECK: %2 = load volatile i32, ptr @vt
// CHECK: %add = add nsw i32 %2, 1
// CHECK: store volatile i32 %add, ptr @vt
// CHECK: [[I3:%.*]] = load volatile i32, ptr @vt
// CHECK: [[Add3:%.*]] = add nsw i32 [[I3]], 1
// CHECK: store volatile i32 [[Add3]], ptr @vt
static_cast<volatile int&>(vt) = static_cast<volatile int&>(vt) + 1;
// CHECK: %3 = load volatile i32, ptr @vt
// CHECK: %add5 = add nsw i32 %3, 1
// CHECK: store volatile i32 %add5, ptr @vt
// CHECK: [[I4:%.*]] = load volatile i32, ptr @vt
// CHECK: [[Add4:%.*]] = add nsw i32 [[I4]], 1
// CHECK: store volatile i32 [[Add4]], ptr @vt
vt = const_cast<int&>(vol);
// %4 = load i32, ptr @vol
// store i32 %4, ptr @vt
// [[I5:%.*]] = load i32, ptr @vol
// store i32 [[I5]], ptr @vt
}
30 changes: 30 additions & 0 deletions clang/test/Driver/toc-conf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// RUN: %clang %s --target=powerpc-unknown-aix -mno-tocdata -mtocdata -mno-tocdata -### 2>&1 | FileCheck %s -check-prefix=CHECK-FLAG1
// RUN: %clang %s --target=powerpc-unknown-aix -mno-tocdata -mtocdata -mno-tocdata -mtocdata -### 2>&1 | FileCheck %s -check-prefix=CHECK-FLAG2
// RUN: %clang %s --target=powerpc-unknown-aix -mtocdata=g1,g2 -mno-tocdata=g2 -mtocdata=g3,g4 -mno-tocdata=g5,g1 -### 2>&1 | FileCheck %s -check-prefix=CHECK-EQCONF
// RUN: %clang %s --target=powerpc-unknown-aix -mtocdata=g1 -mtocdata -mno-tocdata -mtocdata=g2,g3 -mno-tocdata=g4,g5,g3 -### 2>&1 | FileCheck %s -check-prefix=CHECK-CONF1
// RUN: %clang %s --target=powerpc-unknown-aix -mno-tocdata=g1 -mno-tocdata -mtocdata -### 2>&1 | FileCheck %s -check-prefix=CHECK-CONF2

int g1, g4, g5;
extern int g2;
int g3 = 0;
void func() {
g2 = 0;
}

// CHECK-FLAG1-NOT: warning:
// CHECK-FLAG1: "-cc1"{{.*}}" "-mno-tocdata"

// CHECK-FLAG2-NOT: warning:
// CHECK-FLAG2: "-cc1"{{.*}}" "-mtocdata"

// CHECK-EQCONF-NOT: warning:
// CHECK-EQCONF: "-cc1"{{.*}}" "-mno-tocdata"
// CHECK-EQCONF: "-mtocdata=g3,g4"

// CHECK-CONF1-NOT: warning:
// CHECK-CONF1: "-cc1"{{.*}}" "-mno-tocdata"
// CHECK-CONF1: "-mtocdata=g2,g1"

// CHECK-CONF2-NOT: warning:
// CHECK-CONF2: "-cc1"{{.*}}" "-mtocdata"
// CHECK-CONF2: "-mno-tocdata=g1"
16 changes: 16 additions & 0 deletions clang/test/Driver/tocdata-cc1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// RUN: %clang -### --target=powerpc-ibm-aix-xcoff -mcmodel=medium -mtocdata %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-NOTOC %s
// RUN: %clang -### --target=powerpc-ibm-aix-xcoff -mcmodel=large -mtocdata %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-NOTOC %s
// RUN: %clang -### --target=powerpc-ibm-aix-xcoff -mtocdata %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-TOC %s
// RUN: %clang -### --target=powerpc64-ibm-aix-xcoff -mcmodel=medium -mtocdata %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-NOTOC %s
// RUN: %clang -### --target=powerpc64-ibm-aix-xcoff -mcmodel=large -mtocdata %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-NOTOC %s
// RUN: %clang -### --target=powerpc64-ibm-aix-xcoff -mtocdata %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-TOC %s
// CHECK-NOTOC: warning: ignoring '-mtocdata' as it is only supported for -mcmodel=small
// CHECK-NOTOC-NOT: "-cc1"{{.*}}" "-mtocdata"
// CHECK-TOC: "-cc1"{{.*}}" "-mtocdata"
// CHECK-TOC-NOT: warning: ignoring '-mtocdata' as it is only supported for -mcmodel=small
13 changes: 0 additions & 13 deletions clang/test/Modules/missing-module-declaration.cppm

This file was deleted.

2 changes: 1 addition & 1 deletion clang/test/Modules/no-undeclared-includes-builtins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// headers.

// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/no-undeclared-includes-builtins/libcxx -I %S/Inputs/no-undeclared-includes-builtins/glibc %s
// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fbuiltin-headers-in-system-modules -fimplicit-module-maps -I %S/Inputs/no-undeclared-includes-builtins/libcxx -I %S/Inputs/no-undeclared-includes-builtins/glibc %s
// expected-no-diagnostics

#include <stddef.h>
2 changes: 1 addition & 1 deletion clang/test/Modules/pr72828.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ struct s {

void f() {
auto [x] = s();
[x] {};
(void) [x] {};
}

// Check that we can generate the LLVM IR expectedly.
Expand Down
32 changes: 18 additions & 14 deletions clang/test/Modules/stddef.c
Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fbuiltin-headers-in-system-modules -fmodules-cache-path=%t -I%S/Inputs/StdDef %s -verify -fno-modules-error-recovery
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fbuiltin-headers-in-system-modules -fmodules-cache-path=%t -I%S/Inputs/StdDef %s -verify=builtin-headers-in-system-modules -fno-modules-error-recovery
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I%S/Inputs/StdDef %s -verify -fno-modules-error-recovery
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I%S/Inputs/StdDef %s -verify=no-builtin-headers-in-system-modules -fno-modules-error-recovery

#include "ptrdiff_t.h"

ptrdiff_t pdt;

// size_t is declared in both size_t.h and __stddef_size_t.h, both of which are
// modular headers. Regardless of whether stddef.h joins the StdDef test module
// or is in its _Builtin_stddef module, __stddef_size_t.h will be in
// _Builtin_stddef.size_t. It's not defined which module will win as the expected
// provider of size_t. For the purposes of this test it doesn't matter which header
// gets reported, just as long as it isn't other.h or include_again.h.
size_t st; // expected-error-re {{missing '#include "{{size_t|__stddef_size_t}}.h"'; 'size_t' must be declared before it is used}}
// expected-note@size_t.h:* 0+ {{here}}
// expected-note@__stddef_size_t.h:* 0+ {{here}}
// size_t is declared in both size_t.h and __stddef_size_t.h. If
// -fbuiltin-headers-in-system-modules is set, then __stddef_size_t.h is a
// non-modular header that will be transitively pulled in the StdDef test module
// by include_again.h. Otherwise it will be in the _Builtin_stddef module. In
// any case it's not defined which module will win as the expected provider of
// size_t. For the purposes of this test it doesn't matter which of the two
// providing headers get reported.
size_t st; // builtin-headers-in-system-modules-error-re {{missing '#include "{{size_t|include_again}}.h"'; 'size_t' must be declared before it is used}} \
no-builtin-headers-in-system-modules-error-re {{missing '#include "{{size_t|__stddef_size_t}}.h"'; 'size_t' must be declared before it is used}}
// builtin-headers-in-system-modules-note@size_t.h:* 0+ {{here}} \
no-builtin-headers-in-system-modules-note@size_t.h:* 0+ {{here}}
// builtin-headers-in-system-modules-note@__stddef_size_t.h:* 0+ {{here}} \
no-builtin-headers-in-system-modules-note@__stddef_size_t.h:* 0+ {{here}}

#include "include_again.h"
// Includes <stddef.h> which includes <__stddef_size_t.h> which imports the
// _Builtin_stddef.size_t module.
// Includes <stddef.h> which includes <__stddef_size_t.h>.

size_t st2;

#include "size_t.h"
// Redeclares size_t, but the type merger should figure it out.
// Redeclares size_t when -fbuiltin-headers-in-system-modules is not passed, but
// the type merger should figure it out.

size_t st3;
28 changes: 26 additions & 2 deletions clang/test/Sema/attr-cleanup.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only
// RUN: %clang_cc1 -Wfree-nonheap-object -fsyntax-only -verify %s

void c1(int *a);

typedef __typeof__(sizeof(0)) size_t;
extern int g1 __attribute((cleanup(c1))); // expected-warning {{'cleanup' attribute only applies to local variables}}
int g2 __attribute((cleanup(c1))); // expected-warning {{'cleanup' attribute only applies to local variables}}
static int g3 __attribute((cleanup(c1))); // expected-warning {{'cleanup' attribute only applies to local variables}}
Expand Down Expand Up @@ -48,3 +48,27 @@ void t6(void) {
}

void t7(__attribute__((cleanup(c4))) int a) {} // expected-warning {{'cleanup' attribute only applies to local variables}}

extern void free(void *);
extern void *malloc(size_t size);
void t8(void) {
void *p
__attribute__((
cleanup(
free // expected-warning{{attempt to call free on non-heap object 'p'}}
)
))
= malloc(10);
}
typedef __attribute__((aligned(2))) int Aligned2Int;
void t9(void){
Aligned2Int __attribute__((cleanup(c1))) xwarn; // expected-warning{{passing 2-byte aligned argument to 4-byte aligned parameter 1 of 'c1' may result in an unaligned pointer access}}
}

__attribute__((enforce_tcb("TCB1"))) void func1(int *x) {
*x = 5;
}
__attribute__((enforce_tcb("TCB2"))) void t10() {
int __attribute__((cleanup(func1))) x = 5; // expected-warning{{calling 'func1' is a violation of trusted computing base 'TCB2'}}
}

115 changes: 115 additions & 0 deletions clang/test/Sema/complex-arithmetic.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// RUN: %clang_cc1 -verify %s
// expected-no-diagnostics

// This tests evaluation of _Complex arithmetic at compile time.

#define APPROX_EQ(a, b) ( \
__builtin_fabs(__real (a) - __real (b)) < 0.0001 && \
__builtin_fabs(__imag (a) - __imag (b)) < 0.0001 \
)

#define EVAL(a, b) _Static_assert(a == b, "")
#define EVALF(a, b) _Static_assert(APPROX_EQ(a, b), "")

// _Complex float + _Complex float
void a() {
EVALF((2.f + 3i) + (4.f + 5i), 6.f + 8i);
EVALF((2.f + 3i) - (4.f + 5i), -2.f - 2i);
EVALF((2.f + 3i) * (4.f + 5i), -7.f + 22i);
EVALF((2.f + 3i) / (4.f + 5i), 0.5609f + 0.0487i);

EVALF((2. + 3i) + (4. + 5i), 6. + 8i);
EVALF((2. + 3i) - (4. + 5i), -2. - 2i);
EVALF((2. + 3i) * (4. + 5i), -7. + 22i);
EVALF((2. + 3i) / (4. + 5i), .5609 + .0487i);
}

// _Complex int + _Complex int
void b() {
EVAL((2 + 3i) + (4 + 5i), 6 + 8i);
EVAL((2 + 3i) - (4 + 5i), -2 - 2i);
EVAL((2 + 3i) * (4 + 5i), -7 + 22i);
EVAL((8 + 30i) / (4 + 5i), 4 + 1i);
}

// _Complex float + float
void c() {
EVALF((2.f + 4i) + 3.f, 5.f + 4i);
EVALF((2.f + 4i) - 3.f, -1.f + 4i);
EVALF((2.f + 4i) * 3.f, 6.f + 12i);
EVALF((2.f + 4i) / 2.f, 1.f + 2i);

EVALF(3.f + (2.f + 4i), 5.f + 4i);
EVALF(3.f - (2.f + 4i), 1.f - 4i);
EVALF(3.f * (2.f + 4i), 6.f + 12i);
EVALF(3.f / (2.f + 4i), .3f - 0.6i);

EVALF((2. + 4i) + 3., 5. + 4i);
EVALF((2. + 4i) - 3., -1. + 4i);
EVALF((2. + 4i) * 3., 6. + 12i);
EVALF((2. + 4i) / 2., 1. + 2i);

EVALF(3. + (2. + 4i), 5. + 4i);
EVALF(3. - (2. + 4i), 1. - 4i);
EVALF(3. * (2. + 4i), 6. + 12i);
EVALF(3. / (2. + 4i), .3 - 0.6i);
}

// _Complex int + int
void d() {
EVAL((2 + 4i) + 3, 5 + 4i);
EVAL((2 + 4i) - 3, -1 + 4i);
EVAL((2 + 4i) * 3, 6 + 12i);
EVAL((2 + 4i) / 2, 1 + 2i);

EVAL(3 + (2 + 4i), 5 + 4i);
EVAL(3 - (2 + 4i), 1 - 4i);
EVAL(3 * (2 + 4i), 6 + 12i);
EVAL(20 / (2 + 4i), 2 - 4i);
}

// _Complex float + int
void e() {
EVALF((2.f + 4i) + 3, 5.f + 4i);
EVALF((2.f + 4i) - 3, -1.f + 4i);
EVALF((2.f + 4i) * 3, 6.f + 12i);
EVALF((2.f + 4i) / 2, 1.f + 2i);

EVALF(3 + (2.f + 4i), 5.f + 4i);
EVALF(3 - (2.f + 4i), 1.f - 4i);
EVALF(3 * (2.f + 4i), 6.f + 12i);
EVALF(3 / (2.f + 4i), .3f - 0.6i);

EVALF((2. + 4i) + 3, 5. + 4i);
EVALF((2. + 4i) - 3, -1. + 4i);
EVALF((2. + 4i) * 3, 6. + 12i);
EVALF((2. + 4i) / 2, 1. + 2i);

EVALF(3 + (2. + 4i), 5. + 4i);
EVALF(3 - (2. + 4i), 1. - 4i);
EVALF(3 * (2. + 4i), 6. + 12i);
EVALF(3 / (2. + 4i), .3 - 0.6i);
}

// _Complex int + float
void f() {
EVALF((2 + 4i) + 3.f, 5.f + 4i);
EVALF((2 + 4i) - 3.f, -1.f + 4i);
EVALF((2 + 4i) * 3.f, 6.f + 12i);
EVALF((2 + 4i) / 2.f, 1.f + 2i);

EVALF(3.f + (2 + 4i), 5.f + 4i);
EVALF(3.f - (2 + 4i), 1.f - 4i);
EVALF(3.f * (2 + 4i), 6.f + 12i);
EVALF(3.f / (2 + 4i), .3f - 0.6i);

EVALF((2 + 4i) + 3., 5. + 4i);
EVALF((2 + 4i) - 3., -1. + 4i);
EVALF((2 + 4i) * 3., 6. + 12i);
EVALF((2 + 4i) / 2., 1. + 2i);

EVALF(3. + (2 + 4i), 5. + 4i);
EVALF(3. - (2 + 4i), 1. - 4i);
EVALF(3. * (2 + 4i), 6. + 12i);
EVALF(3. / (2 + 4i), .3 - 0.6i);
}
6 changes: 6 additions & 0 deletions clang/test/Sema/const-init.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c23 %s

// Division by 0 here is an error iff the variable is 'constexpr'.
const _Bool inf1 = (1.0/0.0 == __builtin_inf());
constexpr _Bool inf2 = (1.0/0.0 == __builtin_inf()); // expected-error {{must be initialized by a constant expression}} expected-note {{division by zero}}
constexpr _Bool inf3 = __builtin_inf() == __builtin_inf();
34 changes: 34 additions & 0 deletions clang/test/SemaCXX/constexpr-explicit-object-lambda.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// RUN: %clang_cc1 -std=c++23 -verify %s
// expected-no-diagnostics

struct S {
int i = 42;
constexpr auto f1() {
return [this](this auto) {
return this->i;
}();
};

constexpr auto f2() {
return [this](this auto&&) {
return this->i;
}();
};

constexpr auto f3() {
return [i = this->i](this auto) {
return i;
}();
};

constexpr auto f4() {
return [i = this->i](this auto&&) {
return i;
}();
};
};

static_assert(S().f1() == 42);
static_assert(S().f2() == 42);
static_assert(S().f3() == 42);
static_assert(S().f4() == 42);
17 changes: 17 additions & 0 deletions clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,20 @@ using AFoo = Foo<U>*; // expected-note {{template is declared here}}

AFoo s = {1}; // expected-error {{alias template 'AFoo' requires template arguments; argument deduction only allowed for}}
} // namespace test17

namespace test18 {
template<typename T>
concept False = false; // expected-note {{because 'false' evaluated to false}}

template <typename T> struct Foo { T t; };

template<typename T> requires False<T> // expected-note {{because 'int' does not satisfy 'False'}}
Foo(T) -> Foo<int>;

template <typename U>
using Bar = Foo<U>; // expected-note {{could not match 'Foo<type-parameter-0-0>' against 'int'}} \
// expected-note {{candidate template ignored: constraints not satisfied}} \
// expected-note {{candidate function template not viable}}

Bar s = {1}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments}}
} // namespace test18
4 changes: 4 additions & 0 deletions clang/unittests/Interpreter/InterpreterExtensionsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@ class TestCreateResetExecutor : public Interpreter {
void resetExecutor() { Interpreter::ResetExecutor(); }
};

#ifdef _AIX
TEST(InterpreterExtensionsTest, DISABLED_ExecutorCreateReset) {
#else
TEST(InterpreterExtensionsTest, ExecutorCreateReset) {
#endif
// Make sure we can create the executer on the platform.
if (!HostSupportsJit())
GTEST_SKIP();
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/asan/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ function(add_asan_tests arch test_runtime)
function(generate_asan_tests test_objects test_suite testname)
generate_compiler_rt_tests(${test_objects} ${test_suite} ${testname} ${arch}
COMPILE_DEPS ${ASAN_UNITTEST_HEADERS} ${ASAN_IGNORELIST_FILE}
DEPS llvm_gtest asan
DEPS asan
KIND ${TEST_KIND}
${ARGN}
)
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/fuzzer/FuzzerUtilLinux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ void SetThreadName(std::thread &thread, const std::string &name) {
#if LIBFUZZER_LINUX || LIBFUZZER_FREEBSD
(void)pthread_setname_np(thread.native_handle(), name.c_str());
#elif LIBFUZZER_NETBSD
(void)pthread_set_name_np(thread.native_handle(), "%s", name.c_str());
(void)pthread_setname_np(thread.native_handle(), "%s", const_cast<char *>(name.c_str()));
#endif
}

Expand Down
4 changes: 2 additions & 2 deletions compiler-rt/lib/fuzzer/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST FUZZER_SUPPORTED_ARCH)
FuzzerUnitTests "Fuzzer-${arch}-Test" ${arch}
SOURCES FuzzerUnittest.cpp ${COMPILER_RT_GTEST_SOURCE}
RUNTIME ${LIBFUZZER_TEST_RUNTIME}
DEPS llvm_gtest ${LIBFUZZER_TEST_RUNTIME_DEPS}
DEPS ${LIBFUZZER_TEST_RUNTIME_DEPS}
CFLAGS ${LIBFUZZER_UNITTEST_CFLAGS} ${LIBFUZZER_TEST_RUNTIME_CFLAGS}
LINK_FLAGS ${LIBFUZZER_UNITTEST_LINK_FLAGS} ${LIBFUZZER_TEST_RUNTIME_LINK_FLAGS})
set_target_properties(FuzzerUnitTests PROPERTIES
Expand All @@ -84,7 +84,7 @@ if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST FUZZER_SUPPORTED_ARCH)
generate_compiler_rt_tests(FuzzedDataProviderTestObjects
FuzzedDataProviderUnitTests "FuzzerUtils-${arch}-Test" ${arch}
SOURCES FuzzedDataProviderUnittest.cpp ${COMPILER_RT_GTEST_SOURCE}
DEPS llvm_gtest ${LIBFUZZER_TEST_RUNTIME_DEPS} ${COMPILER_RT_SOURCE_DIR}/include/fuzzer/FuzzedDataProvider.h
DEPS ${LIBFUZZER_TEST_RUNTIME_DEPS} ${COMPILER_RT_SOURCE_DIR}/include/fuzzer/FuzzedDataProvider.h
CFLAGS ${LIBFUZZER_UNITTEST_CFLAGS} ${LIBFUZZER_TEST_RUNTIME_CFLAGS}
LINK_FLAGS ${LIBFUZZER_UNITTEST_LINK_FLAGS} ${LIBFUZZER_TEST_RUNTIME_LINK_FLAGS})
set_target_properties(FuzzedDataProviderUnitTests PROPERTIES
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/gwp_asan/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST GWP_ASAN_SUPPORTED_ARCH)
GwpAsanUnitTests "GwpAsan-${arch}-Test" ${arch}
SOURCES ${GWP_ASAN_UNITTESTS} ${COMPILER_RT_GTEST_SOURCE}
RUNTIME ${GWP_ASAN_TEST_RUNTIME}
DEPS llvm_gtest ${GWP_ASAN_UNIT_TEST_HEADERS}
DEPS ${GWP_ASAN_UNIT_TEST_HEADERS}
CFLAGS ${GWP_ASAN_UNITTEST_CFLAGS}
LINK_FLAGS ${GWP_ASAN_UNITTEST_LINK_FLAGS})
set_target_properties(GwpAsanUnitTests PROPERTIES
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/hwasan/hwasan_interceptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@ void InitializeInterceptors() {
CHECK_EQ(inited, 0);

# if HWASAN_WITH_INTERCEPTORS
__interception::DoesNotSupportStaticLinking();
InitializeCommonInterceptors();

(void)(read_iovec);
Expand Down
4 changes: 2 additions & 2 deletions compiler-rt/lib/interception/interception.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,11 @@ const interpose_substitution substitution_##func_name[] \
".type " SANITIZER_STRINGIFY(TRAMPOLINE(func)) ", " \
ASM_TYPE_FUNCTION_STR "\n" \
SANITIZER_STRINGIFY(TRAMPOLINE(func)) ":\n" \
SANITIZER_STRINGIFY(CFI_STARTPROC) "\n" \
C_ASM_STARTPROC "\n" \
C_ASM_TAIL_CALL(SANITIZER_STRINGIFY(TRAMPOLINE(func)), \
"__interceptor_" \
SANITIZER_STRINGIFY(ASM_PREEMPTIBLE_SYM(func))) "\n" \
SANITIZER_STRINGIFY(CFI_ENDPROC) "\n" \
C_ASM_ENDPROC "\n" \
".size " SANITIZER_STRINGIFY(TRAMPOLINE(func)) ", " \
".-" SANITIZER_STRINGIFY(TRAMPOLINE(func)) "\n" \
);
Expand Down
1 change: 0 additions & 1 deletion compiler-rt/lib/interception/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ macro(add_interception_tests_for_arch arch)
RUNTIME ${INTERCEPTION_COMMON_LIB}
SOURCES ${INTERCEPTION_UNITTESTS} ${COMPILER_RT_GTEST_SOURCE}
COMPILE_DEPS ${INTERCEPTION_TEST_HEADERS}
DEPS llvm_gtest
CFLAGS ${INTERCEPTION_TEST_CFLAGS_COMMON}
LINK_FLAGS ${INTERCEPTION_TEST_LINK_FLAGS_COMMON})
endmacro()
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/lsan/lsan_interceptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ namespace __lsan {
void InitializeInterceptors() {
// Fuchsia doesn't use interceptors that require any setup.
#if !SANITIZER_FUCHSIA
__interception::DoesNotSupportStaticLinking();
InitializeSignalInterceptors();

INTERCEPT_FUNCTION(malloc);
Expand Down
2 changes: 2 additions & 0 deletions compiler-rt/lib/msan/msan_interceptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1762,6 +1762,8 @@ void InitializeInterceptors() {
static int inited = 0;
CHECK_EQ(inited, 0);

__interception::DoesNotSupportStaticLinking();

new(interceptor_ctx()) InterceptorContext();

InitializeCommonInterceptors();
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/msan/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ macro(msan_compile obj_list source arch kind cflags)
${obj_list} ${source} ${arch}
KIND ${kind}
COMPILE_DEPS ${MSAN_UNITTEST_HEADERS}
DEPS llvm_gtest msan
DEPS msan
CFLAGS -isystem ${CMAKE_CURRENT_BINARY_DIR}/../libcxx_msan_${arch}/include/c++/v1
${MSAN_UNITTEST_INSTRUMENTED_CFLAGS} ${cflags}
)
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/orc/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ macro(add_orc_unittest testname)
SOURCES ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE}
RUNTIME "${ORC_RUNTIME_LIBS}"
COMPILE_DEPS ${TEST_HEADERS} ${ORC_HEADERS}
DEPS llvm_gtest ${ORC_DEPS}
DEPS ${ORC_DEPS}
CFLAGS ${ORC_UNITTEST_CFLAGS} ${COMPILER_RT_GTEST_CFLAGS}
LINK_FLAGS ${ORC_UNITTEST_LINK_FLAGS})
endif()
Expand Down
14 changes: 12 additions & 2 deletions compiler-rt/lib/sanitizer_common/sanitizer_asm.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@
# define CFI_RESTORE(reg)
#endif

#if defined(__aarch64__) && defined(__ARM_FEATURE_BTI_DEFAULT)
# define ASM_STARTPROC CFI_STARTPROC; hint #34
# define C_ASM_STARTPROC SANITIZER_STRINGIFY(CFI_STARTPROC) "\nhint #34"
#else
# define ASM_STARTPROC CFI_STARTPROC
# define C_ASM_STARTPROC SANITIZER_STRINGIFY(CFI_STARTPROC)
#endif
#define ASM_ENDPROC CFI_ENDPROC
#define C_ASM_ENDPROC SANITIZER_STRINGIFY(CFI_ENDPROC)
#if defined(__x86_64__) || defined(__i386__) || defined(__sparc__)
# define ASM_TAIL_CALL jmp
#elif defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \
Expand Down Expand Up @@ -114,9 +124,9 @@
.globl __interceptor_trampoline_##name; \
ASM_TYPE_FUNCTION(__interceptor_trampoline_##name); \
__interceptor_trampoline_##name: \
CFI_STARTPROC; \
ASM_STARTPROC; \
ASM_TAIL_CALL ASM_PREEMPTIBLE_SYM(__interceptor_##name); \
CFI_ENDPROC; \
ASM_ENDPROC; \
ASM_SIZE(__interceptor_trampoline_##name)
# define ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT 1
# endif // Architecture supports interceptor trampoline
Expand Down
19 changes: 18 additions & 1 deletion compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,24 @@ static void setlim(int res, rlim_t lim) {

void DisableCoreDumperIfNecessary() {
if (common_flags()->disable_coredump) {
setlim(RLIMIT_CORE, 0);
rlimit rlim;
CHECK_EQ(0, getrlimit(RLIMIT_CORE, &rlim));
// On Linux, if the kernel.core_pattern sysctl starts with a '|' (i.e. it
// is being piped to a coredump handler such as systemd-coredumpd), the
// kernel ignores RLIMIT_CORE (since we aren't creating a file in the file
// system) except for the magic value of 1, which disables coredumps when
// piping. 1 byte is too small for any kind of valid core dump, so it
// also disables coredumps if kernel.core_pattern creates files directly.
// While most piped coredump handlers do respect the crashing processes'
// RLIMIT_CORE, this is notable not the case for Debian's systemd-coredump
// due to a local patch that changes sysctl.d/50-coredump.conf to ignore
// the specified limit and instead use RLIM_INFINITY.
//
// The alternative to using RLIMIT_CORE=1 would be to use prctl() with the
// PR_SET_DUMPABLE flag, however that also prevents ptrace(), so makes it
// impossible to attach a debugger.
rlim.rlim_cur = Min<rlim_t>(SANITIZER_LINUX ? 1 : 0, rlim.rlim_max);
CHECK_EQ(0, setrlimit(RLIMIT_CORE, &rlim));
}
}

Expand Down
13 changes: 13 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_procmaps_bsd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,19 @@ void GetMemoryProfile(fill_profile_f cb, uptr *stats) {
cb(0, InfoProc->ki_rssize * GetPageSizeCached(), false, stats);
UnmapOrDie(InfoProc, Size, true);
}
#elif SANITIZER_NETBSD
void GetMemoryProfile(fill_profile_f cb, uptr *stats) {
struct kinfo_proc2 *InfoProc;
uptr Len = sizeof(*InfoProc);
uptr Size = Len;
const int Mib[] = {CTL_KERN, KERN_PROC2, KERN_PROC_PID, getpid(), Size, 1};
InfoProc = (struct kinfo_proc2 *)MmapOrDie(Size, "GetMemoryProfile()");
CHECK_EQ(
internal_sysctl(Mib, ARRAY_SIZE(Mib), nullptr, (uptr *)InfoProc, &Len, 0),
0);
cb(0, InfoProc->p_vm_rssize * GetPageSizeCached(), false, stats);
UnmapOrDie(InfoProc, Size, true);
}
#endif

void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ void MemoryMappingLayout::DumpListOfModules(
}
}

#if SANITIZER_LINUX || SANITIZER_ANDROID || SANITIZER_SOLARIS || SANITIZER_NETBSD
#if SANITIZER_LINUX || SANITIZER_ANDROID || SANITIZER_SOLARIS
void GetMemoryProfile(fill_profile_f cb, uptr *stats) {
char *smaps = nullptr;
uptr smaps_cap = 0;
Expand Down
1 change: 0 additions & 1 deletion compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,6 @@ macro(add_sanitizer_tests_for_arch arch)
RUNTIME "${SANITIZER_COMMON_LIB}"
SOURCES ${SANITIZER_UNITTESTS} ${COMPILER_RT_GTEST_SOURCE} ${COMPILER_RT_GMOCK_SOURCE}
COMPILE_DEPS ${SANITIZER_TEST_HEADERS}
DEPS llvm_gtest
CFLAGS ${SANITIZER_TEST_CFLAGS_COMMON} ${extra_flags}
LINK_FLAGS ${SANITIZER_TEST_LINK_FLAGS_COMMON} ${TARGET_LINK_FLAGS} ${extra_flags})

Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ macro(add_scudo_unittest testname)
"${testname}-${arch}-Test" ${arch}
SOURCES ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE}
COMPILE_DEPS ${SCUDO_TEST_HEADERS}
DEPS llvm_gtest scudo_standalone
DEPS scudo_standalone
RUNTIME ${RUNTIME}
CFLAGS ${SCUDO_UNITTEST_CFLAGS}
LINK_FLAGS ${SCUDO_UNITTEST_LINK_FLAGS})
Expand Down
2 changes: 2 additions & 0 deletions compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2861,6 +2861,8 @@ void InitializeInterceptors() {
REAL(memcpy) = internal_memcpy;
#endif

__interception::DoesNotSupportStaticLinking();

new(interceptor_ctx()) InterceptorContext();

// Interpose __tls_get_addr before the common interposers. This is needed
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/tsan/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ foreach (header ${TSAN_HEADERS})
list(APPEND TSAN_RTL_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../${header})
endforeach()

set(TSAN_DEPS llvm_gtest tsan)
set(TSAN_DEPS tsan)
# TSan uses C++ standard library headers.
if (TARGET cxx-headers OR HAVE_LIBCXX)
set(TSAN_DEPS cxx-headers)
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/xray/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ macro(add_xray_unittest testname)
${XRAY_HEADERS} ${XRAY_ALL_SOURCE_FILES_ABS_PATHS}
"test_helpers.h"
RUNTIME "${XRAY_RUNTIME_LIBS}"
DEPS llvm_gtest xray llvm-xray LLVMXRay LLVMTestingSupport
DEPS xray llvm-xray LLVMXRay LLVMTestingSupport
CFLAGS ${XRAY_UNITTEST_CFLAGS}
LINK_FLAGS ${TARGET_LINK_FLAGS} ${XRAY_UNITTEST_LINK_FLAGS}
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// UNSUPPORTED: hwasan, ubsan
// RUN: not %clangxx -static %s -o /dev/null
7 changes: 6 additions & 1 deletion compiler-rt/test/sanitizer_common/TestCases/corelimit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ int main() {
getrlimit(RLIMIT_CORE, &lim_core);
void *p;
if (sizeof(p) == 8) {
assert(0 == lim_core.rlim_cur);
#ifdef __linux__
// See comments in DisableCoreDumperIfNecessary().
assert(lim_core.rlim_cur == 1);
#else
assert(lim_core.rlim_cur == 0);
#endif
}
return 0;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// RUN: %clangxx %target_itanium_abi_host_triple -O0 -g %s -c -o %t.o
// RUN: %test_debuginfo %s %t.o
// Radar 9168773
// XFAIL: !system-darwin && gdb-clang-incompatibility

// DEBUGGER: ptype A
// Work around a gdb bug where it believes that a class is a
Expand Down
9 changes: 9 additions & 0 deletions flang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,8 @@ static bool parseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
// pre-processed inputs.
.Case("f95", Language::Fortran)
.Case("f95-cpp-input", Language::Fortran)
// CUDA Fortran
.Case("cuda", Language::Fortran)
.Default(Language::Unknown);

// Flang's intermediate representations.
Expand Down Expand Up @@ -877,6 +879,13 @@ static bool parseDialectArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
if (args.hasArg(clang::driver::options::OPT_flarge_sizes))
res.getDefaultKinds().set_sizeIntegerKind(8);

// -x cuda
auto language = args.getLastArgValue(clang::driver::options::OPT_x);
if (language.equals("cuda")) {
res.getFrontendOpts().features.Enable(
Fortran::common::LanguageFeature::CUDA);
}

// -fopenmp and -fopenacc
if (args.hasArg(clang::driver::options::OPT_fopenacc)) {
res.getFrontendOpts().features.Enable(
Expand Down
11 changes: 8 additions & 3 deletions flang/lib/Frontend/FrontendAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,14 @@ bool FrontendAction::beginSourceFile(CompilerInstance &ci,
invoc.collectMacroDefinitions();
}

// Enable CUDA Fortran if source file is *.cuf/*.CUF.
invoc.getFortranOpts().features.Enable(Fortran::common::LanguageFeature::CUDA,
getCurrentInput().getIsCUDAFortran());
if (!invoc.getFortranOpts().features.IsEnabled(
Fortran::common::LanguageFeature::CUDA)) {
// Enable CUDA Fortran if source file is *.cuf/*.CUF and not already
// enabled.
invoc.getFortranOpts().features.Enable(
Fortran::common::LanguageFeature::CUDA,
getCurrentInput().getIsCUDAFortran());
}

// Decide between fixed and free form (if the user didn't express any
// preference, use the file extension to decide)
Expand Down
84 changes: 79 additions & 5 deletions flang/lib/Lower/OpenMP/OpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,10 @@ genParallelOp(Fortran::lower::AbstractConverter &converter,
return reductionSymbols;
};

mlir::UnitAttr byrefAttr;
if (ReductionProcessor::doReductionByRef(reductionVars))
byrefAttr = converter.getFirOpBuilder().getUnitAttr();

OpWithBodyGenInfo genInfo =
OpWithBodyGenInfo(converter, semaCtx, currentLocation, eval)
.setGenNested(genNested)
Expand All @@ -620,7 +624,7 @@ genParallelOp(Fortran::lower::AbstractConverter &converter,
: mlir::ArrayAttr::get(converter.getFirOpBuilder().getContext(),
reductionDeclSymbols),
procBindKindAttr, /*private_vars=*/llvm::SmallVector<mlir::Value>{},
/*privatizers=*/nullptr);
/*privatizers=*/nullptr, byrefAttr);
}

bool privatize = !outerCombined;
Expand Down Expand Up @@ -684,7 +688,8 @@ genParallelOp(Fortran::lower::AbstractConverter &converter,
delayedPrivatizationInfo.privatizers.empty()
? nullptr
: mlir::ArrayAttr::get(converter.getFirOpBuilder().getContext(),
privatizers));
privatizers),
byrefAttr);
}

static mlir::omp::SectionOp
Expand Down Expand Up @@ -793,6 +798,58 @@ genTaskGroupOp(Fortran::lower::AbstractConverter &converter,
/*task_reductions=*/nullptr, allocateOperands, allocatorOperands);
}

// This helper function implements the functionality of "promoting"
// non-CPTR arguments of use_device_ptr to use_device_addr
// arguments (automagic conversion of use_device_ptr ->
// use_device_addr in these cases). The way we do so currently is
// through the shuffling of operands from the devicePtrOperands to
// deviceAddrOperands where neccesary and re-organizing the types,
// locations and symbols to maintain the correct ordering of ptr/addr
// input -> BlockArg.
//
// This effectively implements some deprecated OpenMP functionality
// that some legacy applications unfortunately depend on
// (deprecated in specification version 5.2):
//
// "If a list item in a use_device_ptr clause is not of type C_PTR,
// the behavior is as if the list item appeared in a use_device_addr
// clause. Support for such list items in a use_device_ptr clause
// is deprecated."
static void promoteNonCPtrUseDevicePtrArgsToUseDeviceAddr(
llvm::SmallVector<mlir::Value> &devicePtrOperands,
llvm::SmallVector<mlir::Value> &deviceAddrOperands,
llvm::SmallVector<mlir::Type> &useDeviceTypes,
llvm::SmallVector<mlir::Location> &useDeviceLocs,
llvm::SmallVector<const Fortran::semantics::Symbol *> &useDeviceSymbols) {
auto moveElementToBack = [](size_t idx, auto &vector) {
auto *iter = std::next(vector.begin(), idx);
vector.push_back(*iter);
vector.erase(iter);
};

// Iterate over our use_device_ptr list and shift all non-cptr arguments into
// use_device_addr.
for (auto *it = devicePtrOperands.begin(); it != devicePtrOperands.end();) {
if (!fir::isa_builtin_cptr_type(fir::unwrapRefType(it->getType()))) {
deviceAddrOperands.push_back(*it);
// We have to shuffle the symbols around as well, to maintain
// the correct Input -> BlockArg for use_device_ptr/use_device_addr.
// NOTE: However, as map's do not seem to be included currently
// this isn't as pertinent, but we must try to maintain for
// future alterations. I believe the reason they are not currently
// is that the BlockArg assign/lowering needs to be extended
// to a greater set of types.
auto idx = std::distance(devicePtrOperands.begin(), it);
moveElementToBack(idx, useDeviceTypes);
moveElementToBack(idx, useDeviceLocs);
moveElementToBack(idx, useDeviceSymbols);
it = devicePtrOperands.erase(it);
continue;
}
++it;
}
}

static mlir::omp::DataOp
genDataOp(Fortran::lower::AbstractConverter &converter,
Fortran::semantics::SemanticsContext &semaCtx,
Expand All @@ -815,6 +872,20 @@ genDataOp(Fortran::lower::AbstractConverter &converter,
useDeviceSymbols);
cp.processUseDeviceAddr(deviceAddrOperands, useDeviceTypes, useDeviceLocs,
useDeviceSymbols);
// This function implements the deprecated functionality of use_device_ptr
// that allows users to provide non-CPTR arguments to it with the caveat
// that the compiler will treat them as use_device_addr. A lot of legacy
// code may still depend on this functionality, so we should support it
// in some manner. We do so currently by simply shifting non-cptr operands
// from the use_device_ptr list into the front of the use_device_addr list
// whilst maintaining the ordering of useDeviceLocs, useDeviceSymbols and
// useDeviceTypes to use_device_ptr/use_device_addr input for BlockArg
// ordering.
// TODO: Perhaps create a user provideable compiler option that will
// re-introduce a hard-error rather than a warning in these cases.
promoteNonCPtrUseDevicePtrArgsToUseDeviceAddr(
devicePtrOperands, deviceAddrOperands, useDeviceTypes, useDeviceLocs,
useDeviceSymbols);
cp.processMap(currentLocation, llvm::omp::Directive::OMPD_target_data,
stmtCtx, mapOperands);

Expand Down Expand Up @@ -1583,7 +1654,7 @@ static void createWsLoop(Fortran::lower::AbstractConverter &converter,
llvm::SmallVector<const Fortran::semantics::Symbol *> reductionSymbols;
mlir::omp::ClauseOrderKindAttr orderClauseOperand;
mlir::omp::ClauseScheduleKindAttr scheduleValClauseOperand;
mlir::UnitAttr nowaitClauseOperand, scheduleSimdClauseOperand;
mlir::UnitAttr nowaitClauseOperand, byrefOperand, scheduleSimdClauseOperand;
mlir::IntegerAttr orderedClauseOperand;
mlir::omp::ScheduleModifierAttr scheduleModClauseOperand;
std::size_t loopVarTypeSize;
Expand All @@ -1600,6 +1671,9 @@ static void createWsLoop(Fortran::lower::AbstractConverter &converter,
convertLoopBounds(converter, loc, lowerBound, upperBound, step,
loopVarTypeSize);

if (ReductionProcessor::doReductionByRef(reductionVars))
byrefOperand = firOpBuilder.getUnitAttr();

auto wsLoopOp = firOpBuilder.create<mlir::omp::WsLoopOp>(
loc, lowerBound, upperBound, step, linearVars, linearStepVars,
reductionVars,
Expand All @@ -1609,8 +1683,8 @@ static void createWsLoop(Fortran::lower::AbstractConverter &converter,
reductionDeclSymbols),
scheduleValClauseOperand, scheduleChunkClauseOperand,
/*schedule_modifiers=*/nullptr,
/*simd_modifier=*/nullptr, nowaitClauseOperand, orderedClauseOperand,
orderClauseOperand,
/*simd_modifier=*/nullptr, nowaitClauseOperand, byrefOperand,
orderedClauseOperand, orderClauseOperand,
/*inclusive=*/firOpBuilder.getUnitAttr());

// Handle attribute based clauses.
Expand Down
137 changes: 110 additions & 27 deletions flang/lib/Lower/OpenMP/ReductionProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,16 @@

#include "flang/Lower/AbstractConverter.h"
#include "flang/Optimizer/Builder/Todo.h"
#include "flang/Optimizer/Dialect/FIRType.h"
#include "flang/Optimizer/HLFIR/HLFIROps.h"
#include "flang/Parser/tools.h"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
#include "llvm/Support/CommandLine.h"

static llvm::cl::opt<bool> forceByrefReduction(
"force-byref-reduction",
llvm::cl::desc("Pass all reduction arguments by reference"),
llvm::cl::Hidden);

namespace Fortran {
namespace lower {
Expand Down Expand Up @@ -76,16 +83,24 @@ bool ReductionProcessor::supportedIntrinsicProcReduction(
}

std::string ReductionProcessor::getReductionName(llvm::StringRef name,
mlir::Type ty) {
mlir::Type ty, bool isByRef) {
ty = fir::unwrapRefType(ty);

// extra string to distinguish reduction functions for variables passed by
// reference
llvm::StringRef byrefAddition{""};
if (isByRef)
byrefAddition = "_byref";

return (llvm::Twine(name) +
(ty.isIntOrIndex() ? llvm::Twine("_i_") : llvm::Twine("_f_")) +
llvm::Twine(ty.getIntOrFloatBitWidth()))
llvm::Twine(ty.getIntOrFloatBitWidth()) + byrefAddition)
.str();
}

std::string ReductionProcessor::getReductionName(
Fortran::parser::DefinedOperator::IntrinsicOperator intrinsicOp,
mlir::Type ty) {
mlir::Type ty, bool isByRef) {
std::string reductionName;

switch (intrinsicOp) {
Expand All @@ -108,13 +123,14 @@ std::string ReductionProcessor::getReductionName(
break;
}

return getReductionName(reductionName, ty);
return getReductionName(reductionName, ty, isByRef);
}

mlir::Value
ReductionProcessor::getReductionInitValue(mlir::Location loc, mlir::Type type,
ReductionIdentifier redId,
fir::FirOpBuilder &builder) {
type = fir::unwrapRefType(type);
assert((fir::isa_integer(type) || fir::isa_real(type) ||
type.isa<fir::LogicalType>()) &&
"only integer, logical and real types are currently supported");
Expand Down Expand Up @@ -188,6 +204,7 @@ mlir::Value ReductionProcessor::createScalarCombiner(
fir::FirOpBuilder &builder, mlir::Location loc, ReductionIdentifier redId,
mlir::Type type, mlir::Value op1, mlir::Value op2) {
mlir::Value reductionOp;
type = fir::unwrapRefType(type);
switch (redId) {
case ReductionIdentifier::MAX:
reductionOp =
Expand Down Expand Up @@ -268,7 +285,8 @@ mlir::Value ReductionProcessor::createScalarCombiner(

mlir::omp::ReductionDeclareOp ReductionProcessor::createReductionDecl(
fir::FirOpBuilder &builder, llvm::StringRef reductionOpName,
const ReductionIdentifier redId, mlir::Type type, mlir::Location loc) {
const ReductionIdentifier redId, mlir::Type type, mlir::Location loc,
bool isByRef) {
mlir::OpBuilder::InsertionGuard guard(builder);
mlir::ModuleOp module = builder.getModule();

Expand All @@ -278,14 +296,24 @@ mlir::omp::ReductionDeclareOp ReductionProcessor::createReductionDecl(
return decl;

mlir::OpBuilder modBuilder(module.getBodyRegion());
mlir::Type valTy = fir::unwrapRefType(type);
if (!isByRef)
type = valTy;

decl = modBuilder.create<mlir::omp::ReductionDeclareOp>(loc, reductionOpName,
type);
builder.createBlock(&decl.getInitializerRegion(),
decl.getInitializerRegion().end(), {type}, {loc});
builder.setInsertionPointToEnd(&decl.getInitializerRegion().back());

mlir::Value init = getReductionInitValue(loc, type, redId, builder);
builder.create<mlir::omp::YieldOp>(loc, init);
if (isByRef) {
mlir::Value alloca = builder.create<fir::AllocaOp>(loc, valTy);
builder.createStoreWithConvert(loc, init, alloca);
builder.create<mlir::omp::YieldOp>(loc, alloca);
} else {
builder.create<mlir::omp::YieldOp>(loc, init);
}

builder.createBlock(&decl.getReductionRegion(),
decl.getReductionRegion().end(), {type, type},
Expand All @@ -294,14 +322,45 @@ mlir::omp::ReductionDeclareOp ReductionProcessor::createReductionDecl(
builder.setInsertionPointToEnd(&decl.getReductionRegion().back());
mlir::Value op1 = decl.getReductionRegion().front().getArgument(0);
mlir::Value op2 = decl.getReductionRegion().front().getArgument(1);
mlir::Value outAddr = op1;

op1 = builder.loadIfRef(loc, op1);
op2 = builder.loadIfRef(loc, op2);

mlir::Value reductionOp =
createScalarCombiner(builder, loc, redId, type, op1, op2);
builder.create<mlir::omp::YieldOp>(loc, reductionOp);
if (isByRef) {
builder.create<fir::StoreOp>(loc, reductionOp, outAddr);
builder.create<mlir::omp::YieldOp>(loc, outAddr);
} else {
builder.create<mlir::omp::YieldOp>(loc, reductionOp);
}

return decl;
}

// TODO: By-ref vs by-val reductions are currently toggled for the whole
// operation (possibly effecting multiple reduction variables).
// This could cause a problem with openmp target reductions because
// by-ref trivial types may not be supported.
bool ReductionProcessor::doReductionByRef(
const llvm::SmallVectorImpl<mlir::Value> &reductionVars) {
if (reductionVars.empty())
return false;
if (forceByrefReduction)
return true;

for (mlir::Value reductionVar : reductionVars) {
if (auto declare =
mlir::dyn_cast<hlfir::DeclareOp>(reductionVar.getDefiningOp()))
reductionVar = declare.getMemref();

if (!fir::isa_trivial(fir::unwrapRefType(reductionVar.getType())))
return true;
}
return false;
}

void ReductionProcessor::addReductionDecl(
mlir::Location currentLocation,
Fortran::lower::AbstractConverter &converter,
Expand All @@ -315,6 +374,37 @@ void ReductionProcessor::addReductionDecl(
const auto &redOperator{
std::get<Fortran::parser::OmpReductionOperator>(reduction.t)};
const auto &objectList{std::get<Fortran::parser::OmpObjectList>(reduction.t)};

if (!std::holds_alternative<Fortran::parser::DefinedOperator>(
redOperator.u)) {
if (const auto *reductionIntrinsic =
std::get_if<Fortran::parser::ProcedureDesignator>(&redOperator.u)) {
if (!ReductionProcessor::supportedIntrinsicProcReduction(
*reductionIntrinsic)) {
return;
}
} else {
return;
}
}

// initial pass to collect all recuction vars so we can figure out if this
// should happen byref
for (const Fortran::parser::OmpObject &ompObject : objectList.v) {
if (const auto *name{
Fortran::parser::Unwrap<Fortran::parser::Name>(ompObject)}) {
if (const Fortran::semantics::Symbol * symbol{name->symbol}) {
if (reductionSymbols)
reductionSymbols->push_back(symbol);
mlir::Value symVal = converter.getSymbolAddress(*symbol);
if (auto declOp = symVal.getDefiningOp<hlfir::DeclareOp>())
symVal = declOp.getBase();
reductionVars.push_back(symVal);
}
}
}
const bool isByRef = doReductionByRef(reductionVars);

if (const auto &redDefinedOp =
std::get_if<Fortran::parser::DefinedOperator>(&redOperator.u)) {
const auto &intrinsicOp{
Expand All @@ -338,23 +428,20 @@ void ReductionProcessor::addReductionDecl(
if (const auto *name{
Fortran::parser::Unwrap<Fortran::parser::Name>(ompObject)}) {
if (const Fortran::semantics::Symbol * symbol{name->symbol}) {
if (reductionSymbols)
reductionSymbols->push_back(symbol);
mlir::Value symVal = converter.getSymbolAddress(*symbol);
if (auto declOp = symVal.getDefiningOp<hlfir::DeclareOp>())
symVal = declOp.getBase();
mlir::Type redType =
symVal.getType().cast<fir::ReferenceType>().getEleTy();
reductionVars.push_back(symVal);
if (redType.isa<fir::LogicalType>())
auto redType = symVal.getType().cast<fir::ReferenceType>();
if (redType.getEleTy().isa<fir::LogicalType>())
decl = createReductionDecl(
firOpBuilder,
getReductionName(intrinsicOp, firOpBuilder.getI1Type()), redId,
redType, currentLocation);
else if (redType.isIntOrIndexOrFloat()) {
decl = createReductionDecl(firOpBuilder,
getReductionName(intrinsicOp, redType),
redId, redType, currentLocation);
getReductionName(intrinsicOp, firOpBuilder.getI1Type(),
isByRef),
redId, redType, currentLocation, isByRef);
else if (redType.getEleTy().isIntOrIndexOrFloat()) {
decl = createReductionDecl(
firOpBuilder, getReductionName(intrinsicOp, redType, isByRef),
redId, redType, currentLocation, isByRef);
} else {
TODO(currentLocation, "Reduction of some types is not supported");
}
Expand All @@ -374,21 +461,17 @@ void ReductionProcessor::addReductionDecl(
if (const auto *name{
Fortran::parser::Unwrap<Fortran::parser::Name>(ompObject)}) {
if (const Fortran::semantics::Symbol * symbol{name->symbol}) {
if (reductionSymbols)
reductionSymbols->push_back(symbol);
mlir::Value symVal = converter.getSymbolAddress(*symbol);
if (auto declOp = symVal.getDefiningOp<hlfir::DeclareOp>())
symVal = declOp.getBase();
mlir::Type redType =
symVal.getType().cast<fir::ReferenceType>().getEleTy();
reductionVars.push_back(symVal);
assert(redType.isIntOrIndexOrFloat() &&
auto redType = symVal.getType().cast<fir::ReferenceType>();
assert(redType.getEleTy().isIntOrIndexOrFloat() &&
"Unsupported reduction type");
decl = createReductionDecl(
firOpBuilder,
getReductionName(getRealName(*reductionIntrinsic).ToString(),
redType),
redId, redType, currentLocation);
redType, isByRef),
redId, redType, currentLocation, isByRef);
reductionDeclSymbols.push_back(mlir::SymbolRefAttr::get(
firOpBuilder.getContext(), decl.getSymName()));
}
Expand Down
Loading