392 changes: 239 additions & 153 deletions clang/lib/CodeGen/CGStmtOpenMP.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ add_clang_library(clangCodeGen
MacroPPCallbacks.cpp
MicrosoftCXXABI.cpp
ModuleBuilder.cpp
ObjectFilePCHContainerOperations.cpp
ObjectFilePCHContainerWriter.cpp
PatternInit.cpp
SanitizerMetadata.cpp
SwiftCallingConv.cpp
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
const CodeGenOptions &CodeGenOpts = CGM.getCodeGenOpts();
if (CodeGenOpts.PointerAuth.FunctionPointers)
Fn->addFnAttr("ptrauth-calls");
if (CodeGenOpts.PointerAuth.IndirectGotos)
Fn->addFnAttr("ptrauth-indirect-gotos");

// Apply xray attributes to the function (as a string, for now)
bool AlwaysXRayAttr = false;
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -4374,7 +4374,8 @@ class CodeGenFunction : public CodeGenTypeCache {
RValue EmitCall(const CGFunctionInfo &CallInfo, const CGCallee &Callee,
ReturnValueSlot ReturnValue, const CallArgList &Args,
llvm::CallBase **callOrInvoke, bool IsMustTail,
SourceLocation Loc);
SourceLocation Loc,
bool IsVirtualFunctionPointerThunk = false);
RValue EmitCall(const CGFunctionInfo &CallInfo, const CGCallee &Callee,
ReturnValueSlot ReturnValue, const CallArgList &Args,
llvm::CallBase **callOrInvoke = nullptr,
Expand Down Expand Up @@ -4696,6 +4697,9 @@ class CodeGenFunction : public CodeGenTypeCache {
llvm::Value *EmitRISCVBuiltinExpr(unsigned BuiltinID, const CallExpr *E,
ReturnValueSlot ReturnValue);

llvm::Value *EmitRISCVCpuSupports(const CallExpr *E);
llvm::Value *EmitRISCVCpuInit();

void AddAMDGPUFenceAddressSpaceMMRA(llvm::Instruction *Inst,
const CallExpr *E);
void ProcessOrderScopeAMDGCN(llvm::Value *Order, llvm::Value *Scope,
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ createTargetCodeGenInfo(CodeGenModule &CGM) {
return createWindowsAArch64TargetCodeGenInfo(CGM, AArch64ABIKind::Win64);
else if (Target.getABI() == "aapcs-soft")
Kind = AArch64ABIKind::AAPCSSoft;
else if (Target.getABI() == "pauthtest")
Kind = AArch64ABIKind::PAuthTest;

return createAArch64TargetCodeGenInfo(CGM, Kind);
}
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -973,8 +973,16 @@ class CodeGenModule : public CodeGenTypeCache {
llvm::Constant *getFunctionPointer(llvm::Constant *Pointer,
QualType FunctionType);

llvm::Constant *getMemberFunctionPointer(const FunctionDecl *FD,
llvm::Type *Ty = nullptr);

llvm::Constant *getMemberFunctionPointer(llvm::Constant *Pointer,
QualType FT);

CGPointerAuthInfo getFunctionPointerAuthInfo(QualType T);

CGPointerAuthInfo getMemberFunctionPointerAuthInfo(QualType FT);

CGPointerAuthInfo getPointerAuthInfoForPointeeType(QualType type);

CGPointerAuthInfo getPointerAuthInfoForType(QualType type);
Expand Down
254 changes: 242 additions & 12 deletions clang/lib/CodeGen/ItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,9 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {

bool NeedsVTTParameter(GlobalDecl GD) override;

llvm::Constant *
getOrCreateVirtualFunctionPointerThunk(const CXXMethodDecl *MD);

/**************************** RTTI Uniqueness ******************************/

protected:
Expand Down Expand Up @@ -426,6 +429,9 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
const CXXRecordDecl *RD) override;

private:
llvm::Constant *
getSignedVirtualMemberFunctionPointer(const CXXMethodDecl *MD);

bool hasAnyUnusedVirtualInlineFunction(const CXXRecordDecl *RD) const {
const auto &VtableLayout =
CGM.getItaniumVTableContext().getVTableLayout(RD);
Expand Down Expand Up @@ -835,7 +841,25 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
CalleePtr->addIncoming(VirtualFn, FnVirtual);
CalleePtr->addIncoming(NonVirtualFn, FnNonVirtual);

CGCallee Callee(FPT, CalleePtr);
CGPointerAuthInfo PointerAuth;

if (const auto &Schema =
CGM.getCodeGenOpts().PointerAuth.CXXMemberFunctionPointers) {
llvm::PHINode *DiscriminatorPHI = Builder.CreatePHI(CGF.IntPtrTy, 2);
DiscriminatorPHI->addIncoming(llvm::ConstantInt::get(CGF.IntPtrTy, 0),
FnVirtual);
const auto &AuthInfo =
CGM.getMemberFunctionPointerAuthInfo(QualType(MPT, 0));
assert(Schema.getKey() == AuthInfo.getKey() &&
"Keys for virtual and non-virtual member functions must match");
auto *NonVirtualDiscriminator = AuthInfo.getDiscriminator();
DiscriminatorPHI->addIncoming(NonVirtualDiscriminator, FnNonVirtual);
PointerAuth = CGPointerAuthInfo(
Schema.getKey(), Schema.getAuthenticationMode(), Schema.isIsaPointer(),
Schema.authenticatesNullValues(), DiscriminatorPHI);
}

CGCallee Callee(FPT, CalleePtr, PointerAuth);
return Callee;
}

Expand All @@ -853,6 +877,25 @@ llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(
"memptr.offset");
}

// See if it's possible to return a constant signed pointer.
static llvm::Constant *pointerAuthResignConstant(
llvm::Value *Ptr, const CGPointerAuthInfo &CurAuthInfo,
const CGPointerAuthInfo &NewAuthInfo, CodeGenModule &CGM) {
const auto *CPA = dyn_cast<llvm::ConstantPtrAuth>(Ptr);

if (!CPA)
return nullptr;

assert(CPA->getKey()->getZExtValue() == CurAuthInfo.getKey() &&
CPA->getAddrDiscriminator()->isZeroValue() &&
CPA->getDiscriminator() == CurAuthInfo.getDiscriminator() &&
"unexpected key or discriminators");

return CGM.getConstantSignedPointer(
CPA->getPointer(), NewAuthInfo.getKey(), nullptr,
cast<llvm::ConstantInt>(NewAuthInfo.getDiscriminator()));
}

/// Perform a bitcast, derived-to-base, or base-to-derived member pointer
/// conversion.
///
Expand Down Expand Up @@ -880,21 +923,63 @@ llvm::Value *
ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
const CastExpr *E,
llvm::Value *src) {
// Use constant emission if we can.
if (isa<llvm::Constant>(src))
return EmitMemberPointerConversion(E, cast<llvm::Constant>(src));

assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
E->getCastKind() == CK_BaseToDerivedMemberPointer ||
E->getCastKind() == CK_ReinterpretMemberPointer);

CGBuilderTy &Builder = CGF.Builder;
QualType DstType = E->getType();

if (DstType->isMemberFunctionPointerType()) {
if (const auto &NewAuthInfo =
CGM.getMemberFunctionPointerAuthInfo(DstType)) {
QualType SrcType = E->getSubExpr()->getType();
assert(SrcType->isMemberFunctionPointerType());
const auto &CurAuthInfo = CGM.getMemberFunctionPointerAuthInfo(SrcType);
llvm::Value *MemFnPtr = Builder.CreateExtractValue(src, 0, "memptr.ptr");
llvm::Type *OrigTy = MemFnPtr->getType();

llvm::BasicBlock *StartBB = Builder.GetInsertBlock();
llvm::BasicBlock *ResignBB = CGF.createBasicBlock("resign");
llvm::BasicBlock *MergeBB = CGF.createBasicBlock("merge");

// Check whether we have a virtual offset or a pointer to a function.
assert(UseARMMethodPtrABI && "ARM ABI expected");
llvm::Value *Adj = Builder.CreateExtractValue(src, 1, "memptr.adj");
llvm::Constant *Ptrdiff_1 = llvm::ConstantInt::get(CGM.PtrDiffTy, 1);
llvm::Value *AndVal = Builder.CreateAnd(Adj, Ptrdiff_1);
llvm::Value *IsVirtualOffset =
Builder.CreateIsNotNull(AndVal, "is.virtual.offset");
Builder.CreateCondBr(IsVirtualOffset, MergeBB, ResignBB);

CGF.EmitBlock(ResignBB);
llvm::Type *PtrTy = llvm::PointerType::getUnqual(CGM.Int8Ty);
MemFnPtr = Builder.CreateIntToPtr(MemFnPtr, PtrTy);
MemFnPtr =
CGF.emitPointerAuthResign(MemFnPtr, SrcType, CurAuthInfo, NewAuthInfo,
isa<llvm::Constant>(src));
MemFnPtr = Builder.CreatePtrToInt(MemFnPtr, OrigTy);
llvm::Value *ResignedVal = Builder.CreateInsertValue(src, MemFnPtr, 0);
ResignBB = Builder.GetInsertBlock();

CGF.EmitBlock(MergeBB);
llvm::PHINode *NewSrc = Builder.CreatePHI(src->getType(), 2);
NewSrc->addIncoming(src, StartBB);
NewSrc->addIncoming(ResignedVal, ResignBB);
src = NewSrc;
}
}

// Under Itanium, reinterprets don't require any additional processing.
if (E->getCastKind() == CK_ReinterpretMemberPointer) return src;

// Use constant emission if we can.
if (isa<llvm::Constant>(src))
return EmitMemberPointerConversion(E, cast<llvm::Constant>(src));

llvm::Constant *adj = getMemberPointerAdjustment(E);
if (!adj) return src;

CGBuilderTy &Builder = CGF.Builder;
bool isDerivedToBase = (E->getCastKind() == CK_DerivedToBaseMemberPointer);

const MemberPointerType *destTy =
Expand Down Expand Up @@ -932,13 +1017,47 @@ ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
return Builder.CreateInsertValue(src, dstAdj, 1);
}

static llvm::Constant *
pointerAuthResignMemberFunctionPointer(llvm::Constant *Src, QualType DestType,
QualType SrcType, CodeGenModule &CGM) {
assert(DestType->isMemberFunctionPointerType() &&
SrcType->isMemberFunctionPointerType() &&
"member function pointers expected");
if (DestType == SrcType)
return Src;

const auto &NewAuthInfo = CGM.getMemberFunctionPointerAuthInfo(DestType);
const auto &CurAuthInfo = CGM.getMemberFunctionPointerAuthInfo(SrcType);

if (!NewAuthInfo && !CurAuthInfo)
return Src;

llvm::Constant *MemFnPtr = Src->getAggregateElement(0u);
if (MemFnPtr->getNumOperands() == 0) {
// src must be a pair of null pointers.
assert(isa<llvm::ConstantInt>(MemFnPtr) && "constant int expected");
return Src;
}

llvm::Constant *ConstPtr = pointerAuthResignConstant(
cast<llvm::User>(MemFnPtr)->getOperand(0), CurAuthInfo, NewAuthInfo, CGM);
ConstPtr = llvm::ConstantExpr::getPtrToInt(ConstPtr, MemFnPtr->getType());
return ConstantFoldInsertValueInstruction(Src, ConstPtr, 0);
}

llvm::Constant *
ItaniumCXXABI::EmitMemberPointerConversion(const CastExpr *E,
llvm::Constant *src) {
assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
E->getCastKind() == CK_BaseToDerivedMemberPointer ||
E->getCastKind() == CK_ReinterpretMemberPointer);

QualType DstType = E->getType();

if (DstType->isMemberFunctionPointerType())
src = pointerAuthResignMemberFunctionPointer(
src, DstType, E->getSubExpr()->getType(), CGM);

// Under Itanium, reinterprets don't require any additional processing.
if (E->getCastKind() == CK_ReinterpretMemberPointer) return src;

Expand Down Expand Up @@ -1036,9 +1155,32 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD,
// least significant bit of adj then makes exactly the same
// discrimination as the least significant bit of ptr does for
// Itanium.
MemPtr[0] = llvm::ConstantInt::get(CGM.PtrDiffTy, VTableOffset);
MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy,
2 * ThisAdjustment.getQuantity() + 1);

// We cannot use the Itanium ABI's representation for virtual member
// function pointers under pointer authentication because it would
// require us to store both the virtual offset and the constant
// discriminator in the pointer, which would be immediately vulnerable
// to attack. Instead we introduce a thunk that does the virtual dispatch
// and store it as if it were a non-virtual member function. This means
// that virtual function pointers may not compare equal anymore, but
// fortunately they aren't required to by the standard, and we do make
// a best-effort attempt to re-use the thunk.
//
// To support interoperation with code in which pointer authentication
// is disabled, derefencing a member function pointer must still handle
// the virtual case, but it can use a discriminator which should never
// be valid.
const auto &Schema =
CGM.getCodeGenOpts().PointerAuth.CXXMemberFunctionPointers;
if (Schema)
MemPtr[0] = llvm::ConstantExpr::getPtrToInt(
getSignedVirtualMemberFunctionPointer(MD), CGM.PtrDiffTy);
else
MemPtr[0] = llvm::ConstantInt::get(CGM.PtrDiffTy, VTableOffset);
// Don't set the LSB of adj to 1 if pointer authentication for member
// function pointers is enabled.
MemPtr[1] = llvm::ConstantInt::get(
CGM.PtrDiffTy, 2 * ThisAdjustment.getQuantity() + !Schema);
} else {
// Itanium C++ ABI 2.3:
// For a virtual function, [the pointer field] is 1 plus the
Expand All @@ -1060,7 +1202,7 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD,
// function type is incomplete.
Ty = CGM.PtrDiffTy;
}
llvm::Constant *addr = CGM.GetAddrOfFunction(MD, Ty);
llvm::Constant *addr = CGM.getMemberFunctionPointer(MD, Ty);

MemPtr[0] = llvm::ConstantExpr::getPtrToInt(addr, CGM.PtrDiffTy);
MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy,
Expand All @@ -1080,8 +1222,12 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const APValue &MP,

CharUnits ThisAdjustment = getContext().getMemberPointerPathAdjustment(MP);

if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MPD))
return BuildMemberPointer(MD, ThisAdjustment);
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MPD)) {
llvm::Constant *Src = BuildMemberPointer(MD, ThisAdjustment);
QualType SrcType = getContext().getMemberPointerType(
MD->getType(), MD->getParent()->getTypeForDecl());
return pointerAuthResignMemberFunctionPointer(Src, MPType, SrcType, CGM);
}

CharUnits FieldOffset =
getContext().toCharUnitsFromBits(getContext().getFieldOffset(MPD));
Expand Down Expand Up @@ -3185,6 +3331,78 @@ bool ItaniumCXXABI::NeedsVTTParameter(GlobalDecl GD) {
return false;
}

llvm::Constant *
ItaniumCXXABI::getOrCreateVirtualFunctionPointerThunk(const CXXMethodDecl *MD) {
SmallString<256> MethodName;
llvm::raw_svector_ostream Out(MethodName);
getMangleContext().mangleCXXName(MD, Out);
MethodName += "_vfpthunk_";
StringRef ThunkName = MethodName.str();
llvm::Function *ThunkFn;
if ((ThunkFn = cast_or_null<llvm::Function>(
CGM.getModule().getNamedValue(ThunkName))))
return ThunkFn;

const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeCXXMethodDeclaration(MD);
llvm::FunctionType *ThunkTy = CGM.getTypes().GetFunctionType(FnInfo);
llvm::GlobalValue::LinkageTypes Linkage =
MD->isExternallyVisible() ? llvm::GlobalValue::LinkOnceODRLinkage
: llvm::GlobalValue::InternalLinkage;
ThunkFn =
llvm::Function::Create(ThunkTy, Linkage, ThunkName, &CGM.getModule());
if (Linkage == llvm::GlobalValue::LinkOnceODRLinkage)
ThunkFn->setVisibility(llvm::GlobalValue::HiddenVisibility);
assert(ThunkFn->getName() == ThunkName && "name was uniqued!");

CGM.SetLLVMFunctionAttributes(MD, FnInfo, ThunkFn, /*IsThunk=*/true);
CGM.SetLLVMFunctionAttributesForDefinition(MD, ThunkFn);

// Stack protection sometimes gets inserted after the musttail call.
ThunkFn->removeFnAttr(llvm::Attribute::StackProtect);
ThunkFn->removeFnAttr(llvm::Attribute::StackProtectStrong);
ThunkFn->removeFnAttr(llvm::Attribute::StackProtectReq);

// Start codegen.
CodeGenFunction CGF(CGM);
CGF.CurGD = GlobalDecl(MD);
CGF.CurFuncIsThunk = true;

// Build FunctionArgs.
FunctionArgList FunctionArgs;
CGF.BuildFunctionArgList(CGF.CurGD, FunctionArgs);

CGF.StartFunction(GlobalDecl(), FnInfo.getReturnType(), ThunkFn, FnInfo,
FunctionArgs, MD->getLocation(), SourceLocation());
llvm::Value *ThisVal = loadIncomingCXXThis(CGF);
setCXXABIThisValue(CGF, ThisVal);

CallArgList CallArgs;
for (const VarDecl *VD : FunctionArgs)
CGF.EmitDelegateCallArg(CallArgs, VD, SourceLocation());

const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
RequiredArgs Required = RequiredArgs::forPrototypePlus(FPT, /*this*/ 1);
const CGFunctionInfo &CallInfo =
CGM.getTypes().arrangeCXXMethodCall(CallArgs, FPT, Required, 0);
CGCallee Callee = CGCallee::forVirtual(nullptr, GlobalDecl(MD),
getThisAddress(CGF), ThunkTy);
llvm::CallBase *CallOrInvoke;
CGF.EmitCall(CallInfo, Callee, ReturnValueSlot(), CallArgs, &CallOrInvoke,
/*IsMustTail=*/true, SourceLocation(), true);
auto *Call = cast<llvm::CallInst>(CallOrInvoke);
Call->setTailCallKind(llvm::CallInst::TCK_MustTail);
if (Call->getType()->isVoidTy())
CGF.Builder.CreateRetVoid();
else
CGF.Builder.CreateRet(Call);

// Finish the function to maintain CodeGenFunction invariants.
// FIXME: Don't emit unreachable code.
CGF.EmitBlock(CGF.createBasicBlock());
CGF.FinishFunction();
return ThunkFn;
}

namespace {
class ItaniumRTTIBuilder {
CodeGenModule &CGM; // Per-module state.
Expand Down Expand Up @@ -4875,6 +5093,18 @@ ItaniumCXXABI::LoadVTablePtr(CodeGenFunction &CGF, Address This,
return {CGF.GetVTablePtr(This, CGM.Int8PtrTy, RD), RD};
}

llvm::Constant *
ItaniumCXXABI::getSignedVirtualMemberFunctionPointer(const CXXMethodDecl *MD) {
const CXXMethodDecl *origMD =
cast<CXXMethodDecl>(CGM.getItaniumVTableContext()
.findOriginalMethod(MD->getCanonicalDecl())
.getDecl());
llvm::Constant *thunk = getOrCreateVirtualFunctionPointerThunk(origMD);
QualType funcType = CGM.getContext().getMemberPointerType(
MD->getType(), MD->getParent()->getTypeForDecl());
return CGM.getMemberFunctionPointer(thunk, funcType);
}

void WebAssemblyCXXABI::emitBeginCatch(CodeGenFunction &CGF,
const CXXCatchStmt *C) {
if (CGF.getTarget().hasFeature("exception-handling"))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
//===--- ObjectFilePCHContainerOperations.cpp -----------------------------===//
//===--- ObjectFilePCHContainerWriter.cpp -----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/CodeGen/ObjectFilePCHContainerWriter.h"
#include "CGDebugInfo.h"
#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
Expand Down Expand Up @@ -351,46 +351,3 @@ ObjectFilePCHContainerWriter::CreatePCHContainerGenerator(
return std::make_unique<PCHContainerGenerator>(
CI, MainFileName, OutputFileName, std::move(OS), Buffer);
}

ArrayRef<StringRef> ObjectFilePCHContainerReader::getFormats() const {
static StringRef Formats[] = {"obj", "raw"};
return Formats;
}

StringRef
ObjectFilePCHContainerReader::ExtractPCH(llvm::MemoryBufferRef Buffer) const {
StringRef PCH;
auto OFOrErr = llvm::object::ObjectFile::createObjectFile(Buffer);
if (OFOrErr) {
auto &OF = OFOrErr.get();
bool IsCOFF = isa<llvm::object::COFFObjectFile>(*OF);
// Find the clang AST section in the container.
for (auto &Section : OF->sections()) {
StringRef Name;
if (Expected<StringRef> NameOrErr = Section.getName())
Name = *NameOrErr;
else
consumeError(NameOrErr.takeError());

if ((!IsCOFF && Name == "__clangast") || (IsCOFF && Name == "clangast")) {
if (Expected<StringRef> E = Section.getContents())
return *E;
else {
handleAllErrors(E.takeError(), [&](const llvm::ErrorInfoBase &EIB) {
EIB.log(llvm::errs());
});
return "";
}
}
}
}
handleAllErrors(OFOrErr.takeError(), [&](const llvm::ErrorInfoBase &EIB) {
if (EIB.convertToErrorCode() ==
llvm::object::object_error::invalid_file_type)
// As a fallback, treat the buffer as a raw AST.
PCH = Buffer.getBuffer();
else
EIB.log(llvm::errs());
});
return PCH;
}
1 change: 1 addition & 0 deletions clang/lib/CodeGen/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@ enum class AArch64ABIKind {
DarwinPCS,
Win64,
AAPCSSoft,
PAuthTest,
};

std::unique_ptr<TargetCodeGenInfo>
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Driver/ToolChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1031,11 +1031,12 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
}
case llvm::Triple::aarch64: {
llvm::Triple Triple = getTriple();
tools::aarch64::setPAuthABIInTriple(getDriver(), Args, Triple);
if (!Triple.isOSBinFormatMachO())
return getTripleString();
return Triple.getTriple();

if (Triple.isArm64e())
return getTripleString();
return Triple.getTriple();

// FIXME: older versions of ld64 expect the "arm64" component in the actual
// triple string and query it to determine whether an LTO file can be
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Driver/ToolChains/AIX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,12 @@ void AIX::addClangTargetOptions(
if (!Args.getLastArgNoClaim(options::OPT_fsized_deallocation,
options::OPT_fno_sized_deallocation))
CC1Args.push_back("-fno-sized-deallocation");

if (Args.hasFlag(options::OPT_ferr_pragma_mc_func_aix,
options::OPT_fno_err_pragma_mc_func_aix, false))
CC1Args.push_back("-ferr-pragma-mc-func-aix");
else
CC1Args.push_back("-fno-err-pragma-mc-func-aix");
}

void AIX::addProfileRTLibs(const llvm::opt::ArgList &Args,
Expand Down
21 changes: 21 additions & 0 deletions clang/lib/Driver/ToolChains/Arch/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,3 +449,24 @@ void aarch64::getAArch64TargetFeatures(const Driver &D,
if (Args.getLastArg(options::OPT_mno_bti_at_return_twice))
Features.push_back("+no-bti-at-return-twice");
}

void aarch64::setPAuthABIInTriple(const Driver &D, const ArgList &Args,
llvm::Triple &Triple) {
Arg *ABIArg = Args.getLastArg(options::OPT_mabi_EQ);
bool HasPAuthABI =
ABIArg ? (StringRef(ABIArg->getValue()) == "pauthtest") : false;

switch (Triple.getEnvironment()) {
case llvm::Triple::UnknownEnvironment:
if (HasPAuthABI)
Triple.setEnvironment(llvm::Triple::PAuthTest);
break;
case llvm::Triple::PAuthTest:
break;
default:
if (HasPAuthABI)
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< ABIArg->getAsString(Args) << Triple.getTriple();
break;
}
}
3 changes: 3 additions & 0 deletions clang/lib/Driver/ToolChains/Arch/AArch64.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ void getAArch64TargetFeatures(const Driver &D, const llvm::Triple &Triple,
std::string getAArch64TargetCPU(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple, llvm::opt::Arg *&A);

void setPAuthABIInTriple(const Driver &D, const llvm::opt::ArgList &Args,
llvm::Triple &triple);

} // end namespace aarch64
} // end namespace target
} // end namespace driver
Expand Down
86 changes: 53 additions & 33 deletions clang/lib/Driver/ToolChains/Arch/LoongArch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D,
const llvm::Triple &Triple,
const ArgList &Args,
std::vector<StringRef> &Features) {
// Enable the `lsx` feature on 64-bit LoongArch by default.
if (Triple.isLoongArch64() &&
(!Args.hasArgNoClaim(clang::driver::options::OPT_march_EQ)))
Features.push_back("+lsx");

std::string ArchName;
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
ArchName = A->getValue();
Expand All @@ -145,9 +150,11 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D,
} else if (A->getOption().matches(options::OPT_msingle_float)) {
Features.push_back("+f");
Features.push_back("-d");
Features.push_back("-lsx");
} else /*Soft-float*/ {
Features.push_back("-f");
Features.push_back("-d");
Features.push_back("-lsx");
}
} else if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) {
StringRef FPU = A->getValue();
Expand All @@ -157,9 +164,11 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D,
} else if (FPU == "32") {
Features.push_back("+f");
Features.push_back("-d");
Features.push_back("-lsx");
} else if (FPU == "0" || FPU == "none") {
Features.push_back("-f");
Features.push_back("-d");
Features.push_back("-lsx");
} else {
D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << FPU;
}
Expand All @@ -174,6 +183,42 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D,
A->ignoreTargetSpecific();
if (Arg *A = Args.getLastArgNoClaim(options::OPT_mfpu_EQ))
A->ignoreTargetSpecific();
if (Arg *A = Args.getLastArgNoClaim(options::OPT_msimd_EQ))
A->ignoreTargetSpecific();

// Select lsx/lasx feature determined by -msimd=.
// Option -msimd= precedes -m[no-]lsx and -m[no-]lasx.
if (const Arg *A = Args.getLastArg(options::OPT_msimd_EQ)) {
StringRef MSIMD = A->getValue();
if (MSIMD == "lsx") {
// Option -msimd=lsx depends on 64-bit FPU.
// -m*-float and -mfpu=none/0/32 conflict with -msimd=lsx.
if (llvm::find(Features, "-d") != Features.end())
D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LSX*/ 0;
else
Features.push_back("+lsx");
} else if (MSIMD == "lasx") {
// Option -msimd=lasx depends on 64-bit FPU and LSX.
// -m*-float, -mfpu=none/0/32 and -mno-lsx conflict with -msimd=lasx.
if (llvm::find(Features, "-d") != Features.end())
D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LASX*/ 1;
else if (llvm::find(Features, "-lsx") != Features.end())
D.Diag(diag::err_drv_loongarch_invalid_simd_option_combination);

// The command options do not contain -mno-lasx.
if (!Args.getLastArg(options::OPT_mno_lasx)) {
Features.push_back("+lsx");
Features.push_back("+lasx");
}
} else if (MSIMD == "none") {
if (llvm::find(Features, "+lsx") != Features.end())
Features.push_back("-lsx");
if (llvm::find(Features, "+lasx") != Features.end())
Features.push_back("-lasx");
} else {
D.Diag(diag::err_drv_loongarch_invalid_msimd_EQ) << MSIMD;
}
}

// Select lsx feature determined by -m[no-]lsx.
if (const Arg *A = Args.getLastArg(options::OPT_mlsx, options::OPT_mno_lsx)) {
Expand All @@ -197,44 +242,13 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D,
if (A->getOption().matches(options::OPT_mlasx)) {
if (llvm::find(Features, "-d") != Features.end())
D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LASX*/ 1;
else if (llvm::find(Features, "-lsx") != Features.end())
D.Diag(diag::err_drv_loongarch_invalid_simd_option_combination);
else { /*-mlasx*/
Features.push_back("+lsx");
Features.push_back("+lasx");
}
} else /*-mno-lasx*/
Features.push_back("-lasx");
}

// Select lsx/lasx feature determined by -msimd=.
// Option -msimd= has lower priority than -m[no-]lsx and -m[no-]lasx.
if (const Arg *A = Args.getLastArg(options::OPT_msimd_EQ)) {
StringRef MSIMD = A->getValue();
if (MSIMD == "lsx") {
// Option -msimd=lsx depends on 64-bit FPU.
// -m*-float and -mfpu=none/0/32 conflict with -mlsx.
if (llvm::find(Features, "-d") != Features.end())
D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LSX*/ 0;
// The previous option does not contain feature -lsx.
else if (llvm::find(Features, "-lsx") == Features.end())
Features.push_back("+lsx");
} else if (MSIMD == "lasx") {
// Option -msimd=lasx depends on 64-bit FPU and LSX.
// -m*-float and -mfpu=none/0/32 conflict with -mlsx.
if (llvm::find(Features, "-d") != Features.end())
D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LASX*/ 1;
else if (llvm::find(Features, "-lsx") != Features.end())
D.Diag(diag::err_drv_loongarch_invalid_simd_option_combination);
// The previous option does not contain feature -lasx.
else if (llvm::find(Features, "-lasx") == Features.end()) {
Features.push_back("+lsx");
Features.push_back("+lasx");
}
} else if (MSIMD != "none") {
D.Diag(diag::err_drv_loongarch_invalid_msimd_EQ) << MSIMD;
}
}
}

std::string loongarch::postProcessTargetCPUString(const std::string &CPU,
Expand All @@ -253,8 +267,14 @@ std::string loongarch::postProcessTargetCPUString(const std::string &CPU,
std::string loongarch::getLoongArchTargetCPU(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple) {
std::string CPU;
std::string Arch;
// If we have -march, use that.
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
CPU = A->getValue();
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
Arch = A->getValue();
if (Arch == "la64v1.0" || Arch == "la64v1.1")
CPU = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64());
else
CPU = Arch;
}
return postProcessTargetCPUString(CPU, Triple);
}
3 changes: 3 additions & 0 deletions clang/lib/Driver/ToolChains/Arch/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ static std::string normalizeCPUName(StringRef CPUName, const llvm::Triple &T) {
.Case("power8", "pwr8")
.Case("power9", "pwr9")
.Case("power10", "pwr10")
.Case("power11", "pwr11")
.Case("future", "future")
.Case("powerpc", "ppc")
.Case("powerpc64", "ppc64")
Expand Down Expand Up @@ -103,6 +104,8 @@ const char *ppc::getPPCAsmModeForCPU(StringRef Name) {
.Case("power9", "-mpower9")
.Case("pwr10", "-mpower10")
.Case("power10", "-mpower10")
.Case("pwr11", "-mpower11")
.Case("power11", "-mpower11")
.Default("-many");
}

Expand Down
63 changes: 60 additions & 3 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1486,6 +1486,41 @@ void AddUnalignedAccessWarning(ArgStringList &CmdArgs) {
}
}

// Each combination of options here forms a signing schema, and in most cases
// each signing schema is its own incompatible ABI. The default values of the
// options represent the default signing schema.
static void handlePAuthABI(const ArgList &DriverArgs, ArgStringList &CC1Args) {
if (!DriverArgs.hasArg(options::OPT_fptrauth_intrinsics,
options::OPT_fno_ptrauth_intrinsics))
CC1Args.push_back("-fptrauth-intrinsics");

if (!DriverArgs.hasArg(options::OPT_fptrauth_calls,
options::OPT_fno_ptrauth_calls))
CC1Args.push_back("-fptrauth-calls");

if (!DriverArgs.hasArg(options::OPT_fptrauth_returns,
options::OPT_fno_ptrauth_returns))
CC1Args.push_back("-fptrauth-returns");

if (!DriverArgs.hasArg(options::OPT_fptrauth_auth_traps,
options::OPT_fno_ptrauth_auth_traps))
CC1Args.push_back("-fptrauth-auth-traps");

if (!DriverArgs.hasArg(
options::OPT_fptrauth_vtable_pointer_address_discrimination,
options::OPT_fno_ptrauth_vtable_pointer_address_discrimination))
CC1Args.push_back("-fptrauth-vtable-pointer-address-discrimination");

if (!DriverArgs.hasArg(
options::OPT_fptrauth_vtable_pointer_type_discrimination,
options::OPT_fno_ptrauth_vtable_pointer_type_discrimination))
CC1Args.push_back("-fptrauth-vtable-pointer-type-discrimination");

if (!DriverArgs.hasArg(options::OPT_fptrauth_init_fini,
options::OPT_fno_ptrauth_init_fini))
CC1Args.push_back("-fptrauth-init-fini");
}

static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs, bool isAArch64) {
const Arg *A = isAArch64
Expand Down Expand Up @@ -1548,16 +1583,30 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,

CmdArgs.push_back(
Args.MakeArgString(Twine("-msign-return-address=") + Scope));
if (Scope != "none")
if (Scope != "none") {
if (Triple.getEnvironment() == llvm::Triple::PAuthTest)
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << Triple.getTriple();
CmdArgs.push_back(
Args.MakeArgString(Twine("-msign-return-address-key=") + Key));
if (BranchProtectionPAuthLR)
}
if (BranchProtectionPAuthLR) {
if (Triple.getEnvironment() == llvm::Triple::PAuthTest)
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << Triple.getTriple();
CmdArgs.push_back(
Args.MakeArgString(Twine("-mbranch-protection-pauth-lr")));
}
if (IndirectBranches)
CmdArgs.push_back("-mbranch-target-enforce");
if (GuardedControlStack)
// GCS is currently untested with PAuthABI, but enabling this could be allowed
// in future after testing with a suitable system.
if (GuardedControlStack) {
if (Triple.getEnvironment() == llvm::Triple::PAuthTest)
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << Triple.getTriple();
CmdArgs.push_back("-mguarded-control-stack");
}
}

void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args,
Expand Down Expand Up @@ -1701,6 +1750,8 @@ void RenderAArch64ABI(const llvm::Triple &Triple, const ArgList &Args,
ABIName = A->getValue();
else if (Triple.isOSDarwin())
ABIName = "darwinpcs";
else if (Triple.getEnvironment() == llvm::Triple::PAuthTest)
ABIName = "pauthtest";
else
ABIName = "aapcs";

Expand Down Expand Up @@ -1737,6 +1788,9 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
// Enable/disable return address signing and indirect branch targets.
CollectARMPACBTIOptions(getToolChain(), Args, CmdArgs, true /*isAArch64*/);

if (Triple.getEnvironment() == llvm::Triple::PAuthTest)
handlePAuthABI(Args, CmdArgs);

// Handle -msve_vector_bits=<bits>
if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ)) {
StringRef Val = A->getValue();
Expand Down Expand Up @@ -1794,6 +1848,9 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
Args.addOptInFlag(
CmdArgs, options::OPT_fptrauth_function_pointer_type_discrimination,
options::OPT_fno_ptrauth_function_pointer_type_discrimination);

Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_indirect_gotos,
options::OPT_fno_ptrauth_indirect_gotos);
}

void Clang::AddLoongArchTargetArgs(const ArgList &Args,
Expand Down
65 changes: 12 additions & 53 deletions clang/lib/Driver/ToolChains/Cuda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,13 +461,6 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("--output-file");
std::string OutputFileName = TC.getInputFilename(Output);

// If we are invoking `nvlink` internally we need to output a `.cubin` file.
// FIXME: This should hopefully be removed if NVIDIA updates their tooling.
if (!C.getInputArgs().getLastArg(options::OPT_c)) {
SmallString<256> Filename(Output.getFilename());
llvm::sys::path::replace_extension(Filename, "cubin");
OutputFileName = Filename.str();
}
if (Output.isFilename() && OutputFileName != Output.getFilename())
C.addTempFile(Args.MakeArgString(OutputFileName));

Expand Down Expand Up @@ -612,64 +605,34 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-arch");
CmdArgs.push_back(Args.MakeArgString(GPUArch));

if (Args.hasArg(options::OPT_ptxas_path_EQ))
CmdArgs.push_back(Args.MakeArgString(
"--pxtas-path=" + Args.getLastArgValue(options::OPT_ptxas_path_EQ)));

// Add paths specified in LIBRARY_PATH environment variable as -L options.
addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH");

// Add standard library search paths passed on the command line.
Args.AddAllArgs(CmdArgs, options::OPT_L);
getToolChain().AddFilePathLibArgs(Args, CmdArgs);
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);

if (C.getDriver().isUsingLTO())
addLTOOptions(getToolChain(), Args, CmdArgs, Output, Inputs[0],
C.getDriver().getLTOMode() == LTOK_Thin);

// Add paths for the default clang library path.
SmallString<256> DefaultLibPath =
llvm::sys::path::parent_path(TC.getDriver().Dir);
llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME);
CmdArgs.push_back(Args.MakeArgString(Twine("-L") + DefaultLibPath));

for (const auto &II : Inputs) {
if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR ||
II.getType() == types::TY_LTO_BC || II.getType() == types::TY_LLVM_BC) {
C.getDriver().Diag(diag::err_drv_no_linker_llvm_support)
<< getToolChain().getTripleString();
continue;
}

// The 'nvlink' application performs RDC-mode linking when given a '.o'
// file and device linking when given a '.cubin' file. We always want to
// perform device linking, so just rename any '.o' files.
// FIXME: This should hopefully be removed if NVIDIA updates their tooling.
if (II.isFilename()) {
auto InputFile = getToolChain().getInputFilename(II);
if (llvm::sys::path::extension(InputFile) != ".cubin") {
// If there are no actions above this one then this is direct input and
// we can copy it. Otherwise the input is internal so a `.cubin` file
// should exist.
if (II.getAction() && II.getAction()->getInputs().size() == 0) {
const char *CubinF =
Args.MakeArgString(getToolChain().getDriver().GetTemporaryPath(
llvm::sys::path::stem(InputFile), "cubin"));
if (llvm::sys::fs::copy_file(InputFile, C.addTempFile(CubinF)))
continue;

CmdArgs.push_back(CubinF);
} else {
SmallString<256> Filename(InputFile);
llvm::sys::path::replace_extension(Filename, "cubin");
CmdArgs.push_back(Args.MakeArgString(Filename));
}
} else {
CmdArgs.push_back(Args.MakeArgString(InputFile));
}
} else if (!II.isNothing()) {
II.getInputArg().renderAsInput(Args, CmdArgs);
}
}

C.addCommand(std::make_unique<Command>(
JA, *this,
ResponseFileSupport{ResponseFileSupport::RF_Full, llvm::sys::WEM_UTF8,
"--options-file"},
Args.MakeArgString(getToolChain().GetProgramPath("nvlink")), CmdArgs,
Inputs, Output));
Args.MakeArgString(getToolChain().GetProgramPath("clang-nvlink-wrapper")),
CmdArgs, Inputs, Output));
}

void NVPTX::getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple,
Expand Down Expand Up @@ -949,11 +912,7 @@ std::string CudaToolChain::getInputFilename(const InputInfo &Input) const {
if (Input.getType() != types::TY_Object || getDriver().offloadDeviceOnly())
return ToolChain::getInputFilename(Input);

// Replace extension for object files with cubin because nvlink relies on
// these particular file names.
SmallString<256> Filename(ToolChain::getInputFilename(Input));
llvm::sys::path::replace_extension(Filename, "cubin");
return std::string(Filename);
return ToolChain::getInputFilename(Input);
}

llvm::opt::DerivedArgList *
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Driver/ToolChains/Cuda.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ class LLVM_LIBRARY_VISIBILITY NVPTXToolChain : public ToolChain {
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
return false;
}
bool HasNativeLLVMSupport() const override { return true; }
bool isPICDefaultForced() const override { return false; }
bool SupportsProfiling() const override { return false; }

Expand Down Expand Up @@ -192,6 +193,8 @@ class LLVM_LIBRARY_VISIBILITY CudaToolChain : public NVPTXToolChain {
return &HostTC.getTriple();
}

bool HasNativeLLVMSupport() const override { return false; }

std::string getInputFilename(const InputInfo &Input) const override;

llvm::opt::DerivedArgList *
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Driver/ToolChains/Linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ std::string Linux::getMultiarchTriple(const Driver &D,
case llvm::Triple::aarch64:
if (IsAndroid)
return "aarch64-linux-android";
if (hasEffectiveTriple() &&
getEffectiveTriple().getEnvironment() == llvm::Triple::PAuthTest)
return "aarch64-linux-pauthtest";
return "aarch64-linux-gnu";
case llvm::Triple::aarch64_be:
return "aarch64_be-linux-gnu";
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Driver/ToolChains/PS4CPU.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ class LLVM_LIBRARY_VISIBILITY PS5CPU : public PS4PS5Base {
llvm::opt::ArgStringList &CmdArgs, const char *Prefix,
const char *Suffix) const override;
const char *getProfileRTLibName() const override {
return "libclang_rt.profile-x86_64_nosubmission.a";
return "libclang_rt.profile_nosubmission.a";
}

protected:
Expand Down
89 changes: 51 additions & 38 deletions clang/lib/Driver/ToolChains/WebAssembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ std::string wasm::Linker::getLinkerPath(const ArgList &Args) const {
return ToolChain.GetProgramPath(ToolChain.getDefaultLinker());
}

static bool TargetBuildsComponents(const llvm::Triple &TargetTriple) {
// WASIp2 and above are all based on components, so test for WASI but exclude
// the original `wasi` target in addition to the `wasip1` name.
return TargetTriple.isOSWASI() && TargetTriple.getOSName() != "wasip1" &&
TargetTriple.getOSName() != "wasi";
}

void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
Expand Down Expand Up @@ -158,46 +165,52 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());

if (Args.hasFlag(options::OPT_wasm_opt, options::OPT_no_wasm_opt, true)) {
// When optimizing, if wasm-opt is available, run it.
std::string WasmOptPath;
if (Args.getLastArg(options::OPT_O_Group)) {
WasmOptPath = ToolChain.GetProgramPath("wasm-opt");
if (WasmOptPath == "wasm-opt") {
WasmOptPath = {};
}
// Don't use wasm-opt by default on `wasip2` as it doesn't have support for
// components at this time. Retain the historical default otherwise, though,
// of running `wasm-opt` by default.
bool WasmOptDefault = !TargetBuildsComponents(ToolChain.getTriple());
bool RunWasmOpt = Args.hasFlag(options::OPT_wasm_opt,
options::OPT_no_wasm_opt, WasmOptDefault);

// If wasm-opt is enabled and optimizations are happening look for the
// `wasm-opt` program. If it's not found auto-disable it.
std::string WasmOptPath;
if (RunWasmOpt && Args.getLastArg(options::OPT_O_Group)) {
WasmOptPath = ToolChain.GetProgramPath("wasm-opt");
if (WasmOptPath == "wasm-opt") {
WasmOptPath = {};
}
}

if (!WasmOptPath.empty()) {
CmdArgs.push_back("--keep-section=target_features");
}
if (!WasmOptPath.empty()) {
CmdArgs.push_back("--keep-section=target_features");
}

C.addCommand(std::make_unique<Command>(JA, *this,
ResponseFileSupport::AtFileCurCP(),
Linker, CmdArgs, Inputs, Output));

if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
if (!WasmOptPath.empty()) {
StringRef OOpt = "s";
if (A->getOption().matches(options::OPT_O4) ||
A->getOption().matches(options::OPT_Ofast))
OOpt = "4";
else if (A->getOption().matches(options::OPT_O0))
OOpt = "0";
else if (A->getOption().matches(options::OPT_O))
OOpt = A->getValue();

if (OOpt != "0") {
const char *WasmOpt = Args.MakeArgString(WasmOptPath);
ArgStringList OptArgs;
OptArgs.push_back(Output.getFilename());
OptArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt));
OptArgs.push_back("-o");
OptArgs.push_back(Output.getFilename());
C.addCommand(std::make_unique<Command>(
JA, *this, ResponseFileSupport::AtFileCurCP(), WasmOpt, OptArgs,
Inputs, Output));
}
C.addCommand(std::make_unique<Command>(JA, *this,
ResponseFileSupport::AtFileCurCP(),
Linker, CmdArgs, Inputs, Output));

if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
if (!WasmOptPath.empty()) {
StringRef OOpt = "s";
if (A->getOption().matches(options::OPT_O4) ||
A->getOption().matches(options::OPT_Ofast))
OOpt = "4";
else if (A->getOption().matches(options::OPT_O0))
OOpt = "0";
else if (A->getOption().matches(options::OPT_O))
OOpt = A->getValue();

if (OOpt != "0") {
const char *WasmOpt = Args.MakeArgString(WasmOptPath);
ArgStringList OptArgs;
OptArgs.push_back(Output.getFilename());
OptArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt));
OptArgs.push_back("-o");
OptArgs.push_back(Output.getFilename());
C.addCommand(std::make_unique<Command>(
JA, *this, ResponseFileSupport::AtFileCurCP(), WasmOpt, OptArgs,
Inputs, Output));
}
}
}
Expand Down Expand Up @@ -241,7 +254,7 @@ WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple,
}

const char *WebAssembly::getDefaultLinker() const {
if (getOS() == "wasip2")
if (TargetBuildsComponents(getTriple()))
return "wasm-component-ld";
return "wasm-ld";
}
Expand Down
25 changes: 22 additions & 3 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1488,20 +1488,30 @@ void CompilerInvocation::setDefaultPointerAuthOptions(
Key::ASDA, LangOpts.PointerAuthVTPtrAddressDiscrimination,
LangOpts.PointerAuthVTPtrTypeDiscrimination ? Discrimination::Type
: Discrimination::None);
Opts.CXXTypeInfoVTablePointer =
PointerAuthSchema(Key::ASDA, false, Discrimination::None);

if (LangOpts.PointerAuthTypeInfoVTPtrDiscrimination)
Opts.CXXTypeInfoVTablePointer =
PointerAuthSchema(Key::ASDA, true, Discrimination::Constant,
StdTypeInfoVTablePointerConstantDiscrimination);
else
Opts.CXXTypeInfoVTablePointer =
PointerAuthSchema(Key::ASDA, false, Discrimination::None);

Opts.CXXVTTVTablePointers =
PointerAuthSchema(Key::ASDA, false, Discrimination::None);
Opts.CXXVirtualFunctionPointers = Opts.CXXVirtualVariadicFunctionPointers =
PointerAuthSchema(Key::ASIA, true, Discrimination::Decl);
Opts.CXXMemberFunctionPointers =
PointerAuthSchema(Key::ASIA, false, Discrimination::Type);
}
Opts.IndirectGotos = LangOpts.PointerAuthIndirectGotos;
}

static void parsePointerAuthOptions(PointerAuthOptions &Opts,
const LangOptions &LangOpts,
const llvm::Triple &Triple,
DiagnosticsEngine &Diags) {
if (!LangOpts.PointerAuthCalls)
if (!LangOpts.PointerAuthCalls && !LangOpts.PointerAuthIndirectGotos)
return;

CompilerInvocation::setDefaultPointerAuthOptions(Opts, LangOpts, Triple);
Expand Down Expand Up @@ -3405,12 +3415,17 @@ static void GeneratePointerAuthArgs(const LangOptions &Opts,
GenerateArg(Consumer, OPT_fptrauth_calls);
if (Opts.PointerAuthReturns)
GenerateArg(Consumer, OPT_fptrauth_returns);
if (Opts.PointerAuthIndirectGotos)
GenerateArg(Consumer, OPT_fptrauth_indirect_gotos);
if (Opts.PointerAuthAuthTraps)
GenerateArg(Consumer, OPT_fptrauth_auth_traps);
if (Opts.PointerAuthVTPtrAddressDiscrimination)
GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_address_discrimination);
if (Opts.PointerAuthVTPtrTypeDiscrimination)
GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_type_discrimination);
if (Opts.PointerAuthTypeInfoVTPtrDiscrimination)
GenerateArg(Consumer, OPT_fptrauth_type_info_vtable_pointer_discrimination);

if (Opts.PointerAuthInitFini)
GenerateArg(Consumer, OPT_fptrauth_init_fini);
if (Opts.PointerAuthFunctionTypeDiscrimination)
Expand All @@ -3422,11 +3437,15 @@ static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
Opts.PointerAuthIntrinsics = Args.hasArg(OPT_fptrauth_intrinsics);
Opts.PointerAuthCalls = Args.hasArg(OPT_fptrauth_calls);
Opts.PointerAuthReturns = Args.hasArg(OPT_fptrauth_returns);
Opts.PointerAuthIndirectGotos = Args.hasArg(OPT_fptrauth_indirect_gotos);
Opts.PointerAuthAuthTraps = Args.hasArg(OPT_fptrauth_auth_traps);
Opts.PointerAuthVTPtrAddressDiscrimination =
Args.hasArg(OPT_fptrauth_vtable_pointer_address_discrimination);
Opts.PointerAuthVTPtrTypeDiscrimination =
Args.hasArg(OPT_fptrauth_vtable_pointer_type_discrimination);
Opts.PointerAuthTypeInfoVTPtrDiscrimination =
Args.hasArg(OPT_fptrauth_type_info_vtable_pointer_discrimination);

Opts.PointerAuthInitFini = Args.hasArg(OPT_fptrauth_init_fini);
Opts.PointerAuthFunctionTypeDiscrimination =
Args.hasArg(OPT_fptrauth_function_pointer_type_discrimination);
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Interpreter/Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/CodeGenAction.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/CodeGen/ObjectFilePCHContainerWriter.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Job.h"
Expand All @@ -38,6 +38,7 @@
#include "clang/Interpreter/Value.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Sema/Lookup.h"
#include "clang/Serialization/ObjectFilePCHContainerReader.h"
#include "llvm/ExecutionEngine/JITSymbol.h"
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/IR/Module.h"
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Interpreter/InterpreterUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Job.h"
Expand Down
12 changes: 8 additions & 4 deletions clang/lib/Lex/DependencyDirectivesScanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ struct Scanner {
[[nodiscard]] dependency_directives_scan::Token &
lexToken(const char *&First, const char *const End);

dependency_directives_scan::Token &lexIncludeFilename(const char *&First,
const char *const End);
[[nodiscard]] dependency_directives_scan::Token &
lexIncludeFilename(const char *&First, const char *const End);

void skipLine(const char *&First, const char *const End);
void skipDirective(StringRef Name, const char *&First, const char *const End);
Expand Down Expand Up @@ -544,7 +544,7 @@ Scanner::lexIncludeFilename(const char *&First, const char *const End) {
void Scanner::lexPPDirectiveBody(const char *&First, const char *const End) {
while (true) {
const dependency_directives_scan::Token &Tok = lexToken(First, End);
if (Tok.is(tok::eod))
if (Tok.is(tok::eod) || Tok.is(tok::eof))
break;
}
}
Expand Down Expand Up @@ -912,7 +912,11 @@ bool Scanner::lexPPLine(const char *&First, const char *const End) {
case pp___include_macros:
case pp_include_next:
case pp_import:
lexIncludeFilename(First, End);
// Ignore missing filenames in include or import directives.
if (lexIncludeFilename(First, End).is(tok::eod)) {
skipDirective(Id, First, End);
return true;
}
break;
default:
break;
Expand Down
25 changes: 25 additions & 0 deletions clang/lib/Parse/ParsePragma.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "clang/Basic/PragmaKinds.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Lex/Token.h"
#include "clang/Parse/LoopHint.h"
#include "clang/Parse/ParseDiagnostic.h"
Expand Down Expand Up @@ -411,6 +412,19 @@ struct PragmaRISCVHandler : public PragmaHandler {
Sema &Actions;
};

struct PragmaMCFuncHandler : public PragmaHandler {
PragmaMCFuncHandler(bool ReportError)
: PragmaHandler("mc_func"), ReportError(ReportError) {}
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
Token &Tok) override {
if (ReportError)
PP.Diag(Tok, diag::err_pragma_mc_func_not_supported);
}

private:
bool ReportError = false;
};

void markAsReinjectedForRelexing(llvm::MutableArrayRef<clang::Token> Toks) {
for (auto &T : Toks)
T.setFlag(clang::Token::IsReinjected);
Expand Down Expand Up @@ -568,6 +582,12 @@ void Parser::initializePragmaHandlers() {
RISCVPragmaHandler = std::make_unique<PragmaRISCVHandler>(Actions);
PP.AddPragmaHandler("clang", RISCVPragmaHandler.get());
}

if (getTargetInfo().getTriple().isOSAIX()) {
MCFuncPragmaHandler = std::make_unique<PragmaMCFuncHandler>(
PP.getPreprocessorOpts().ErrorOnPragmaMcfuncOnAIX);
PP.AddPragmaHandler(MCFuncPragmaHandler.get());
}
}

void Parser::resetPragmaHandlers() {
Expand Down Expand Up @@ -702,6 +722,11 @@ void Parser::resetPragmaHandlers() {
PP.RemovePragmaHandler("clang", RISCVPragmaHandler.get());
RISCVPragmaHandler.reset();
}

if (getTargetInfo().getTriple().isOSAIX()) {
PP.RemovePragmaHandler(MCFuncPragmaHandler.get());
MCFuncPragmaHandler.reset();
}
}

/// Handle the annotation token produced for #pragma unused(...)
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/Parse/ParseStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,15 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
goto Retry;
}

case tok::kw_template: {
SourceLocation DeclEnd;
ParsedAttributes Attrs(AttrFactory);
ParseTemplateDeclarationOrSpecialization(DeclaratorContext::Block, DeclEnd,
Attrs,
getAccessSpecifierIfPresent());
return StmtError();
}

case tok::kw_case: // C99 6.8.1: labeled-statement
return ParseCaseStatement(StmtCtx);
case tok::kw_default: // C99 6.8.1: labeled-statement
Expand Down
119 changes: 74 additions & 45 deletions clang/lib/Sema/SemaAPINotes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -783,51 +783,77 @@ static void ProcessVersionedAPINotes(
}
}

static std::optional<api_notes::Context>
UnwindNamespaceContext(DeclContext *DC, api_notes::APINotesManager &APINotes) {
if (auto NamespaceContext = dyn_cast<NamespaceDecl>(DC)) {
for (auto Reader : APINotes.findAPINotes(NamespaceContext->getLocation())) {
// Retrieve the context ID for the parent namespace of the decl.
std::stack<NamespaceDecl *> NamespaceStack;
{
for (auto CurrentNamespace = NamespaceContext; CurrentNamespace;
CurrentNamespace =
dyn_cast<NamespaceDecl>(CurrentNamespace->getParent())) {
if (!CurrentNamespace->isInlineNamespace())
NamespaceStack.push(CurrentNamespace);
}
}
std::optional<api_notes::ContextID> NamespaceID;
while (!NamespaceStack.empty()) {
auto CurrentNamespace = NamespaceStack.top();
NamespaceStack.pop();
NamespaceID =
Reader->lookupNamespaceID(CurrentNamespace->getName(), NamespaceID);
if (!NamespaceID)
return std::nullopt;
}
if (NamespaceID)
return api_notes::Context(*NamespaceID,
api_notes::ContextKind::Namespace);
}
}
return std::nullopt;
}

static std::optional<api_notes::Context>
UnwindTagContext(TagDecl *DC, api_notes::APINotesManager &APINotes) {
assert(DC && "tag context must not be null");
for (auto Reader : APINotes.findAPINotes(DC->getLocation())) {
// Retrieve the context ID for the parent tag of the decl.
std::stack<TagDecl *> TagStack;
{
for (auto CurrentTag = DC; CurrentTag;
CurrentTag = dyn_cast<TagDecl>(CurrentTag->getParent()))
TagStack.push(CurrentTag);
}
assert(!TagStack.empty());
std::optional<api_notes::Context> Ctx =
UnwindNamespaceContext(TagStack.top()->getDeclContext(), APINotes);
while (!TagStack.empty()) {
auto CurrentTag = TagStack.top();
TagStack.pop();
auto CtxID = Reader->lookupTagID(CurrentTag->getName(), Ctx);
if (!CtxID)
return std::nullopt;
Ctx = api_notes::Context(*CtxID, api_notes::ContextKind::Tag);
}
return Ctx;
}
return std::nullopt;
}

/// Process API notes that are associated with this declaration, mapping them
/// to attributes as appropriate.
void Sema::ProcessAPINotes(Decl *D) {
if (!D)
return;

auto GetNamespaceContext =
[&](DeclContext *DC) -> std::optional<api_notes::Context> {
if (auto NamespaceContext = dyn_cast<NamespaceDecl>(DC)) {
for (auto Reader :
APINotes.findAPINotes(NamespaceContext->getLocation())) {
// Retrieve the context ID for the parent namespace of the decl.
std::stack<NamespaceDecl *> NamespaceStack;
{
for (auto CurrentNamespace = NamespaceContext; CurrentNamespace;
CurrentNamespace =
dyn_cast<NamespaceDecl>(CurrentNamespace->getParent())) {
if (!CurrentNamespace->isInlineNamespace())
NamespaceStack.push(CurrentNamespace);
}
}
std::optional<api_notes::ContextID> NamespaceID;
while (!NamespaceStack.empty()) {
auto CurrentNamespace = NamespaceStack.top();
NamespaceStack.pop();
NamespaceID = Reader->lookupNamespaceID(CurrentNamespace->getName(),
NamespaceID);
if (!NamespaceID)
break;
}
if (NamespaceID)
return api_notes::Context(*NamespaceID,
api_notes::ContextKind::Namespace);
}
}
return std::nullopt;
};

// Globals.
if (D->getDeclContext()->isFileContext() ||
D->getDeclContext()->isNamespace() ||
D->getDeclContext()->isExternCContext() ||
D->getDeclContext()->isExternCXXContext()) {
std::optional<api_notes::Context> APINotesContext =
GetNamespaceContext(D->getDeclContext());
UnwindNamespaceContext(D->getDeclContext(), APINotes);
// Global variables.
if (auto VD = dyn_cast<VarDecl>(D)) {
for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
Expand Down Expand Up @@ -899,6 +925,8 @@ void Sema::ProcessAPINotes(Decl *D) {
}

for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
if (auto ParentTag = dyn_cast<TagDecl>(Tag->getDeclContext()))
APINotesContext = UnwindTagContext(ParentTag, APINotes);
auto Info = Reader->lookupTag(LookupName, APINotesContext);
ProcessVersionedAPINotes(*this, Tag, Info);
}
Expand Down Expand Up @@ -1014,23 +1042,24 @@ void Sema::ProcessAPINotes(Decl *D) {
}
}

if (auto CXXRecord = dyn_cast<CXXRecordDecl>(D->getDeclContext())) {
auto GetRecordContext = [&](api_notes::APINotesReader *Reader)
-> std::optional<api_notes::ContextID> {
auto ParentContext = GetNamespaceContext(CXXRecord->getDeclContext());
if (auto Found = Reader->lookupTagID(CXXRecord->getName(), ParentContext))
return *Found;

return std::nullopt;
};

if (auto TagContext = dyn_cast<TagDecl>(D->getDeclContext())) {
if (auto CXXMethod = dyn_cast<CXXMethodDecl>(D)) {
for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
if (auto Context = GetRecordContext(Reader)) {
auto Info = Reader->lookupCXXMethod(*Context, CXXMethod->getName());
if (auto Context = UnwindTagContext(TagContext, APINotes)) {
auto Info =
Reader->lookupCXXMethod(Context->id, CXXMethod->getName());
ProcessVersionedAPINotes(*this, CXXMethod, Info);
}
}
}

if (auto Tag = dyn_cast<TagDecl>(D)) {
for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
if (auto Context = UnwindTagContext(TagContext, APINotes)) {
auto Info = Reader->lookupTag(Tag->getName(), Context);
ProcessVersionedAPINotes(*this, Tag, Info);
}
}
}
}
}
17 changes: 17 additions & 0 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10909,6 +10909,14 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
if (isObjCPointer && checkArithmeticOnObjCPointer(*this, Loc, PExp))
return QualType();

// Arithmetic on label addresses is normally allowed, except when we add
// a ptrauth signature to the addresses.
if (isa<AddrLabelExpr>(PExp) && getLangOpts().PointerAuthIndirectGotos) {
Diag(Loc, diag::err_ptrauth_indirect_goto_addrlabel_arithmetic)
<< /*addition*/ 1;
return QualType();
}

// Check array bounds for pointer arithemtic
CheckArrayAccess(PExp, IExp);

Expand Down Expand Up @@ -10983,6 +10991,15 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
checkArithmeticOnObjCPointer(*this, Loc, LHS.get()))
return QualType();

// Arithmetic on label addresses is normally allowed, except when we add
// a ptrauth signature to the addresses.
if (isa<AddrLabelExpr>(LHS.get()) &&
getLangOpts().PointerAuthIndirectGotos) {
Diag(Loc, diag::err_ptrauth_indirect_goto_addrlabel_arithmetic)
<< /*subtraction*/ 0;
return QualType();
}

// The result type of a pointer-int computation is the pointer type.
if (RHS.get()->getType()->isIntegerType()) {
// Subtracting from a null pointer should produce a warning.
Expand Down
222 changes: 48 additions & 174 deletions clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,6 @@ class DSAStackTy {
SourceLocation DefaultAttrLoc;
DefaultmapInfo DefaultmapMap[OMPC_DEFAULTMAP_unknown + 1];
OpenMPDirectiveKind Directive = OMPD_unknown;
/// GenericLoopDirective with bind clause is mapped to other directives,
/// like for, distribute and simd. Presently, set MappedDirective to
/// OMPLoop. This may also be used in a similar way for other constructs.
OpenMPDirectiveKind MappedDirective = OMPD_unknown;
DeclarationNameInfo DirectiveName;
Scope *CurScope = nullptr;
DeclContext *Context = nullptr;
Expand Down Expand Up @@ -645,24 +641,6 @@ class DSAStackTy {
const SharingMapTy *Top = getTopOfStackOrNull();
return Top ? Top->Directive : OMPD_unknown;
}
OpenMPDirectiveKind getMappedDirective() const {
const SharingMapTy *Top = getTopOfStackOrNull();
return Top ? Top->MappedDirective : OMPD_unknown;
}
void setCurrentDirective(OpenMPDirectiveKind NewDK) {
SharingMapTy *Top = getTopOfStackOrNull();
assert(Top &&
"Before calling setCurrentDirective Top of Stack not to be NULL.");
// Store the old into MappedDirective & assign argument NewDK to Directive.
Top->Directive = NewDK;
}
void setMappedDirective(OpenMPDirectiveKind NewDK) {
SharingMapTy *Top = getTopOfStackOrNull();
assert(Top &&
"Before calling setMappedDirective Top of Stack not to be NULL.");
// Store the old into MappedDirective & assign argument NewDK to Directive.
Top->MappedDirective = NewDK;
}
/// Returns directive kind at specified level.
OpenMPDirectiveKind getDirective(unsigned Level) const {
assert(!isStackEmpty() && "No directive at specified level.");
Expand Down Expand Up @@ -5981,127 +5959,63 @@ static bool teamsLoopCanBeParallelFor(Stmt *AStmt, Sema &SemaRef) {
return Checker.teamsLoopCanBeParallelFor();
}

bool SemaOpenMP::mapLoopConstruct(
llvm::SmallVector<OMPClause *> &ClausesWithoutBind,
ArrayRef<OMPClause *> Clauses, OpenMPBindClauseKind &BindKind,
OpenMPDirectiveKind &Kind, OpenMPDirectiveKind &PrevMappedDirective,
SourceLocation StartLoc, SourceLocation EndLoc,
const DeclarationNameInfo &DirName, OpenMPDirectiveKind CancelRegion) {

bool UseClausesWithoutBind = false;

// Restricting to "#pragma omp loop bind"
if (getLangOpts().OpenMP >= 50 && Kind == OMPD_loop) {

const OpenMPDirectiveKind ParentDirective = DSAStack->getParentDirective();

if (BindKind == OMPC_BIND_unknown) {
// Setting the enclosing teams or parallel construct for the loop
// directive without bind clause.
// [5.0:129:25-28] If the bind clause is not present on the construct and
// the loop construct is closely nested inside a teams or parallel
// construct, the binding region is the corresponding teams or parallel
// region. If none of those conditions hold, the binding region is not
// defined.
BindKind = OMPC_BIND_thread; // Default bind(thread) if binding is unknown
ArrayRef<OpenMPDirectiveKind> ParentLeafs =
getLeafConstructsOrSelf(ParentDirective);

if (ParentDirective == OMPD_unknown) {
Diag(DSAStack->getDefaultDSALocation(),
diag::err_omp_bind_required_on_loop);
} else if (ParentLeafs.back() == OMPD_parallel) {
BindKind = OMPC_BIND_parallel;
} else if (ParentLeafs.back() == OMPD_teams) {
BindKind = OMPC_BIND_teams;
}
} else {
// bind clause is present in loop directive. When the loop directive is
// changed to a new directive the bind clause is not used. So, we should
// set flag indicating to only use the clauses that aren't the
// bind clause.
UseClausesWithoutBind = true;
}

for (OMPClause *C : Clauses) {
// Spec restriction : bind(teams) and reduction not permitted.
if (BindKind == OMPC_BIND_teams &&
C->getClauseKind() == llvm::omp::Clause::OMPC_reduction)
Diag(DSAStack->getDefaultDSALocation(),
diag::err_omp_loop_reduction_clause);

// A new Vector ClausesWithoutBind, which does not contain the bind
// clause, for passing to new directive.
if (C->getClauseKind() != llvm::omp::Clause::OMPC_bind)
ClausesWithoutBind.push_back(C);
}

switch (BindKind) {
case OMPC_BIND_parallel:
Kind = OMPD_for;
DSAStack->setCurrentDirective(OMPD_for);
DSAStack->setMappedDirective(OMPD_loop);
PrevMappedDirective = OMPD_loop;
break;
case OMPC_BIND_teams:
Kind = OMPD_distribute;
DSAStack->setCurrentDirective(OMPD_distribute);
DSAStack->setMappedDirective(OMPD_loop);
PrevMappedDirective = OMPD_loop;
break;
case OMPC_BIND_thread:
Kind = OMPD_simd;
DSAStack->setCurrentDirective(OMPD_simd);
DSAStack->setMappedDirective(OMPD_loop);
PrevMappedDirective = OMPD_loop;
break;
case OMPC_BIND_unknown:
break;
}
} else if (PrevMappedDirective == OMPD_loop) {
/// An initial pass after recognizing all the statements is done in the
/// Parser when the directive OMPD_loop is mapped to OMPD_for,
/// OMPD_distribute or OMPD_simd. A second transform pass with call from
/// clang::TreeTransform::TransformOMPExecutableDirective() is done
/// with the Directive as one of the above mapped directive without
/// the bind clause. Then "PrevMappedDirective" stored in the
/// OMPExecutableDirective is accessed and hence this else statement.

DSAStack->setMappedDirective(OMPD_loop);
}

return UseClausesWithoutBind;
}

StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName,
OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc,
OpenMPDirectiveKind PrevMappedDirective) {
Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) {
assert(isOpenMPExecutableDirective(Kind) && "Unexpected directive category");

StmtResult Res = StmtError();
OpenMPBindClauseKind BindKind = OMPC_BIND_unknown;
llvm::SmallVector<OMPClause *> ClausesWithoutBind;
bool UseClausesWithoutBind = false;
llvm::SmallVector<OMPClause *, 8> ClausesWithImplicit;

if (const OMPBindClause *BC =
OMPExecutableDirective::getSingleClause<OMPBindClause>(Clauses))
BindKind = BC->getBindKind();

// Variable used to note down the DirectiveKind because mapLoopConstruct may
// change "Kind" variable, due to mapping of "omp loop" to other directives.
OpenMPDirectiveKind DK = Kind;
if (Kind == OMPD_loop || PrevMappedDirective == OMPD_loop) {
UseClausesWithoutBind = mapLoopConstruct(
ClausesWithoutBind, Clauses, BindKind, Kind, PrevMappedDirective,
StartLoc, EndLoc, DirName, CancelRegion);
DK = OMPD_loop;
if (Kind == OMPD_loop && BindKind == OMPC_BIND_unknown) {
const OpenMPDirectiveKind ParentDirective = DSAStack->getParentDirective();

// Setting the enclosing teams or parallel construct for the loop
// directive without bind clause.
// [5.0:129:25-28] If the bind clause is not present on the construct and
// the loop construct is closely nested inside a teams or parallel
// construct, the binding region is the corresponding teams or parallel
// region. If none of those conditions hold, the binding region is not
// defined.
BindKind = OMPC_BIND_thread; // Default bind(thread) if binding is unknown
ArrayRef<OpenMPDirectiveKind> ParentLeafs =
getLeafConstructsOrSelf(ParentDirective);

if (ParentDirective == OMPD_unknown) {
Diag(DSAStack->getDefaultDSALocation(),
diag::err_omp_bind_required_on_loop);
} else if (ParentLeafs.back() == OMPD_parallel) {
BindKind = OMPC_BIND_parallel;
} else if (ParentLeafs.back() == OMPD_teams) {
BindKind = OMPC_BIND_teams;
}

assert(BindKind != OMPC_BIND_unknown && "Expecting BindKind");

OMPClause *C =
ActOnOpenMPBindClause(BindKind, SourceLocation(), SourceLocation(),
SourceLocation(), SourceLocation());
ClausesWithImplicit.push_back(C);
}

// Diagnose "loop bind(teams)" with "reduction".
if (Kind == OMPD_loop && BindKind == OMPC_BIND_teams) {
for (OMPClause *C : Clauses) {
if (C->getClauseKind() == OMPC_reduction)
Diag(DSAStack->getDefaultDSALocation(),
diag::err_omp_loop_reduction_clause);
}
}

// First check CancelRegion which is then used in checkNestingOfRegions.
if (checkCancelRegion(SemaRef, Kind, CancelRegion, StartLoc) ||
checkNestingOfRegions(SemaRef, DSAStack, DK, DirName, CancelRegion,
checkNestingOfRegions(SemaRef, DSAStack, Kind, DirName, CancelRegion,
BindKind, StartLoc)) {
return StmtError();
}
Expand All @@ -6111,15 +6025,10 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
isOpenMPTargetDataManagementDirective(Kind)))
Diag(StartLoc, diag::warn_hip_omp_target_directives);

llvm::SmallVector<OMPClause *, 8> ClausesWithImplicit;
VarsWithInheritedDSAType VarsWithInheritedDSA;
bool ErrorFound = false;
if (getLangOpts().OpenMP >= 50 && UseClausesWithoutBind) {
ClausesWithImplicit.append(ClausesWithoutBind.begin(),
ClausesWithoutBind.end());
} else {
ClausesWithImplicit.append(Clauses.begin(), Clauses.end());
}
ClausesWithImplicit.append(Clauses.begin(), Clauses.end());

if (AStmt && !SemaRef.CurContext->isDependentContext() &&
isOpenMPCapturingDirective(Kind)) {
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
Expand Down Expand Up @@ -9170,13 +9079,9 @@ static bool checkOpenMPIterationSpace(
auto *CXXFor = dyn_cast_or_null<CXXForRangeStmt>(S);
// Ranged for is supported only in OpenMP 5.0.
if (!For && (SemaRef.LangOpts.OpenMP <= 45 || !CXXFor)) {
OpenMPDirectiveKind DK = (SemaRef.getLangOpts().OpenMP < 50 ||
DSA.getMappedDirective() == OMPD_unknown)
? DKind
: DSA.getMappedDirective();
SemaRef.Diag(S->getBeginLoc(), diag::err_omp_not_for)
<< (CollapseLoopCountExpr != nullptr || OrderedLoopCountExpr != nullptr)
<< getOpenMPDirectiveName(DK) << TotalNestedLoopCount
<< getOpenMPDirectiveName(DKind) << TotalNestedLoopCount
<< (CurrentNestedLoopCount > 0) << CurrentNestedLoopCount;
if (TotalNestedLoopCount > 1) {
if (CollapseLoopCountExpr && OrderedLoopCountExpr)
Expand Down Expand Up @@ -9514,7 +9419,7 @@ static Stmt *buildPreInits(ASTContext &Context,
/// contained DeclStmts need to be visible after the execution of the list. Used
/// for OpenMP pre-init declarations/statements.
static void appendFlattenedStmtList(SmallVectorImpl<Stmt *> &TargetList,
Stmt *Item) {
Stmt *Item) {
// nullptr represents an empty list.
if (!Item)
return;
Expand Down Expand Up @@ -10331,34 +10236,12 @@ static bool checkSimdlenSafelenSpecified(Sema &S,
return false;
}

static bool checkGenericLoopLastprivate(Sema &S, ArrayRef<OMPClause *> Clauses,
OpenMPDirectiveKind K,
DSAStackTy *Stack);

bool SemaOpenMP::checkLastPrivateForMappedDirectives(
ArrayRef<OMPClause *> Clauses) {

// Check for syntax of lastprivate
// Param of the lastprivate have different meanings in the mapped directives
// e.g. "omp loop" Only loop iteration vars are allowed in lastprivate clause
// "omp for" lastprivate vars must be shared
if (getLangOpts().OpenMP >= 50 &&
DSAStack->getMappedDirective() == OMPD_loop &&
checkGenericLoopLastprivate(SemaRef, Clauses, OMPD_loop, DSAStack)) {
return false;
}
return true;
}

StmtResult SemaOpenMP::ActOnOpenMPSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();

if (!checkLastPrivateForMappedDirectives(Clauses))
return StmtError();

assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
Expand All @@ -10377,8 +10260,7 @@ StmtResult SemaOpenMP::ActOnOpenMPSimdDirective(

SemaRef.setFunctionHasBranchProtectedScope();
auto *SimdDirective = OMPSimdDirective::Create(
getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
DSAStack->getMappedDirective());
getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
return SimdDirective;
}

Expand All @@ -10388,9 +10270,6 @@ StmtResult SemaOpenMP::ActOnOpenMPForDirective(
if (!AStmt)
return StmtError();

if (!checkLastPrivateForMappedDirectives(Clauses))
return StmtError();

assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
Expand All @@ -10406,8 +10285,7 @@ StmtResult SemaOpenMP::ActOnOpenMPForDirective(

auto *ForDirective = OMPForDirective::Create(
getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion(),
DSAStack->getMappedDirective());
DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
return ForDirective;
}

Expand Down Expand Up @@ -13594,9 +13472,6 @@ StmtResult SemaOpenMP::ActOnOpenMPDistributeDirective(
if (!AStmt)
return StmtError();

if (!checkLastPrivateForMappedDirectives(Clauses))
return StmtError();

assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
Expand All @@ -13613,8 +13488,7 @@ StmtResult SemaOpenMP::ActOnOpenMPDistributeDirective(

SemaRef.setFunctionHasBranchProtectedScope();
auto *DistributeDirective = OMPDistributeDirective::Create(
getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
DSAStack->getMappedDirective());
getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
return DistributeDirective;
}

Expand Down
31 changes: 12 additions & 19 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2576,16 +2576,12 @@ createSubstDiag(Sema &S, TemplateDeductionInfo &Info,
} else {
ErrorLoc = Info.getLocation();
}
char *MessageBuf = new (S.Context) char[Message.size()];
std::copy(Message.begin(), Message.end(), MessageBuf);
SmallString<128> Entity;
llvm::raw_svector_ostream OS(Entity);
Printer(OS);
char *EntityBuf = new (S.Context) char[Entity.size()];
std::copy(Entity.begin(), Entity.end(), EntityBuf);
return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{
StringRef(EntityBuf, Entity.size()), ErrorLoc,
StringRef(MessageBuf, Message.size())};
const ASTContext &C = S.Context;
return new (C) concepts::Requirement::SubstitutionDiagnostic{
C.backupStr(Entity), ErrorLoc, C.backupStr(Message)};
}

concepts::Requirement::SubstitutionDiagnostic *
Expand All @@ -2594,10 +2590,9 @@ concepts::createSubstDiagAt(Sema &S, SourceLocation Location,
SmallString<128> Entity;
llvm::raw_svector_ostream OS(Entity);
Printer(OS);
char *EntityBuf = new (S.Context) char[Entity.size()];
llvm::copy(Entity, EntityBuf);
return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{
/*SubstitutedEntity=*/StringRef(EntityBuf, Entity.size()),
const ASTContext &C = S.Context;
return new (C) concepts::Requirement::SubstitutionDiagnostic{
/*SubstitutedEntity=*/C.backupStr(Entity),
/*DiagLoc=*/Location, /*DiagMessage=*/StringRef()};
}

Expand Down Expand Up @@ -2773,23 +2768,21 @@ TemplateInstantiator::TransformNestedRequirement(
assert(!Trap.hasErrorOccurred() && "Substitution failures must be handled "
"by CheckConstraintSatisfaction.");
}
ASTContext &C = SemaRef.Context;
if (TransConstraint.isUsable() &&
TransConstraint.get()->isInstantiationDependent())
return new (SemaRef.Context)
concepts::NestedRequirement(TransConstraint.get());
return new (C) concepts::NestedRequirement(TransConstraint.get());
if (TransConstraint.isInvalid() || !TransConstraint.get() ||
Satisfaction.HasSubstitutionFailure()) {
SmallString<128> Entity;
llvm::raw_svector_ostream OS(Entity);
Req->getConstraintExpr()->printPretty(OS, nullptr,
SemaRef.getPrintingPolicy());
char *EntityBuf = new (SemaRef.Context) char[Entity.size()];
std::copy(Entity.begin(), Entity.end(), EntityBuf);
return new (SemaRef.Context) concepts::NestedRequirement(
SemaRef.Context, StringRef(EntityBuf, Entity.size()), Satisfaction);
return new (C) concepts::NestedRequirement(
SemaRef.Context, C.backupStr(Entity), Satisfaction);
}
return new (SemaRef.Context) concepts::NestedRequirement(
SemaRef.Context, TransConstraint.get(), Satisfaction);
return new (C)
concepts::NestedRequirement(C, TransConstraint.get(), Satisfaction);
}

TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T,
Expand Down
17 changes: 8 additions & 9 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -1667,15 +1667,15 @@ class TreeTransform {
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
StmtResult RebuildOMPExecutableDirective(
OpenMPDirectiveKind Kind, DeclarationNameInfo DirName,
OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc,
OpenMPDirectiveKind PrevMappedDirective = OMPD_unknown) {
StmtResult RebuildOMPExecutableDirective(OpenMPDirectiveKind Kind,
DeclarationNameInfo DirName,
OpenMPDirectiveKind CancelRegion,
ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc) {

return getSema().OpenMP().ActOnOpenMPExecutableDirective(
Kind, DirName, CancelRegion, Clauses, AStmt, StartLoc, EndLoc,
PrevMappedDirective);
Kind, DirName, CancelRegion, Clauses, AStmt, StartLoc, EndLoc);
}

/// Build a new OpenMP 'if' clause.
Expand Down Expand Up @@ -9182,8 +9182,7 @@ StmtResult TreeTransform<Derived>::TransformOMPExecutableDirective(

return getDerived().RebuildOMPExecutableDirective(
D->getDirectiveKind(), DirName, CancelRegion, TClauses,
AssociatedStmt.get(), D->getBeginLoc(), D->getEndLoc(),
D->getMappedDirective());
AssociatedStmt.get(), D->getBeginLoc(), D->getEndLoc());
}

template <typename Derived>
Expand Down
37 changes: 13 additions & 24 deletions clang/lib/Serialization/ASTReaderStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -785,29 +785,22 @@ void ASTStmtReader::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
E->setRParenLoc(readSourceLocation());
}

static StringRef saveStrToCtx(const std::string &S, ASTContext &Ctx) {
char *Buf = new (Ctx) char[S.size()];
std::copy(S.begin(), S.end(), Buf);
return StringRef(Buf, S.size());
}

static ConstraintSatisfaction
readConstraintSatisfaction(ASTRecordReader &Record) {
ConstraintSatisfaction Satisfaction;
Satisfaction.IsSatisfied = Record.readInt();
Satisfaction.ContainsErrors = Record.readInt();
const ASTContext &C = Record.getContext();
if (!Satisfaction.IsSatisfied) {
unsigned NumDetailRecords = Record.readInt();
for (unsigned i = 0; i != NumDetailRecords; ++i) {
if (/* IsDiagnostic */Record.readInt()) {
SourceLocation DiagLocation = Record.readSourceLocation();
StringRef DiagMessage =
saveStrToCtx(Record.readString(), Record.getContext());
StringRef DiagMessage = C.backupStr(Record.readString());

Satisfaction.Details.emplace_back(
new (Record.getContext())
ConstraintSatisfaction::SubstitutionDiagnostic(DiagLocation,
DiagMessage));
new (C) ConstraintSatisfaction::SubstitutionDiagnostic(
DiagLocation, DiagMessage));
} else
Satisfaction.Details.emplace_back(Record.readExpr());
}
Expand All @@ -828,12 +821,10 @@ void ASTStmtReader::VisitConceptSpecializationExpr(

static concepts::Requirement::SubstitutionDiagnostic *
readSubstitutionDiagnostic(ASTRecordReader &Record) {
StringRef SubstitutedEntity =
saveStrToCtx(Record.readString(), Record.getContext());

const ASTContext &C = Record.getContext();
StringRef SubstitutedEntity = C.backupStr(Record.readString());
SourceLocation DiagLoc = Record.readSourceLocation();
StringRef DiagMessage =
saveStrToCtx(Record.readString(), Record.getContext());
StringRef DiagMessage = C.backupStr(Record.readString());

return new (Record.getContext())
concepts::Requirement::SubstitutionDiagnostic{SubstitutedEntity, DiagLoc,
Expand Down Expand Up @@ -919,22 +910,21 @@ void ASTStmtReader::VisitRequiresExpr(RequiresExpr *E) {
std::move(*Req));
} break;
case concepts::Requirement::RK_Nested: {
ASTContext &C = Record.getContext();
bool HasInvalidConstraint = Record.readInt();
if (HasInvalidConstraint) {
StringRef InvalidConstraint =
saveStrToCtx(Record.readString(), Record.getContext());
R = new (Record.getContext()) concepts::NestedRequirement(
StringRef InvalidConstraint = C.backupStr(Record.readString());
R = new (C) concepts::NestedRequirement(
Record.getContext(), InvalidConstraint,
readConstraintSatisfaction(Record));
break;
}
Expr *E = Record.readExpr();
if (E->isInstantiationDependent())
R = new (Record.getContext()) concepts::NestedRequirement(E);
R = new (C) concepts::NestedRequirement(E);
else
R = new (Record.getContext())
concepts::NestedRequirement(Record.getContext(), E,
readConstraintSatisfaction(Record));
R = new (C) concepts::NestedRequirement(
C, E, readConstraintSatisfaction(Record));
} break;
}
if (!R)
Expand Down Expand Up @@ -2400,7 +2390,6 @@ void ASTStmtReader::VisitOMPExecutableDirective(OMPExecutableDirective *E) {
Record.readOMPChildren(E->Data);
E->setLocStart(readSourceLocation());
E->setLocEnd(readSourceLocation());
E->setMappedDirective(Record.readEnum<OpenMPDirectiveKind>());
}

void ASTStmtReader::VisitOMPLoopBasedDirective(OMPLoopBasedDirective *D) {
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Serialization/ASTWriterStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2389,7 +2389,6 @@ void ASTStmtWriter::VisitOMPExecutableDirective(OMPExecutableDirective *E) {
Record.writeOMPChildren(E->Data);
Record.AddSourceLocation(E->getBeginLoc());
Record.AddSourceLocation(E->getEndLoc());
Record.writeEnum(E->getMappedDirective());
}

void ASTStmtWriter::VisitOMPLoopBasedDirective(OMPLoopBasedDirective *D) {
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Serialization/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
set(LLVM_LINK_COMPONENTS
BitReader
BitstreamReader
Object
Support
TargetParser
)
Expand All @@ -21,6 +22,7 @@ add_clang_library(clangSerialization
ModuleFileExtension.cpp
ModuleManager.cpp
PCHContainerOperations.cpp
ObjectFilePCHContainerReader.cpp

ADDITIONAL_HEADERS
ASTCommon.h
Expand Down
56 changes: 56 additions & 0 deletions clang/lib/Serialization/ObjectFilePCHContainerReader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//===--- ObjectFilePCHContainerReader.cpp ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "clang/Serialization/ObjectFilePCHContainerReader.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/ObjectFile.h"

using namespace clang;

ArrayRef<StringRef> ObjectFilePCHContainerReader::getFormats() const {
static StringRef Formats[] = {"obj", "raw"};
return Formats;
}

StringRef
ObjectFilePCHContainerReader::ExtractPCH(llvm::MemoryBufferRef Buffer) const {
StringRef PCH;
auto OFOrErr = llvm::object::ObjectFile::createObjectFile(Buffer);
if (OFOrErr) {
auto &OF = OFOrErr.get();
bool IsCOFF = isa<llvm::object::COFFObjectFile>(*OF);
// Find the clang AST section in the container.
for (auto &Section : OF->sections()) {
StringRef Name;
if (Expected<StringRef> NameOrErr = Section.getName())
Name = *NameOrErr;
else
consumeError(NameOrErr.takeError());

if ((!IsCOFF && Name == "__clangast") || (IsCOFF && Name == "clangast")) {
if (Expected<StringRef> E = Section.getContents())
return *E;
else {
handleAllErrors(E.takeError(), [&](const llvm::ErrorInfoBase &EIB) {
EIB.log(llvm::errs());
});
return "";
}
}
}
}
handleAllErrors(OFOrErr.takeError(), [&](const llvm::ErrorInfoBase &EIB) {
if (EIB.convertToErrorCode() ==
llvm::object::object_error::invalid_file_type)
// As a fallback, treat the buffer as a raw AST.
PCH = Buffer.getBuffer();
else
EIB.log(llvm::errs());
});
return PCH;
}
38 changes: 38 additions & 0 deletions clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
Expand All @@ -30,8 +31,40 @@ namespace {
class BuiltinFunctionChecker : public Checker<eval::Call> {
public:
bool evalCall(const CallEvent &Call, CheckerContext &C) const;

private:
// From: clang/include/clang/Basic/Builtins.def
// C++ standard library builtins in namespace 'std'.
const CallDescriptionSet BuiltinLikeStdFunctions{
{CDM::SimpleFunc, {"std", "addressof"}}, //
{CDM::SimpleFunc, {"std", "__addressof"}}, //
{CDM::SimpleFunc, {"std", "as_const"}}, //
{CDM::SimpleFunc, {"std", "forward"}}, //
{CDM::SimpleFunc, {"std", "forward_like"}}, //
{CDM::SimpleFunc, {"std", "move"}}, //
{CDM::SimpleFunc, {"std", "move_if_noexcept"}}, //
};

bool isBuiltinLikeFunction(const CallEvent &Call) const;
};

} // namespace

bool BuiltinFunctionChecker::isBuiltinLikeFunction(
const CallEvent &Call) const {
const auto *FD = llvm::dyn_cast_or_null<FunctionDecl>(Call.getDecl());
if (!FD || FD->getNumParams() != 1)
return false;

if (QualType RetTy = FD->getReturnType();
!RetTy->isPointerType() && !RetTy->isReferenceType())
return false;

if (QualType ParmTy = FD->getParamDecl(0)->getType();
!ParmTy->isPointerType() && !ParmTy->isReferenceType())
return false;

return BuiltinLikeStdFunctions.contains(Call);
}

bool BuiltinFunctionChecker::evalCall(const CallEvent &Call,
Expand All @@ -44,6 +77,11 @@ bool BuiltinFunctionChecker::evalCall(const CallEvent &Call,
const LocationContext *LCtx = C.getLocationContext();
const Expr *CE = Call.getOriginExpr();

if (isBuiltinLikeFunction(Call)) {
C.addTransition(state->BindExpr(CE, LCtx, Call.getArgSVal(0)));
return true;
}

switch (FD->getBuiltinID()) {
default:
return false;
Expand Down
72 changes: 71 additions & 1 deletion clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,8 @@ inline void assertStreamStateOpened(const StreamState *SS) {
}

class StreamChecker : public Checker<check::PreCall, eval::Call,
check::DeadSymbols, check::PointerEscape> {
check::DeadSymbols, check::PointerEscape,
check::ASTDecl<TranslationUnitDecl>> {
BugType BT_FileNull{this, "NULL stream pointer", "Stream handling error"};
BugType BT_UseAfterClose{this, "Closed stream", "Stream handling error"};
BugType BT_UseAfterOpenFailed{this, "Invalid stream",
Expand All @@ -276,11 +277,21 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
const CallEvent *Call,
PointerEscapeKind Kind) const;

/// Finds the declarations of 'FILE *stdin, *stdout, *stderr'.
void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager &,
BugReporter &) const;

const BugType *getBT_StreamEof() const { return &BT_StreamEof; }
const BugType *getBT_IndeterminatePosition() const {
return &BT_IndeterminatePosition;
}

/// Assumes that the result of 'fopen' can't alias with the pointee of
/// 'stdin', 'stdout' or 'stderr'.
ProgramStateRef assumeNoAliasingWithStdStreams(ProgramStateRef State,
DefinedSVal RetVal,
CheckerContext &C) const;

const NoteTag *constructSetEofNoteTag(CheckerContext &C,
SymbolRef StreamSym) const {
return C.getNoteTag([this, StreamSym](PathSensitiveBugReport &BR) {
Expand Down Expand Up @@ -451,6 +462,10 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
/// The built-in va_list type is platform-specific
mutable QualType VaListType;

mutable const VarDecl *StdinDecl = nullptr;
mutable const VarDecl *StdoutDecl = nullptr;
mutable const VarDecl *StderrDecl = nullptr;

void evalFopen(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const;

Expand Down Expand Up @@ -887,6 +902,30 @@ bool StreamChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
return C.isDifferent();
}

ProgramStateRef StreamChecker::assumeNoAliasingWithStdStreams(
ProgramStateRef State, DefinedSVal RetVal, CheckerContext &C) const {
auto assumeRetNE = [&C, RetVal](ProgramStateRef State,
const VarDecl *Var) -> ProgramStateRef {
if (!Var)
return State;
const auto *LCtx = C.getLocationContext();
auto &StoreMgr = C.getStoreManager();
auto &SVB = C.getSValBuilder();
SVal VarValue = State->getSVal(StoreMgr.getLValueVar(Var, LCtx));
auto NoAliasState =
SVB.evalBinOp(State, BO_NE, RetVal, VarValue, SVB.getConditionType())
.castAs<DefinedOrUnknownSVal>();
return State->assume(NoAliasState, true);
};

assert(State);
State = assumeRetNE(State, StdinDecl);
State = assumeRetNE(State, StdoutDecl);
State = assumeRetNE(State, StderrDecl);
assert(State);
return State;
}

void StreamChecker::evalFopen(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
Expand All @@ -899,6 +938,7 @@ void StreamChecker::evalFopen(const FnDescription *Desc, const CallEvent &Call,
assert(RetSym && "RetVal must be a symbol here.");

State = State->BindExpr(CE, C.getLocationContext(), RetVal);
State = assumeNoAliasingWithStdStreams(State, RetVal, C);

// Bifurcate the state into two: one with a valid FILE* pointer, the other
// with a NULL.
Expand Down Expand Up @@ -2017,6 +2057,36 @@ ProgramStateRef StreamChecker::checkPointerEscape(
return State;
}

static const VarDecl *
getGlobalStreamPointerByName(const TranslationUnitDecl *TU, StringRef VarName) {
ASTContext &Ctx = TU->getASTContext();
const auto &SM = Ctx.getSourceManager();
const QualType FileTy = Ctx.getFILEType();

if (FileTy.isNull())
return nullptr;

const QualType FilePtrTy = Ctx.getPointerType(FileTy).getCanonicalType();

auto LookupRes = TU->lookup(&Ctx.Idents.get(VarName));
for (const Decl *D : LookupRes) {
if (auto *VD = dyn_cast_or_null<VarDecl>(D)) {
if (SM.isInSystemHeader(VD->getLocation()) && VD->hasExternalStorage() &&
VD->getType().getCanonicalType() == FilePtrTy) {
return VD;
}
}
}
return nullptr;
}

void StreamChecker::checkASTDecl(const TranslationUnitDecl *TU,
AnalysisManager &, BugReporter &) const {
StdinDecl = getGlobalStreamPointerByName(TU, "stdin");
StdoutDecl = getGlobalStreamPointerByName(TU, "stdout");
StderrDecl = getGlobalStreamPointerByName(TU, "stderr");
}

//===----------------------------------------------------------------------===//
// Checker registration.
//===----------------------------------------------------------------------===//
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Tooling/DependencyScanning/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ add_clang_library(clangDependencyScanning
LINK_LIBS
clangAST
clangBasic
clangCodeGen
clangDriver
clangFrontend
clangLex
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#include "clang/Basic/DiagnosticDriver.h"
#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/Basic/DiagnosticSerialization.h"
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Job.h"
Expand All @@ -21,6 +20,7 @@
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Serialization/ObjectFilePCHContainerReader.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
#include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
#include "clang/Tooling/Tooling.h"
Expand Down
24 changes: 24 additions & 0 deletions clang/test/APINotes/Inputs/Headers/Methods.apinotes
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,27 @@ Tags:
- Name: getIncremented
Availability: none
AvailabilityMsg: "oh no"
- Name: getDecremented
Availability: none
AvailabilityMsg: "this should have no effect"
- Name: Outer
Tags:
- Name: Inner
Methods:
- Name: getDecremented
Availability: none
AvailabilityMsg: "nope"
- Name: getIncremented
Availability: none
AvailabilityMsg: "this should have no effect"
Methods:
- Name: getDecremented
Availability: none
AvailabilityMsg: "this should have no effect"
Functions:
- Name: getIncremented
Availability: none
AvailabilityMsg: "this should have no effect"
- Name: getDecremented
Availability: none
AvailabilityMsg: "this should have no effect"
1 change: 0 additions & 1 deletion clang/test/APINotes/Inputs/Headers/Methods.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ struct IntWrapper {
IntWrapper getIncremented() const { return {value + 1}; }
};

// TODO: support nested tags
struct Outer {
struct Inner {
int value;
Expand Down
3 changes: 3 additions & 0 deletions clang/test/APINotes/Inputs/Headers/Namespaces.apinotes
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ Namespaces:
Methods:
- Name: methodInNestedNamespace
SwiftName: swiftMethodInNestedNamespace()
Tags:
- Name: inner_char_box
SwiftName: InnerCharBox
Namespaces:
- Name: Namespace1
Tags:
Expand Down
3 changes: 3 additions & 0 deletions clang/test/APINotes/Inputs/Headers/Namespaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ void funcInNestedNamespace(int i);
struct char_box {
char c;
void methodInNestedNamespace();
struct inner_char_box {
char c;
};
};
}

Expand Down
8 changes: 8 additions & 0 deletions clang/test/APINotes/methods.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Methods -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -x c++
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Methods -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter IntWrapper::getIncremented -x c++ | FileCheck --check-prefix=CHECK-METHOD %s
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Methods -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter Outer::Inner::getDecremented -x c++ | FileCheck --check-prefix=CHECK-DEEP-METHOD %s

#include "Methods.h"

// CHECK-METHOD: Dumping IntWrapper::getIncremented:
// CHECK-METHOD-NEXT: CXXMethodDecl {{.+}} getIncremented
// CHECK-METHOD: UnavailableAttr {{.+}} <<invalid sloc>> "oh no"

// CHECK-DEEP-METHOD: Dumping Outer::Inner::getDecremented:
// CHECK-DEEP-METHOD-NEXT: CXXMethodDecl {{.+}} getDecremented
// CHECK-DEEP-METHOD: UnavailableAttr {{.+}} <<invalid sloc>> "nope"

// CHECK-METHOD-NOT: this should have no effect
// CHECK-DEEP-METHOD-NOT: this should have no effect
5 changes: 5 additions & 0 deletions clang/test/APINotes/namespaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/CxxInterop -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter Namespace1::Nested1::varInNestedNamespace -x objective-c++ | FileCheck -check-prefix=CHECK-GLOBAL-IN-NESTED-NAMESPACE %s
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/CxxInterop -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter Namespace1::Nested2::varInNestedNamespace -x objective-c++ | FileCheck -check-prefix=CHECK-ANOTHER-GLOBAL-IN-NESTED-NAMESPACE %s
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/CxxInterop -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter Namespace1::Nested1::char_box -x objective-c++ | FileCheck -check-prefix=CHECK-STRUCT-IN-NESTED-NAMESPACE %s
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/CxxInterop -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter Namespace1::Nested1::char_box::inner_char_box -x objective-c++ | FileCheck -check-prefix=CHECK-STRUCT-IN-STRUCT-IN-NESTED-NAMESPACE %s
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/CxxInterop -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter Namespace1::Nested1::funcInNestedNamespace -x objective-c++ | FileCheck -check-prefix=CHECK-FUNC-IN-NESTED-NAMESPACE %s
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/CxxInterop -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter Namespace1::Nested1::char_box::methodInNestedNamespace -x objective-c++ | FileCheck -check-prefix=CHECK-METHOD-IN-NESTED-NAMESPACE %s
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/CxxInterop -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter Namespace1::Nested1::Namespace1::char_box -x objective-c++ | FileCheck -check-prefix=CHECK-STRUCT-IN-DEEP-NESTED-NAMESPACE %s
Expand Down Expand Up @@ -56,6 +57,10 @@
// CHECK-STRUCT-IN-NESTED-NAMESPACE-NEXT: CXXRecordDecl {{.+}} imported in Namespaces <undeserialized declarations> struct char_box
// CHECK-STRUCT-IN-NESTED-NAMESPACE: SwiftNameAttr {{.+}} <<invalid sloc>> "NestedCharBox"

// CHECK-STRUCT-IN-STRUCT-IN-NESTED-NAMESPACE: Dumping Namespace1::Nested1::char_box::inner_char_box:
// CHECK-STRUCT-IN-STRUCT-IN-NESTED-NAMESPACE-NEXT: CXXRecordDecl {{.+}} imported in Namespaces <undeserialized declarations> struct inner_char_box
// CHECK-STRUCT-IN-STRUCT-IN-NESTED-NAMESPACE: SwiftNameAttr {{.+}} <<invalid sloc>> "InnerCharBox"

// CHECK-METHOD-IN-NESTED-NAMESPACE: Dumping Namespace1::Nested1::char_box::methodInNestedNamespace:
// CHECK-METHOD-IN-NESTED-NAMESPACE-NEXT: CXXMethodDecl {{.+}} imported in Namespaces methodInNestedNamespace
// CHECK-METHOD-IN-NESTED-NAMESPACE: SwiftNameAttr {{.+}} <<invalid sloc>> "swiftMethodInNestedNamespace()"
Expand Down
13 changes: 13 additions & 0 deletions clang/test/AST/Interp/atomic.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,16 @@ _Static_assert(atomic_is_lock_free((atomic_short*)0), "");
_Static_assert(atomic_is_lock_free((atomic_int*)0), "");
_Static_assert(atomic_is_lock_free((atomic_long*)0), "");
_Static_assert(atomic_is_lock_free(0 + (atomic_char*)0), "");

_Static_assert(__atomic_always_lock_free(1, (void*)1), "");
_Static_assert(__atomic_always_lock_free(1, (void*)-1), "");
_Static_assert(!__atomic_always_lock_free(4, (void*)2), "");
_Static_assert(!__atomic_always_lock_free(4, (void*)-2), "");
_Static_assert(__atomic_always_lock_free(4, (void*)4), "");
_Static_assert(__atomic_always_lock_free(4, (void*)-4), "");

_Static_assert(__atomic_always_lock_free(1, "string"), "");
_Static_assert(!__atomic_always_lock_free(2, "string"), "");
_Static_assert(__atomic_always_lock_free(2, (int[2]){}), "");
void dummyfn();
_Static_assert(__atomic_always_lock_free(2, dummyfn) || 1, "");
Loading