137 changes: 117 additions & 20 deletions clang/lib/AST/TextNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,26 @@ void TextNodeDumper::dumpDeclRef(const Decl *D, StringRef Label) {
});
}

void TextNodeDumper::dumpTemplateArgument(const TemplateArgument &TA) {
llvm::SmallString<128> Str;
{
llvm::raw_svector_ostream SS(Str);
TA.print(PrintPolicy, SS, /*IncludeType=*/true);
}
OS << " '" << Str << "'";

if (TemplateArgument CanonTA = Context->getCanonicalTemplateArgument(TA);
!CanonTA.structurallyEquals(TA)) {
llvm::SmallString<128> CanonStr;
{
llvm::raw_svector_ostream SS(CanonStr);
CanonTA.print(PrintPolicy, SS, /*IncludeType=*/true);
}
if (CanonStr != Str)
OS << ":'" << CanonStr << "'";
}
}

const char *TextNodeDumper::getCommandName(unsigned CommandID) {
if (Traits)
return Traits->getCommandInfo(CommandID)->Name;
Expand Down Expand Up @@ -1086,45 +1106,126 @@ void TextNodeDumper::VisitNullTemplateArgument(const TemplateArgument &) {

void TextNodeDumper::VisitTypeTemplateArgument(const TemplateArgument &TA) {
OS << " type";
dumpType(TA.getAsType());
dumpTemplateArgument(TA);
}

void TextNodeDumper::VisitDeclarationTemplateArgument(
const TemplateArgument &TA) {
OS << " decl";
dumpTemplateArgument(TA);
dumpDeclRef(TA.getAsDecl());
}

void TextNodeDumper::VisitNullPtrTemplateArgument(const TemplateArgument &) {
void TextNodeDumper::VisitNullPtrTemplateArgument(const TemplateArgument &TA) {
OS << " nullptr";
dumpTemplateArgument(TA);
}

void TextNodeDumper::VisitIntegralTemplateArgument(const TemplateArgument &TA) {
OS << " integral " << TA.getAsIntegral();
OS << " integral";
dumpTemplateArgument(TA);
}

void TextNodeDumper::dumpTemplateName(TemplateName TN, StringRef Label) {
AddChild(Label, [=] {
{
llvm::SmallString<128> Str;
{
llvm::raw_svector_ostream SS(Str);
TN.print(SS, PrintPolicy);
}
OS << " '" << Str << "'";

if (TemplateName CanonTN = Context->getCanonicalTemplateName(TN);
CanonTN != TN) {
llvm::SmallString<128> CanonStr;
{
llvm::raw_svector_ostream SS(CanonStr);
CanonTN.print(SS, PrintPolicy);
}
if (CanonStr != Str)
OS << ":'" << CanonStr << "'";
}
}
dumpBareTemplateName(TN);
});
}

void TextNodeDumper::dumpBareTemplateName(TemplateName TN) {
switch (TN.getKind()) {
case TemplateName::Template:
AddChild([=] { Visit(TN.getAsTemplateDecl()); });
return;
case TemplateName::UsingTemplate: {
const UsingShadowDecl *USD = TN.getAsUsingShadowDecl();
AddChild([=] { Visit(USD); });
AddChild("target", [=] { Visit(USD->getTargetDecl()); });
return;
}
case TemplateName::QualifiedTemplate: {
OS << " qualified";
const QualifiedTemplateName *QTN = TN.getAsQualifiedTemplateName();
if (QTN->hasTemplateKeyword())
OS << " keyword";
dumpNestedNameSpecifier(QTN->getQualifier());
dumpBareTemplateName(QTN->getUnderlyingTemplate());
return;
}
case TemplateName::DependentTemplate: {
OS << " dependent";
const DependentTemplateName *DTN = TN.getAsDependentTemplateName();
dumpNestedNameSpecifier(DTN->getQualifier());
return;
}
case TemplateName::SubstTemplateTemplateParm: {
OS << " subst";
const SubstTemplateTemplateParmStorage *STS =
TN.getAsSubstTemplateTemplateParm();
OS << " index " << STS->getIndex();
if (std::optional<unsigned int> PackIndex = STS->getPackIndex())
OS << " pack_index " << *PackIndex;
if (const TemplateTemplateParmDecl *P = STS->getParameter())
AddChild("parameter", [=] { Visit(P); });
dumpDeclRef(STS->getAssociatedDecl(), "associated");
dumpTemplateName(STS->getReplacement(), "replacement");
return;
}
// FIXME: Implement these.
case TemplateName::OverloadedTemplate:
OS << " overloaded";
return;
case TemplateName::AssumedTemplate:
OS << " assumed";
return;
case TemplateName::SubstTemplateTemplateParmPack:
OS << " subst_pack";
return;
}
llvm_unreachable("Unexpected TemplateName Kind");
}

void TextNodeDumper::VisitTemplateTemplateArgument(const TemplateArgument &TA) {
if (TA.getAsTemplate().getKind() == TemplateName::UsingTemplate)
OS << " using";
OS << " template ";
TA.getAsTemplate().dump(OS);
OS << " template";
dumpTemplateArgument(TA);
dumpBareTemplateName(TA.getAsTemplate());
}

void TextNodeDumper::VisitTemplateExpansionTemplateArgument(
const TemplateArgument &TA) {
if (TA.getAsTemplateOrTemplatePattern().getKind() ==
TemplateName::UsingTemplate)
OS << " using";
OS << " template expansion ";
TA.getAsTemplateOrTemplatePattern().dump(OS);
OS << " template expansion";
dumpTemplateArgument(TA);
dumpBareTemplateName(TA.getAsTemplateOrTemplatePattern());
}

void TextNodeDumper::VisitExpressionTemplateArgument(const TemplateArgument &) {
void TextNodeDumper::VisitExpressionTemplateArgument(
const TemplateArgument &TA) {
OS << " expr";
dumpTemplateArgument(TA);
}

void TextNodeDumper::VisitPackTemplateArgument(const TemplateArgument &) {
void TextNodeDumper::VisitPackTemplateArgument(const TemplateArgument &TA) {
OS << " pack";
dumpTemplateArgument(TA);
}

static void dumpBasePath(raw_ostream &OS, const CastExpr *Node) {
Expand Down Expand Up @@ -1913,18 +2014,14 @@ void TextNodeDumper::VisitAutoType(const AutoType *T) {

void TextNodeDumper::VisitDeducedTemplateSpecializationType(
const DeducedTemplateSpecializationType *T) {
if (T->getTemplateName().getKind() == TemplateName::UsingTemplate)
OS << " using";
dumpTemplateName(T->getTemplateName(), "name");
}

void TextNodeDumper::VisitTemplateSpecializationType(
const TemplateSpecializationType *T) {
if (T->isTypeAlias())
OS << " alias";
if (T->getTemplateName().getKind() == TemplateName::UsingTemplate)
OS << " using";
OS << " ";
T->getTemplateName().dump(OS);
dumpTemplateName(T->getTemplateName(), "name");
}

void TextNodeDumper::VisitInjectedClassNameType(
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4251,7 +4251,8 @@ TemplateSpecializationType::TemplateSpecializationType(
assert((T.getKind() == TemplateName::Template ||
T.getKind() == TemplateName::SubstTemplateTemplateParm ||
T.getKind() == TemplateName::SubstTemplateTemplateParmPack ||
T.getKind() == TemplateName::UsingTemplate) &&
T.getKind() == TemplateName::UsingTemplate ||
T.getKind() == TemplateName::QualifiedTemplate) &&
"Unexpected template name for TemplateSpecializationType");

auto *TemplateArgs = reinterpret_cast<TemplateArgument *>(this + 1);
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1586,14 +1586,14 @@ void TypePrinter::printTemplateId(const TemplateSpecializationType *T,
IncludeStrongLifetimeRAII Strong(Policy);

TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl();
// FIXME: Null TD never excercised in test suite.
// FIXME: Null TD never exercised in test suite.
if (FullyQualify && TD) {
if (!Policy.SuppressScope)
AppendScope(TD->getDeclContext(), OS, TD->getDeclName());

OS << TD->getName();
} else {
T->getTemplateName().print(OS, Policy);
T->getTemplateName().print(OS, Policy, TemplateName::Qualified::None);
}

DefaultTemplateArgsPolicyRAII TemplateArgs(Policy);
Expand Down
33 changes: 32 additions & 1 deletion clang/lib/Basic/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,8 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasFullBFloat16 = true;
} else if (Feature == "+egpr") {
HasEGPR = true;
} else if (Feature == "+inline-asm-use-gpr32") {
HasInlineAsmUseGPR32 = true;
} else if (Feature == "+push2pop2") {
HasPush2Pop2 = true;
} else if (Feature == "+ppx") {
Expand Down Expand Up @@ -961,8 +963,10 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasCF)
Builder.defineMacro("__CF__");
// Condition here is aligned with the feature set of mapxf in Options.td
if (HasEGPR && HasPush2Pop2 && HasPPX && HasNDD)
if (HasEGPR && HasPush2Pop2 && HasPPX && HasNDD && HasCCMP && HasNF)
Builder.defineMacro("__APX_F__");
if (HasEGPR && HasInlineAsmUseGPR32)
Builder.defineMacro("__APX_INLINE_ASM_USE_GPR32__");

// Each case falls through to the previous one here.
switch (SSELevel) {
Expand Down Expand Up @@ -1478,6 +1482,18 @@ bool X86TargetInfo::validateAsmConstraint(
case 'C': // SSE floating point constant.
case 'G': // x87 floating point constant.
return true;
case 'j':
Name++;
switch (*Name) {
default:
return false;
case 'r':
Info.setAllowsRegister();
return true;
case 'R':
Info.setAllowsRegister();
return true;
}
case '@':
// CC condition changes.
if (auto Len = matchAsmCCConstraint(Name)) {
Expand Down Expand Up @@ -1750,6 +1766,21 @@ std::string X86TargetInfo::convertConstraint(const char *&Constraint) const {
return std::string("^") + std::string(Constraint++, 2);
}
[[fallthrough]];
case 'j':
switch (Constraint[1]) {
default:
// Break from inner switch and fall through (copy single char),
// continue parsing after copying the current constraint into
// the return string.
break;
case 'r':
case 'R':
// "^" hints llvm that this is a 2 letter constraint.
// "Constraint++" is used to promote the string iterator
// to the next constraint.
return std::string("^") + std::string(Constraint++, 2);
}
[[fallthrough]];
default:
return std::string(1, *Constraint);
}
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/X86.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
bool HasCCMP = false;
bool HasNF = false;
bool HasCF = false;
bool HasInlineAsmUseGPR32 = false;

protected:
llvm::X86::CPUKind CPU = llvm::X86::CK_None;
Expand Down
17 changes: 0 additions & 17 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@
#include "llvm/Transforms/Scalar/GVN.h"
#include "llvm/Transforms/Scalar/JumpThreading.h"
#include "llvm/Transforms/Utils/Debugify.h"
#include "llvm/Transforms/Utils/EntryExitInstrumenter.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include <memory>
#include <optional>
Expand Down Expand Up @@ -983,22 +982,6 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
/*DropTypeTests=*/true));
});

if (CodeGenOpts.InstrumentFunctions ||
CodeGenOpts.InstrumentFunctionEntryBare ||
CodeGenOpts.InstrumentFunctionsAfterInlining ||
CodeGenOpts.InstrumentForProfiling) {
PB.registerPipelineStartEPCallback(
[](ModulePassManager &MPM, OptimizationLevel Level) {
MPM.addPass(createModuleToFunctionPassAdaptor(
EntryExitInstrumenterPass(/*PostInlining=*/false)));
});
PB.registerOptimizerLastEPCallback(
[](ModulePassManager &MPM, OptimizationLevel Level) {
MPM.addPass(createModuleToFunctionPassAdaptor(
EntryExitInstrumenterPass(/*PostInlining=*/true)));
});
}

// Register callbacks to schedule sanitizer passes at the appropriate part
// of the pipeline.
if (LangOpts.Sanitize.has(SanitizerKind::LocalBounds))
Expand Down
14 changes: 5 additions & 9 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5978,11 +5978,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
auto Name = CGM.getCUDARuntime().getDeviceSideName(
cast<DeclRefExpr>(E->getArg(0)->IgnoreImpCasts())->getDecl());
auto Str = CGM.GetAddrOfConstantCString(Name, "");
llvm::Constant *Zeros[] = {llvm::ConstantInt::get(SizeTy, 0),
llvm::ConstantInt::get(SizeTy, 0)};
auto *Ptr = llvm::ConstantExpr::getGetElementPtr(Str.getElementType(),
Str.getPointer(), Zeros);
return RValue::get(Ptr);
return RValue::get(Str.getPointer());
}
}

Expand Down Expand Up @@ -14074,7 +14070,7 @@ Value *CodeGenFunction::EmitX86CpuIs(StringRef CPUStr) {
// Grab the appropriate field from __cpu_model.
llvm::Value *Idxs[] = {ConstantInt::get(Int32Ty, 0),
ConstantInt::get(Int32Ty, Index)};
llvm::Value *CpuValue = Builder.CreateGEP(STy, CpuModel, Idxs);
llvm::Value *CpuValue = Builder.CreateInBoundsGEP(STy, CpuModel, Idxs);
CpuValue = Builder.CreateAlignedLoad(Int32Ty, CpuValue,
CharUnits::fromQuantity(4));

Expand Down Expand Up @@ -14116,7 +14112,7 @@ CodeGenFunction::EmitX86CpuSupports(std::array<uint32_t, 4> FeatureMask) {
// global in the struct STy.
Value *Idxs[] = {Builder.getInt32(0), Builder.getInt32(3),
Builder.getInt32(0)};
Value *CpuFeatures = Builder.CreateGEP(STy, CpuModel, Idxs);
Value *CpuFeatures = Builder.CreateInBoundsGEP(STy, CpuModel, Idxs);
Value *Features = Builder.CreateAlignedLoad(Int32Ty, CpuFeatures,
CharUnits::fromQuantity(4));

Expand All @@ -14137,7 +14133,7 @@ CodeGenFunction::EmitX86CpuSupports(std::array<uint32_t, 4> FeatureMask) {
continue;
Value *Idxs[] = {Builder.getInt32(0), Builder.getInt32(i - 1)};
Value *Features = Builder.CreateAlignedLoad(
Int32Ty, Builder.CreateGEP(ATy, CpuFeatures2, Idxs),
Int32Ty, Builder.CreateInBoundsGEP(ATy, CpuFeatures2, Idxs),
CharUnits::fromQuantity(4));
// Check the value of the bit corresponding to the feature requested.
Value *Mask = Builder.getInt32(M);
Expand Down Expand Up @@ -16724,7 +16720,7 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
llvm::Value *Idxs[] = {ConstantInt::get(Int32Ty, 0),
ConstantInt::get(Int32Ty, FieldIdx)};

FieldValue = Builder.CreateGEP(STy, SysConf, Idxs);
FieldValue = Builder.CreateInBoundsGEP(STy, SysConf, Idxs);
FieldValue = Builder.CreateAlignedLoad(Int32Ty, FieldValue,
CharUnits::fromQuantity(4));
} else if (SupportMethod == SYS_CALL) {
Expand Down
10 changes: 2 additions & 8 deletions clang/lib/CodeGen/CGCUDANV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,6 @@ class CGNVCUDARuntime : public CGCUDARuntime {
bool RelocatableDeviceCode;
/// Mangle context for device.
std::unique_ptr<MangleContext> DeviceMC;
/// Some zeros used for GEPs.
llvm::Constant *Zeros[2];

llvm::FunctionCallee getSetupArgumentFn() const;
llvm::FunctionCallee getLaunchFn() const;
Expand All @@ -91,9 +89,7 @@ class CGNVCUDARuntime : public CGCUDARuntime {
/// where the C code specifies const char*.
llvm::Constant *makeConstantString(const std::string &Str,
const std::string &Name = "") {
auto ConstStr = CGM.GetAddrOfConstantCString(Str, Name.c_str());
return llvm::ConstantExpr::getGetElementPtr(ConstStr.getElementType(),
ConstStr.getPointer(), Zeros);
return CGM.GetAddrOfConstantCString(Str, Name.c_str()).getPointer();
}

/// Helper function which generates an initialized constant array from Str,
Expand All @@ -117,7 +113,7 @@ class CGNVCUDARuntime : public CGCUDARuntime {
}
if (Alignment)
GV->setAlignment(llvm::Align(Alignment));
return llvm::ConstantExpr::getGetElementPtr(GV->getValueType(), GV, Zeros);
return GV;
}

/// Helper function that generates an empty dummy function returning void.
Expand Down Expand Up @@ -230,8 +226,6 @@ CGNVCUDARuntime::CGNVCUDARuntime(CodeGenModule &CGM)
IntTy = CGM.IntTy;
SizeTy = CGM.SizeTy;
VoidTy = CGM.VoidTy;
Zeros[0] = llvm::ConstantInt::get(SizeTy, 0);
Zeros[1] = Zeros[0];
PtrTy = CGM.UnqualPtrTy;
}

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2836,7 +2836,7 @@ CGDebugInfo::CreateTypeDefinition(const RecordType *Ty) {

// Collect data fields (including static variables and any initializers).
CollectRecordFields(RD, DefUnit, EltTys, FwdDecl);
if (CXXDecl)
if (CXXDecl && !CGM.getCodeGenOpts().DebugOmitUnreferencedMethods)
CollectCXXMemberFunctions(CXXDecl, DefUnit, EltTys, FwdDecl);

LexicalBlockStack.pop_back();
Expand Down
7 changes: 2 additions & 5 deletions clang/lib/CodeGen/CGExprAgg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,11 +448,7 @@ AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
AggValueSlot Dest = EnsureSlot(E->getType());
LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType());
LValue Start = CGF.EmitLValueForFieldInitialization(DestLV, *Field);
llvm::Value *Zero = llvm::ConstantInt::get(CGF.PtrDiffTy, 0);
llvm::Value *IdxStart[] = { Zero, Zero };
llvm::Value *ArrayStart = Builder.CreateInBoundsGEP(
ArrayPtr.getElementType(), ArrayPtr.emitRawPointer(CGF), IdxStart,
"arraystart");
llvm::Value *ArrayStart = ArrayPtr.emitRawPointer(CGF);
CGF.EmitStoreThroughLValue(RValue::get(ArrayStart), Start);
++Field;

Expand All @@ -467,6 +463,7 @@ AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
Ctx.hasSameType(Field->getType()->getPointeeType(),
ArrayType->getElementType())) {
// End pointer.
llvm::Value *Zero = llvm::ConstantInt::get(CGF.PtrDiffTy, 0);
llvm::Value *IdxEnd[] = { Zero, Size };
llvm::Value *ArrayEnd = Builder.CreateInBoundsGEP(
ArrayPtr.getElementType(), ArrayPtr.emitRawPointer(CGF), IdxEnd,
Expand Down
9 changes: 3 additions & 6 deletions clang/lib/CodeGen/CGObjCGNU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,7 @@ class CGObjCGNU : public CGObjCRuntime {
llvm::Constant *MakeConstantString(StringRef Str, const char *Name = "") {
ConstantAddress Array =
CGM.GetAddrOfConstantCString(std::string(Str), Name);
return llvm::ConstantExpr::getGetElementPtr(Array.getElementType(),
Array.getPointer(), Zeros);
return Array.getPointer();
}

/// Emits a linkonce_odr string, whose name is the prefix followed by the
Expand All @@ -221,8 +220,7 @@ class CGObjCGNU : public CGObjCRuntime {
GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
ConstStr = GV;
}
return llvm::ConstantExpr::getGetElementPtr(ConstStr->getValueType(),
ConstStr, Zeros);
return ConstStr;
}

/// Returns a property name and encoding string.
Expand Down Expand Up @@ -1477,8 +1475,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
TypesGlobal = GV;
}
return llvm::ConstantExpr::getGetElementPtr(TypesGlobal->getValueType(),
TypesGlobal, Zeros);
return TypesGlobal;
}
llvm::Constant *GetConstantSelector(Selector Sel,
const std::string &TypeEncoding) override {
Expand Down
23 changes: 14 additions & 9 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5341,6 +5341,18 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
!IsDefinitionAvailableExternally &&
D->needsDestruction(getContext()) == QualType::DK_cxx_destructor;

// It is helpless to emit the definition for an available_externally variable
// which can't be marked as const.
// We don't need to check if it needs global ctor or dtor. See the above
// comment for ideas.
if (IsDefinitionAvailableExternally &&
(!D->hasConstantInitialization() ||
// TODO: Update this when we have interface to check constexpr
// destructor.
D->needsDestruction(getContext()) ||
!D->getType().isConstantStorage(getContext(), true, true)))
return;

const VarDecl *InitDecl;
const Expr *InitExpr = D->getAnyInitializer(InitDecl);

Expand Down Expand Up @@ -6119,9 +6131,6 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
return ConstantAddress(
C, C->getValueType(), CharUnits::fromQuantity(C->getAlignment()));

llvm::Constant *Zero = llvm::Constant::getNullValue(Int32Ty);
llvm::Constant *Zeros[] = { Zero, Zero };

const ASTContext &Context = getContext();
const llvm::Triple &Triple = getTriple();

Expand Down Expand Up @@ -6192,8 +6201,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {

// Decay array -> ptr
CFConstantStringClassRef =
IsSwiftABI ? llvm::ConstantExpr::getPtrToInt(C, Ty)
: llvm::ConstantExpr::getGetElementPtr(Ty, C, Zeros);
IsSwiftABI ? llvm::ConstantExpr::getPtrToInt(C, Ty) : C;
}

QualType CFTy = Context.getCFConstantStringType();
Expand Down Expand Up @@ -6249,10 +6257,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
GV->setSection(".rodata");

// String.
llvm::Constant *Str =
llvm::ConstantExpr::getGetElementPtr(GV->getValueType(), GV, Zeros);

Fields.add(Str);
Fields.add(GV);

// String length.
llvm::IntegerType *LengthTy =
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Driver/ToolChains/Arch/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,4 +310,6 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
Features.push_back("+prefer-no-gather");
if (Args.hasArg(options::OPT_mno_scatter))
Features.push_back("+prefer-no-scatter");
if (Args.hasArg(options::OPT_mapx_inline_asm_use_gpr32))
Features.push_back("+inline-asm-use-gpr32");
}
15 changes: 15 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Frontend/Debug/Options.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/CodeGen.h"
Expand Down Expand Up @@ -4642,6 +4643,7 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T,
Args.addOptInFlag(CmdArgs, options::OPT_fforce_dwarf_frame,
options::OPT_fno_force_dwarf_frame);

bool EnableTypeUnits = false;
if (Args.hasFlag(options::OPT_fdebug_types_section,
options::OPT_fno_debug_types_section, false)) {
if (!(T.isOSBinFormatELF() || T.isOSBinFormatWasm())) {
Expand All @@ -4652,11 +4654,24 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T,
} else if (checkDebugInfoOption(
Args.getLastArg(options::OPT_fdebug_types_section), Args, D,
TC)) {
EnableTypeUnits = true;
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-generate-type-units");
}
}

if (const Arg *A =
Args.getLastArg(options::OPT_gomit_unreferenced_methods,
options::OPT_gno_omit_unreferenced_methods))
(void)checkDebugInfoOption(A, Args, D, TC);
if (Args.hasFlag(options::OPT_gomit_unreferenced_methods,
options::OPT_gno_omit_unreferenced_methods, false) &&
(DebugInfoKind == llvm::codegenoptions::DebugInfoConstructor ||
DebugInfoKind == llvm::codegenoptions::LimitedDebugInfo) &&
!EnableTypeUnits) {
CmdArgs.push_back("-gomit-unreferenced-methods");
}

// To avoid join/split of directory+filename, the integrated assembler prefers
// the directory form of .file on all DWARF versions. GNU as doesn't allow the
// form before DWARF v5.
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Driver/ToolChains/HIPUtility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ class HIPUndefinedFatBinSymbols {
std::string ID = IA->getId().str();
if (!ID.empty()) {
ID = llvm::utohexstr(llvm::MD5Hash(ID), /*LowerCase=*/true);
FatBinSymbols.insert(Twine(FatBinPrefix + "_" + ID).str());
FatBinSymbols.insert((FatBinPrefix + Twine('_') + ID).str());
GPUBinHandleSymbols.insert(
Twine(GPUBinHandlePrefix + "_" + ID).str());
(GPUBinHandlePrefix + Twine('_') + ID).str());
continue;
}
if (IA->getInputArg().getNumValues() == 0)
Expand Down
12 changes: 10 additions & 2 deletions clang/lib/Driver/ToolChains/SPIRV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "SPIRV.h"
#include "CommonArgs.h"
#include "clang/Basic/Version.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/InputInfo.h"
Expand All @@ -32,8 +33,15 @@ void SPIRV::constructTranslateCommand(Compilation &C, const Tool &T,

CmdArgs.append({"-o", Output.getFilename()});

const char *Exec =
C.getArgs().MakeArgString(T.getToolChain().GetProgramPath("llvm-spirv"));
// Try to find "llvm-spirv-<LLVM_VERSION_MAJOR>". Otherwise, fall back to
// plain "llvm-spirv".
using namespace std::string_literals;
auto VersionedTool = "llvm-spirv-"s + std::to_string(LLVM_VERSION_MAJOR);
std::string ExeCand = T.getToolChain().GetProgramPath(VersionedTool.c_str());
if (!llvm::sys::fs::can_execute(ExeCand))
ExeCand = T.getToolChain().GetProgramPath("llvm-spirv");

const char *Exec = C.getArgs().MakeArgString(ExeCand);
C.addCommand(std::make_unique<Command>(JA, T, ResponseFileSupport::None(),
Exec, CmdArgs, Input, Output));
}
Expand Down
23 changes: 23 additions & 0 deletions clang/lib/Format/FormatToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,29 @@ struct FormatToken {
return isOneOf(tok::star, tok::amp, tok::ampamp);
}

bool isCppAlternativeOperatorKeyword() const {
assert(!TokenText.empty());
if (!isalpha(TokenText[0]))
return false;

switch (Tok.getKind()) {
case tok::ampamp:
case tok::ampequal:
case tok::amp:
case tok::pipe:
case tok::tilde:
case tok::exclaim:
case tok::exclaimequal:
case tok::pipepipe:
case tok::pipeequal:
case tok::caret:
case tok::caretequal:
return true;
default:
return false;
}
}

bool isUnaryOperator() const {
switch (Tok.getKind()) {
case tok::plus:
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4846,8 +4846,12 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
Right.is(TT_TemplateOpener)) {
return true;
}
if (Left.Tok.getIdentifierInfo() && Right.is(tok::numeric_constant))
// C++ Core Guidelines suppression tag, e.g. `[[suppress(type.5)]]`.
if (Left.is(tok::identifier) && Right.is(tok::numeric_constant))
return Right.TokenText[0] != '.';
// `Left` is a keyword (including C++ alternative operator) or identifier.
if (Left.Tok.getIdentifierInfo() && Right.Tok.isLiteral())
return true;
} else if (Style.isProto()) {
if (Right.is(tok::period) &&
Left.isOneOf(Keywords.kw_optional, Keywords.kw_required,
Expand Down
12 changes: 4 additions & 8 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1410,13 +1410,6 @@ void UnwrappedLineParser::readTokenWithJavaScriptASI() {
}
}

static bool isAltOperator(const FormatToken &Tok) {
return isalpha(Tok.TokenText[0]) &&
Tok.isOneOf(tok::ampamp, tok::ampequal, tok::amp, tok::pipe,
tok::tilde, tok::exclaim, tok::exclaimequal, tok::pipepipe,
tok::pipeequal, tok::caret, tok::caretequal);
}

void UnwrappedLineParser::parseStructuralElement(
const FormatToken *OpeningBrace, IfStmtKind *IfKind,
FormatToken **IfLeftBrace, bool *HasDoWhile, bool *HasLabel) {
Expand Down Expand Up @@ -1699,7 +1692,7 @@ void UnwrappedLineParser::parseStructuralElement(
for (const bool InRequiresExpression =
OpeningBrace && OpeningBrace->is(TT_RequiresExpressionLBrace);
!eof();) {
if (IsCpp && isAltOperator(*FormatTok)) {
if (IsCpp && FormatTok->isCppAlternativeOperatorKeyword()) {
if (auto *Next = Tokens->peekNextToken(/*SkipComment=*/true);
Next && Next->isBinaryOperator()) {
FormatTok->Tok.setKind(tok::identifier);
Expand Down Expand Up @@ -4026,6 +4019,9 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
if (AngleNestingLevel == 0) {
if (FormatTok->is(tok::colon)) {
IsDerived = true;
} else if (FormatTok->is(tok::identifier) &&
FormatTok->Previous->is(tok::coloncolon)) {
ClassName = FormatTok;
} else if (FormatTok->is(tok::l_paren) &&
IsNonMacroIdentifier(FormatTok->Previous)) {
break;
Expand Down
19 changes: 19 additions & 0 deletions clang/lib/Headers/intrin.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,25 @@ static __inline__ void __DEFAULT_FN_ATTRS __stosq(unsigned __int64 *__dst,
static __inline__ void __DEFAULT_FN_ATTRS __halt(void) {
__asm__ volatile("hlt");
}

static inline int _inp(unsigned short port) {
int ret;
__asm__ volatile("inb %w1, %b0" : "=a"(ret) : "Nd"(port));
return ret;
}

static inline unsigned short _inpw(unsigned short port) {
unsigned short ret;
__asm__ volatile("inw %w1, %w0" : "=a"(ret) : "Nd"(port));
return ret;
}

static inline unsigned long _inpd(unsigned short port) {
unsigned long ret;
__asm__ volatile("inl %w1, %k0" : "=a"(ret) : "Nd"(port));
return ret;
}

#endif

#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
Expand Down
18 changes: 4 additions & 14 deletions clang/lib/Headers/ptrauth.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,17 @@ typedef enum {
ptrauth_key_asda = 2,
ptrauth_key_asdb = 3,

#ifdef __APPLE__
/* A process-independent key which can be used to sign code pointers.
Signing and authenticating with this key is a no-op in processes
which disable ABI pointer authentication. */
/* A process-independent key which can be used to sign code pointers. */
ptrauth_key_process_independent_code = ptrauth_key_asia,

/* A process-specific key which can be used to sign code pointers.
Signing and authenticating with this key is enforced even in processes
which disable ABI pointer authentication. */
/* A process-specific key which can be used to sign code pointers. */
ptrauth_key_process_dependent_code = ptrauth_key_asib,

/* A process-independent key which can be used to sign data pointers.
Signing and authenticating with this key is a no-op in processes
which disable ABI pointer authentication. */
/* A process-independent key which can be used to sign data pointers. */
ptrauth_key_process_independent_data = ptrauth_key_asda,

/* A process-specific key which can be used to sign data pointers.
Signing and authenticating with this key is a no-op in processes
which disable ABI pointer authentication. */
/* A process-specific key which can be used to sign data pointers. */
ptrauth_key_process_dependent_data = ptrauth_key_asdb,
#endif /* __APPLE__ */

} ptrauth_key;

Expand Down
23 changes: 17 additions & 6 deletions clang/lib/Parse/ParseExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Basic/TemplateKinds.h"
#include "clang/Basic/TokenKinds.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Parse/ParseDiagnostic.h"
Expand Down Expand Up @@ -3026,13 +3027,23 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType,
SS, ObjectType, ObjectHadErrors,
TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), Id, IdLoc,
EnteringContext, Result, TemplateSpecified);
else if (TemplateSpecified &&
Actions.ActOnTemplateName(
getCurScope(), SS, *TemplateKWLoc, Result, ObjectType,
EnteringContext, Template,
/*AllowInjectedClassName*/ true) == TNK_Non_template)
return true;

if (TemplateSpecified) {
TemplateNameKind TNK =
Actions.ActOnTemplateName(getCurScope(), SS, *TemplateKWLoc, Result,
ObjectType, EnteringContext, Template,
/*AllowInjectedClassName=*/true);
if (TNK == TNK_Non_template)
return true;

// C++2c [tem.names]p6
// A name prefixed by the keyword template shall be followed by a template
// argument list or refer to a class template or an alias template.
if ((TNK == TNK_Function_template || TNK == TNK_Dependent_template_name ||
TNK == TNK_Var_template) &&
!Tok.is(tok::less))
Diag(IdLoc, diag::missing_template_arg_list_after_template_kw);
}
return false;
}

Expand Down
66 changes: 27 additions & 39 deletions clang/lib/Parse/ParseOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/EnterExpressionEvaluationContext.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaAMDGPU.h"
#include "clang/Sema/SemaCodeCompletion.h"
#include "clang/Sema/SemaOpenMP.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/UniqueVector.h"
#include "llvm/Frontend/OpenMP/OMPAssume.h"
#include "llvm/Frontend/OpenMP/OMPContext.h"
#include <bitset>
#include <optional>

using namespace clang;
Expand Down Expand Up @@ -1646,19 +1646,17 @@ bool Parser::parseOMPDeclareVariantMatchClause(SourceLocation Loc,
void Parser::ParseOpenMPClauses(OpenMPDirectiveKind DKind,
SmallVectorImpl<OMPClause *> &Clauses,
SourceLocation Loc) {
SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>,
llvm::omp::Clause_enumSize + 1>
FirstClauses(llvm::omp::Clause_enumSize + 1);
std::bitset<llvm::omp::Clause_enumSize + 1> SeenClauses;
while (Tok.isNot(tok::annot_pragma_openmp_end)) {
OpenMPClauseKind CKind = Tok.isAnnotation()
? OMPC_unknown
: getOpenMPClauseKind(PP.getSpelling(Tok));
Actions.OpenMP().StartOpenMPClause(CKind);
OMPClause *Clause = ParseOpenMPClause(
DKind, CKind, !FirstClauses[unsigned(CKind)].getInt());
OMPClause *Clause =
ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]);
SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end,
StopBeforeMatch);
FirstClauses[unsigned(CKind)].setInt(true);
SeenClauses[unsigned(CKind)] = true;
if (Clause != nullptr)
Clauses.push_back(Clause);
if (Tok.is(tok::annot_pragma_openmp_end)) {
Expand Down Expand Up @@ -2114,19 +2112,17 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
/*AllowScopeSpecifier=*/true)) {
SmallVector<OMPClause *, 1> Clauses;
if (Tok.isNot(tok::annot_pragma_openmp_end)) {
SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>,
llvm::omp::Clause_enumSize + 1>
FirstClauses(llvm::omp::Clause_enumSize + 1);
std::bitset<llvm::omp::Clause_enumSize + 1> SeenClauses;
while (Tok.isNot(tok::annot_pragma_openmp_end)) {
OpenMPClauseKind CKind =
Tok.isAnnotation() ? OMPC_unknown
: getOpenMPClauseKind(PP.getSpelling(Tok));
Actions.OpenMP().StartOpenMPClause(CKind);
OMPClause *Clause = ParseOpenMPClause(
OMPD_allocate, CKind, !FirstClauses[unsigned(CKind)].getInt());
OMPClause *Clause = ParseOpenMPClause(OMPD_allocate, CKind,
!SeenClauses[unsigned(CKind)]);
SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end,
StopBeforeMatch);
FirstClauses[unsigned(CKind)].setInt(true);
SeenClauses[unsigned(CKind)] = true;
if (Clause != nullptr)
Clauses.push_back(Clause);
if (Tok.is(tok::annot_pragma_openmp_end)) {
Expand All @@ -2150,9 +2146,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
case OMPD_requires: {
SourceLocation StartLoc = ConsumeToken();
SmallVector<OMPClause *, 5> Clauses;
SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>,
llvm::omp::Clause_enumSize + 1>
FirstClauses(llvm::omp::Clause_enumSize + 1);
std::bitset<llvm::omp::Clause_enumSize + 1> SeenClauses;
if (Tok.is(tok::annot_pragma_openmp_end)) {
Diag(Tok, diag::err_omp_expected_clause)
<< getOpenMPDirectiveName(OMPD_requires);
Expand All @@ -2163,11 +2157,11 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
? OMPC_unknown
: getOpenMPClauseKind(PP.getSpelling(Tok));
Actions.OpenMP().StartOpenMPClause(CKind);
OMPClause *Clause = ParseOpenMPClause(
OMPD_requires, CKind, !FirstClauses[unsigned(CKind)].getInt());
OMPClause *Clause = ParseOpenMPClause(OMPD_requires, CKind,
!SeenClauses[unsigned(CKind)]);
SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end,
StopBeforeMatch);
FirstClauses[unsigned(CKind)].setInt(true);
SeenClauses[unsigned(CKind)] = true;
if (Clause != nullptr)
Clauses.push_back(Clause);
if (Tok.is(tok::annot_pragma_openmp_end)) {
Expand Down Expand Up @@ -2510,9 +2504,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
ParsingOpenMPDirectiveRAII DirScope(*this);
ParenBraceBracketBalancer BalancerRAIIObj(*this);
SmallVector<OMPClause *, 5> Clauses;
SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>,
llvm::omp::Clause_enumSize + 1>
FirstClauses(llvm::omp::Clause_enumSize + 1);
std::bitset<llvm::omp::Clause_enumSize + 1> SeenClauses;
unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |
Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope;
SourceLocation Loc = ReadDirectiveWithinMetadirective
Expand Down Expand Up @@ -2717,19 +2709,17 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
/*AllowScopeSpecifier=*/false)) {
SmallVector<OMPClause *, 1> Clauses;
if (Tok.isNot(tok::annot_pragma_openmp_end)) {
SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>,
llvm::omp::Clause_enumSize + 1>
FirstClauses(llvm::omp::Clause_enumSize + 1);
std::bitset<llvm::omp::Clause_enumSize + 1> SeenClauses;
while (Tok.isNot(tok::annot_pragma_openmp_end)) {
OpenMPClauseKind CKind =
Tok.isAnnotation() ? OMPC_unknown
: getOpenMPClauseKind(PP.getSpelling(Tok));
Actions.OpenMP().StartOpenMPClause(CKind);
OMPClause *Clause = ParseOpenMPClause(
OMPD_allocate, CKind, !FirstClauses[unsigned(CKind)].getInt());
OMPClause *Clause = ParseOpenMPClause(OMPD_allocate, CKind,
!SeenClauses[unsigned(CKind)]);
SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end,
StopBeforeMatch);
FirstClauses[unsigned(CKind)].setInt(true);
SeenClauses[unsigned(CKind)] = true;
if (Clause != nullptr)
Clauses.push_back(Clause);
if (Tok.is(tok::annot_pragma_openmp_end)) {
Expand Down Expand Up @@ -2926,13 +2916,11 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
ImplicitClauseAllowed = false;
Actions.OpenMP().StartOpenMPClause(CKind);
HasImplicitClause = false;
OMPClause *Clause = ParseOpenMPClause(
DKind, CKind, !FirstClauses[unsigned(CKind)].getInt());
FirstClauses[unsigned(CKind)].setInt(true);
if (Clause) {
FirstClauses[unsigned(CKind)].setPointer(Clause);
OMPClause *Clause =
ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]);
SeenClauses[unsigned(CKind)] = true;
if (Clause)
Clauses.push_back(Clause);
}

// Skip ',' if any.
if (Tok.is(tok::comma))
Expand All @@ -2948,7 +2936,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
// If the depend or doacross clause is specified, the ordered construct
// is a stand-alone directive.
for (auto CK : {OMPC_depend, OMPC_doacross}) {
if (FirstClauses[unsigned(CK)].getInt()) {
if (SeenClauses[unsigned(CK)]) {
if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) ==
ParsedStmtContext()) {
Diag(Loc, diag::err_omp_immediate_directive)
Expand All @@ -2960,7 +2948,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
}
}

if (DKind == OMPD_tile && !FirstClauses[unsigned(OMPC_sizes)].getInt()) {
if (DKind == OMPD_tile && !SeenClauses[unsigned(OMPC_sizes)]) {
Diag(Loc, diag::err_omp_required_clause)
<< getOpenMPDirectiveName(OMPD_tile) << "sizes";
}
Expand Down Expand Up @@ -3758,15 +3746,15 @@ OMPClause *Parser::ParseOpenMPOMPXAttributesClause(bool ParseOnly) {
case ParsedAttr::AT_AMDGPUFlatWorkGroupSize:
if (!PA.checkExactlyNumArgs(Actions, 2))
continue;
if (auto *A = Actions.CreateAMDGPUFlatWorkGroupSizeAttr(
if (auto *A = Actions.AMDGPU().CreateAMDGPUFlatWorkGroupSizeAttr(
PA, PA.getArgAsExpr(0), PA.getArgAsExpr(1)))
Attrs.push_back(A);
continue;
case ParsedAttr::AT_AMDGPUWavesPerEU:
if (!PA.checkAtLeastNumArgs(Actions, 1) ||
!PA.checkAtMostNumArgs(Actions, 2))
continue;
if (auto *A = Actions.CreateAMDGPUWavesPerEUAttr(
if (auto *A = Actions.AMDGPU().CreateAMDGPUWavesPerEUAttr(
PA, PA.getArgAsExpr(0),
PA.getNumArgs() > 1 ? PA.getArgAsExpr(1) : nullptr))
Attrs.push_back(A);
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/Sema/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@ add_clang_library(clangSema
Scope.cpp
ScopeInfo.cpp
Sema.cpp
SemaAMDGPU.cpp
SemaARM.cpp
SemaAccess.cpp
SemaAttr.cpp
SemaAPINotes.cpp
SemaAvailability.cpp
SemaBPF.cpp
SemaBase.cpp
SemaCXXScopeSpec.cpp
SemaCast.cpp
Expand All @@ -50,27 +53,34 @@ add_clang_library(clangSema
SemaExprObjC.cpp
SemaFixItUtils.cpp
SemaHLSL.cpp
SemaHexagon.cpp
SemaInit.cpp
SemaLambda.cpp
SemaLookup.cpp
SemaLoongArch.cpp
SemaMIPS.cpp
SemaModule.cpp
SemaNVPTX.cpp
SemaObjC.cpp
SemaObjCProperty.cpp
SemaOpenACC.cpp
SemaOpenMP.cpp
SemaOverload.cpp
SemaPPC.cpp
SemaPseudoObject.cpp
SemaRISCV.cpp
SemaStmt.cpp
SemaStmtAsm.cpp
SemaStmtAttr.cpp
SemaSYCL.cpp
SemaSystemZ.cpp
SemaTemplate.cpp
SemaTemplateDeduction.cpp
SemaTemplateInstantiate.cpp
SemaTemplateInstantiateDecl.cpp
SemaTemplateVariadic.cpp
SemaType.cpp
SemaWasm.cpp
SemaX86.cpp
TypeLocBuilder.cpp

Expand Down
24 changes: 24 additions & 0 deletions clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,27 @@
#include "clang/Sema/RISCVIntrinsicManager.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaAMDGPU.h"
#include "clang/Sema/SemaARM.h"
#include "clang/Sema/SemaBPF.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaCodeCompletion.h"
#include "clang/Sema/SemaConsumer.h"
#include "clang/Sema/SemaHLSL.h"
#include "clang/Sema/SemaHexagon.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaLoongArch.h"
#include "clang/Sema/SemaMIPS.h"
#include "clang/Sema/SemaNVPTX.h"
#include "clang/Sema/SemaObjC.h"
#include "clang/Sema/SemaOpenACC.h"
#include "clang/Sema/SemaOpenMP.h"
#include "clang/Sema/SemaPPC.h"
#include "clang/Sema/SemaPseudoObject.h"
#include "clang/Sema/SemaRISCV.h"
#include "clang/Sema/SemaSYCL.h"
#include "clang/Sema/SemaSystemZ.h"
#include "clang/Sema/SemaWasm.h"
#include "clang/Sema/SemaX86.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/TemplateInstCallback.h"
Expand Down Expand Up @@ -206,16 +216,26 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
LateTemplateParser(nullptr), LateTemplateParserCleanup(nullptr),
OpaqueParser(nullptr), CurContext(nullptr), ExternalSource(nullptr),
CurScope(nullptr), Ident_super(nullptr),
AMDGPUPtr(std::make_unique<SemaAMDGPU>(*this)),
ARMPtr(std::make_unique<SemaARM>(*this)),
BPFPtr(std::make_unique<SemaBPF>(*this)),
CodeCompletionPtr(
std::make_unique<SemaCodeCompletion>(*this, CodeCompleter)),
CUDAPtr(std::make_unique<SemaCUDA>(*this)),
HLSLPtr(std::make_unique<SemaHLSL>(*this)),
HexagonPtr(std::make_unique<SemaHexagon>(*this)),
LoongArchPtr(std::make_unique<SemaLoongArch>(*this)),
MIPSPtr(std::make_unique<SemaMIPS>(*this)),
NVPTXPtr(std::make_unique<SemaNVPTX>(*this)),
ObjCPtr(std::make_unique<SemaObjC>(*this)),
OpenACCPtr(std::make_unique<SemaOpenACC>(*this)),
OpenMPPtr(std::make_unique<SemaOpenMP>(*this)),
PPCPtr(std::make_unique<SemaPPC>(*this)),
PseudoObjectPtr(std::make_unique<SemaPseudoObject>(*this)),
RISCVPtr(std::make_unique<SemaRISCV>(*this)),
SYCLPtr(std::make_unique<SemaSYCL>(*this)),
SystemZPtr(std::make_unique<SemaSystemZ>(*this)),
WasmPtr(std::make_unique<SemaWasm>(*this)),
X86Ptr(std::make_unique<SemaX86>(*this)),
MSPointerToMemberRepresentationMethod(
LangOpts.getMSPointerToMemberRepresentationMethod()),
Expand Down Expand Up @@ -1357,6 +1377,10 @@ void Sema::ActOnEndOfTranslationUnit() {
Consumer.CompleteExternalDeclaration(D);
}

if (LangOpts.HLSL)
HLSL().DiagnoseAvailabilityViolations(
getASTContext().getTranslationUnitDecl());

// If there were errors, disable 'unused' warnings since they will mostly be
// noise. Don't warn for a use from a module: either we should warn on all
// file-scope declarations in modules or not at all, but whether the
Expand Down
311 changes: 311 additions & 0 deletions clang/lib/Sema/SemaAMDGPU.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,311 @@
//===------ SemaAMDGPU.cpp ------- AMDGPU target-specific routines --------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements semantic analysis functions specific to AMDGPU.
//
//===----------------------------------------------------------------------===//

#include "clang/Sema/SemaAMDGPU.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Sema/Ownership.h"
#include "clang/Sema/Sema.h"
#include "llvm/Support/AtomicOrdering.h"
#include <cstdint>

namespace clang {

SemaAMDGPU::SemaAMDGPU(Sema &S) : SemaBase(S) {}

bool SemaAMDGPU::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID,
CallExpr *TheCall) {
// position of memory order and scope arguments in the builtin
unsigned OrderIndex, ScopeIndex;
switch (BuiltinID) {
case AMDGPU::BI__builtin_amdgcn_global_load_lds: {
constexpr const int SizeIdx = 2;
llvm::APSInt Size;
Expr *ArgExpr = TheCall->getArg(SizeIdx);
ExprResult R = SemaRef.VerifyIntegerConstantExpression(ArgExpr, &Size);
if (R.isInvalid())
return true;
switch (Size.getSExtValue()) {
case 1:
case 2:
case 4:
return false;
default:
Diag(ArgExpr->getExprLoc(),
diag::err_amdgcn_global_load_lds_size_invalid_value)
<< ArgExpr->getSourceRange();
Diag(ArgExpr->getExprLoc(),
diag::note_amdgcn_global_load_lds_size_valid_value)
<< ArgExpr->getSourceRange();
return true;
}
}
case AMDGPU::BI__builtin_amdgcn_get_fpenv:
case AMDGPU::BI__builtin_amdgcn_set_fpenv:
return false;
case AMDGPU::BI__builtin_amdgcn_atomic_inc32:
case AMDGPU::BI__builtin_amdgcn_atomic_inc64:
case AMDGPU::BI__builtin_amdgcn_atomic_dec32:
case AMDGPU::BI__builtin_amdgcn_atomic_dec64:
OrderIndex = 2;
ScopeIndex = 3;
break;
case AMDGPU::BI__builtin_amdgcn_fence:
OrderIndex = 0;
ScopeIndex = 1;
break;
default:
return false;
}

ExprResult Arg = TheCall->getArg(OrderIndex);
auto ArgExpr = Arg.get();
Expr::EvalResult ArgResult;

if (!ArgExpr->EvaluateAsInt(ArgResult, getASTContext()))
return Diag(ArgExpr->getExprLoc(), diag::err_typecheck_expect_int)
<< ArgExpr->getType();
auto Ord = ArgResult.Val.getInt().getZExtValue();

// Check validity of memory ordering as per C11 / C++11's memody model.
// Only fence needs check. Atomic dec/inc allow all memory orders.
if (!llvm::isValidAtomicOrderingCABI(Ord))
return Diag(ArgExpr->getBeginLoc(),
diag::warn_atomic_op_has_invalid_memory_order)
<< 0 << ArgExpr->getSourceRange();
switch (static_cast<llvm::AtomicOrderingCABI>(Ord)) {
case llvm::AtomicOrderingCABI::relaxed:
case llvm::AtomicOrderingCABI::consume:
if (BuiltinID == AMDGPU::BI__builtin_amdgcn_fence)
return Diag(ArgExpr->getBeginLoc(),
diag::warn_atomic_op_has_invalid_memory_order)
<< 0 << ArgExpr->getSourceRange();
break;
case llvm::AtomicOrderingCABI::acquire:
case llvm::AtomicOrderingCABI::release:
case llvm::AtomicOrderingCABI::acq_rel:
case llvm::AtomicOrderingCABI::seq_cst:
break;
}

Arg = TheCall->getArg(ScopeIndex);
ArgExpr = Arg.get();
Expr::EvalResult ArgResult1;
// Check that sync scope is a constant literal
if (!ArgExpr->EvaluateAsConstantExpr(ArgResult1, getASTContext()))
return Diag(ArgExpr->getExprLoc(), diag::err_expr_not_string_literal)
<< ArgExpr->getType();

return false;
}

static bool
checkAMDGPUFlatWorkGroupSizeArguments(Sema &S, Expr *MinExpr, Expr *MaxExpr,
const AMDGPUFlatWorkGroupSizeAttr &Attr) {
// Accept template arguments for now as they depend on something else.
// We'll get to check them when they eventually get instantiated.
if (MinExpr->isValueDependent() || MaxExpr->isValueDependent())
return false;

uint32_t Min = 0;
if (!S.checkUInt32Argument(Attr, MinExpr, Min, 0))
return true;

uint32_t Max = 0;
if (!S.checkUInt32Argument(Attr, MaxExpr, Max, 1))
return true;

if (Min == 0 && Max != 0) {
S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
<< &Attr << 0;
return true;
}
if (Min > Max) {
S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
<< &Attr << 1;
return true;
}

return false;
}

AMDGPUFlatWorkGroupSizeAttr *
SemaAMDGPU::CreateAMDGPUFlatWorkGroupSizeAttr(const AttributeCommonInfo &CI,
Expr *MinExpr, Expr *MaxExpr) {
ASTContext &Context = getASTContext();
AMDGPUFlatWorkGroupSizeAttr TmpAttr(Context, CI, MinExpr, MaxExpr);

if (checkAMDGPUFlatWorkGroupSizeArguments(SemaRef, MinExpr, MaxExpr, TmpAttr))
return nullptr;
return ::new (Context)
AMDGPUFlatWorkGroupSizeAttr(Context, CI, MinExpr, MaxExpr);
}

void SemaAMDGPU::addAMDGPUFlatWorkGroupSizeAttr(Decl *D,
const AttributeCommonInfo &CI,
Expr *MinExpr, Expr *MaxExpr) {
if (auto *Attr = CreateAMDGPUFlatWorkGroupSizeAttr(CI, MinExpr, MaxExpr))
D->addAttr(Attr);
}

void SemaAMDGPU::handleAMDGPUFlatWorkGroupSizeAttr(Decl *D,
const ParsedAttr &AL) {
Expr *MinExpr = AL.getArgAsExpr(0);
Expr *MaxExpr = AL.getArgAsExpr(1);

addAMDGPUFlatWorkGroupSizeAttr(D, AL, MinExpr, MaxExpr);
}

static bool checkAMDGPUWavesPerEUArguments(Sema &S, Expr *MinExpr,
Expr *MaxExpr,
const AMDGPUWavesPerEUAttr &Attr) {
if (S.DiagnoseUnexpandedParameterPack(MinExpr) ||
(MaxExpr && S.DiagnoseUnexpandedParameterPack(MaxExpr)))
return true;

// Accept template arguments for now as they depend on something else.
// We'll get to check them when they eventually get instantiated.
if (MinExpr->isValueDependent() || (MaxExpr && MaxExpr->isValueDependent()))
return false;

uint32_t Min = 0;
if (!S.checkUInt32Argument(Attr, MinExpr, Min, 0))
return true;

uint32_t Max = 0;
if (MaxExpr && !S.checkUInt32Argument(Attr, MaxExpr, Max, 1))
return true;

if (Min == 0 && Max != 0) {
S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
<< &Attr << 0;
return true;
}
if (Max != 0 && Min > Max) {
S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
<< &Attr << 1;
return true;
}

return false;
}

AMDGPUWavesPerEUAttr *
SemaAMDGPU::CreateAMDGPUWavesPerEUAttr(const AttributeCommonInfo &CI,
Expr *MinExpr, Expr *MaxExpr) {
ASTContext &Context = getASTContext();
AMDGPUWavesPerEUAttr TmpAttr(Context, CI, MinExpr, MaxExpr);

if (checkAMDGPUWavesPerEUArguments(SemaRef, MinExpr, MaxExpr, TmpAttr))
return nullptr;

return ::new (Context) AMDGPUWavesPerEUAttr(Context, CI, MinExpr, MaxExpr);
}

void SemaAMDGPU::addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI,
Expr *MinExpr, Expr *MaxExpr) {
if (auto *Attr = CreateAMDGPUWavesPerEUAttr(CI, MinExpr, MaxExpr))
D->addAttr(Attr);
}

void SemaAMDGPU::handleAMDGPUWavesPerEUAttr(Decl *D, const ParsedAttr &AL) {
if (!AL.checkAtLeastNumArgs(SemaRef, 1) || !AL.checkAtMostNumArgs(SemaRef, 2))
return;

Expr *MinExpr = AL.getArgAsExpr(0);
Expr *MaxExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr;

addAMDGPUWavesPerEUAttr(D, AL, MinExpr, MaxExpr);
}

void SemaAMDGPU::handleAMDGPUNumSGPRAttr(Decl *D, const ParsedAttr &AL) {
uint32_t NumSGPR = 0;
Expr *NumSGPRExpr = AL.getArgAsExpr(0);
if (!SemaRef.checkUInt32Argument(AL, NumSGPRExpr, NumSGPR))
return;

D->addAttr(::new (getASTContext())
AMDGPUNumSGPRAttr(getASTContext(), AL, NumSGPR));
}

void SemaAMDGPU::handleAMDGPUNumVGPRAttr(Decl *D, const ParsedAttr &AL) {
uint32_t NumVGPR = 0;
Expr *NumVGPRExpr = AL.getArgAsExpr(0);
if (!SemaRef.checkUInt32Argument(AL, NumVGPRExpr, NumVGPR))
return;

D->addAttr(::new (getASTContext())
AMDGPUNumVGPRAttr(getASTContext(), AL, NumVGPR));
}

static bool
checkAMDGPUMaxNumWorkGroupsArguments(Sema &S, Expr *XExpr, Expr *YExpr,
Expr *ZExpr,
const AMDGPUMaxNumWorkGroupsAttr &Attr) {
if (S.DiagnoseUnexpandedParameterPack(XExpr) ||
(YExpr && S.DiagnoseUnexpandedParameterPack(YExpr)) ||
(ZExpr && S.DiagnoseUnexpandedParameterPack(ZExpr)))
return true;

// Accept template arguments for now as they depend on something else.
// We'll get to check them when they eventually get instantiated.
if (XExpr->isValueDependent() || (YExpr && YExpr->isValueDependent()) ||
(ZExpr && ZExpr->isValueDependent()))
return false;

uint32_t NumWG = 0;
Expr *Exprs[3] = {XExpr, YExpr, ZExpr};
for (int i = 0; i < 3; i++) {
if (Exprs[i]) {
if (!S.checkUInt32Argument(Attr, Exprs[i], NumWG, i,
/*StrictlyUnsigned=*/true))
return true;
if (NumWG == 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_is_zero)
<< &Attr << Exprs[i]->getSourceRange();
return true;
}
}
}

return false;
}

AMDGPUMaxNumWorkGroupsAttr *SemaAMDGPU::CreateAMDGPUMaxNumWorkGroupsAttr(
const AttributeCommonInfo &CI, Expr *XExpr, Expr *YExpr, Expr *ZExpr) {
ASTContext &Context = getASTContext();
AMDGPUMaxNumWorkGroupsAttr TmpAttr(Context, CI, XExpr, YExpr, ZExpr);

if (checkAMDGPUMaxNumWorkGroupsArguments(SemaRef, XExpr, YExpr, ZExpr,
TmpAttr))
return nullptr;

return ::new (Context)
AMDGPUMaxNumWorkGroupsAttr(Context, CI, XExpr, YExpr, ZExpr);
}

void SemaAMDGPU::addAMDGPUMaxNumWorkGroupsAttr(Decl *D,
const AttributeCommonInfo &CI,
Expr *XExpr, Expr *YExpr,
Expr *ZExpr) {
if (auto *Attr = CreateAMDGPUMaxNumWorkGroupsAttr(CI, XExpr, YExpr, ZExpr))
D->addAttr(Attr);
}

void SemaAMDGPU::handleAMDGPUMaxNumWorkGroupsAttr(Decl *D,
const ParsedAttr &AL) {
Expr *YExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr;
Expr *ZExpr = (AL.getNumArgs() > 2) ? AL.getArgAsExpr(2) : nullptr;
addAMDGPUMaxNumWorkGroupsAttr(D, AL, AL.getArgAsExpr(0), YExpr, ZExpr);
}

} // namespace clang
1,088 changes: 1,088 additions & 0 deletions clang/lib/Sema/SemaARM.cpp

Large diffs are not rendered by default.

24 changes: 18 additions & 6 deletions clang/lib/Sema/SemaAvailability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DelayedDiagnostic.h"
Expand Down Expand Up @@ -228,8 +229,9 @@ shouldDiagnoseAvailabilityByDefault(const ASTContext &Context,
ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13);
break;
case llvm::Triple::ShaderModel:
// Always enable availability diagnostics for shader models.
return true;
// FIXME: This will be updated when HLSL strict diagnostic mode
// is implemented (issue #90096)
return false;
default:
// New targets should always warn about availability.
return Triple.getVendor() == llvm::Triple::Apple;
Expand Down Expand Up @@ -409,10 +411,11 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
std::string PlatformName(
AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
llvm::StringRef TargetEnvironment(AvailabilityAttr::getPrettyEnviromentName(
TI.getTriple().getEnvironmentName()));
TI.getTriple().getEnvironment()));
llvm::StringRef AttrEnvironment =
AA->getEnvironment() ? AvailabilityAttr::getPrettyEnviromentName(
AA->getEnvironment()->getName())
AvailabilityAttr::getEnvironmentType(
AA->getEnvironment()->getName()))
: "";
bool UseEnvironment =
(!AttrEnvironment.empty() && !TargetEnvironment.empty());
Expand All @@ -438,6 +441,10 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
<< S.Context.getTargetInfo().getPlatformMinVersion().getAsString()
<< UseEnvironment << AttrEnvironment << TargetEnvironment;

// Do not offer to silence the warning or fixits for HLSL
if (S.getLangOpts().HLSL)
return;

if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) {
if (const auto *TD = dyn_cast<TagDecl>(Enclosing))
if (TD->getDeclName().isEmpty()) {
Expand Down Expand Up @@ -839,10 +846,11 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
std::string PlatformName(
AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
llvm::StringRef TargetEnvironment(AvailabilityAttr::getPrettyEnviromentName(
TI.getTriple().getEnvironmentName()));
TI.getTriple().getEnvironment()));
llvm::StringRef AttrEnvironment =
AA->getEnvironment() ? AvailabilityAttr::getPrettyEnviromentName(
AA->getEnvironment()->getName())
AvailabilityAttr::getEnvironmentType(
AA->getEnvironment()->getName()))
: "";
bool UseEnvironment =
(!AttrEnvironment.empty() && !TargetEnvironment.empty());
Expand All @@ -865,6 +873,10 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
<< SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString()
<< UseEnvironment << AttrEnvironment << TargetEnvironment;

// Do not offer to silence the warning or fixits for HLSL
if (SemaRef.getLangOpts().HLSL)
return;

auto FixitDiag =
SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence)
<< Range << D
Expand Down
174 changes: 174 additions & 0 deletions clang/lib/Sema/SemaBPF.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
//===------ SemaBPF.cpp ---------- BPF target-specific routines -----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements semantic analysis functions specific to BPF.
//
//===----------------------------------------------------------------------===//

#include "clang/Sema/SemaBPF.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Type.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Sema/Sema.h"
#include "llvm/ADT/APSInt.h"
#include <optional>

namespace clang {

SemaBPF::SemaBPF(Sema &S) : SemaBase(S) {}

static bool isValidPreserveFieldInfoArg(Expr *Arg) {
if (Arg->getType()->getAsPlaceholderType())
return false;

// The first argument needs to be a record field access.
// If it is an array element access, we delay decision
// to BPF backend to check whether the access is a
// field access or not.
return (Arg->IgnoreParens()->getObjectKind() == OK_BitField ||
isa<MemberExpr>(Arg->IgnoreParens()) ||
isa<ArraySubscriptExpr>(Arg->IgnoreParens()));
}

static bool isValidPreserveTypeInfoArg(Expr *Arg) {
QualType ArgType = Arg->getType();
if (ArgType->getAsPlaceholderType())
return false;

// for TYPE_EXISTENCE/TYPE_MATCH/TYPE_SIZEOF reloc type
// format:
// 1. __builtin_preserve_type_info(*(<type> *)0, flag);
// 2. <type> var;
// __builtin_preserve_type_info(var, flag);
if (!isa<DeclRefExpr>(Arg->IgnoreParens()) &&
!isa<UnaryOperator>(Arg->IgnoreParens()))
return false;

// Typedef type.
if (ArgType->getAs<TypedefType>())
return true;

// Record type or Enum type.
const Type *Ty = ArgType->getUnqualifiedDesugaredType();
if (const auto *RT = Ty->getAs<RecordType>()) {
if (!RT->getDecl()->getDeclName().isEmpty())
return true;
} else if (const auto *ET = Ty->getAs<EnumType>()) {
if (!ET->getDecl()->getDeclName().isEmpty())
return true;
}

return false;
}

static bool isValidPreserveEnumValueArg(Expr *Arg) {
QualType ArgType = Arg->getType();
if (ArgType->getAsPlaceholderType())
return false;

// for ENUM_VALUE_EXISTENCE/ENUM_VALUE reloc type
// format:
// __builtin_preserve_enum_value(*(<enum_type> *)<enum_value>,
// flag);
const auto *UO = dyn_cast<UnaryOperator>(Arg->IgnoreParens());
if (!UO)
return false;

const auto *CE = dyn_cast<CStyleCastExpr>(UO->getSubExpr());
if (!CE)
return false;
if (CE->getCastKind() != CK_IntegralToPointer &&
CE->getCastKind() != CK_NullToPointer)
return false;

// The integer must be from an EnumConstantDecl.
const auto *DR = dyn_cast<DeclRefExpr>(CE->getSubExpr());
if (!DR)
return false;

const EnumConstantDecl *Enumerator =
dyn_cast<EnumConstantDecl>(DR->getDecl());
if (!Enumerator)
return false;

// The type must be EnumType.
const Type *Ty = ArgType->getUnqualifiedDesugaredType();
const auto *ET = Ty->getAs<EnumType>();
if (!ET)
return false;

// The enum value must be supported.
return llvm::is_contained(ET->getDecl()->enumerators(), Enumerator);
}

bool SemaBPF::CheckBPFBuiltinFunctionCall(unsigned BuiltinID,
CallExpr *TheCall) {
assert((BuiltinID == BPF::BI__builtin_preserve_field_info ||
BuiltinID == BPF::BI__builtin_btf_type_id ||
BuiltinID == BPF::BI__builtin_preserve_type_info ||
BuiltinID == BPF::BI__builtin_preserve_enum_value) &&
"unexpected BPF builtin");
ASTContext &Context = getASTContext();
if (SemaRef.checkArgCount(TheCall, 2))
return true;

// The second argument needs to be a constant int
Expr *Arg = TheCall->getArg(1);
std::optional<llvm::APSInt> Value = Arg->getIntegerConstantExpr(Context);
diag::kind kind;
if (!Value) {
if (BuiltinID == BPF::BI__builtin_preserve_field_info)
kind = diag::err_preserve_field_info_not_const;
else if (BuiltinID == BPF::BI__builtin_btf_type_id)
kind = diag::err_btf_type_id_not_const;
else if (BuiltinID == BPF::BI__builtin_preserve_type_info)
kind = diag::err_preserve_type_info_not_const;
else
kind = diag::err_preserve_enum_value_not_const;
Diag(Arg->getBeginLoc(), kind) << 2 << Arg->getSourceRange();
return true;
}

// The first argument
Arg = TheCall->getArg(0);
bool InvalidArg = false;
bool ReturnUnsignedInt = true;
if (BuiltinID == BPF::BI__builtin_preserve_field_info) {
if (!isValidPreserveFieldInfoArg(Arg)) {
InvalidArg = true;
kind = diag::err_preserve_field_info_not_field;
}
} else if (BuiltinID == BPF::BI__builtin_preserve_type_info) {
if (!isValidPreserveTypeInfoArg(Arg)) {
InvalidArg = true;
kind = diag::err_preserve_type_info_invalid;
}
} else if (BuiltinID == BPF::BI__builtin_preserve_enum_value) {
if (!isValidPreserveEnumValueArg(Arg)) {
InvalidArg = true;
kind = diag::err_preserve_enum_value_invalid;
}
ReturnUnsignedInt = false;
} else if (BuiltinID == BPF::BI__builtin_btf_type_id) {
ReturnUnsignedInt = false;
}

if (InvalidArg) {
Diag(Arg->getBeginLoc(), kind) << 1 << Arg->getSourceRange();
return true;
}

if (ReturnUnsignedInt)
TheCall->setType(Context.UnsignedIntTy);
else
TheCall->setType(Context.UnsignedLongTy);
return false;
}

} // namespace clang
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ SemaBase::ImmediateDiagBuilder::~ImmediateDiagBuilder() {
SemaRef.EmitCurrentDiagnostic(DiagID);
}

PartialDiagnostic SemaBase::PDiag(unsigned DiagID) {
return PartialDiagnostic(DiagID, SemaRef.Context.getDiagAllocator());
}

const SemaBase::SemaDiagnosticBuilder &
operator<<(const SemaBase::SemaDiagnosticBuilder &Diag,
const PartialDiagnostic &PD) {
Expand Down
3,064 changes: 47 additions & 3,017 deletions clang/lib/Sema/SemaChecking.cpp

Large diffs are not rendered by default.

29 changes: 15 additions & 14 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaObjC.h"
#include "clang/Sema/SemaOpenMP.h"
#include "clang/Sema/SemaPPC.h"
#include "clang/Sema/SemaRISCV.h"
#include "clang/Sema/SemaWasm.h"
#include "clang/Sema/Template.h"
#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/SmallString.h"
Expand Down Expand Up @@ -538,8 +540,9 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
} else if (AllowDeducedTemplate) {
if (auto *TD = getAsTypeTemplateDecl(IIDecl)) {
assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD);
TemplateName Template =
FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD);
TemplateName Template = Context.getQualifiedTemplateName(
SS ? SS->getScopeRep() : nullptr, /*TemplateKeyword=*/false,
FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD));
T = Context.getDeducedTemplateSpecializationType(Template, QualType(),
false);
// Don't wrap in a further UsingType.
Expand Down Expand Up @@ -1137,12 +1140,10 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
dyn_cast<UsingShadowDecl>(*Result.begin());
assert(!FoundUsingShadow ||
TD == cast<TemplateDecl>(FoundUsingShadow->getTargetDecl()));
Template =
FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD);
if (SS.isNotEmpty())
Template = Context.getQualifiedTemplateName(SS.getScopeRep(),
/*TemplateKeyword=*/false,
Template);
Template = Context.getQualifiedTemplateName(
SS.getScopeRep(),
/*TemplateKeyword=*/false,
FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD));
} else {
// All results were non-template functions. This is a function template
// name.
Expand Down Expand Up @@ -2930,9 +2931,9 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
else if (const auto *UA = dyn_cast<UuidAttr>(Attr))
NewAttr = S.mergeUuidAttr(D, *UA, UA->getGuid(), UA->getGuidDecl());
else if (const auto *IMA = dyn_cast<WebAssemblyImportModuleAttr>(Attr))
NewAttr = S.mergeImportModuleAttr(D, *IMA);
NewAttr = S.Wasm().mergeImportModuleAttr(D, *IMA);
else if (const auto *INA = dyn_cast<WebAssemblyImportNameAttr>(Attr))
NewAttr = S.mergeImportNameAttr(D, *INA);
NewAttr = S.Wasm().mergeImportNameAttr(D, *INA);
else if (const auto *TCBA = dyn_cast<EnforceTCBAttr>(Attr))
NewAttr = S.mergeEnforceTCBAttr(D, *TCBA);
else if (const auto *TCBLA = dyn_cast<EnforceTCBLeafAttr>(Attr))
Expand Down Expand Up @@ -8896,7 +8897,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
// PPC MMA non-pointer types are not allowed as non-local variable types.
if (Context.getTargetInfo().getTriple().isPPC64() &&
!NewVD->isLocalVarDecl() &&
CheckPPCMMAType(T, NewVD->getLocation())) {
PPC().CheckPPCMMAType(T, NewVD->getLocation())) {
NewVD->setInvalidDecl();
return;
}
Expand Down Expand Up @@ -12057,7 +12058,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,

// PPC MMA non-pointer types are not allowed as function return types.
if (Context.getTargetInfo().getTriple().isPPC64() &&
CheckPPCMMAType(NewFD->getReturnType(), NewFD->getLocation())) {
PPC().CheckPPCMMAType(NewFD->getReturnType(), NewFD->getLocation())) {
NewFD->setInvalidDecl();
}

Expand Down Expand Up @@ -15349,7 +15350,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,

// PPC MMA non-pointer types are not allowed as function argument types.
if (Context.getTargetInfo().getTriple().isPPC64() &&
CheckPPCMMAType(New->getOriginalType(), New->getLocation())) {
PPC().CheckPPCMMAType(New->getOriginalType(), New->getLocation())) {
New->setInvalidDecl();
}

Expand Down Expand Up @@ -18764,7 +18765,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,

// PPC MMA non-pointer types are not allowed as field types.
if (Context.getTargetInfo().getTriple().isPPC64() &&
CheckPPCMMAType(T, NewFD->getLocation()))
PPC().CheckPPCMMAType(T, NewFD->getLocation()))
NewFD->setInvalidDecl();

NewFD->setAccess(AS);
Expand Down
445 changes: 51 additions & 394 deletions clang/lib/Sema/SemaDeclAttr.cpp

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11547,12 +11547,12 @@ bool Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName();
bool TemplateMatches =
Context.hasSameTemplateName(SpecifiedName, GuidedTemplate);
auto TKind = SpecifiedName.getKind();
// A Using TemplateName can't actually be valid (either it's qualified, or
// we're in the wrong scope). But we have diagnosed these problems
// already.
bool SimplyWritten = TKind == TemplateName::Template ||
TKind == TemplateName::UsingTemplate;

const QualifiedTemplateName *Qualifiers =
SpecifiedName.getAsQualifiedTemplateName();
assert(Qualifiers && "expected QualifiedTemplate");
bool SimplyWritten = !Qualifiers->hasTemplateKeyword() &&
Qualifiers->getQualifier() == nullptr;
if (SimplyWritten && TemplateMatches)
AcceptableReturnType = true;
else {
Expand Down
38 changes: 17 additions & 21 deletions clang/lib/Sema/SemaDeclObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -567,9 +567,8 @@ void SemaObjC::ActOnSuperClassOfClassInterface(
if (TypoCorrection Corrected = SemaRef.CorrectTypo(
DeclarationNameInfo(SuperName, SuperLoc), Sema::LookupOrdinaryName,
SemaRef.TUScope, nullptr, CCC, Sema::CTK_ErrorRecovery)) {
SemaRef.diagnoseTypo(Corrected,
SemaRef.PDiag(diag::err_undef_superclass_suggest)
<< SuperName << ClassName);
SemaRef.diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest)
<< SuperName << ClassName);
PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>();
}
}
Expand Down Expand Up @@ -1322,9 +1321,9 @@ void SemaObjC::FindProtocolDeclaration(bool WarnOnDeclarations,
Sema::LookupObjCProtocolName, SemaRef.TUScope,
nullptr, CCC, Sema::CTK_ErrorRecovery);
if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>()))
SemaRef.diagnoseTypo(
Corrected, SemaRef.PDiag(diag::err_undeclared_protocol_suggest)
<< Pair.first);
SemaRef.diagnoseTypo(Corrected,
PDiag(diag::err_undeclared_protocol_suggest)
<< Pair.first);
}

if (!PDecl) {
Expand Down Expand Up @@ -1703,9 +1702,9 @@ void SemaObjC::actOnObjCTypeArgsOrProtocolQualifiers(
if (corrected) {
// Did we find a protocol?
if (auto proto = corrected.getCorrectionDeclAs<ObjCProtocolDecl>()) {
SemaRef.diagnoseTypo(
corrected, SemaRef.PDiag(diag::err_undeclared_protocol_suggest)
<< identifiers[i]);
SemaRef.diagnoseTypo(corrected,
PDiag(diag::err_undeclared_protocol_suggest)
<< identifiers[i]);
lookupKind = Sema::LookupObjCProtocolName;
protocols[i] = proto;
++numProtocolsResolved;
Expand All @@ -1715,7 +1714,7 @@ void SemaObjC::actOnObjCTypeArgsOrProtocolQualifiers(
// Did we find a type?
if (auto typeDecl = corrected.getCorrectionDeclAs<TypeDecl>()) {
SemaRef.diagnoseTypo(corrected,
SemaRef.PDiag(diag::err_unknown_typename_suggest)
PDiag(diag::err_unknown_typename_suggest)
<< identifiers[i]);
lookupKind = Sema::LookupOrdinaryName;
typeDecls[i] = typeDecl;
Expand All @@ -1725,10 +1724,9 @@ void SemaObjC::actOnObjCTypeArgsOrProtocolQualifiers(

// Did we find an Objective-C class?
if (auto objcClass = corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) {
SemaRef.diagnoseTypo(
corrected,
SemaRef.PDiag(diag::err_unknown_type_or_class_name_suggest)
<< identifiers[i] << true);
SemaRef.diagnoseTypo(corrected,
PDiag(diag::err_unknown_type_or_class_name_suggest)
<< identifiers[i] << true);
lookupKind = Sema::LookupOrdinaryName;
typeDecls[i] = objcClass;
++numTypeDeclsResolved;
Expand Down Expand Up @@ -2009,10 +2007,9 @@ ObjCImplementationDecl *SemaObjC::ActOnStartClassImplementation(
// Suggest the (potentially) correct interface name. Don't provide a
// code-modification hint or use the typo name for recovery, because
// this is just a warning. The program may actually be correct.
SemaRef.diagnoseTypo(Corrected,
SemaRef.PDiag(diag::warn_undef_interface_suggest)
<< ClassName,
/*ErrorRecovery*/ false);
SemaRef.diagnoseTypo(
Corrected, PDiag(diag::warn_undef_interface_suggest) << ClassName,
/*ErrorRecovery*/ false);
} else {
Diag(ClassLoc, diag::warn_undef_interface) << ClassName;
}
Expand Down Expand Up @@ -5439,8 +5436,7 @@ ObjCInterfaceDecl *SemaObjC::getObjCInterfaceDecl(const IdentifierInfo *&Id,
if (TypoCorrection C = SemaRef.CorrectTypo(
DeclarationNameInfo(Id, IdLoc), Sema::LookupOrdinaryName,
SemaRef.TUScope, nullptr, CCC, Sema::CTK_ErrorRecovery)) {
SemaRef.diagnoseTypo(C, SemaRef.PDiag(diag::err_undef_interface_suggest)
<< Id);
SemaRef.diagnoseTypo(C, PDiag(diag::err_undef_interface_suggest) << Id);
IDecl = C.getCorrectionDeclAs<ObjCInterfaceDecl>();
Id = IDecl->getIdentifier();
}
Expand Down Expand Up @@ -5544,7 +5540,7 @@ void SemaObjC::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
SemaRef.MarkFunctionReferenced(Field->getLocation(), Destructor);
SemaRef.CheckDestructorAccess(
Field->getLocation(), Destructor,
SemaRef.PDiag(diag::err_access_dtor_ivar)
PDiag(diag::err_access_dtor_ivar)
<< Context.getBaseElementType(Field->getType()));
}
}
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3284,10 +3284,10 @@ ExprResult Sema::BuildDeclarationNameExpr(
return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {});
}

if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) {
if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) {
// Specifically diagnose references to class templates that are missing
// a template argument list.
diagnoseMissingTemplateArguments(TemplateName(Template), Loc);
diagnoseMissingTemplateArguments(SS, /*TemplateKeyword=*/false, TD, Loc);
return ExprError();
}

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaLambda.h"
#include "clang/Sema/SemaObjC.h"
#include "clang/Sema/SemaPPC.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/APInt.h"
Expand Down Expand Up @@ -931,7 +932,7 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,

// PPC MMA non-pointer types are not allowed as throw expr types.
if (Ex && Context.getTargetInfo().getTriple().isPPC64())
CheckPPCMMAType(Ex->getType(), Ex->getBeginLoc());
PPC().CheckPPCMMAType(Ex->getType(), Ex->getBeginLoc());

return new (Context)
CXXThrowExpr(Ex, Context.VoidTy, OpLoc, IsThrownVarInScope);
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaExprMember.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1194,7 +1194,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,

if (VarTemplateDecl *VarTempl = dyn_cast<VarTemplateDecl>(MemberDecl)) {
if (!TemplateArgs) {
diagnoseMissingTemplateArguments(TemplateName(VarTempl), MemberLoc);
diagnoseMissingTemplateArguments(
SS, /*TemplateKeyword=*/TemplateKWLoc.isValid(), VarTempl, MemberLoc);
return ExprError();
}

Expand Down
10 changes: 5 additions & 5 deletions clang/lib/Sema/SemaExprObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2134,7 +2134,7 @@ ExprResult SemaObjC::HandleExprPropertyRefExpr(
}
} else {
SemaRef.diagnoseTypo(Corrected,
SemaRef.PDiag(diag::err_property_not_found_suggest)
PDiag(diag::err_property_not_found_suggest)
<< MemberName << QualType(OPT, 0));
return HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc,
TypoResult, MemberLoc,
Expand Down Expand Up @@ -2369,15 +2369,15 @@ SemaObjC::getObjCMessageKind(Scope *S, IdentifierInfo *Name,
if (Corrected.isKeyword()) {
// If we've found the keyword "super" (the only keyword that would be
// returned by CorrectTypo), this is a send to super.
SemaRef.diagnoseTypo(
Corrected, SemaRef.PDiag(diag::err_unknown_receiver_suggest) << Name);
SemaRef.diagnoseTypo(Corrected, PDiag(diag::err_unknown_receiver_suggest)
<< Name);
return ObjCSuperMessage;
} else if (ObjCInterfaceDecl *Class =
Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) {
// If we found a declaration, correct when it refers to an Objective-C
// class.
SemaRef.diagnoseTypo(
Corrected, SemaRef.PDiag(diag::err_unknown_receiver_suggest) << Name);
SemaRef.diagnoseTypo(Corrected, PDiag(diag::err_unknown_receiver_suggest)
<< Name);
QualType T = Context.getObjCInterfaceType(Class);
TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc);
ReceiverType = SemaRef.CreateParsedType(T, TSInfo);
Expand Down
297 changes: 297 additions & 0 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@
//===----------------------------------------------------------------------===//

#include "clang/Sema/SemaHLSL.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/Sema.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/TargetParser/Triple.h"
#include <iterator>
Expand Down Expand Up @@ -290,3 +294,296 @@ void SemaHLSL::DiagnoseAttrStageMismatch(
<< A << HLSLShaderAttr::ConvertShaderTypeToStr(Stage)
<< (AllowedStages.size() != 1) << join(StageStrings, ", ");
}

namespace {

/// This class implements HLSL availability diagnostics for default
/// and relaxed mode
///
/// The goal of this diagnostic is to emit an error or warning when an
/// unavailable API is found in code that is reachable from the shader
/// entry function or from an exported function (when compiling a shader
/// library).
///
/// This is done by traversing the AST of all shader entry point functions
/// and of all exported functions, and any functions that are refrenced
/// from this AST. In other words, any functions that are reachable from
/// the entry points.
class DiagnoseHLSLAvailability
: public RecursiveASTVisitor<DiagnoseHLSLAvailability> {

Sema &SemaRef;

// Stack of functions to be scaned
llvm::SmallVector<const FunctionDecl *, 8> DeclsToScan;

// Tracks which environments functions have been scanned in.
//
// Maps FunctionDecl to an unsigned number that represents the set of shader
// environments the function has been scanned for.
// Since HLSLShaderAttr::ShaderType enum is generated from Attr.td and is
// defined without any assigned values, it is guaranteed to be numbered
// sequentially from 0 up and we can use it to 'index' individual bits
// in the set.
// The N'th bit in the set will be set if the function has been scanned
// in shader environment whose ShaderType integer value equals N.
// For example, if a function has been scanned in compute and pixel stage
// environment, the value will be 0x21 (100001 binary) because
// (int)HLSLShaderAttr::ShaderType::Pixel == 1 and
// (int)HLSLShaderAttr::ShaderType::Compute == 5.
// A FunctionDecl is mapped to 0 (or not included in the map) if it has not
// been scanned in any environment.
llvm::DenseMap<const FunctionDecl *, unsigned> ScannedDecls;

// Do not access these directly, use the get/set methods below to make
// sure the values are in sync
llvm::Triple::EnvironmentType CurrentShaderEnvironment;
unsigned CurrentShaderStageBit;

// True if scanning a function that was already scanned in a different
// shader stage context, and therefore we should not report issues that
// depend only on shader model version because they would be duplicate.
bool ReportOnlyShaderStageIssues;

// Helper methods for dealing with current stage context / environment
void SetShaderStageContext(HLSLShaderAttr::ShaderType ShaderType) {
static_assert(sizeof(unsigned) >= 4);
assert((unsigned)ShaderType < 31); // 31 is reserved for "unknown"

CurrentShaderEnvironment = HLSLShaderAttr::getTypeAsEnvironment(ShaderType);
CurrentShaderStageBit = (1 << ShaderType);
}

void SetUnknownShaderStageContext() {
CurrentShaderEnvironment = llvm::Triple::UnknownEnvironment;
CurrentShaderStageBit = (1 << 31);
}

llvm::Triple::EnvironmentType GetCurrentShaderEnvironment() const {
return CurrentShaderEnvironment;
}

bool InUnknownShaderStageContext() const {
return CurrentShaderEnvironment == llvm::Triple::UnknownEnvironment;
}

// Helper methods for dealing with shader stage bitmap
void AddToScannedFunctions(const FunctionDecl *FD) {
unsigned &ScannedStages = ScannedDecls.getOrInsertDefault(FD);
ScannedStages |= CurrentShaderStageBit;
}

unsigned GetScannedStages(const FunctionDecl *FD) {
return ScannedDecls.getOrInsertDefault(FD);
}

bool WasAlreadyScannedInCurrentStage(const FunctionDecl *FD) {
return WasAlreadyScannedInCurrentStage(GetScannedStages(FD));
}

bool WasAlreadyScannedInCurrentStage(unsigned ScannerStages) {
return ScannerStages & CurrentShaderStageBit;
}

static bool NeverBeenScanned(unsigned ScannedStages) {
return ScannedStages == 0;
}

// Scanning methods
void HandleFunctionOrMethodRef(FunctionDecl *FD, Expr *RefExpr);
void CheckDeclAvailability(NamedDecl *D, const AvailabilityAttr *AA,
SourceRange Range);
const AvailabilityAttr *FindAvailabilityAttr(const Decl *D);
bool HasMatchingEnvironmentOrNone(const AvailabilityAttr *AA);

public:
DiagnoseHLSLAvailability(Sema &SemaRef) : SemaRef(SemaRef) {}

// AST traversal methods
void RunOnTranslationUnit(const TranslationUnitDecl *TU);
void RunOnFunction(const FunctionDecl *FD);

bool VisitDeclRefExpr(DeclRefExpr *DRE) {
FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(DRE->getDecl());
if (FD)
HandleFunctionOrMethodRef(FD, DRE);
return true;
}

bool VisitMemberExpr(MemberExpr *ME) {
FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(ME->getMemberDecl());
if (FD)
HandleFunctionOrMethodRef(FD, ME);
return true;
}
};

void DiagnoseHLSLAvailability::HandleFunctionOrMethodRef(FunctionDecl *FD,
Expr *RefExpr) {
assert((isa<DeclRefExpr>(RefExpr) || isa<MemberExpr>(RefExpr)) &&
"expected DeclRefExpr or MemberExpr");

// has a definition -> add to stack to be scanned
const FunctionDecl *FDWithBody = nullptr;
if (FD->hasBody(FDWithBody)) {
if (!WasAlreadyScannedInCurrentStage(FDWithBody))
DeclsToScan.push_back(FDWithBody);
return;
}

// no body -> diagnose availability
const AvailabilityAttr *AA = FindAvailabilityAttr(FD);
if (AA)
CheckDeclAvailability(
FD, AA, SourceRange(RefExpr->getBeginLoc(), RefExpr->getEndLoc()));
}

void DiagnoseHLSLAvailability::RunOnTranslationUnit(
const TranslationUnitDecl *TU) {
// Iterate over all shader entry functions and library exports, and for those
// that have a body (definiton), run diag scan on each, setting appropriate
// shader environment context based on whether it is a shader entry function
// or an exported function.
for (auto &D : TU->decls()) {
const FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(D);
if (!FD || !FD->isThisDeclarationADefinition())
continue;

// shader entry point
auto ShaderAttr = FD->getAttr<HLSLShaderAttr>();
if (ShaderAttr) {
SetShaderStageContext(ShaderAttr->getType());
RunOnFunction(FD);
continue;
}
// exported library function with definition
// FIXME: tracking issue #92073
#if 0
if (FD->getFormalLinkage() == Linkage::External) {
SetUnknownShaderStageContext();
RunOnFunction(FD);
}
#endif
}
}

void DiagnoseHLSLAvailability::RunOnFunction(const FunctionDecl *FD) {
assert(DeclsToScan.empty() && "DeclsToScan should be empty");
DeclsToScan.push_back(FD);

while (!DeclsToScan.empty()) {
// Take one decl from the stack and check it by traversing its AST.
// For any CallExpr found during the traversal add it's callee to the top of
// the stack to be processed next. Functions already processed are stored in
// ScannedDecls.
const FunctionDecl *FD = DeclsToScan.back();
DeclsToScan.pop_back();

// Decl was already scanned
const unsigned ScannedStages = GetScannedStages(FD);
if (WasAlreadyScannedInCurrentStage(ScannedStages))
continue;

ReportOnlyShaderStageIssues = !NeverBeenScanned(ScannedStages);

AddToScannedFunctions(FD);
TraverseStmt(FD->getBody());
}
}

bool DiagnoseHLSLAvailability::HasMatchingEnvironmentOrNone(
const AvailabilityAttr *AA) {
IdentifierInfo *IIEnvironment = AA->getEnvironment();
if (!IIEnvironment)
return true;

llvm::Triple::EnvironmentType CurrentEnv = GetCurrentShaderEnvironment();
if (CurrentEnv == llvm::Triple::UnknownEnvironment)
return false;

llvm::Triple::EnvironmentType AttrEnv =
AvailabilityAttr::getEnvironmentType(IIEnvironment->getName());

return CurrentEnv == AttrEnv;
}

const AvailabilityAttr *
DiagnoseHLSLAvailability::FindAvailabilityAttr(const Decl *D) {
AvailabilityAttr const *PartialMatch = nullptr;
// Check each AvailabilityAttr to find the one for this platform.
// For multiple attributes with the same platform try to find one for this
// environment.
for (const auto *A : D->attrs()) {
if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
StringRef AttrPlatform = Avail->getPlatform()->getName();
StringRef TargetPlatform =
SemaRef.getASTContext().getTargetInfo().getPlatformName();

// Match the platform name.
if (AttrPlatform == TargetPlatform) {
// Find the best matching attribute for this environment
if (HasMatchingEnvironmentOrNone(Avail))
return Avail;
PartialMatch = Avail;
}
}
}
return PartialMatch;
}

// Check availability against target shader model version and current shader
// stage and emit diagnostic
void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D,
const AvailabilityAttr *AA,
SourceRange Range) {
if (ReportOnlyShaderStageIssues && !AA->getEnvironment())
return;

bool EnvironmentMatches = HasMatchingEnvironmentOrNone(AA);
VersionTuple Introduced = AA->getIntroduced();
VersionTuple TargetVersion =
SemaRef.Context.getTargetInfo().getPlatformMinVersion();

if (TargetVersion >= Introduced && EnvironmentMatches)
return;

// Do not diagnose shade-stage-specific availability when the shader stage
// context is unknown
if (InUnknownShaderStageContext() && AA->getEnvironment() != nullptr)
return;

// Emit diagnostic message
const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo();
llvm::StringRef PlatformName(
AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));

llvm::StringRef CurrentEnvStr =
AvailabilityAttr::getPrettyEnviromentName(GetCurrentShaderEnvironment());

llvm::StringRef AttrEnvStr = AA->getEnvironment()
? AvailabilityAttr::getPrettyEnviromentName(
AvailabilityAttr::getEnvironmentType(
AA->getEnvironment()->getName()))
: "";
bool UseEnvironment = !AttrEnvStr.empty();

if (EnvironmentMatches) {
SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability)
<< Range << D << PlatformName << Introduced.getAsString()
<< UseEnvironment << CurrentEnvStr;
} else {
SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability_unavailable)
<< Range << D;
}

SemaRef.Diag(D->getLocation(), diag::note_partial_availability_specified_here)
<< D << PlatformName << Introduced.getAsString()
<< SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString()
<< UseEnvironment << AttrEnvStr << CurrentEnvStr;
}

} // namespace

void SemaHLSL::DiagnoseAvailabilityViolations(TranslationUnitDecl *TU) {
DiagnoseHLSLAvailability(SemaRef).RunOnTranslationUnit(TU);
}
Loading