40 changes: 31 additions & 9 deletions clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -471,23 +471,25 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasSVE2 && HasSVE2SM4)
Builder.defineMacro("__ARM_FEATURE_SVE2_SM4", "1");

if (HasSVEB16B16)
Builder.defineMacro("__ARM_FEATURE_SVE_B16B16", "1");

if (HasSME) {
Builder.defineMacro("__ARM_FEATURE_SME");
Builder.defineMacro("__ARM_FEATURE_LOCALLY_STREAMING", "1");
}

if (HasSME2) {
Builder.defineMacro("__ARM_FEATURE_SME", "1");
if (HasSME2)
Builder.defineMacro("__ARM_FEATURE_SME2", "1");
Builder.defineMacro("__ARM_FEATURE_LOCALLY_STREAMING", "1");
}

if (HasSME2p1) {
Builder.defineMacro("__ARM_FEATURE_SME", "1");
Builder.defineMacro("__ARM_FEATURE_SME2", "1");
if (HasSME2p1)
Builder.defineMacro("__ARM_FEATURE_SME2p1", "1");
Builder.defineMacro("__ARM_FEATURE_LOCALLY_STREAMING", "1");
}

if (HasSMEF16F16)
Builder.defineMacro("__ARM_FEATURE_SME_F16F16", "1");

if (HasSMEB16B16)
Builder.defineMacro("__ARM_FEATURE_SME_B16B16", "1");

if (HasCRC)
Builder.defineMacro("__ARM_FEATURE_CRC32", "1");
Expand Down Expand Up @@ -749,6 +751,7 @@ bool AArch64TargetInfo::hasFeature(StringRef Feature) const {
.Case("sve", FPU & SveMode)
.Case("sve-bf16", FPU & SveMode && HasBFloat16)
.Case("sve-i8mm", FPU & SveMode && HasMatMul)
.Case("sve-b16b16", HasSVEB16B16)
.Case("f32mm", FPU & SveMode && HasMatmulFP32)
.Case("f64mm", FPU & SveMode && HasMatmulFP64)
.Case("sve2", FPU & SveMode && HasSVE2)
Expand All @@ -763,6 +766,8 @@ bool AArch64TargetInfo::hasFeature(StringRef Feature) const {
.Case("sme-f64f64", HasSMEF64F64)
.Case("sme-i16i64", HasSMEI16I64)
.Case("sme-fa64", HasSMEFA64)
.Case("sme-f16f16", HasSMEF16F16)
.Case("sme-b16b16", HasSMEB16B16)
.Cases("memtag", "memtag2", HasMTE)
.Case("sb", HasSB)
.Case("predres", HasPredRes)
Expand Down Expand Up @@ -863,6 +868,8 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasSVE2 = true;
HasSVE2SM4 = true;
}
if (Feature == "+sve-b16b16")
HasSVEB16B16 = true;
if (Feature == "+sve2-bitperm") {
FPU |= NeonMode;
FPU |= SveMode;
Expand Down Expand Up @@ -919,6 +926,21 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasSVE2 = true;
HasSMEFA64 = true;
}
if (Feature == "+sme-f16f16") {
HasSME = true;
HasSME2 = true;
HasBFloat16 = true;
HasFullFP16 = true;
HasSMEF16F16 = true;
}
if (Feature == "+sme-b16b16") {
HasSME = true;
HasSME2 = true;
HasBFloat16 = true;
HasFullFP16 = true;
HasSVEB16B16 = true;
HasSMEB16B16 = true;
}
if (Feature == "+sb")
HasSB = true;
if (Feature == "+predres")
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Basic/Targets/AArch64.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
bool HasSVE2AES = false;
bool HasSVE2SHA3 = false;
bool HasSVE2SM4 = false;
bool HasSVEB16B16 = false;
bool HasSVE2BitPerm = false;
bool HasMatmulFP64 = false;
bool HasMatmulFP32 = false;
Expand All @@ -71,6 +72,8 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
bool HasSME2 = false;
bool HasSMEF64F64 = false;
bool HasSMEI16I64 = false;
bool HasSMEF16F16 = false;
bool HasSMEB16B16 = false;
bool HasSME2p1 = false;
bool HasSB = false;
bool HasPredRes = false;
Expand Down
16 changes: 8 additions & 8 deletions clang/lib/Basic/Targets/WebAssembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const {
.Case("bulk-memory", HasBulkMemory)
.Case("exception-handling", HasExceptionHandling)
.Case("extended-const", HasExtendedConst)
.Case("half-precision", HasHalfPrecision)
.Case("fp16", HasFP16)
.Case("multimemory", HasMultiMemory)
.Case("multivalue", HasMultivalue)
.Case("mutable-globals", HasMutableGlobals)
Expand Down Expand Up @@ -84,8 +84,8 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__wasm_extended_const__");
if (HasMultiMemory)
Builder.defineMacro("__wasm_multimemory__");
if (HasHalfPrecision)
Builder.defineMacro("__wasm_half_precision__");
if (HasFP16)
Builder.defineMacro("__wasm_fp16__");
if (HasMultivalue)
Builder.defineMacro("__wasm_multivalue__");
if (HasMutableGlobals)
Expand Down Expand Up @@ -162,7 +162,7 @@ bool WebAssemblyTargetInfo::initFeatureMap(
Features["bulk-memory"] = true;
Features["exception-handling"] = true;
Features["extended-const"] = true;
Features["half-precision"] = true;
Features["fp16"] = true;
Features["multimemory"] = true;
Features["nontrapping-fptoint"] = true;
Features["tail-call"] = true;
Expand Down Expand Up @@ -212,13 +212,13 @@ bool WebAssemblyTargetInfo::handleTargetFeatures(
HasExtendedConst = false;
continue;
}
if (Feature == "+half-precision") {
if (Feature == "+fp16") {
SIMDLevel = std::max(SIMDLevel, SIMD128);
HasHalfPrecision = true;
HasFP16 = true;
continue;
}
if (Feature == "-half-precision") {
HasHalfPrecision = false;
if (Feature == "-fp16") {
HasFP16 = false;
continue;
}
if (Feature == "+multimemory") {
Expand Down
6 changes: 2 additions & 4 deletions clang/lib/Basic/Targets/WebAssembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {
bool HasBulkMemory = false;
bool HasExceptionHandling = false;
bool HasExtendedConst = false;
bool HasHalfPrecision = false;
bool HasFP16 = false;
bool HasMultiMemory = false;
bool HasMultivalue = false;
bool HasMutableGlobals = false;
Expand Down Expand Up @@ -90,9 +90,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {

StringRef getABI() const override;
bool setABI(const std::string &Name) override;
bool useFP16ConversionIntrinsics() const override {
return !HasHalfPrecision;
}
bool useFP16ConversionIntrinsics() const override { return !HasFP16; }

protected:
void getTargetDefines(const LangOptions &Opts,
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
#include "llvm/Transforms/Instrumentation/NumericalStabilitySanitizer.h"
#include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"
#include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h"
#include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h"
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
Expand Down Expand Up @@ -471,6 +472,7 @@ static bool initTargetOptions(DiagnosticsEngine &Diags,
Options.MCOptions.Dwarf64 = CodeGenOpts.Dwarf64;
Options.MCOptions.PreserveAsmComments = CodeGenOpts.PreserveAsmComments;
Options.MCOptions.Crel = CodeGenOpts.Crel;
Options.MCOptions.ImplicitMapSyms = CodeGenOpts.ImplicitMapSyms;
Options.MCOptions.X86RelaxRelocations = CodeGenOpts.X86RelaxRelocations;
Options.MCOptions.CompressDebugSections =
CodeGenOpts.getCompressDebugSections();
Expand Down Expand Up @@ -989,6 +991,13 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
FPM.addPass(BoundsCheckingPass());
});

if (LangOpts.Sanitize.has(SanitizerKind::Realtime))
PB.registerScalarOptimizerLateEPCallback(
[](FunctionPassManager &FPM, OptimizationLevel Level) {
RealtimeSanitizerOptions Opts;
FPM.addPass(RealtimeSanitizerPass(Opts));
});

// Don't add sanitizers if we are here from ThinLTO PostLink. That already
// done on PreLink stage.
if (!IsThinLTOPostLink) {
Expand Down
47 changes: 20 additions & 27 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18497,22 +18497,14 @@ llvm::Value *CodeGenFunction::EmitScalarOrConstFoldImmArg(unsigned ICEArguments,
return Arg;
}

Intrinsic::ID getDotProductIntrinsic(QualType QT, int elementCount) {
if (QT->hasFloatingRepresentation()) {
switch (elementCount) {
case 2:
return Intrinsic::dx_dot2;
case 3:
return Intrinsic::dx_dot3;
case 4:
return Intrinsic::dx_dot4;
}
}
if (QT->hasSignedIntegerRepresentation())
return Intrinsic::dx_sdot;

assert(QT->hasUnsignedIntegerRepresentation());
return Intrinsic::dx_udot;
// Return dot product intrinsic that corresponds to the QT scalar type
Intrinsic::ID getDotProductIntrinsic(CGHLSLRuntime &RT, QualType QT) {
if (QT->isFloatingType())
return RT.getFDotIntrinsic();
if (QT->isSignedIntegerType())
return RT.getSDotIntrinsic();
assert(QT->isUnsignedIntegerType());
return RT.getUDotIntrinsic();
}

Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
Expand Down Expand Up @@ -18555,37 +18547,38 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
Value *Op1 = EmitScalarExpr(E->getArg(1));
llvm::Type *T0 = Op0->getType();
llvm::Type *T1 = Op1->getType();

// If the arguments are scalars, just emit a multiply
if (!T0->isVectorTy() && !T1->isVectorTy()) {
if (T0->isFloatingPointTy())
return Builder.CreateFMul(Op0, Op1, "dx.dot");
return Builder.CreateFMul(Op0, Op1, "hlsl.dot");

if (T0->isIntegerTy())
return Builder.CreateMul(Op0, Op1, "dx.dot");
return Builder.CreateMul(Op0, Op1, "hlsl.dot");

// Bools should have been promoted
llvm_unreachable(
"Scalar dot product is only supported on ints and floats.");
}
// For vectors, validate types and emit the appropriate intrinsic

// A VectorSplat should have happened
assert(T0->isVectorTy() && T1->isVectorTy() &&
"Dot product of vector and scalar is not supported.");

// A vector sext or sitofp should have happened
assert(T0->getScalarType() == T1->getScalarType() &&
"Dot product of vectors need the same element types.");

auto *VecTy0 = E->getArg(0)->getType()->getAs<VectorType>();
[[maybe_unused]] auto *VecTy1 =
E->getArg(1)->getType()->getAs<VectorType>();
// A HLSLVectorTruncation should have happend

assert(VecTy0->getElementType() == VecTy1->getElementType() &&
"Dot product of vectors need the same element types.");

assert(VecTy0->getNumElements() == VecTy1->getNumElements() &&
"Dot product requires vectors to be of the same size.");

return Builder.CreateIntrinsic(
/*ReturnType=*/T0->getScalarType(),
getDotProductIntrinsic(E->getArg(0)->getType(),
VecTy0->getNumElements()),
ArrayRef<Value *>{Op0, Op1}, nullptr, "dx.dot");
getDotProductIntrinsic(CGM.getHLSLRuntime(), VecTy0->getElementType()),
ArrayRef<Value *>{Op0, Op1}, nullptr, "hlsl.dot");
} break;
case Builtin::BI__builtin_hlsl_lerp: {
Value *X = EmitScalarExpr(E->getArg(0));
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2421,6 +2421,8 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
FuncAttrs.addAttribute(llvm::Attribute::NoCfCheck);
if (TargetDecl->hasAttr<LeafAttr>())
FuncAttrs.addAttribute(llvm::Attribute::NoCallback);
if (TargetDecl->hasAttr<BPFFastCallAttr>())
FuncAttrs.addAttribute("bpf_fastcall");

HasOptnone = TargetDecl->hasAttr<OptimizeNoneAttr>();
if (auto *AllocSize = TargetDecl->getAttr<AllocSizeAttr>()) {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3561,6 +3561,7 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const EnumType *Ty) {

SmallVector<llvm::Metadata *, 16> Enumerators;
ED = ED->getDefinition();
assert(ED && "An enumeration definition is required");
for (const auto *Enum : ED->enumerators()) {
Enumerators.push_back(
DBuilder.createEnumerator(Enum->getName(), Enum->getInitVal()));
Expand Down
15 changes: 13 additions & 2 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4392,13 +4392,24 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
return LV;
}

llvm::Value *CodeGenFunction::EmitMatrixIndexExpr(const Expr *E) {
llvm::Value *Idx = EmitScalarExpr(E);
if (Idx->getType() == IntPtrTy)
return Idx;
bool IsSigned = E->getType()->isSignedIntegerOrEnumerationType();
return Builder.CreateIntCast(Idx, IntPtrTy, IsSigned);
}

LValue CodeGenFunction::EmitMatrixSubscriptExpr(const MatrixSubscriptExpr *E) {
assert(
!E->isIncomplete() &&
"incomplete matrix subscript expressions should be rejected during Sema");
LValue Base = EmitLValue(E->getBase());
llvm::Value *RowIdx = EmitScalarExpr(E->getRowIdx());
llvm::Value *ColIdx = EmitScalarExpr(E->getColumnIdx());

// Extend or truncate the index type to 32 or 64-bits if needed.
llvm::Value *RowIdx = EmitMatrixIndexExpr(E->getRowIdx());
llvm::Value *ColIdx = EmitMatrixIndexExpr(E->getColumnIdx());

llvm::Value *NumRows = Builder.getIntN(
RowIdx->getType()->getScalarSizeInBits(),
E->getBase()->getType()->castAs<ConstantMatrixType>()->getNumRows());
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2007,8 +2007,8 @@ Value *ScalarExprEmitter::VisitMatrixSubscriptExpr(MatrixSubscriptExpr *E) {

// Handle the vector case. The base must be a vector, the index must be an
// integer value.
Value *RowIdx = Visit(E->getRowIdx());
Value *ColumnIdx = Visit(E->getColumnIdx());
Value *RowIdx = CGF.EmitMatrixIndexExpr(E->getRowIdx());
Value *ColumnIdx = CGF.EmitMatrixIndexExpr(E->getColumnIdx());

const auto *MatrixTy = E->getBase()->getType()->castAs<ConstantMatrixType>();
unsigned NumRows = MatrixTy->getNumRows();
Expand Down Expand Up @@ -2785,7 +2785,7 @@ static bool matchesPostDecrInWhile(const UnaryOperator *UO, bool isInc,
if (isInc || isPre)
return false;

// -fsanitize-undefined-ignore-overflow-pattern=post-decr-while
// -fsanitize-undefined-ignore-overflow-pattern=unsigned-post-decr-while
if (!Ctx.getLangOpts().isOverflowPatternExcluded(
LangOptions::OverflowPatternExclusionKind::PostDecrInWhile))
return false;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ class CGHLSLRuntime {
GENERATE_HLSL_INTRINSIC_FUNCTION(Rsqrt, rsqrt)
GENERATE_HLSL_INTRINSIC_FUNCTION(Saturate, saturate)
GENERATE_HLSL_INTRINSIC_FUNCTION(ThreadId, thread_id)
GENERATE_HLSL_INTRINSIC_FUNCTION(FDot, fdot)
GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot)
GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot)

//===----------------------------------------------------------------------===//
// End of reserved area for HLSL intrinsic getters.
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,13 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
if (SanOpts.has(SanitizerKind::ShadowCallStack))
Fn->addFnAttr(llvm::Attribute::ShadowCallStack);

if (SanOpts.has(SanitizerKind::Realtime))
if (FD && FD->getASTContext().hasAnyFunctionEffects())
for (const FunctionEffectWithCondition &Fe : FD->getFunctionEffects()) {
if (Fe.Effect.kind() == FunctionEffect::Kind::NonBlocking)
Fn->addFnAttr(llvm::Attribute::SanitizeRealtime);
}

// Apply fuzzing attribute to the function.
if (SanOpts.hasOneOf(SanitizerKind::Fuzzer | SanitizerKind::FuzzerNoLink))
Fn->addFnAttr(llvm::Attribute::OptForFuzzing);
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -4280,6 +4280,7 @@ class CodeGenFunction : public CodeGenTypeCache {
LValue EmitUnaryOpLValue(const UnaryOperator *E);
LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
bool Accessed = false);
llvm::Value *EmitMatrixIndexExpr(const Expr *E);
LValue EmitMatrixSubscriptExpr(const MatrixSubscriptExpr *E);
LValue EmitArraySectionExpr(const ArraySectionExpr *E,
bool IsLowerBound = true);
Expand Down
13 changes: 9 additions & 4 deletions clang/lib/CodeGen/CodeGenPGO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1195,10 +1195,15 @@ void CodeGenPGO::emitCounterSetOrIncrement(CGBuilderTy &Builder, const Stmt *S,

unsigned Counter = (*RegionCounterMap)[S];

llvm::Value *Args[] = {FuncNameVar,
Builder.getInt64(FunctionHash),
Builder.getInt32(NumRegionCounters),
Builder.getInt32(Counter), StepV};
// Make sure that pointer to global is passed in with zero addrspace
// This is relevant during GPU profiling
auto *NormalizedFuncNameVarPtr =
llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(
FuncNameVar, llvm::PointerType::get(CGM.getLLVMContext(), 0));

llvm::Value *Args[] = {
NormalizedFuncNameVarPtr, Builder.getInt64(FunctionHash),
Builder.getInt32(NumRegionCounters), Builder.getInt32(Counter), StepV};

if (llvm::EnableSingleByteCoverage)
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::instrprof_cover),
Expand Down
14 changes: 7 additions & 7 deletions clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,18 +171,18 @@ getHIPOffloadTargetTriple(const Driver &D, const ArgList &Args) {
}

// static
std::string Driver::GetResourcesPath(StringRef BinaryPath,
StringRef CustomResourceDir) {
std::string Driver::GetResourcesPath(StringRef BinaryPath) {
// Since the resource directory is embedded in the module hash, it's important
// that all places that need it call this function, so that they get the
// exact same string ("a/../b/" and "b/" get different hashes, for example).

// Dir is bin/ or lib/, depending on where BinaryPath is.
std::string Dir = std::string(llvm::sys::path::parent_path(BinaryPath));

StringRef Dir = llvm::sys::path::parent_path(BinaryPath);
SmallString<128> P(Dir);
if (CustomResourceDir != "") {
llvm::sys::path::append(P, CustomResourceDir);

StringRef ConfiguredResourceDir(CLANG_RESOURCE_DIR);
if (!ConfiguredResourceDir.empty()) {
llvm::sys::path::append(P, ConfiguredResourceDir);
} else {
// On Windows, libclang.dll is in bin/.
// On non-Windows, libclang.so/.dylib is in lib/.
Expand Down Expand Up @@ -239,7 +239,7 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,
#endif

// Compute the path to the resource directory.
ResourceDir = GetResourcesPath(ClangExecutable, CLANG_RESOURCE_DIR);
ResourceDir = GetResourcesPath(ClangExecutable);
}

void Driver::setDriverMode(StringRef Value) {
Expand Down
21 changes: 14 additions & 7 deletions clang/lib/Driver/SanitizerArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -558,11 +558,15 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
SanitizerKind::Leak | SanitizerKind::Thread |
SanitizerKind::Memory | SanitizerKind::KernelAddress |
SanitizerKind::Scudo | SanitizerKind::SafeStack),
std::make_pair(SanitizerKind::MemTag,
SanitizerKind::Address | SanitizerKind::KernelAddress |
SanitizerKind::HWAddress |
SanitizerKind::KernelHWAddress),
std::make_pair(SanitizerKind::KCFI, SanitizerKind::Function)};
std::make_pair(SanitizerKind::MemTag, SanitizerKind::Address |
SanitizerKind::KernelAddress |
SanitizerKind::HWAddress |
SanitizerKind::KernelHWAddress),
std::make_pair(SanitizerKind::KCFI, SanitizerKind::Function),
std::make_pair(SanitizerKind::Realtime,
SanitizerKind::Address | SanitizerKind::Thread |
SanitizerKind::Undefined | SanitizerKind::Memory)};

// Enable toolchain specific default sanitizers if not explicitly disabled.
SanitizerMask Default = TC.getDefaultSanitizers() & ~AllRemove;

Expand Down Expand Up @@ -1453,9 +1457,12 @@ static int parseOverflowPatternExclusionValues(const Driver &D,
llvm::StringSwitch<int>(Value)
.Case("none", LangOptionsBase::None)
.Case("all", LangOptionsBase::All)
.Case("add-overflow-test", LangOptionsBase::AddOverflowTest)
.Case("add-unsigned-overflow-test",
LangOptionsBase::AddUnsignedOverflowTest)
.Case("add-signed-overflow-test",
LangOptionsBase::AddSignedOverflowTest)
.Case("negated-unsigned-const", LangOptionsBase::NegUnsignedConst)
.Case("post-decr-while", LangOptionsBase::PostDecrInWhile)
.Case("unsigned-post-decr-while", LangOptionsBase::PostDecrInWhile)
.Default(0);
if (E == 0)
D.Diag(clang::diag::err_drv_unsupported_option_argument)
Expand Down
13 changes: 13 additions & 0 deletions clang/lib/Driver/ToolChains/Arch/Sparc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,4 +264,17 @@ void sparc::getSparcTargetFeatures(const Driver &D, const ArgList &Args,

if (Args.hasArg(options::OPT_ffixed_i5))
Features.push_back("+reserve-i5");

if (Args.hasArg(options::OPT_mfix_gr712rc)) {
Features.push_back("+fix-tn0009");
Features.push_back("+fix-tn0011");
Features.push_back("+fix-tn0012");
Features.push_back("+fix-tn0013");
}

if (Args.hasArg(options::OPT_mfix_ut700)) {
Features.push_back("+fix-tn0009");
Features.push_back("+fix-tn0010");
Features.push_back("+fix-tn0013");
}
}
16 changes: 14 additions & 2 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2554,6 +2554,7 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
const llvm::Triple &Triple = C.getDefaultToolChain().getTriple();
bool IsELF = Triple.isOSBinFormatELF();
bool Crel = false, ExperimentalCrel = false;
bool ImplicitMapSyms = false;
bool UseRelaxRelocations = C.getDefaultToolChain().useRelaxRelocations();
bool UseNoExecStack = false;
bool Msa = false;
Expand Down Expand Up @@ -2642,6 +2643,15 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
// recognize but skip over here.
continue;
break;
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
case llvm::Triple::aarch64_32:
if (Equal.first == "-mmapsyms") {
ImplicitMapSyms = Equal.second == "implicit";
checkArg(IsELF, {"default", "implicit"});
continue;
}
break;
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::mips64:
Expand Down Expand Up @@ -2786,6 +2796,8 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
<< "-Wa,--crel" << D.getTargetTriple();
}
}
if (ImplicitMapSyms)
CmdArgs.push_back("-mmapsyms=implicit");
if (Msa)
CmdArgs.push_back("-mmsa");
if (!UseRelaxRelocations)
Expand Down Expand Up @@ -7960,8 +7972,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_keep_persistent_storage_variables);
Args.addOptInFlag(CmdArgs, options::OPT_fcomplete_member_pointers,
options::OPT_fno_complete_member_pointers);
Args.addOptOutFlag(CmdArgs, options::OPT_fcxx_static_destructors,
options::OPT_fno_cxx_static_destructors);
if (Arg *A = Args.getLastArg(options::OPT_cxx_static_destructors_EQ))
A->render(Args, CmdArgs);

addMachineOutlinerArgs(D, Args, CmdArgs, Triple, /*IsLTO=*/false);

Expand Down
30 changes: 28 additions & 2 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1143,10 +1143,27 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
addMachineOutlinerArgs(D, Args, CmdArgs, ToolChain.getEffectiveTriple(),
/*IsLTO=*/true, PluginOptPrefix);

bool IsELF = Triple.isOSBinFormatELF();
bool Crel = false;
bool ImplicitMapSyms = false;
for (const Arg *A : Args.filtered(options::OPT_Wa_COMMA)) {
for (StringRef V : A->getValues()) {
if (V == "--crel")
auto Equal = V.split('=');
auto checkArg = [&](bool ValidTarget,
std::initializer_list<const char *> Set) {
if (!ValidTarget) {
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< (Twine("-Wa,") + Equal.first + "=").str()
<< Triple.getTriple();
} else if (!llvm::is_contained(Set, Equal.second)) {
D.Diag(diag::err_drv_unsupported_option_argument)
<< (Twine("-Wa,") + Equal.first + "=").str() << Equal.second;
}
};
if (Equal.first == "-mmapsyms") {
ImplicitMapSyms = Equal.second == "implicit";
checkArg(IsELF && Triple.isAArch64(), {"default", "implicit"});
} else if (V == "--crel")
Crel = true;
else if (V == "--no-crel")
Crel = false;
Expand All @@ -1156,13 +1173,16 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
}
}
if (Crel) {
if (Triple.isOSBinFormatELF() && !Triple.isMIPS()) {
if (IsELF && !Triple.isMIPS()) {
CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + "-crel"));
} else {
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< "-Wa,--crel" << D.getTargetTriple();
}
}
if (ImplicitMapSyms)
CmdArgs.push_back(
Args.MakeArgString(Twine(PluginOptPrefix) + "-implicit-mapsyms"));
}

void tools::addOpenMPRuntimeLibraryPath(const ToolChain &TC,
Expand Down Expand Up @@ -1436,6 +1456,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
if (!Args.hasArg(options::OPT_shared))
HelperStaticRuntimes.push_back("hwasan-preinit");
}
if (SanArgs.needsRtsanRt() && SanArgs.linkRuntimes())
SharedRuntimes.push_back("rtsan");
}

// The stats_client library is also statically linked into DSOs.
Expand All @@ -1461,6 +1483,10 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
StaticRuntimes.push_back("asan_cxx");
}

if (!SanArgs.needsSharedRt() && SanArgs.needsRtsanRt() &&
SanArgs.linkRuntimes())
StaticRuntimes.push_back("rtsan");

if (!SanArgs.needsSharedRt() && SanArgs.needsMemProfRt()) {
StaticRuntimes.push_back("memprof");
if (SanArgs.linkCXXRuntimes())
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Driver/ToolChains/Darwin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1519,6 +1519,8 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
const char *sanitizer = nullptr;
if (Sanitize.needsUbsanRt()) {
sanitizer = "UndefinedBehaviorSanitizer";
} else if (Sanitize.needsRtsanRt()) {
sanitizer = "RealtimeSanitizer";
} else if (Sanitize.needsAsanRt()) {
sanitizer = "AddressSanitizer";
} else if (Sanitize.needsTsanRt()) {
Expand All @@ -1541,6 +1543,11 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
AddLinkSanitizerLibArgs(Args, CmdArgs, "asan");
}
}
if (Sanitize.needsRtsanRt()) {
assert(Sanitize.needsSharedRt() &&
"Static sanitizer runtimes not supported");
AddLinkSanitizerLibArgs(Args, CmdArgs, "rtsan");
}
if (Sanitize.needsLsanRt())
AddLinkSanitizerLibArgs(Args, CmdArgs, "lsan");
if (Sanitize.needsUbsanRt()) {
Expand Down Expand Up @@ -3539,6 +3546,7 @@ SanitizerMask Darwin::getSupportedSanitizers() const {
Res |= SanitizerKind::Address;
Res |= SanitizerKind::PointerCompare;
Res |= SanitizerKind::PointerSubtract;
Res |= SanitizerKind::Realtime;
Res |= SanitizerKind::Leak;
Res |= SanitizerKind::Fuzzer;
Res |= SanitizerKind::FuzzerNoLink;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/ToolChains/Linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,7 @@ SanitizerMask Linux::getSupportedSanitizers() const {
Res |= SanitizerKind::Address;
Res |= SanitizerKind::PointerCompare;
Res |= SanitizerKind::PointerSubtract;
Res |= SanitizerKind::Realtime;
Res |= SanitizerKind::Fuzzer;
Res |= SanitizerKind::FuzzerNoLink;
Res |= SanitizerKind::KernelAddress;
Expand Down
36 changes: 14 additions & 22 deletions clang/lib/Format/ContinuationIndenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,25 +128,6 @@ static bool startsSegmentOfBuilderTypeCall(const FormatToken &Tok) {
return Tok.isMemberAccess() && Tok.Previous && Tok.Previous->closesScope();
}

// Returns \c true if \c Current starts a new parameter.
static bool startsNextParameter(const FormatToken &Current,
const FormatStyle &Style) {
assert(Current.Previous);
const auto &Previous = *Current.Previous;
if (Current.is(TT_CtorInitializerComma) &&
Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma) {
return true;
}
if (Style.Language == FormatStyle::LK_Proto && Current.is(TT_SelectorName))
return true;
return Previous.is(tok::comma) && !Current.isTrailingComment() &&
((Previous.isNot(TT_CtorInitializerComma) ||
Style.BreakConstructorInitializers !=
FormatStyle::BCIS_BeforeComma) &&
(Previous.isNot(TT_InheritanceComma) ||
Style.BreakInheritanceList != FormatStyle::BILS_BeforeComma));
}

// Returns \c true if \c Token in an alignable binary operator
static bool isAlignableBinaryOperator(const FormatToken &Token) {
// No need to align binary operators that only have two operands.
Expand Down Expand Up @@ -437,7 +418,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
// sets BreakBeforeParameter to avoid bin packing and this creates a
// completely unnecessary line break after a template type that isn't
// line-wrapped.
(Previous.NestingLevel == 1 || Style.BinPackParameters)) ||
(Previous.NestingLevel == 1 ||
Style.BinPackParameters == FormatStyle::BPPS_BinPack)) ||
(Style.BreakBeforeTernaryOperators && Current.is(TT_ConditionalExpr) &&
Previous.isNot(tok::question)) ||
(!Style.BreakBeforeTernaryOperators &&
Expand Down Expand Up @@ -848,6 +830,12 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
const auto IsSimpleFunction = [&](const FormatToken &Tok) {
if (!Tok.FakeLParens.empty() && Tok.FakeLParens.back() > prec::Unknown)
return false;
// Nested calls that involve `new` expressions also look like simple
// function calls, eg:
// - foo(new Bar())
// - foo(::new Bar())
if (Tok.is(tok::kw_new) || Tok.startsSequence(tok::coloncolon, tok::kw_new))
return true;
const auto *Previous = Tok.Previous;
if (!Previous || (!Previous->isOneOf(TT_FunctionDeclarationLParen,
TT_LambdaDefinitionLParen) &&
Expand All @@ -870,6 +858,9 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
// caaaaaaaaaaaall(
// caaaaaaaaaaaall(
// caaaaaaaaaaaaaaaaaaaaaaall(aaaaaaaaaaaaaa, aaaaaaaaa))));
// or
// caaaaaaaaaaaaaaaaaaaaal(
// new SomethingElseeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee());
!IsSimpleFunction(Current)) {
CurrentState.NoLineBreak = true;
}
Expand Down Expand Up @@ -1951,11 +1942,12 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
// for backwards compatibility.
bool ObjCBinPackProtocolList =
(Style.ObjCBinPackProtocolList == FormatStyle::BPS_Auto &&
Style.BinPackParameters) ||
Style.BinPackParameters == FormatStyle::BPPS_BinPack) ||
Style.ObjCBinPackProtocolList == FormatStyle::BPS_Always;

bool BinPackDeclaration =
(State.Line->Type != LT_ObjCDecl && Style.BinPackParameters) ||
(State.Line->Type != LT_ObjCDecl &&
Style.BinPackParameters == FormatStyle::BPPS_BinPack) ||
(State.Line->Type == LT_ObjCDecl && ObjCBinPackProtocolList);

bool GenericSelection =
Expand Down
19 changes: 16 additions & 3 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,19 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BinaryOperatorStyle> {
}
};

template <>
struct ScalarEnumerationTraits<FormatStyle::BinPackParametersStyle> {
static void enumeration(IO &IO, FormatStyle::BinPackParametersStyle &Value) {
IO.enumCase(Value, "BinPack", FormatStyle::BPPS_BinPack);
IO.enumCase(Value, "OnePerLine", FormatStyle::BPPS_OnePerLine);
IO.enumCase(Value, "AlwaysOnePerLine", FormatStyle::BPPS_AlwaysOnePerLine);

// For backward compatibility.
IO.enumCase(Value, "true", FormatStyle::BPPS_BinPack);
IO.enumCase(Value, "false", FormatStyle::BPPS_OnePerLine);
}
};

template <> struct ScalarEnumerationTraits<FormatStyle::BinPackStyle> {
static void enumeration(IO &IO, FormatStyle::BinPackStyle &Value) {
IO.enumCase(Value, "Auto", FormatStyle::BPS_Auto);
Expand Down Expand Up @@ -1461,7 +1474,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
LLVMStyle.AttributeMacros.push_back("__capability");
LLVMStyle.BinPackArguments = true;
LLVMStyle.BinPackParameters = true;
LLVMStyle.BinPackParameters = FormatStyle::BPPS_BinPack;
LLVMStyle.BitFieldColonSpacing = FormatStyle::BFCS_Both;
LLVMStyle.BracedInitializerIndentWidth = std::nullopt;
LLVMStyle.BraceWrapping = {/*AfterCaseLabel=*/false,
Expand Down Expand Up @@ -1836,7 +1849,7 @@ FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) {
ChromiumStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
ChromiumStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
ChromiumStyle.AllowShortLoopsOnASingleLine = false;
ChromiumStyle.BinPackParameters = false;
ChromiumStyle.BinPackParameters = FormatStyle::BPPS_OnePerLine;
ChromiumStyle.DerivePointerAlignment = false;
if (Language == FormatStyle::LK_ObjC)
ChromiumStyle.ColumnLimit = 80;
Expand All @@ -1851,7 +1864,7 @@ FormatStyle getMozillaStyle() {
MozillaStyle.AlwaysBreakAfterDefinitionReturnType =
FormatStyle::DRTBS_TopLevel;
MozillaStyle.BinPackArguments = false;
MozillaStyle.BinPackParameters = false;
MozillaStyle.BinPackParameters = FormatStyle::BPPS_OnePerLine;
MozillaStyle.BreakAfterReturnType = FormatStyle::RTBS_TopLevel;
MozillaStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla;
MozillaStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
Expand Down
17 changes: 17 additions & 0 deletions clang/lib/Format/FormatToken.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,5 +322,22 @@ CommaSeparatedList::getColumnFormat(unsigned RemainingCharacters) const {
return BestFormat;
}

bool startsNextParameter(const FormatToken &Current, const FormatStyle &Style) {
assert(Current.Previous);
const auto &Previous = *Current.Previous;
if (Current.is(TT_CtorInitializerComma) &&
Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma) {
return true;
}
if (Style.Language == FormatStyle::LK_Proto && Current.is(TT_SelectorName))
return true;
return Previous.is(tok::comma) && !Current.isTrailingComment() &&
((Previous.isNot(TT_CtorInitializerComma) ||
Style.BreakConstructorInitializers !=
FormatStyle::BCIS_BeforeComma) &&
(Previous.isNot(TT_InheritanceComma) ||
Style.BreakInheritanceList != FormatStyle::BILS_BeforeComma));
}

} // namespace format
} // namespace clang
3 changes: 3 additions & 0 deletions clang/lib/Format/FormatToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -1978,6 +1978,9 @@ inline bool continuesLineComment(const FormatToken &FormatTok,
FormatTok.OriginalColumn >= MinContinueColumn;
}

// Returns \c true if \c Current starts a new parameter.
bool startsNextParameter(const FormatToken &Current, const FormatStyle &Style);

} // namespace format
} // namespace clang

Expand Down
28 changes: 21 additions & 7 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ class AnnotatingParser {
if (Precedence > prec::Conditional && Precedence < prec::Relational)
return false;
}
if (Prev.is(TT_ConditionalExpr))
if (Prev.isOneOf(tok::question, tok::colon) && !Style.isProto())
SeenTernaryOperator = true;
updateParameterCount(Left, CurrentToken);
if (Style.Language == FormatStyle::LK_Proto) {
Expand Down Expand Up @@ -2875,6 +2875,8 @@ class AnnotatingParser {
// Search for unexpected tokens.
for (auto *Prev = BeforeRParen; Prev != LParen; Prev = Prev->Previous) {
if (Prev->is(tok::r_paren)) {
if (Prev->is(TT_CastRParen))
return false;
Prev = Prev->MatchingParen;
if (!Prev)
return false;
Expand Down Expand Up @@ -4478,10 +4480,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
}
if (Left.is(tok::colon))
return Left.isNot(TT_ObjCMethodExpr);
if (Left.is(tok::coloncolon)) {
return Right.is(tok::star) && Right.is(TT_PointerOrReference) &&
Style.PointerAlignment != FormatStyle::PAS_Left;
}
if (Left.is(tok::coloncolon))
return false;
if (Left.is(tok::less) || Right.isOneOf(tok::greater, tok::less)) {
if (Style.Language == FormatStyle::LK_TextProto ||
(Style.Language == FormatStyle::LK_Proto &&
Expand Down Expand Up @@ -4591,8 +4591,14 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (!BeforeLeft)
return false;
if (BeforeLeft->is(tok::coloncolon)) {
return Left.is(tok::star) &&
Style.PointerAlignment != FormatStyle::PAS_Right;
if (Left.isNot(tok::star))
return false;
assert(Style.PointerAlignment != FormatStyle::PAS_Right);
if (!Right.startsSequence(tok::identifier, tok::r_paren))
return true;
assert(Right.Next);
const auto *LParen = Right.Next->MatchingParen;
return !LParen || LParen->isNot(TT_FunctionTypeLParen);
}
return !BeforeLeft->isOneOf(tok::l_paren, tok::l_square);
}
Expand Down Expand Up @@ -5475,6 +5481,14 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
return true;
}

// Ignores the first parameter as this will be handled separately by
// BreakFunctionDefinitionParameters or AlignAfterOpenBracket.
if (Style.BinPackParameters == FormatStyle::BPPS_AlwaysOnePerLine &&
Line.MightBeFunctionDecl && !Left.opensScope() &&
startsNextParameter(Right, Style)) {
return true;
}

const auto *BeforeLeft = Left.Previous;
const auto *AfterRight = Right.Next;

Expand Down
10 changes: 7 additions & 3 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3130,7 +3130,7 @@ std::string CompilerInvocation::GetResourcesPath(const char *Argv0,
void *MainAddr) {
std::string ClangExecutable =
llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
return Driver::GetResourcesPath(ClangExecutable, CLANG_RESOURCE_DIR);
return Driver::GetResourcesPath(ClangExecutable);
}

static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts,
Expand Down Expand Up @@ -4274,9 +4274,13 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
llvm::StringSwitch<unsigned>(A->getValue(i))
.Case("none", LangOptionsBase::None)
.Case("all", LangOptionsBase::All)
.Case("add-overflow-test", LangOptionsBase::AddOverflowTest)
.Case("add-unsigned-overflow-test",
LangOptionsBase::AddUnsignedOverflowTest)
.Case("add-signed-overflow-test",
LangOptionsBase::AddSignedOverflowTest)
.Case("negated-unsigned-const", LangOptionsBase::NegUnsignedConst)
.Case("post-decr-while", LangOptionsBase::PostDecrInWhile)
.Case("unsigned-post-decr-while",
LangOptionsBase::PostDecrInWhile)
.Default(0);
}
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Frontend/InitPreprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_unicode_literals", "200710L");
Builder.defineMacro("__cpp_user_defined_literals", "200809L");
Builder.defineMacro("__cpp_lambdas", "200907L");
Builder.defineMacro("__cpp_constexpr", LangOpts.CPlusPlus26 ? "202306L"
Builder.defineMacro("__cpp_constexpr", LangOpts.CPlusPlus26 ? "202406L"
: LangOpts.CPlusPlus23 ? "202211L"
: LangOpts.CPlusPlus20 ? "201907L"
: LangOpts.CPlusPlus17 ? "201603L"
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2326,7 +2326,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
}

if (getLangOpts().HLSL)
MaybeParseHLSLAnnotations(D);
while (MaybeParseHLSLAnnotations(D))
;

if (Tok.is(tok::kw_requires))
ParseTrailingRequiresClause(D);
Expand Down
13 changes: 13 additions & 0 deletions clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3139,6 +3139,19 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclaration(
return Actions.BuildDeclaratorGroup(Decls);
}

// Befriending a concept is invalid and would already fail if
// we did nothing here, but this allows us to issue a more
// helpful diagnostic.
if (Tok.is(tok::kw_concept)) {
Diag(Tok.getLocation(),
DS.isFriendSpecified() || NextToken().is(tok::kw_friend)
? diag::err_friend_concept
: diag::
err_concept_decls_may_only_appear_in_global_namespace_scope);
SkipUntil(tok::semi, tok::r_brace, StopBeforeMatch);
return nullptr;
}

ParsingDeclarator DeclaratorInfo(*this, DS, DeclAttrs,
DeclaratorContext::Member);
if (TemplateInfo.TemplateParams)
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
RHS = ExprError();
}
// If this is left-associative, only parse things on the RHS that bind
// more tightly than the current operator. If it is left-associative, it
// more tightly than the current operator. If it is right-associative, it
// is okay, to bind exactly as tightly. For example, compile A=B=C=D as
// A=(B=(C=D)), where each paren is a level of recursion here.
// The function takes ownership of the RHS.
Expand Down
127 changes: 55 additions & 72 deletions clang/lib/Sema/CheckExprLifetime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,66 +326,6 @@ static bool shouldTrackFirstArgument(const FunctionDecl *FD) {
return false;
}

static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call,
LocalVisitor Visit) {
auto VisitPointerArg = [&](const Decl *D, Expr *Arg, bool Value) {
// We are not interested in the temporary base objects of gsl Pointers:
// Temp().ptr; // Here ptr might not dangle.
if (isa<MemberExpr>(Arg->IgnoreImpCasts()))
return;
// Once we initialized a value with a reference, it can no longer dangle.
if (!Value) {
for (const IndirectLocalPathEntry &PE : llvm::reverse(Path)) {
if (PE.Kind == IndirectLocalPathEntry::GslReferenceInit)
continue;
if (PE.Kind == IndirectLocalPathEntry::GslPointerInit ||
PE.Kind == IndirectLocalPathEntry::GslPointerAssignment)
return;
break;
}
}
Path.push_back({Value ? IndirectLocalPathEntry::GslPointerInit
: IndirectLocalPathEntry::GslReferenceInit,
Arg, D});
if (Arg->isGLValue())
visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding,
Visit,
/*EnableLifetimeWarnings=*/true);
else
visitLocalsRetainedByInitializer(Path, Arg, Visit, true,
/*EnableLifetimeWarnings=*/true);
Path.pop_back();
};

if (auto *MCE = dyn_cast<CXXMemberCallExpr>(Call)) {
const auto *MD = cast_or_null<CXXMethodDecl>(MCE->getDirectCallee());
if (MD && shouldTrackImplicitObjectArg(MD))
VisitPointerArg(MD, MCE->getImplicitObjectArgument(),
!MD->getReturnType()->isReferenceType());
return;
} else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(Call)) {
FunctionDecl *Callee = OCE->getDirectCallee();
if (Callee && Callee->isCXXInstanceMember() &&
shouldTrackImplicitObjectArg(cast<CXXMethodDecl>(Callee)))
VisitPointerArg(Callee, OCE->getArg(0),
!Callee->getReturnType()->isReferenceType());
return;
} else if (auto *CE = dyn_cast<CallExpr>(Call)) {
FunctionDecl *Callee = CE->getDirectCallee();
if (Callee && shouldTrackFirstArgument(Callee))
VisitPointerArg(Callee, CE->getArg(0),
!Callee->getReturnType()->isReferenceType());
return;
}

if (auto *CCE = dyn_cast<CXXConstructExpr>(Call)) {
const auto *Ctor = CCE->getConstructor();
const CXXRecordDecl *RD = Ctor->getParent();
if (CCE->getNumArgs() > 0 && RD->hasAttr<PointerAttr>())
VisitPointerArg(Ctor->getParamDecl(0), CCE->getArgs()[0], true);
}
}

static bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) {
const TypeSourceInfo *TSI = FD->getTypeSourceInfo();
if (!TSI)
Expand Down Expand Up @@ -423,8 +363,10 @@ static bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) {
return false;
}

static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call,
LocalVisitor Visit) {
// Visit lifetimebound or gsl-pointer arguments.
static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,
LocalVisitor Visit,
bool EnableLifetimeWarnings) {
const FunctionDecl *Callee;
ArrayRef<Expr *> Args;

Expand Down Expand Up @@ -458,6 +400,34 @@ static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call,
/*EnableLifetimeWarnings=*/false);
Path.pop_back();
};
auto VisitGSLPointerArg = [&](const Decl *D, Expr *Arg, bool Value) {
// We are not interested in the temporary base objects of gsl Pointers:
// Temp().ptr; // Here ptr might not dangle.
if (isa<MemberExpr>(Arg->IgnoreImpCasts()))
return;
// Once we initialized a value with a reference, it can no longer dangle.
if (!Value) {
for (const IndirectLocalPathEntry &PE : llvm::reverse(Path)) {
if (PE.Kind == IndirectLocalPathEntry::GslReferenceInit)
continue;
if (PE.Kind == IndirectLocalPathEntry::GslPointerInit ||
PE.Kind == IndirectLocalPathEntry::GslPointerAssignment)
return;
break;
}
}
Path.push_back({Value ? IndirectLocalPathEntry::GslPointerInit
: IndirectLocalPathEntry::GslReferenceInit,
Arg, D});
if (Arg->isGLValue())
visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding,
Visit,
/*EnableLifetimeWarnings=*/true);
else
visitLocalsRetainedByInitializer(Path, Arg, Visit, true,
/*EnableLifetimeWarnings=*/true);
Path.pop_back();
};

bool CheckCoroCall = false;
if (const auto *RD = Callee->getReturnType()->getAsRecordDecl()) {
Expand All @@ -478,13 +448,30 @@ static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call,
CheckCoroObjArg = false;
if (implicitObjectParamIsLifetimeBound(Callee) || CheckCoroObjArg)
VisitLifetimeBoundArg(Callee, ObjectArg);
else if (EnableLifetimeWarnings) {
if (auto *CME = dyn_cast<CXXMethodDecl>(Callee);
CME && shouldTrackImplicitObjectArg(CME))
VisitGSLPointerArg(Callee, ObjectArg,
!Callee->getReturnType()->isReferenceType());
}
}

for (unsigned I = 0,
N = std::min<unsigned>(Callee->getNumParams(), Args.size());
I != N; ++I) {
if (CheckCoroCall || Callee->getParamDecl(I)->hasAttr<LifetimeBoundAttr>())
VisitLifetimeBoundArg(Callee->getParamDecl(I), Args[I]);
else if (EnableLifetimeWarnings && I == 0) {
if (shouldTrackFirstArgument(Callee)) {
VisitGSLPointerArg(Callee, Args[0],
!Callee->getReturnType()->isReferenceType());
} else {
if (auto *CCE = dyn_cast<CXXConstructExpr>(Call);
CCE && CCE->getConstructor()->getParent()->hasAttr<PointerAttr>())
VisitGSLPointerArg(CCE->getConstructor()->getParamDecl(0), Args[0],
true);
}
}
}
}

Expand Down Expand Up @@ -557,11 +544,9 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
EnableLifetimeWarnings);
}

if (isa<CallExpr>(Init)) {
if (EnableLifetimeWarnings)
handleGslAnnotatedTypes(Path, Init, Visit);
return visitLifetimeBoundArguments(Path, Init, Visit);
}
if (isa<CallExpr>(Init))
return visitFunctionCallArguments(Path, Init, Visit,
EnableLifetimeWarnings);

switch (Init->getStmtClass()) {
case Stmt::DeclRefExprClass: {
Expand Down Expand Up @@ -835,11 +820,9 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
}
}

if (isa<CallExpr>(Init) || isa<CXXConstructExpr>(Init)) {
if (EnableLifetimeWarnings)
handleGslAnnotatedTypes(Path, Init, Visit);
return visitLifetimeBoundArguments(Path, Init, Visit);
}
if (isa<CallExpr>(Init) || isa<CXXConstructExpr>(Init))
return visitFunctionCallArguments(Path, Init, Visit,
EnableLifetimeWarnings);

switch (Init->getStmtClass()) {
case Stmt::UnaryOperatorClass: {
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Sema/HLSLExternalSemaSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -503,9 +503,11 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
.addSimpleTemplateParams(*SemaPtr, {"element_type"})
.Record;

onCompletion(Decl, [this](CXXRecordDecl *Decl) {
setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
ResourceKind::TypedBuffer, /*IsROV=*/false)
ResourceKind::TypedBuffer,
/*IsROV=*/false)
.addArraySubscriptOperators()
.completeDefinition();
});
Expand Down
26 changes: 24 additions & 2 deletions clang/lib/Sema/SemaConcept.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -977,8 +977,30 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
// equivalence.
LocalInstantiationScope ScopeForParameters(S);
if (auto *FD = DeclInfo.getDecl()->getAsFunction())
for (auto *PVD : FD->parameters())
ScopeForParameters.InstantiatedLocal(PVD, PVD);
for (auto *PVD : FD->parameters()) {
if (!PVD->isParameterPack()) {
ScopeForParameters.InstantiatedLocal(PVD, PVD);
continue;
}
// This is hacky: we're mapping the parameter pack to a size-of-1 argument
// to avoid building SubstTemplateTypeParmPackTypes for
// PackExpansionTypes. The SubstTemplateTypeParmPackType node would
// otherwise reference the AssociatedDecl of the template arguments, which
// is, in this case, the template declaration.
//
// However, as we are in the process of comparing potential
// re-declarations, the canonical declaration is the declaration itself at
// this point. So if we didn't expand these packs, we would end up with an
// incorrect profile difference because we will be profiling the
// canonical types!
//
// FIXME: Improve the "no-transform" machinery in FindInstantiatedDecl so
// that we can eliminate the Scope in the cases where the declarations are
// not necessarily instantiated. It would also benefit the noexcept
// specifier comparison.
ScopeForParameters.MakeInstantiatedLocalArgPack(PVD);
ScopeForParameters.InstantiatedLocalPackArg(PVD, PVD);
}

std::optional<Sema::CXXThisScopeRAII> ThisScope;

Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7502,6 +7502,12 @@ NamedDecl *Sema::ActOnVariableDeclarator(
/*never a friend*/ false, IsMemberSpecialization, Invalid);

if (TemplateParams) {
if (DC->isDependentContext()) {
ContextRAII SavedContext(*this, DC);
if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams))
Invalid = true;
}

if (!TemplateParams->size() &&
D.getName().getKind() != UnqualifiedIdKind::IK_TemplateId) {
// There is an extraneous 'template<>' for this variable. Complain
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6889,6 +6889,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_HLSLSV_GroupIndex:
handleSimpleAttribute<HLSLSV_GroupIndexAttr>(S, D, AL);
break;
case ParsedAttr::AT_HLSLGroupSharedAddressSpace:
handleSimpleAttribute<HLSLGroupSharedAddressSpaceAttr>(S, D, AL);
break;
case ParsedAttr::AT_HLSLSV_DispatchThreadID:
S.HLSL().handleSV_DispatchThreadIDAttr(D, AL);
break;
Expand Down
20 changes: 15 additions & 5 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5033,8 +5033,7 @@ ExprResult Sema::CreateBuiltinMatrixSubscriptExpr(Expr *Base, Expr *RowIdx,
}
}

ExprResult ConvExpr =
tryConvertExprToType(IndexExpr, Context.getSizeType());
ExprResult ConvExpr = IndexExpr;
assert(!ConvExpr.isInvalid() &&
"should be able to convert any integer type to size type");
return ConvExpr.get();
Expand Down Expand Up @@ -17464,11 +17463,22 @@ static void RemoveNestedImmediateInvocation(
ExprResult TransformInitializer(Expr *Init, bool NotCopyInit) {
if (!Init)
return Init;

// We cannot use IgnoreImpCasts because we need to preserve
// full expressions.
while (true) {
if (auto *ICE = dyn_cast<ImplicitCastExpr>(Init))
Init = ICE->getSubExpr();
else if (auto *ICE = dyn_cast<MaterializeTemporaryExpr>(Init))
Init = ICE->getSubExpr();
else
break;
}
/// ConstantExpr are the first layer of implicit node to be removed so if
/// Init isn't a ConstantExpr, no ConstantExpr will be skipped.
if (auto *CE = dyn_cast<ConstantExpr>(Init))
if (CE->isImmediateInvocation())
RemoveImmediateInvocation(CE);
if (auto *CE = dyn_cast<ConstantExpr>(Init);
CE && CE->isImmediateInvocation())
RemoveImmediateInvocation(CE);
return Base::TransformInitializer(Init, NotCopyInit);
}
ExprResult TransformDeclRefExpr(DeclRefExpr *E) {
Expand Down
18 changes: 18 additions & 0 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaHLSL.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaLambda.h"
#include "clang/Sema/SemaObjC.h"
Expand Down Expand Up @@ -6248,6 +6249,23 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
TSTToBeDeduced->getTemplateName().getAsTemplateDecl(), RhsT,
Info) == TemplateDeductionResult::Success;
}
case BTT_IsScalarizedLayoutCompatible: {
if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() &&
Self.RequireCompleteType(Lhs->getTypeLoc().getBeginLoc(), LhsT,
diag::err_incomplete_type))
return true;
if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() &&
Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT,
diag::err_incomplete_type))
return true;

DiagnoseVLAInCXXTypeTrait(
Self, Lhs, tok::kw___builtin_hlsl_is_scalarized_layout_compatible);
DiagnoseVLAInCXXTypeTrait(
Self, Rhs, tok::kw___builtin_hlsl_is_scalarized_layout_compatible);

return Self.HLSL().IsScalarizedLayoutCompatible(LhsT, RhsT);
}
default:
llvm_unreachable("not a BTT");
}
Expand Down
477 changes: 464 additions & 13 deletions clang/lib/Sema/SemaHLSL.cpp

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
constexpr auto CanRepresentAll = [](bool FromSigned, unsigned FromWidth,
bool ToSigned, unsigned ToWidth) {
return (FromWidth < ToWidth + (FromSigned == ToSigned)) &&
(FromSigned <= ToSigned);
!(FromSigned && !ToSigned);
};

if (CanRepresentAll(FromSigned, FromWidth, ToSigned, ToWidth))
Expand Down Expand Up @@ -542,7 +542,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
// If the bit-field width was dependent, it might end up being small
// enough to fit in the target type (unless the target type is unsigned
// and the source type is signed, in which case it will never fit)
if (DependentBitField && (FromSigned <= ToSigned))
if (DependentBitField && !(FromSigned && !ToSigned))
return NK_Dependent_Narrowing;

// Otherwise, such a conversion is always narrowing
Expand Down
9 changes: 2 additions & 7 deletions clang/lib/Sema/SemaStmtAsm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,8 @@ static void removeLValueToRValueCast(Expr *E) {
/// and fix the argument with removing LValueToRValue cast from the expression.
static void emitAndFixInvalidAsmCastLValue(const Expr *LVal, Expr *BadArgument,
Sema &S) {
if (!S.getLangOpts().HeinousExtensions) {
S.Diag(LVal->getBeginLoc(), diag::err_invalid_asm_cast_lvalue)
<< BadArgument->getSourceRange();
} else {
S.Diag(LVal->getBeginLoc(), diag::warn_invalid_asm_cast_lvalue)
<< BadArgument->getSourceRange();
}
S.Diag(LVal->getBeginLoc(), diag::warn_invalid_asm_cast_lvalue)
<< BadArgument->getSourceRange();
removeLValueToRValueCast(BadArgument);
}

Expand Down
20 changes: 13 additions & 7 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8089,13 +8089,14 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
return true;
}

DeclContext *DC = ClassTemplate->getDeclContext();

bool isMemberSpecialization = false;
bool isPartialSpecialization = false;

if (SS.isSet()) {
if (TUK != TagUseKind::Reference && TUK != TagUseKind::Friend &&
diagnoseQualifiedDeclaration(SS, ClassTemplate->getDeclContext(),
ClassTemplate->getDeclName(),
diagnoseQualifiedDeclaration(SS, DC, ClassTemplate->getDeclName(),
TemplateNameLoc, &TemplateId,
/*IsMemberSpecialization=*/false))
return true;
Expand All @@ -8117,6 +8118,12 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
if (TemplateParams && CheckTemplateDeclScope(S, TemplateParams))
return true;

if (TemplateParams && DC->isDependentContext()) {
ContextRAII SavedContext(*this, DC);
if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams))
return true;
}

if (TemplateParams && TemplateParams->size() > 0) {
isPartialSpecialization = true;

Expand Down Expand Up @@ -8282,9 +8289,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
= cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl);
ClassTemplatePartialSpecializationDecl *Partial =
ClassTemplatePartialSpecializationDecl::Create(
Context, Kind, ClassTemplate->getDeclContext(), KWLoc,
TemplateNameLoc, TemplateParams, ClassTemplate, CanonicalConverted,
CanonType, PrevPartial);
Context, Kind, DC, KWLoc, TemplateNameLoc, TemplateParams,
ClassTemplate, CanonicalConverted, CanonType, PrevPartial);
Partial->setTemplateArgsAsWritten(TemplateArgs);
SetNestedNameSpecifier(*this, Partial, SS);
if (TemplateParameterLists.size() > 1 && SS.isSet()) {
Expand All @@ -8306,8 +8312,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// Create a new class template specialization declaration node for
// this explicit specialization or friend declaration.
Specialization = ClassTemplateSpecializationDecl::Create(
Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc,
ClassTemplate, CanonicalConverted, PrevDecl);
Context, Kind, DC, KWLoc, TemplateNameLoc, ClassTemplate,
CanonicalConverted, PrevDecl);
Specialization->setTemplateArgsAsWritten(TemplateArgs);
SetNestedNameSpecifier(*this, Specialization, SS);
if (TemplateParameterLists.size() > 0) {
Expand Down
23 changes: 17 additions & 6 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -6669,9 +6669,15 @@ QualType
TreeTransform<Derived>::TransformPackIndexingType(TypeLocBuilder &TLB,
PackIndexingTypeLoc TL) {
// Transform the index
ExprResult IndexExpr = getDerived().TransformExpr(TL.getIndexExpr());
if (IndexExpr.isInvalid())
return QualType();
ExprResult IndexExpr;
{
EnterExpressionEvaluationContext ConstantContext(
SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);

IndexExpr = getDerived().TransformExpr(TL.getIndexExpr());
if (IndexExpr.isInvalid())
return QualType();
}
QualType Pattern = TL.getPattern();

const PackIndexingType *PIT = TL.getTypePtr();
Expand Down Expand Up @@ -15299,9 +15305,14 @@ TreeTransform<Derived>::TransformPackIndexingExpr(PackIndexingExpr *E) {
return E;

// Transform the index
ExprResult IndexExpr = getDerived().TransformExpr(E->getIndexExpr());
if (IndexExpr.isInvalid())
return ExprError();
ExprResult IndexExpr;
{
EnterExpressionEvaluationContext ConstantContext(
SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
IndexExpr = getDerived().TransformExpr(E->getIndexExpr());
if (IndexExpr.isInvalid())
return ExprError();
}

SmallVector<Expr *, 5> ExpandedExprs;
if (!E->expandsToEmptyPack() && E->getExpressions().empty()) {
Expand Down
39 changes: 39 additions & 0 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9955,6 +9955,45 @@ void ASTReader::finishPendingActions() {
}
PendingDefinitions.clear();

for (auto [D, Previous] : PendingWarningForDuplicatedDefsInModuleUnits) {
auto hasDefinitionImpl = [this](Decl *D, auto hasDefinitionImpl) {
if (auto *VD = dyn_cast<VarDecl>(D))
return VD->isThisDeclarationADefinition() ||
VD->isThisDeclarationADemotedDefinition();

if (auto *TD = dyn_cast<TagDecl>(D))
return TD->isThisDeclarationADefinition() ||
TD->isThisDeclarationADemotedDefinition();

if (auto *FD = dyn_cast<FunctionDecl>(D))
return FD->isThisDeclarationADefinition() || PendingBodies.count(FD);

if (auto *RTD = dyn_cast<RedeclarableTemplateDecl>(D))
return hasDefinitionImpl(RTD->getTemplatedDecl(), hasDefinitionImpl);

// Conservatively return false here.
return false;
};

auto hasDefinition = [&hasDefinitionImpl](Decl *D) {
return hasDefinitionImpl(D, hasDefinitionImpl);
};

// It is not good to prevent multiple declarations since the forward
// declaration is common. Let's try to avoid duplicated definitions
// only.
if (!hasDefinition(D) || !hasDefinition(Previous))
continue;

Module *PM = Previous->getOwningModule();
Module *DM = D->getOwningModule();
Diag(D->getLocation(), diag::warn_decls_in_multiple_modules)
<< cast<NamedDecl>(Previous) << PM->getTopLevelModuleName()
<< (DM ? DM->getTopLevelModuleName() : "global module");
Diag(Previous->getLocation(), diag::note_also_found);
}
PendingWarningForDuplicatedDefsInModuleUnits.clear();

// Load the bodies of any functions or methods we've encountered. We do
// this now (delayed) so that we can be sure that the declaration chains
// have been fully wired up (hasBody relies on this).
Expand Down
52 changes: 33 additions & 19 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,9 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> {
static void attachPreviousDecl(ASTReader &Reader, Decl *D, Decl *Previous,
Decl *Canon);

static void checkMultipleDefinitionInNamedModules(ASTReader &Reader, Decl *D,
Decl *Previous);

template <typename DeclT>
static void attachLatestDeclImpl(Redeclarable<DeclT> *D, Decl *Latest);
static void attachLatestDeclImpl(...);
Expand Down Expand Up @@ -2064,7 +2067,7 @@ void ASTDeclMerger::MergeDefinitionData(
Reader.MergedDeclContexts.insert(std::make_pair(MergeDD.Definition,
DD.Definition));
Reader.PendingDefinitions.erase(MergeDD.Definition);
MergeDD.Definition->setCompleteDefinition(false);
MergeDD.Definition->demoteThisDefinitionToDeclaration();
Reader.mergeDefinitionVisibility(DD.Definition, MergeDD.Definition);
assert(!Reader.Lookups.contains(MergeDD.Definition) &&
"already loaded pending lookups for merged definition");
Expand Down Expand Up @@ -2175,6 +2178,9 @@ void ASTDeclReader::ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update,
D->DefinitionData = Canon->DefinitionData;
ReadCXXDefinitionData(*DD, D, LambdaContext, IndexInLambdaContext);

// Mark this declaration as being a definition.
D->setCompleteDefinition(true);

// We might already have a different definition for this record. This can
// happen either because we're reading an update record, or because we've
// already done some merging. Either way, just merge into it.
Expand All @@ -2183,9 +2189,6 @@ void ASTDeclReader::ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update,
return;
}

// Mark this declaration as being a definition.
D->setCompleteDefinition(true);

// If this is not the first declaration or is an update record, we can have
// other redeclarations already. Make a note that we need to propagate the
// DefinitionData pointer onto them.
Expand Down Expand Up @@ -3690,14 +3693,9 @@ static void inheritDefaultTemplateArguments(ASTContext &Context,
// [basic.link]/p10:
// If two declarations of an entity are attached to different modules,
// the program is ill-formed;
static void checkMultipleDefinitionInNamedModules(ASTReader &Reader, Decl *D,
Decl *Previous) {
Module *M = Previous->getOwningModule();

// We only care about the case in named modules.
if (!M || !M->isNamedModule())
return;

void ASTDeclReader::checkMultipleDefinitionInNamedModules(ASTReader &Reader,
Decl *D,
Decl *Previous) {
// If it is previous implcitly introduced, it is not meaningful to
// diagnose it.
if (Previous->isImplicit())
Expand All @@ -3714,17 +3712,33 @@ static void checkMultipleDefinitionInNamedModules(ASTReader &Reader, Decl *D,
// FIXME: Maybe this shows the implicit instantiations may have incorrect
// module owner ships. But given we've finished the compilation of a module,
// how can we add new entities to that module?
if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(Previous);
VTSD && !VTSD->isExplicitSpecialization())
if (isa<VarTemplateSpecializationDecl>(Previous))
return;
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(Previous);
CTSD && !CTSD->isExplicitSpecialization())
if (isa<ClassTemplateSpecializationDecl>(Previous))
return;
if (auto *Func = dyn_cast<FunctionDecl>(Previous))
if (auto *FTSI = Func->getTemplateSpecializationInfo();
FTSI && !FTSI->isExplicitSpecialization())
if (auto *Func = dyn_cast<FunctionDecl>(Previous);
Func && Func->getTemplateSpecializationInfo())
return;

Module *M = Previous->getOwningModule();
if (!M)
return;

// We only forbids merging decls within named modules.
if (!M->isNamedModule()) {
// Try to warn the case that we merged decls from global module.
if (!M->isGlobalModule())
return;

if (D->getOwningModule() &&
M->getTopLevelModule() == D->getOwningModule()->getTopLevelModule())
return;

Reader.PendingWarningForDuplicatedDefsInModuleUnits.push_back(
{D, Previous});
return;
}

// It is fine if they are in the same module.
if (Reader.getContext().isInSameModule(M, D->getOwningModule()))
return;
Expand Down
107 changes: 72 additions & 35 deletions clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,12 +288,65 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
EmitStackError(C, R, RetE);
}

static const MemSpaceRegion *getStackOrGlobalSpaceRegion(const MemRegion *R) {
assert(R);
if (const auto *MemSpace = R->getMemorySpace()) {
if (const auto *SSR = MemSpace->getAs<StackSpaceRegion>())
return SSR;
if (const auto *GSR = MemSpace->getAs<GlobalsSpaceRegion>())
return GSR;
}
// If R describes a lambda capture, it will be a symbolic region
// referring to a field region of another symbolic region.
if (const auto *SymReg = R->getBaseRegion()->getAs<SymbolicRegion>()) {
if (const auto *OriginReg = SymReg->getSymbol()->getOriginRegion())
return getStackOrGlobalSpaceRegion(OriginReg);
}
return nullptr;
}

std::optional<std::string> printReferrer(const MemRegion *Referrer) {
assert(Referrer);
const StringRef ReferrerMemorySpace = [](const MemSpaceRegion *Space) {
if (isa<StaticGlobalSpaceRegion>(Space))
return "static";
if (isa<GlobalsSpaceRegion>(Space))
return "global";
assert(isa<StackSpaceRegion>(Space));
return "stack";
}(getStackOrGlobalSpaceRegion(Referrer));

while (!Referrer->canPrintPretty()) {
if (const auto *SymReg = dyn_cast<SymbolicRegion>(Referrer);
SymReg && SymReg->getSymbol()->getOriginRegion()) {
Referrer = SymReg->getSymbol()->getOriginRegion()->getBaseRegion();
} else if (isa<CXXThisRegion>(Referrer)) {
// Skip members of a class, it is handled in CheckExprLifetime.cpp as
// warn_bind_ref_member_to_parameter or
// warn_init_ptr_member_to_parameter_addr
return std::nullopt;
} else {
Referrer->dump();
assert(false && "Unexpected referrer region type.");
return std::nullopt;
}
}
assert(Referrer);
assert(Referrer->canPrintPretty());

std::string buf;
llvm::raw_string_ostream os(buf);
os << ReferrerMemorySpace << " variable ";
Referrer->printPretty(os);
return buf;
}

void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
CheckerContext &Ctx) const {
if (!ChecksEnabled[CK_StackAddrEscapeChecker])
return;

ProgramStateRef State = Ctx.getState();
ExplodedNode *Node = Ctx.getPredecessor();

// Iterate over all bindings to global variables and see if it contains
// a memory region in the stack space.
Expand All @@ -307,23 +360,22 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
/// referred by an other stack variable from different stack frame.
bool checkForDanglingStackVariable(const MemRegion *Referrer,
const MemRegion *Referred) {
const auto *ReferrerMemSpace =
Referrer->getMemorySpace()->getAs<StackSpaceRegion>();
const auto *ReferrerMemSpace = getStackOrGlobalSpaceRegion(Referrer);
const auto *ReferredMemSpace =
Referred->getMemorySpace()->getAs<StackSpaceRegion>();

if (!ReferrerMemSpace || !ReferredMemSpace)
return false;

const auto *ReferrerFrame = ReferrerMemSpace->getStackFrame();
const auto *ReferredFrame = ReferredMemSpace->getStackFrame();
const auto *ReferrerStackSpace =
ReferrerMemSpace->getAs<StackSpaceRegion>();
if (!ReferrerStackSpace)
return false;

if (ReferrerMemSpace && ReferredMemSpace) {
if (ReferredFrame == PoppedFrame &&
ReferrerFrame->isParentOf(PoppedFrame)) {
V.emplace_back(Referrer, Referred);
return true;
}
if (ReferredMemSpace->getStackFrame() == PoppedFrame &&
ReferrerStackSpace->getStackFrame()->isParentOf(PoppedFrame)) {
V.emplace_back(Referrer, Referred);
return true;
}
return false;
}
Expand Down Expand Up @@ -352,35 +404,36 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
};

CallBack Cb(Ctx);
ProgramStateRef State = Node->getState();
State->getStateManager().getStoreManager().iterBindings(State->getStore(),
Cb);

if (Cb.V.empty())
return;

// Generate an error node.
ExplodedNode *N = Ctx.generateNonFatalErrorNode(State);
ExplodedNode *N = Ctx.generateNonFatalErrorNode(State, Node);
if (!N)
return;

if (!BT_stackleak)
BT_stackleak =
std::make_unique<BugType>(CheckNames[CK_StackAddrEscapeChecker],
"Stack address stored into global variable");
"Stack address leaks outside of stack frame");

for (const auto &P : Cb.V) {
const MemRegion *Referrer = P.first->getBaseRegion();
const MemRegion *Referred = P.second;

// Generate a report for this bug.
const StringRef CommonSuffix =
"upon returning to the caller. This will be a dangling reference";
" upon returning to the caller. This will be a dangling reference";
SmallString<128> Buf;
llvm::raw_svector_ostream Out(Buf);
const SourceRange Range = genName(Out, Referred, Ctx.getASTContext());

if (isa<CXXTempObjectRegion, CXXLifetimeExtendedObjectRegion>(Referrer)) {
Out << " is still referred to by a temporary object on the stack "
Out << " is still referred to by a temporary object on the stack"
<< CommonSuffix;
auto Report =
std::make_unique<PathSensitiveBugReport>(*BT_stackleak, Out.str(), N);
Expand All @@ -390,28 +443,12 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
return;
}

const StringRef ReferrerMemorySpace = [](const MemSpaceRegion *Space) {
if (isa<StaticGlobalSpaceRegion>(Space))
return "static";
if (isa<GlobalsSpaceRegion>(Space))
return "global";
assert(isa<StackSpaceRegion>(Space));
return "stack";
}(Referrer->getMemorySpace());

// We should really only have VarRegions here.
// Anything else is really surprising, and we should get notified if such
// ever happens.
const auto *ReferrerVar = dyn_cast<VarRegion>(Referrer);
if (!ReferrerVar) {
assert(false && "We should have a VarRegion here");
continue; // Defensively skip this one.
auto ReferrerVariable = printReferrer(Referrer);
if (!ReferrerVariable) {
continue;
}
const std::string ReferrerVarName =
ReferrerVar->getDecl()->getDeclName().getAsString();

Out << " is still referred to by the " << ReferrerMemorySpace
<< " variable '" << ReferrerVarName << "' " << CommonSuffix;
Out << " is still referred to by the " << *ReferrerVariable << CommonSuffix;
auto Report =
std::make_unique<PathSensitiveBugReport>(*BT_stackleak, Out.str(), N);
if (Range.isValid())
Expand Down
21 changes: 21 additions & 0 deletions clang/test/AST/ByteCode/c.c
Original file line number Diff line number Diff line change
Expand Up @@ -297,3 +297,24 @@ void T1(void) {

enum teste1 test1f(void), (*test1)(void) = test1f; // pedantic-warning {{ISO C forbids forward references to 'enum' types}}
enum teste1 { TEST1 };

void func(void) {
_Static_assert(func + 1 - func == 1, ""); // pedantic-warning {{arithmetic on a pointer to the function type}} \
// pedantic-warning {{arithmetic on pointers to the function type}} \
// pedantic-warning {{not an integer constant expression}}
_Static_assert(func + 0xdead000000000000UL - 0xdead000000000000UL == func, ""); // pedantic-warning 2{{arithmetic on a pointer to the function type}} \
// pedantic-warning {{not an integer constant expression}} \
// pedantic-note {{cannot refer to element 16045481047390945280 of non-array object in a constant expression}}
_Static_assert(func + 1 != func, ""); // pedantic-warning {{arithmetic on a pointer to the function type}} \
// pedantic-warning {{expression is not an integer constant expression}}
func + 0xdead000000000000UL; // all-warning {{expression result unused}} \
// pedantic-warning {{arithmetic on a pointer to the function type}}
func - 0xdead000000000000UL; // all-warning {{expression result unused}} \
// pedantic-warning {{arithmetic on a pointer to the function type}}
}

void foo3 (void)
{
void* x = 0;
void* y = &*x;
}
135 changes: 51 additions & 84 deletions clang/test/AST/ByteCode/intap.cpp
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -fms-extensions -std=c++11 -verify %s
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -fms-extensions -std=c++20 -verify %s
// RUN: %clang_cc1 -std=c++11 -fms-extensions -verify=ref %s
// RUN: %clang_cc1 -std=c++20 -fms-extensions -verify=ref %s
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -fms-extensions -std=c++11 -verify=expected,both %s
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -fms-extensions -std=c++20 -verify=expected,both %s
// RUN: %clang_cc1 -std=c++11 -fms-extensions -verify=ref,both %s
// RUN: %clang_cc1 -std=c++20 -fms-extensions -verify=ref,both %s


using MaxBitInt = _BitInt(128);
#define INT_MIN (~__INT_MAX__)

constexpr _BitInt(2) A = 0;
constexpr _BitInt(2) B = A + 1;
constexpr _BitInt(2) C = B + 1; // expected-warning {{from 2 to -2}} \
// ref-warning {{from 2 to -2}}
constexpr _BitInt(2) C = B + 1; // both-warning {{from 2 to -2}}
static_assert(C == -2, "");
static_assert(C - B == A, ""); // expected-error {{not an integral constant expression}} \
// expected-note {{value -3 is outside the range of representable values}} \
// ref-error {{not an integral constant expression}} \
// ref-note {{value -3 is outside the range of representable values}}
static_assert(C - B == A, ""); // both-error {{not an integral constant expression}} \
// both-note {{value -3 is outside the range of representable values}}

static_assert(B - 1 == 0, "");

Expand All @@ -38,10 +35,8 @@ static_assert(BI1 == 3, "");

constexpr _BitInt(4) MulA = 5;
constexpr _BitInt(4) MulB = 7;
static_assert(MulA * MulB == 50, ""); // ref-error {{not an integral constant expression}} \
// ref-note {{value 35 is outside the range of representable values of type '_BitInt(4)'}} \
// expected-error {{not an integral constant expression}} \
// expected-note {{value 35 is outside the range of representable values of type '_BitInt(4)'}}
static_assert(MulA * MulB == 50, ""); // both-error {{not an integral constant expression}} \
// both-note {{value 35 is outside the range of representable values of type '_BitInt(4)'}}
static_assert(MulA * 5 == 25, "");
static_assert(-1 * MulB == -7, "");

Expand All @@ -50,29 +45,21 @@ constexpr _BitInt(4) DivA = 2;
constexpr _BitInt(2) DivB = 1;
static_assert(DivA / DivB == 2, "");

constexpr _BitInt(4) DivC = DivA / 0; // ref-error {{must be initialized by a constant expression}} \
// ref-note {{division by zero}} \
// expected-error {{must be initialized by a constant expression}} \
// expected-note {{division by zero}}
constexpr _BitInt(4) DivC = DivA / 0; // both-error {{must be initialized by a constant expression}} \
// both-note {{division by zero}}

constexpr _BitInt(7) RemA = 47;
constexpr _BitInt(6) RemB = 9;
static_assert(RemA % RemB == 2, "");
static_assert(RemA % 0 == 1, ""); // ref-error {{not an integral constant expression}} \
// ref-note {{division by zero}} \
// expected-error {{not an integral constant expression}} \
// expected-note {{division by zero}}
static_assert(RemA % 0 == 1, ""); // both-error {{not an integral constant expression}} \
// both-note {{division by zero}}

constexpr _BitInt(32) bottom = -1;
constexpr _BitInt(32) top = INT_MIN;
constexpr _BitInt(32) nope = top / bottom; // ref-error {{must be initialized by a constant expression}} \
// ref-note {{value 2147483648 is outside the range}} \
// expected-error {{must be initialized by a constant expression}} \
// expected-note {{value 2147483648 is outside the range}}
constexpr _BitInt(32) noooo = top % bottom; // ref-error {{must be initialized by a constant expression}} \
// ref-note {{value 2147483648 is outside the range}} \
// expected-error {{must be initialized by a constant expression}} \
// expected-note {{value 2147483648 is outside the range}}
constexpr _BitInt(32) nope = top / bottom; // both-error {{must be initialized by a constant expression}} \
// both-note {{value 2147483648 is outside the range}}
constexpr _BitInt(32) noooo = top % bottom; // both-error {{must be initialized by a constant expression}} \
// both-note {{value 2147483648 is outside the range}}

namespace APCast {
constexpr _BitInt(10) A = 1;
Expand All @@ -91,55 +78,48 @@ typedef __int128 int128_t;
typedef unsigned __int128 uint128_t;
static const __uint128_t UINT128_MAX =__uint128_t(__int128_t(-1L));
static_assert(UINT128_MAX == -1, "");
static_assert(UINT128_MAX == 1, ""); // expected-error {{static assertion failed}} \
// expected-note {{'340282366920938463463374607431768211455 == 1'}} \
// ref-error {{static assertion failed}} \
// ref-note {{'340282366920938463463374607431768211455 == 1'}}
static_assert(UINT128_MAX == 1, ""); // both-error {{static assertion failed}} \
// both-note {{'340282366920938463463374607431768211455 == 1'}}

static const __int128_t INT128_MAX = UINT128_MAX >> (__int128_t)1;
static_assert(INT128_MAX != 0, "");
static_assert(INT128_MAX == 0, ""); // expected-error {{failed}} \
// expected-note {{evaluates to '170141183460469231731687303715884105727 == 0'}} \
// ref-error {{failed}} \
// ref-note {{evaluates to '170141183460469231731687303715884105727 == 0'}}
static_assert(INT128_MAX == 0, ""); // both-error {{failed}} \
// both-note {{evaluates to '170141183460469231731687303715884105727 == 0'}}
static const __int128_t INT128_MIN = -INT128_MAX - 1;


namespace PointerArithmeticOverflow {
int n;
constexpr int *p = (&n + 1) + (unsigned __int128)-1; // both-error {{constant expression}} \
// both-note {{cannot refer to element 3402}}
}

namespace i128 {

constexpr int128_t I128_1 = 12;
static_assert(I128_1 == 12, "");
static_assert(I128_1 != 10, "");
static_assert(I128_1 != 12, ""); // expected-error{{failed}} \
// ref-error{{failed}} \
// expected-note{{evaluates to}} \
// ref-note{{evaluates to}}
static_assert(I128_1 != 12, ""); // both-error{{failed}} \
// both-note{{evaluates to}}

static const __uint128_t UINT128_MAX =__uint128_t(__int128_t(-1L));
static_assert(UINT128_MAX == -1, "");
static_assert(UINT128_MAX == 1, ""); // expected-error {{static assertion failed}} \
// expected-note {{'340282366920938463463374607431768211455 == 1'}} \
// ref-error {{static assertion failed}} \
// ref-note {{'340282366920938463463374607431768211455 == 1'}}
static_assert(UINT128_MAX == 1, ""); // both-error {{static assertion failed}} \
// both-note {{'340282366920938463463374607431768211455 == 1'}}

constexpr uint128_t TooMuch = UINT128_MAX * 2;

static const __int128_t INT128_MAX = UINT128_MAX >> (__int128_t)1;
static_assert(INT128_MAX != 0, "");
static_assert(INT128_MAX == 0, ""); // expected-error {{failed}} \
// expected-note {{evaluates to '170141183460469231731687303715884105727 == 0'}} \
// ref-error {{failed}} \
// ref-note {{evaluates to '170141183460469231731687303715884105727 == 0'}}
static_assert(INT128_MAX == 0, ""); // both-error {{failed}} \
// both-note {{evaluates to '170141183460469231731687303715884105727 == 0'}}

constexpr int128_t TooMuch2 = INT128_MAX * INT128_MAX; // ref-error {{must be initialized by a constant expression}} \
// ref-note {{value 28948022309329048855892746252171976962977213799489202546401021394546514198529 is outside the range of representable}} \
// expected-error {{must be initialized by a constant expression}} \
// expected-note {{value 28948022309329048855892746252171976962977213799489202546401021394546514198529 is outside the range of representable}}
constexpr int128_t TooMuch2 = INT128_MAX * INT128_MAX; // both-error {{must be initialized by a constant expression}} \
// both-note {{value 28948022309329048855892746252171976962977213799489202546401021394546514198529 is outside the range of representable}}

static const __int128_t INT128_MIN = -INT128_MAX - 1;
constexpr __int128 A = INT128_MAX + 1; // expected-error {{must be initialized by a constant expression}} \
// expected-note {{value 170141183460469231731687303715884105728 is outside the range}} \
// ref-error {{must be initialized by a constant expression}} \
// ref-note {{value 170141183460469231731687303715884105728 is outside the range}}
constexpr __int128 A = INT128_MAX + 1; // both-error {{must be initialized by a constant expression}} \
// both-note {{value 170141183460469231731687303715884105728 is outside the range}}
constexpr int128_t Two = (int128_t)1 << 1ul;
static_assert(Two == 2, "");
static_assert(Two, "");
Expand Down Expand Up @@ -205,22 +185,17 @@ namespace i128 {
static_assert(CastTo<long double>(12) == 12, "");
#endif

constexpr int128_t Error = __LDBL_MAX__; // ref-warning {{implicit conversion of out of range value}} \
// ref-error {{must be initialized by a constant expression}} \
// ref-note {{is outside the range of representable values of type}} \
// expected-warning {{implicit conversion of out of range value}} \
// expected-error {{must be initialized by a constant expression}} \
// expected-note {{is outside the range of representable values of type}}
constexpr int128_t Error = __LDBL_MAX__; // both-warning {{implicit conversion of out of range value}} \
// both-error {{must be initialized by a constant expression}} \
// both-note {{is outside the range of representable values of type}}

constexpr uint128_t Zero = 0;
static_assert((Zero -1) == -1, "");
constexpr int128_t Five = 5;
static_assert(Five - Zero == Five, "");

constexpr int128_t Sub1 = INT128_MIN - 1; // expected-error {{must be initialized by a constant expression}} \
// expected-note {{-170141183460469231731687303715884105729 is outside the range}} \
// ref-error {{must be initialized by a constant expression}} \
// ref-note {{-170141183460469231731687303715884105729 is outside the range}}
constexpr int128_t Sub1 = INT128_MIN - 1; // both-error {{must be initialized by a constant expression}} \
// both-note {{-170141183460469231731687303715884105729 is outside the range}}
}

namespace AddSubOffset {
Expand All @@ -236,16 +211,14 @@ namespace Bitfields {
struct S1 {
unsigned _BitInt(128) a : 2;
};
constexpr S1 s1{100}; // ref-warning {{changes value from 100 to 0}} \
// expected-warning {{changes value from 100 to 0}}
constexpr S1 s1{100}; // both-warning {{changes value from 100 to 0}}
constexpr S1 s12{3};
static_assert(s12.a == 3, "");

struct S2 {
unsigned __int128 a : 2;
};
constexpr S2 s2{100}; // ref-warning {{changes value from 100 to 0}} \
// expected-warning {{changes value from 100 to 0}}
constexpr S2 s2{100}; // both-warning {{changes value from 100 to 0}}
}

namespace BitOps {
Expand All @@ -266,21 +239,15 @@ namespace IncDec {
int128_t a = INT128_MAX;

if (Pre)
++a; // ref-note {{value 170141183460469231731687303715884105728 is outside the range}} \
// expected-note {{value 170141183460469231731687303715884105728 is outside the range}}
++a; // both-note {{value 170141183460469231731687303715884105728 is outside the range}}
else
a++; // ref-note {{value 170141183460469231731687303715884105728 is outside the range}} \
// expected-note {{value 170141183460469231731687303715884105728 is outside the range}}
a++; // both-note {{value 170141183460469231731687303715884105728 is outside the range}}
return a;
}
static_assert(maxPlus1(true) == 0, ""); // ref-error {{not an integral constant expression}} \
// ref-note {{in call to}} \
// expected-error {{not an integral constant expression}} \
// expected-note {{in call to}}
static_assert(maxPlus1(false) == 0, ""); // ref-error {{not an integral constant expression}} \
// ref-note {{in call to}} \
// expected-error {{not an integral constant expression}} \
// expected-note {{in call to}}
static_assert(maxPlus1(true) == 0, ""); // both-error {{not an integral constant expression}} \
// both-note {{in call to}}
static_assert(maxPlus1(false) == 0, ""); // both-error {{not an integral constant expression}} \
// both-note {{in call to}}

constexpr int128_t inc1(bool Pre) {
int128_t A = 0;
Expand Down
57 changes: 23 additions & 34 deletions clang/test/AST/ByteCode/invalid.cpp
Original file line number Diff line number Diff line change
@@ -1,68 +1,57 @@
// RUN: %clang_cc1 -fcxx-exceptions -std=c++20 -fexperimental-new-constant-interpreter -verify %s
// RUN: %clang_cc1 -fcxx-exceptions -std=c++20 -verify=ref %s
// RUN: %clang_cc1 -fcxx-exceptions -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s
// RUN: %clang_cc1 -fcxx-exceptions -std=c++20 -verify=ref,both %s

namespace Throw {

constexpr int ConditionalThrow(bool t) {
if (t)
throw 4; // expected-note {{subexpression not valid in a constant expression}} \
// ref-note {{subexpression not valid in a constant expression}}
throw 4; // both-note {{subexpression not valid in a constant expression}}

return 0;
}

static_assert(ConditionalThrow(false) == 0, "");
static_assert(ConditionalThrow(true) == 0, ""); // expected-error {{not an integral constant expression}} \
// expected-note {{in call to 'ConditionalThrow(true)'}} \
// ref-error {{not an integral constant expression}} \
// ref-note {{in call to 'ConditionalThrow(true)'}}
static_assert(ConditionalThrow(true) == 0, ""); // both-error {{not an integral constant expression}} \
// both-note {{in call to 'ConditionalThrow(true)'}}

constexpr int Throw() { // expected-error {{never produces a constant expression}} \
// ref-error {{never produces a constant expression}}
throw 5; // expected-note {{subexpression not valid in a constant expression}} \
// ref-note {{subexpression not valid in a constant expression}}
constexpr int Throw() { // both-error {{never produces a constant expression}}
throw 5; // both-note {{subexpression not valid in a constant expression}}
return 0;
}

constexpr int NoSubExpr() { // ref-error {{never produces a constant expression}} \
// expected-error {{never produces a constant expression}}
throw; // ref-note 2{{subexpression not valid}} \
// expected-note 2{{subexpression not valid}}
constexpr int NoSubExpr() { // both-error {{never produces a constant expression}}
throw; // both-note 2{{subexpression not valid}}
return 0;
}
static_assert(NoSubExpr() == 0, ""); // ref-error {{not an integral constant expression}} \
// ref-note {{in call to}} \
// expected-error {{not an integral constant expression}} \
// expected-note {{in call to}}
static_assert(NoSubExpr() == 0, ""); // both-error {{not an integral constant expression}} \
// both-note {{in call to}}
}

namespace Asm {
constexpr int ConditionalAsm(bool t) {
if (t)
asm(""); // expected-note {{subexpression not valid in a constant expression}} \
// ref-note {{subexpression not valid in a constant expression}}
asm(""); // both-note {{subexpression not valid in a constant expression}}

return 0;
}
static_assert(ConditionalAsm(false) == 0, "");
static_assert(ConditionalAsm(true) == 0, ""); // expected-error {{not an integral constant expression}} \
// expected-note {{in call to 'ConditionalAsm(true)'}} \
// ref-error {{not an integral constant expression}} \
// ref-note {{in call to 'ConditionalAsm(true)'}}
static_assert(ConditionalAsm(true) == 0, ""); // both-error {{not an integral constant expression}} \
// both-note {{in call to 'ConditionalAsm(true)'}}


constexpr int Asm() { // expected-error {{never produces a constant expression}} \
// ref-error {{never produces a constant expression}}
__asm volatile(""); // expected-note {{subexpression not valid in a constant expression}} \
// ref-note {{subexpression not valid in a constant expression}}
constexpr int Asm() { // both-error {{never produces a constant expression}}
__asm volatile(""); // both-note {{subexpression not valid in a constant expression}}
return 0;
}
}

namespace Casts {
constexpr int a = reinterpret_cast<int>(12); // expected-error {{must be initialized by a constant expression}} \
// expected-note {{reinterpret_cast is not allowed}} \
// ref-error {{must be initialized by a constant expression}} \
// ref-note {{reinterpret_cast is not allowed}}
constexpr int a = reinterpret_cast<int>(12); // both-error {{must be initialized by a constant expression}} \
// both-note {{reinterpret_cast is not allowed}}

void func() {
struct B {};
B b;
(void)*reinterpret_cast<void*>(&b); // both-error {{indirection not permitted on operand of type 'void *'}}
}
}
1 change: 1 addition & 0 deletions clang/test/AST/ByteCode/literals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ static_assert(Failed2 == 0, ""); // both-error {{not an integral constant expres
// both-note {{initializer of 'Failed2' is not a constant expression}}

const int x = *(volatile int*)0x1234;
static_assert((void{}, true), "");

namespace ScalarTypes {
constexpr int ScalarInitInt = int();
Expand Down
22 changes: 8 additions & 14 deletions clang/test/AST/ByteCode/new-delete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ namespace std {
namespace PlacementNew {
constexpr int foo() { // both-error {{never produces a constant expression}}
char c[sizeof(int)];
new (c) int{12}; // ref-note {{call to placement 'operator new'}} \
new (c) int{12}; // ref-note {{this placement new expression is not supported in constant expressions before C++2c}} \
// expected-note {{subexpression not valid in a constant expression}}
return 0;
}
Expand Down Expand Up @@ -309,7 +309,7 @@ namespace placement_new_delete {
constexpr bool bad(int which) {
switch (which) {
case 0:
delete new (placement_new_arg{}) int; // ref-note {{call to placement 'operator new'}} \
delete new (placement_new_arg{}) int; // ref-note {{this placement new expression is not supported in constant expressions}} \
// expected-note {{subexpression not valid in a constant expression}}
break;

Expand All @@ -328,7 +328,7 @@ namespace placement_new_delete {
case 4:
// FIXME: This technically follows the standard's rules, but it seems
// unreasonable to expect implementations to support this.
delete new (std::align_val_t{64}) Overaligned; // ref-note {{placement new expression is not yet supported}} \
delete new (std::align_val_t{64}) Overaligned; // ref-note {{this placement new expression is not supported in constant expressions}} \
// expected-note {{subexpression not valid in a constant expression}}
break;
}
Expand Down Expand Up @@ -404,7 +404,7 @@ constexpr typename std::remove_reference<T>::type&& move(T &&t) noexcept {

namespace cxx2a {
struct A {
int* p = new int(42); // both-note 7{{heap allocation performed here}}
int* p = new int(42); // both-note 3{{heap allocation performed here}}
consteval int ret_i() const { return p ? *p : 0; }
consteval A ret_a() const { return A{}; }
constexpr ~A() { delete p; }
Expand Down Expand Up @@ -433,9 +433,7 @@ void test() {
{ A k = to_lvalue_ref(A()); } // both-error {{'cxx2a::to_lvalue_ref' is not a constant expression}} \
// both-note {{reference to temporary is not a constant expression}} \
// both-note {{temporary created here}}
{ A k = to_lvalue_ref(A().ret_a()); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
// both-note {{heap-allocated object is not a constant expression}} \
// both-error {{'cxx2a::to_lvalue_ref' is not a constant expression}} \
{ A k = to_lvalue_ref(A().ret_a()); } // both-error {{'cxx2a::to_lvalue_ref' is not a constant expression}} \
// both-note {{reference to temporary is not a constant expression}} \
// both-note {{temporary created here}}
{ int k = A().ret_a().ret_i(); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
Expand All @@ -445,19 +443,15 @@ void test() {
{ int k = const_a_ref(a); }
{ int k = rvalue_ref(A()); }
{ int k = rvalue_ref(std::move(a)); }
{ int k = const_a_ref(A().ret_a()); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
// both-note {{is not a constant expression}}
{ int k = const_a_ref(to_lvalue_ref(A().ret_a())); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
// both-note {{is not a constant expression}}
{ int k = const_a_ref(A().ret_a()); }
{ int k = const_a_ref(to_lvalue_ref(A().ret_a())); }
{ int k = const_a_ref(to_lvalue_ref(std::move(a))); }
{ int k = by_value_a(A().ret_a()); }
{ int k = by_value_a(to_lvalue_ref(static_cast<const A&&>(a))); }
{ int k = (A().ret_a(), A().ret_i()); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
// both-note {{is not a constant expression}} \
// both-warning {{left operand of comma operator has no effect}}
{ int k = (const_a_ref(A().ret_a()), A().ret_i()); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
// both-note {{is not a constant expression}} \
// both-warning {{left operand of comma operator has no effect}}
{ int k = (const_a_ref(A().ret_a()), A().ret_i()); } // both-warning {{left operand of comma operator has no effect}}
}
}

Expand Down
4 changes: 4 additions & 0 deletions clang/test/AST/HLSL/ast-dump-comment-cbuffe-tbufferr.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,16 @@ tbuffer B {
}

// AST:HLSLBufferDecl {{.*}}:11:1, line:20:1> line:11:9 cbuffer A
// AST-NEXT:-HLSLResourceClassAttr {{.*}} <<invalid sloc>> Implicit CBuffer
// AST-NEXT:-HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit CBuffer
// AST-NEXT:FullComment {{.*}}<line:10:4, col:17>
// AST-NEXT:`-ParagraphComment {{.*}}<col:4, col:17>
// AST-NEXT:`-TextComment {{.*}}<col:4, col:17> Text=" CBuffer decl."
// AST-NEXT:-VarDecl {{.*}}<line:15:5, col:11> col:11 a 'float'
// AST-NEXT:`-VarDecl {{.*}}<line:19:5, col:9> col:9 b 'int'
// AST-NEXT:HLSLBufferDecl {{.*}}<line:29:1, line:38:1> line:29:9 tbuffer B
// AST-NEXT:-HLSLResourceClassAttr {{.*}} <<invalid sloc>> Implicit SRV
// AST-NEXT:-HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit TBuffer
// AST-NEXT:-FullComment {{.*}}<line:28:4, col:17>
// AST-NEXT: `-ParagraphComment {{.*}}<col:4, col:17>
// AST-NEXT: `-TextComment {{.*}}<col:4, col:17> Text=" TBuffer decl."
Expand Down
8 changes: 6 additions & 2 deletions clang/test/AST/HLSL/cbuffer_tbuffer.hlsl
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -ast-dump -o - %s | FileCheck %s

// CHECK:HLSLBufferDecl 0x[[CB:[0-9a-f]+]] {{.*}} line:5:9 cbuffer CB
// CHECK:HLSLBufferDecl 0x[[CB:[0-9a-f]+]] {{.*}} line:7:9 cbuffer CB
// CHECK:HLSLResourceClassAttr 0x{{[0-9a-f]+}} <<invalid sloc>> Implicit CBuffer
// CHECK-NEXT:HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit CBuffer
// CHECK-NEXT:VarDecl 0x[[A:[0-9a-f]+]] {{.*}} col:9 used a 'float'
cbuffer CB {
float a;
}

// CHECK:HLSLBufferDecl 0x[[TB:[0-9a-f]+]] {{.*}} line:11:9 tbuffer TB
// CHECK:HLSLBufferDecl 0x[[TB:[0-9a-f]+]] {{.*}} line:15:9 tbuffer TB
// CHECK:HLSLResourceClassAttr 0x{{[0-9a-f]+}} <<invalid sloc>> Implicit SRV
// CHECK-NEXT:HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit TBuffer
// CHECK-NEXT:VarDecl 0x[[B:[0-9a-f]+]] {{.*}} col:9 used b 'float'
tbuffer TB {
float b;
Expand Down
2 changes: 2 additions & 0 deletions clang/test/AST/HLSL/packoffset.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
// CHECK: HLSLBufferDecl {{.*}} cbuffer A
cbuffer A
{
// CHECK-NEXT:-HLSLResourceClassAttr {{.*}} <<invalid sloc>> Implicit CBuffer
// CHECK-NEXT:-HLSLResourceAttr {{.*}} <<invalid sloc>> Implicit CBuffer
// CHECK-NEXT: VarDecl {{.*}} A1 'float4'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 0
float4 A1 : packoffset(c);
Expand Down
Loading