58 changes: 43 additions & 15 deletions clang/lib/Analysis/FlowSensitive/Transfer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,9 @@ namespace {

class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
public:
TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env)
: StmtToEnv(StmtToEnv), Env(Env) {}
TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env,
Environment::ValueModel &Model)
: StmtToEnv(StmtToEnv), Env(Env), Model(Model) {}

void VisitBinaryOperator(const BinaryOperator *S) {
const Expr *LHS = S->getLHS();
Expand Down Expand Up @@ -641,17 +642,42 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
}

void VisitConditionalOperator(const ConditionalOperator *S) {
// FIXME: Revisit this once flow conditions are added to the framework. For
// `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow
// condition.
// When we do this, we will need to retrieve the values of the operands from
// the environments for the basic blocks they are computed in, in a similar
// way to how this is done for short-circuited logical operators in
// `getLogicOperatorSubExprValue()`.
if (S->isGLValue())
Env.setStorageLocation(*S, Env.createObject(S->getType()));
else if (!S->getType()->isRecordType()) {
if (Value *Val = Env.createValue(S->getType()))
const Environment *TrueEnv = StmtToEnv.getEnvironment(*S->getTrueExpr());
const Environment *FalseEnv = StmtToEnv.getEnvironment(*S->getFalseExpr());

if (TrueEnv == nullptr || FalseEnv == nullptr) {
// If the true or false branch is dead, we may not have an environment for
// it. We could handle this specifically by forwarding the value or
// location of the live branch, but this case is rare enough that this
// probably isn't worth the additional complexity.
return;
}

if (S->isGLValue()) {
StorageLocation *TrueLoc = TrueEnv->getStorageLocation(*S->getTrueExpr());
StorageLocation *FalseLoc =
FalseEnv->getStorageLocation(*S->getFalseExpr());
if (TrueLoc == FalseLoc && TrueLoc != nullptr)
Env.setStorageLocation(*S, *TrueLoc);
} else if (!S->getType()->isRecordType()) {
// The conditional operator can evaluate to either of the values of the
// two branches. To model this, join these two values together to yield
// the result of the conditional operator.
// Note: Most joins happen in `computeBlockInputState()`, but this case is
// different:
// - `computeBlockInputState()` (which in turn calls `Environment::join()`
// joins values associated with the _same_ expression or storage
// location, then associates the joined value with that expression or
// storage location. This join has nothing to do with transfer --
// instead, it joins together the results of performing transfer on two
// different blocks.
// - Here, we join values associated with _different_ expressions (the
// true and false branch), then associate the joined value with a third
// expression (the conditional operator itself). This join is what it
// means to perform transfer on the conditional operator.
if (Value *Val = Environment::joinValues(
S->getType(), TrueEnv->getValue(*S->getTrueExpr()), *TrueEnv,
FalseEnv->getValue(*S->getFalseExpr()), *FalseEnv, Env, Model))
Env.setValue(*S, *Val);
}
}
Expand Down Expand Up @@ -810,12 +836,14 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {

const StmtToEnvMap &StmtToEnv;
Environment &Env;
Environment::ValueModel &Model;
};

} // namespace

void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) {
TransferVisitor(StmtToEnv, Env).Visit(&S);
void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env,
Environment::ValueModel &Model) {
TransferVisitor(StmtToEnv, Env, Model).Visit(&S);
}

} // namespace dataflow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ builtinTransferStatement(unsigned CurBlockID, const CFGStmt &Elt,
const Stmt *S = Elt.getStmt();
assert(S != nullptr);
transfer(StmtToEnvMap(AC.ACFG, AC.BlockStates, CurBlockID, InputState), *S,
InputState.Env);
InputState.Env, AC.Analysis);
}

/// Built-in transfer function for `CFGInitializer`.
Expand Down Expand Up @@ -452,7 +452,7 @@ transferCFGBlock(const CFGBlock &Block, AnalysisContext &AC,
// terminator condition, but not as a `CFGElement`. The condition of an if
// statement is one such example.
transfer(StmtToEnvMap(AC.ACFG, AC.BlockStates, Block.getBlockID(), State),
*TerminatorCond, State.Env);
*TerminatorCond, State.Env, AC.Analysis);

// If the transfer function didn't produce a value, create an atom so that
// we have *some* value for the condition expression. This ensures that
Expand Down
8 changes: 6 additions & 2 deletions clang/lib/Basic/Targets/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasPrivileged = true;
} else if (Feature == "+aix-small-local-exec-tls") {
HasAIXSmallLocalExecTLS = true;
} else if (Feature == "+aix-small-local-dynamic-tls") {
HasAIXSmallLocalDynamicTLS = true;
} else if (Feature == "+isa-v206-instructions") {
IsISA2_06 = true;
} else if (Feature == "+isa-v207-instructions") {
Expand Down Expand Up @@ -573,9 +575,10 @@ bool PPCTargetInfo::initFeatureMap(
// Privileged instructions are off by default.
Features["privileged"] = false;

// The code generated by the -maix-small-local-exec-tls option is turned
// off by default.
// The code generated by the -maix-small-local-[exec|dynamic]-tls option is
// turned off by default.
Features["aix-small-local-exec-tls"] = false;
Features["aix-small-local-dynamic-tls"] = false;

Features["spe"] = llvm::StringSwitch<bool>(CPU)
.Case("8548", true)
Expand Down Expand Up @@ -713,6 +716,7 @@ bool PPCTargetInfo::hasFeature(StringRef Feature) const {
.Case("rop-protect", HasROPProtect)
.Case("privileged", HasPrivileged)
.Case("aix-small-local-exec-tls", HasAIXSmallLocalExecTLS)
.Case("aix-small-local-dynamic-tls", HasAIXSmallLocalDynamicTLS)
.Case("isa-v206-instructions", IsISA2_06)
.Case("isa-v207-instructions", IsISA2_07)
.Case("isa-v30-instructions", IsISA3_0)
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/PPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
bool HasROPProtect = false;
bool HasPrivileged = false;
bool HasAIXSmallLocalExecTLS = false;
bool HasAIXSmallLocalDynamicTLS = false;
bool HasVSX = false;
bool UseCRBits = false;
bool HasP8Vector = false;
Expand Down
57 changes: 35 additions & 22 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,21 @@ static cl::opt<bool> ClSanitizeOnOptimizerEarlyEP(
"sanitizer-early-opt-ep", cl::Optional,
cl::desc("Insert sanitizers on OptimizerEarlyEP."));

// Experiment to mark cold functions as optsize/minsize/optnone.
// TODO: remove once this is exposed as a proper driver flag.
static cl::opt<PGOOptions::ColdFuncOpt> ClPGOColdFuncAttr(
"pgo-cold-func-opt", cl::init(PGOOptions::ColdFuncOpt::Default), cl::Hidden,
cl::desc(
"Function attribute to apply to cold functions as determined by PGO"),
cl::values(clEnumValN(PGOOptions::ColdFuncOpt::Default, "default",
"Default (no attribute)"),
clEnumValN(PGOOptions::ColdFuncOpt::OptSize, "optsize",
"Mark cold functions with optsize."),
clEnumValN(PGOOptions::ColdFuncOpt::MinSize, "minsize",
"Mark cold functions with minsize."),
clEnumValN(PGOOptions::ColdFuncOpt::OptNone, "optnone",
"Mark cold functions with optnone.")));

extern cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate;

// Re-link builtin bitcodes after optimization
Expand Down Expand Up @@ -768,42 +783,41 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
CodeGenOpts.InstrProfileOutput.empty() ? getDefaultProfileGenName()
: CodeGenOpts.InstrProfileOutput,
"", "", CodeGenOpts.MemoryProfileUsePath, nullptr, PGOOptions::IRInstr,
PGOOptions::NoCSAction, PGOOptions::ColdFuncOpt::Default,
PGOOptions::NoCSAction, ClPGOColdFuncAttr,
CodeGenOpts.DebugInfoForProfiling,
/*PseudoProbeForProfiling=*/false, CodeGenOpts.AtomicProfileUpdate);
else if (CodeGenOpts.hasProfileIRUse()) {
// -fprofile-use.
auto CSAction = CodeGenOpts.hasProfileCSIRUse() ? PGOOptions::CSIRUse
: PGOOptions::NoCSAction;
PGOOpt = PGOOptions(
CodeGenOpts.ProfileInstrumentUsePath, "",
CodeGenOpts.ProfileRemappingFile, CodeGenOpts.MemoryProfileUsePath, VFS,
PGOOptions::IRUse, CSAction, PGOOptions::ColdFuncOpt::Default,
CodeGenOpts.DebugInfoForProfiling);
PGOOpt = PGOOptions(CodeGenOpts.ProfileInstrumentUsePath, "",
CodeGenOpts.ProfileRemappingFile,
CodeGenOpts.MemoryProfileUsePath, VFS,
PGOOptions::IRUse, CSAction, ClPGOColdFuncAttr,
CodeGenOpts.DebugInfoForProfiling);
} else if (!CodeGenOpts.SampleProfileFile.empty())
// -fprofile-sample-use
PGOOpt = PGOOptions(
CodeGenOpts.SampleProfileFile, "", CodeGenOpts.ProfileRemappingFile,
CodeGenOpts.MemoryProfileUsePath, VFS, PGOOptions::SampleUse,
PGOOptions::NoCSAction, PGOOptions::ColdFuncOpt::Default,
PGOOptions::NoCSAction, ClPGOColdFuncAttr,
CodeGenOpts.DebugInfoForProfiling, CodeGenOpts.PseudoProbeForProfiling);
else if (!CodeGenOpts.MemoryProfileUsePath.empty())
// -fmemory-profile-use (without any of the above options)
PGOOpt = PGOOptions("", "", "", CodeGenOpts.MemoryProfileUsePath, VFS,
PGOOptions::NoAction, PGOOptions::NoCSAction,
PGOOptions::ColdFuncOpt::Default,
CodeGenOpts.DebugInfoForProfiling);
ClPGOColdFuncAttr, CodeGenOpts.DebugInfoForProfiling);
else if (CodeGenOpts.PseudoProbeForProfiling)
// -fpseudo-probe-for-profiling
PGOOpt = PGOOptions("", "", "", /*MemoryProfile=*/"", nullptr,
PGOOptions::NoAction, PGOOptions::NoCSAction,
PGOOptions::ColdFuncOpt::Default,
CodeGenOpts.DebugInfoForProfiling, true);
PGOOpt =
PGOOptions("", "", "", /*MemoryProfile=*/"", nullptr,
PGOOptions::NoAction, PGOOptions::NoCSAction,
ClPGOColdFuncAttr, CodeGenOpts.DebugInfoForProfiling, true);
else if (CodeGenOpts.DebugInfoForProfiling)
// -fdebug-info-for-profiling
PGOOpt = PGOOptions("", "", "", /*MemoryProfile=*/"", nullptr,
PGOOptions::NoAction, PGOOptions::NoCSAction,
PGOOptions::ColdFuncOpt::Default, true);
ClPGOColdFuncAttr, true);

// Check to see if we want to generate a CS profile.
if (CodeGenOpts.hasProfileCSIRInstr()) {
Expand All @@ -820,14 +834,13 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
: CodeGenOpts.InstrProfileOutput;
PGOOpt->CSAction = PGOOptions::CSIRInstr;
} else
PGOOpt =
PGOOptions("",
CodeGenOpts.InstrProfileOutput.empty()
? getDefaultProfileGenName()
: CodeGenOpts.InstrProfileOutput,
"", /*MemoryProfile=*/"", nullptr, PGOOptions::NoAction,
PGOOptions::CSIRInstr, PGOOptions::ColdFuncOpt::Default,
CodeGenOpts.DebugInfoForProfiling);
PGOOpt = PGOOptions("",
CodeGenOpts.InstrProfileOutput.empty()
? getDefaultProfileGenName()
: CodeGenOpts.InstrProfileOutput,
"", /*MemoryProfile=*/"", nullptr,
PGOOptions::NoAction, PGOOptions::CSIRInstr,
ClPGOColdFuncAttr, CodeGenOpts.DebugInfoForProfiling);
}
if (TM)
TM->setPGOOption(PGOOpt);
Expand Down
66 changes: 38 additions & 28 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -826,29 +826,32 @@ const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberField(
ASTContext &Ctx, const RecordDecl *RD, StringRef Name, uint64_t &Offset) {
const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
getLangOpts().getStrictFlexArraysLevel();
unsigned FieldNo = 0;
bool IsUnion = RD->isUnion();
uint32_t FieldNo = 0;

for (const Decl *D : RD->decls()) {
if (const auto *Field = dyn_cast<FieldDecl>(D);
Field && (Name.empty() || Field->getNameAsString() == Name) &&
if (RD->isImplicit())
return nullptr;

for (const FieldDecl *FD : RD->fields()) {
if ((Name.empty() || FD->getNameAsString() == Name) &&
Decl::isFlexibleArrayMemberLike(
Ctx, Field, Field->getType(), StrictFlexArraysLevel,
Ctx, FD, FD->getType(), StrictFlexArraysLevel,
/*IgnoreTemplateOrMacroSubstitution=*/true)) {
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
Offset += Layout.getFieldOffset(FieldNo);
return Field;
return FD;
}

if (const auto *Record = dyn_cast<RecordDecl>(D))
if (const FieldDecl *Field =
FindFlexibleArrayMemberField(Ctx, Record, Name, Offset)) {
QualType Ty = FD->getType();
if (Ty->isRecordType()) {
if (const FieldDecl *Field = FindFlexibleArrayMemberField(
Ctx, Ty->getAsRecordDecl(), Name, Offset)) {
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
Offset += Layout.getFieldOffset(FieldNo);
return Field;
}
}

if (!IsUnion && isa<FieldDecl>(D))
if (!RD->isUnion())
++FieldNo;
}

Expand All @@ -858,14 +861,13 @@ const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberField(
static unsigned CountCountedByAttrs(const RecordDecl *RD) {
unsigned Num = 0;

for (const Decl *D : RD->decls()) {
if (const auto *FD = dyn_cast<FieldDecl>(D);
FD && FD->getType()->isCountAttributedType()) {
for (const FieldDecl *FD : RD->fields()) {
if (FD->getType()->isCountAttributedType())
return ++Num;
}

if (const auto *Rec = dyn_cast<RecordDecl>(D))
Num += CountCountedByAttrs(Rec);
QualType Ty = FD->getType();
if (Ty->isRecordType())
Num += CountCountedByAttrs(Ty->getAsRecordDecl());
}

return Num;
Expand Down Expand Up @@ -18265,8 +18267,8 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
if (!E->getArg(0)->getType()->hasFloatingRepresentation())
llvm_unreachable("lerp operand must have a float representation");
return Builder.CreateIntrinsic(
/*ReturnType=*/X->getType(), Intrinsic::dx_lerp,
ArrayRef<Value *>{X, Y, S}, nullptr, "dx.lerp");
/*ReturnType=*/X->getType(), CGM.getHLSLRuntime().getLerpIntrinsic(),
ArrayRef<Value *>{X, Y, S}, nullptr, "hlsl.lerp");
}
case Builtin::BI__builtin_hlsl_elementwise_frac: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
Expand Down Expand Up @@ -18294,20 +18296,28 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
Value *M = EmitScalarExpr(E->getArg(0));
Value *A = EmitScalarExpr(E->getArg(1));
Value *B = EmitScalarExpr(E->getArg(2));
if (E->getArg(0)->getType()->hasFloatingRepresentation()) {
if (E->getArg(0)->getType()->hasFloatingRepresentation())
return Builder.CreateIntrinsic(
/*ReturnType*/ M->getType(), Intrinsic::fmuladd,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.fmad");
}
ArrayRef<Value *>{M, A, B}, nullptr, "hlsl.fmad");

if (E->getArg(0)->getType()->hasSignedIntegerRepresentation()) {
return Builder.CreateIntrinsic(
/*ReturnType*/ M->getType(), Intrinsic::dx_imad,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.imad");
if (CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil)
return Builder.CreateIntrinsic(
/*ReturnType*/ M->getType(), Intrinsic::dx_imad,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.imad");

Value *Mul = Builder.CreateNSWMul(M, A);
return Builder.CreateNSWAdd(Mul, B);
}
assert(E->getArg(0)->getType()->hasUnsignedIntegerRepresentation());
return Builder.CreateIntrinsic(
/*ReturnType=*/M->getType(), Intrinsic::dx_umad,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.umad");
if (CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil)
return Builder.CreateIntrinsic(
/*ReturnType=*/M->getType(), Intrinsic::dx_umad,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.umad");

Value *Mul = Builder.CreateNUWMul(M, A);
return Builder.CreateNUWAdd(Mul, B);
}
case Builtin::BI__builtin_hlsl_elementwise_rcp: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
Expand Down
6 changes: 2 additions & 4 deletions clang/lib/CodeGen/CGCoroutine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -413,10 +413,8 @@ llvm::Function *
CodeGenFunction::generateAwaitSuspendWrapper(Twine const &CoroName,
Twine const &SuspendPointName,
CoroutineSuspendExpr const &S) {
std::string FuncName = "__await_suspend_wrapper_";
FuncName += CoroName.str();
FuncName += '_';
FuncName += SuspendPointName.str();
std::string FuncName =
(CoroName + ".__await_suspend_wrapper__" + SuspendPointName).str();

ASTContext &C = getContext();

Expand Down
108 changes: 56 additions & 52 deletions clang/lib/CodeGen/CGExprConstant.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1540,7 +1540,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
if (auto DstPT = dyn_cast<llvm::PointerType>(DstTy)) {
// The source value may be an integer, or a pointer.
if (isa<llvm::PointerType>(SrcTy))
return Builder.CreateBitCast(Src, DstTy, "conv");
return Src;

assert(SrcType->isIntegerType() && "Not ptr->ptr or int->ptr conversion?");
// First, convert to the correct width so that we control the kind of
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class CGHLSLRuntime {

GENERATE_HLSL_INTRINSIC_FUNCTION(All, all)
GENERATE_HLSL_INTRINSIC_FUNCTION(Any, any)
GENERATE_HLSL_INTRINSIC_FUNCTION(Lerp, lerp)
GENERATE_HLSL_INTRINSIC_FUNCTION(ThreadId, thread_id)

//===----------------------------------------------------------------------===//
Expand Down
11 changes: 8 additions & 3 deletions clang/lib/CodeGen/CoverageMappingGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1208,6 +1208,12 @@ struct CounterCoverageMappingBuilder
/// Find a valid gap range between \p AfterLoc and \p BeforeLoc.
std::optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc,
SourceLocation BeforeLoc) {
// Some statements (like AttributedStmt and ImplicitValueInitExpr) don't
// have valid source locations. Do not emit a gap region if this is the case
// in either AfterLoc end or BeforeLoc end.
if (AfterLoc.isInvalid() || BeforeLoc.isInvalid())
return std::nullopt;

// If AfterLoc is in function-like macro, use the right parenthesis
// location.
if (AfterLoc.isMacroID()) {
Expand Down Expand Up @@ -1368,9 +1374,8 @@ struct CounterCoverageMappingBuilder
for (const Stmt *Child : S->children())
if (Child) {
// If last statement contains terminate statements, add a gap area
// between the two statements. Skipping attributed statements, because
// they don't have valid start location.
if (LastStmt && HasTerminateStmt && !isa<AttributedStmt>(Child)) {
// between the two statements.
if (LastStmt && HasTerminateStmt) {
auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
if (Gap)
fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),
Expand Down
54 changes: 38 additions & 16 deletions clang/lib/Driver/OffloadBundler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1010,13 +1010,19 @@ CompressedOffloadBundle::compress(llvm::compression::Params P,

uint16_t CompressionMethod = static_cast<uint16_t>(P.format);
uint32_t UncompressedSize = Input.getBuffer().size();
uint32_t TotalFileSize = MagicNumber.size() + sizeof(TotalFileSize) +
sizeof(Version) + sizeof(CompressionMethod) +
sizeof(UncompressedSize) + sizeof(TruncatedHash) +
CompressedBuffer.size();

SmallVector<char, 0> FinalBuffer;
llvm::raw_svector_ostream OS(FinalBuffer);
OS << MagicNumber;
OS.write(reinterpret_cast<const char *>(&Version), sizeof(Version));
OS.write(reinterpret_cast<const char *>(&CompressionMethod),
sizeof(CompressionMethod));
OS.write(reinterpret_cast<const char *>(&TotalFileSize),
sizeof(TotalFileSize));
OS.write(reinterpret_cast<const char *>(&UncompressedSize),
sizeof(UncompressedSize));
OS.write(reinterpret_cast<const char *>(&TruncatedHash),
Expand All @@ -1034,6 +1040,8 @@ CompressedOffloadBundle::compress(llvm::compression::Params P,
(UncompressedSize / (1024.0 * 1024.0)) / CompressionTimeSeconds;

llvm::errs() << "Compressed bundle format version: " << Version << "\n"
<< "Total file size (including headers): "
<< formatWithCommas(TotalFileSize) << " bytes\n"
<< "Compression method used: " << MethodUsed << "\n"
<< "Compression level: " << P.level << "\n"
<< "Binary size before compression: "
Expand All @@ -1059,31 +1067,42 @@ CompressedOffloadBundle::decompress(const llvm::MemoryBuffer &Input,

StringRef Blob = Input.getBuffer();

if (Blob.size() < HeaderSize) {
if (Blob.size() < V1HeaderSize)
return llvm::MemoryBuffer::getMemBufferCopy(Blob);
}

if (llvm::identify_magic(Blob) !=
llvm::file_magic::offload_bundle_compressed) {
if (Verbose)
llvm::errs() << "Uncompressed bundle.\n";
return llvm::MemoryBuffer::getMemBufferCopy(Blob);
}

size_t CurrentOffset = MagicSize;

uint16_t ThisVersion;
memcpy(&ThisVersion, Blob.data() + CurrentOffset, sizeof(uint16_t));
CurrentOffset += VersionFieldSize;

uint16_t CompressionMethod;
memcpy(&CompressionMethod, Blob.data() + CurrentOffset, sizeof(uint16_t));
CurrentOffset += MethodFieldSize;

uint32_t TotalFileSize;
if (ThisVersion >= 2) {
if (Blob.size() < V2HeaderSize)
return createStringError(inconvertibleErrorCode(),
"Compressed bundle header size too small");
memcpy(&TotalFileSize, Blob.data() + CurrentOffset, sizeof(uint32_t));
CurrentOffset += FileSizeFieldSize;
}

uint32_t UncompressedSize;
memcpy(&UncompressedSize, Blob.data() + CurrentOffset, sizeof(uint32_t));
CurrentOffset += UncompressedSizeFieldSize;

uint64_t StoredHash;
memcpy(&ThisVersion, Input.getBuffer().data() + MagicNumber.size(),
sizeof(uint16_t));
memcpy(&CompressionMethod, Blob.data() + MagicSize + VersionFieldSize,
sizeof(uint16_t));
memcpy(&UncompressedSize,
Blob.data() + MagicSize + VersionFieldSize + MethodFieldSize,
sizeof(uint32_t));
memcpy(&StoredHash,
Blob.data() + MagicSize + VersionFieldSize + MethodFieldSize +
SizeFieldSize,
sizeof(uint64_t));
memcpy(&StoredHash, Blob.data() + CurrentOffset, sizeof(uint64_t));
CurrentOffset += HashFieldSize;

llvm::compression::Format CompressionFormat;
if (CompressionMethod ==
Expand All @@ -1102,7 +1121,7 @@ CompressedOffloadBundle::decompress(const llvm::MemoryBuffer &Input,
DecompressTimer.startTimer();

SmallVector<uint8_t, 0> DecompressedData;
StringRef CompressedData = Blob.substr(HeaderSize);
StringRef CompressedData = Blob.substr(CurrentOffset);
if (llvm::Error DecompressionError = llvm::compression::decompress(
CompressionFormat, llvm::arrayRefFromStringRef(CompressedData),
DecompressedData, UncompressedSize))
Expand Down Expand Up @@ -1135,8 +1154,11 @@ CompressedOffloadBundle::decompress(const llvm::MemoryBuffer &Input,
double DecompressionSpeedMBs =
(UncompressedSize / (1024.0 * 1024.0)) / DecompressionTimeSeconds;

llvm::errs() << "Compressed bundle format version: " << ThisVersion << "\n"
<< "Decompression method: "
llvm::errs() << "Compressed bundle format version: " << ThisVersion << "\n";
if (ThisVersion >= 2)
llvm::errs() << "Total file size (from header): "
<< formatWithCommas(TotalFileSize) << " bytes\n";
llvm::errs() << "Decompression method: "
<< (CompressionFormat == llvm::compression::Format::Zlib
? "zlib"
: "zstd")
Expand Down
8 changes: 6 additions & 2 deletions clang/lib/Driver/SanitizerArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1192,7 +1192,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
BinaryMetadataIgnorelistFiles);
}

if (TC.getTriple().isOSWindows() && needsUbsanRt()) {
if (TC.getTriple().isOSWindows() && needsUbsanRt() &&
Args.hasFlag(options::OPT_frtlib_defaultlib,
options::OPT_fno_rtlib_defaultlib, true)) {
// Instruct the code generator to embed linker directives in the object file
// that cause the required runtime libraries to be linked.
CmdArgs.push_back(
Expand All @@ -1203,7 +1205,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
"--dependent-lib=" +
TC.getCompilerRTBasename(Args, "ubsan_standalone_cxx")));
}
if (TC.getTriple().isOSWindows() && needsStatsRt()) {
if (TC.getTriple().isOSWindows() && needsStatsRt() &&
Args.hasFlag(options::OPT_frtlib_defaultlib,
options::OPT_fno_rtlib_defaultlib, true)) {
CmdArgs.push_back(Args.MakeArgString(
"--dependent-lib=" + TC.getCompilerRTBasename(Args, "stats_client")));

Expand Down
17 changes: 9 additions & 8 deletions clang/lib/Driver/ToolChains/Arch/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,21 +125,22 @@ void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple,

bool UseSeparateSections = isUseSeparateSections(Triple);
bool HasDefaultDataSections = Triple.isOSBinFormatXCOFF();
if (Args.hasArg(options::OPT_maix_small_local_exec_tls)) {
if (Args.hasArg(options::OPT_maix_small_local_exec_tls) ||
Args.hasArg(options::OPT_maix_small_local_dynamic_tls)) {
if (!Triple.isOSAIX() || !Triple.isArch64Bit())
D.Diag(diag::err_opt_not_valid_on_target) << "-maix-small-local-exec-tls";
D.Diag(diag::err_opt_not_valid_on_target)
<< "-maix-small-local-[exec|dynamic]-tls";

// The -maix-small-local-exec-tls option should only be used with
// The -maix-small-local-[exec|dynamic]-tls option should only be used with
// -fdata-sections, as having data sections turned off with this option
// is not ideal for performance. Moreover, the small-local-exec-tls region
// is a limited resource, and should not be used for variables that may
// be replaced.
// is not ideal for performance. Moreover, the
// small-local-[exec|dynamic]-tls region is a limited resource, and should
// not be used for variables that may be replaced.
if (!Args.hasFlag(options::OPT_fdata_sections,
options::OPT_fno_data_sections,
UseSeparateSections || HasDefaultDataSections))
D.Diag(diag::err_drv_argument_only_allowed_with)
<< "-maix-small-local-exec-tls"
<< "-fdata-sections";
<< "-maix-small-local-[exec|dynamic]-tls" << "-fdata-sections";
}
}

Expand Down
32 changes: 26 additions & 6 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,9 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
ProfileGenerateArg->getValue()));
// The default is to use Clang Instrumentation.
CmdArgs.push_back("-fprofile-instrument=clang");
if (TC.getTriple().isWindowsMSVCEnvironment()) {
if (TC.getTriple().isWindowsMSVCEnvironment() &&
Args.hasFlag(options::OPT_frtlib_defaultlib,
options::OPT_fno_rtlib_defaultlib, true)) {
// Add dependent lib for clang_rt.profile
CmdArgs.push_back(Args.MakeArgString(
"--dependent-lib=" + TC.getCompilerRTBasename(Args, "profile")));
Expand All @@ -656,7 +658,9 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
CmdArgs.push_back("-fprofile-instrument=csllvm");
}
if (PGOGenArg) {
if (TC.getTriple().isWindowsMSVCEnvironment()) {
if (TC.getTriple().isWindowsMSVCEnvironment() &&
Args.hasFlag(options::OPT_frtlib_defaultlib,
options::OPT_fno_rtlib_defaultlib, true)) {
// Add dependent lib for clang_rt.profile
CmdArgs.push_back(Args.MakeArgString(
"--dependent-lib=" + TC.getCompilerRTBasename(Args, "profile")));
Expand Down Expand Up @@ -847,6 +851,16 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) {
if (Arg *A = Args.getLastArg(options::OPT_O_Group))
RelaxDefault = A->getOption().matches(options::OPT_O0);

// RISC-V requires an indirect jump for offsets larger than 1MiB. This cannot
// be done by assembler branch relaxation as it needs a free temporary
// register. Because of this, branch relaxation is handled by a MachineIR
// pass before the assembler. Forcing assembler branch relaxation for -O0
// makes the MachineIR branch relaxation inaccurate and it will miss cases
// where an indirect branch is necessary. To avoid this issue we are
// sacrificing the compile time improvement of using -mrelax-all for -O0.
if (C.getDefaultToolChain().getTriple().isRISCV())
RelaxDefault = false;

if (RelaxDefault) {
RelaxDefault = false;
for (const auto &Act : C.getActions()) {
Expand Down Expand Up @@ -4634,7 +4648,7 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T,

// Emit DW_TAG_template_alias for template aliases? True by default for SCE.
bool UseDebugTemplateAlias =
DebuggerTuning == llvm::DebuggerKind::SCE && RequestedDWARFVersion >= 5;
DebuggerTuning == llvm::DebuggerKind::SCE && RequestedDWARFVersion >= 4;
if (const auto *DebugTemplateAlias = Args.getLastArg(
options::OPT_gtemplate_alias, options::OPT_gno_template_alias)) {
// DW_TAG_template_alias is only supported from DWARFv5 but if a user
Expand Down Expand Up @@ -4733,7 +4747,7 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T,
Output.getFilename());
}

static void ProcessVSRuntimeLibrary(const ArgList &Args,
static void ProcessVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
unsigned RTOptionID = options::OPT__SLASH_MT;

Expand Down Expand Up @@ -4796,6 +4810,12 @@ static void ProcessVSRuntimeLibrary(const ArgList &Args,
// implemented in clang.
CmdArgs.push_back("--dependent-lib=oldnames");
}

// All Arm64EC object files implicitly add softintrin.lib. This is necessary
// even if the file doesn't actually refer to any of the routines because
// the CRT itself has incomplete dependency markings.
if (TC.getTriple().isWindowsArm64EC())
CmdArgs.push_back("--dependent-lib=softintrin");
}

void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Expand Down Expand Up @@ -7051,7 +7071,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,

if (Triple.isWindowsMSVCEnvironment() && !D.IsCLMode() &&
Args.hasArg(options::OPT_fms_runtime_lib_EQ))
ProcessVSRuntimeLibrary(Args, CmdArgs);
ProcessVSRuntimeLibrary(getToolChain(), Args, CmdArgs);

// Handle -fgcc-version, if present.
VersionTuple GNUCVer;
Expand Down Expand Up @@ -8178,7 +8198,7 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
ArgStringList &CmdArgs) const {
bool isNVPTX = getToolChain().getTriple().isNVPTX();

ProcessVSRuntimeLibrary(Args, CmdArgs);
ProcessVSRuntimeLibrary(getToolChain(), Args, CmdArgs);

if (Arg *ShowIncludes =
Args.getLastArg(options::OPT__SLASH_showIncludes,
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ void Flang::addOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const {
Arg *gNArg = Args.getLastArg(options::OPT_gN_Group);
DebugInfoKind = debugLevelToInfoKind(*gNArg);
} else if (Args.hasArg(options::OPT_g_Flag)) {
DebugInfoKind = llvm::codegenoptions::DebugLineTablesOnly;
DebugInfoKind = llvm::codegenoptions::FullDebugInfo;
} else {
DebugInfoKind = llvm::codegenoptions::NoDebugInfo;
}
Expand Down
28 changes: 15 additions & 13 deletions clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,27 +164,29 @@ std::optional<Array> serializeAvailability(const AvailabilityInfo &Avail) {
if (Avail.isDefault())
return std::nullopt;

Object Availability;
Array AvailabilityArray;
Availability["domain"] = Avail.Domain;
serializeObject(Availability, "introduced",
serializeSemanticVersion(Avail.Introduced));
serializeObject(Availability, "deprecated",
serializeSemanticVersion(Avail.Deprecated));
serializeObject(Availability, "obsoleted",
serializeSemanticVersion(Avail.Obsoleted));

if (Avail.isUnconditionallyDeprecated()) {
Object UnconditionallyDeprecated;
UnconditionallyDeprecated["domain"] = "*";
UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true;
AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated));
}
if (Avail.isUnconditionallyUnavailable()) {
Object UnconditionallyUnavailable;
UnconditionallyUnavailable["domain"] = "*";
UnconditionallyUnavailable["isUnconditionallyUnavailable"] = true;
AvailabilityArray.emplace_back(std::move(UnconditionallyUnavailable));
Object Availability;

Availability["domain"] = Avail.Domain;

if (Avail.isUnavailable()) {
Availability["isUnconditionallyUnavailable"] = true;
} else {
serializeObject(Availability, "introduced",
serializeSemanticVersion(Avail.Introduced));
serializeObject(Availability, "deprecated",
serializeSemanticVersion(Avail.Deprecated));
serializeObject(Availability, "obsoleted",
serializeSemanticVersion(Avail.Obsoleted));
}

AvailabilityArray.emplace_back(std::move(Availability));
return AvailabilityArray;
}
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1543,6 +1543,7 @@ class AnnotatingParser {
return false;
if (Line.MustBeDeclaration && Contexts.size() == 1 &&
!Contexts.back().IsExpression && !Line.startsWith(TT_ObjCProperty) &&
!Line.startsWith(tok::l_paren) &&
!Tok->isOneOf(TT_TypeDeclarationParen, TT_RequiresExpressionLParen)) {
if (const auto *Previous = Tok->Previous;
!Previous ||
Expand Down Expand Up @@ -2726,8 +2727,10 @@ class AnnotatingParser {
}
}

if (Tok.Next->isOneOf(tok::question, tok::ampamp))
if (Tok.Next->is(tok::question) ||
(Tok.Next->is(tok::ampamp) && !Tok.Previous->isTypeName(IsCpp))) {
return false;
}

// `foreach((A a, B b) in someList)` should not be seen as a cast.
if (Tok.Next->is(Keywords.kw_in) && Style.isCSharp())
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3660,6 +3660,9 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
case LangOptions::ClangABI::Ver17:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "17.0");
break;
case LangOptions::ClangABI::Ver18:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "18.0");
break;
case LangOptions::ClangABI::Latest:
break;
}
Expand Down Expand Up @@ -4167,6 +4170,8 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.setClangABICompat(LangOptions::ClangABI::Ver15);
else if (Major <= 17)
Opts.setClangABICompat(LangOptions::ClangABI::Ver17);
else if (Major <= 18)
Opts.setClangABICompat(LangOptions::ClangABI::Ver18);
} else if (Ver != "latest") {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Headers/avxintrin.h
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,7 @@ _mm256_permutevar_pd(__m256d __a, __m256i __c)

/// Copies the values stored in a 128-bit vector of [4 x float] as
/// specified by the 128-bit integer vector operand.
///
/// \headerfile <x86intrin.h>
///
/// This intrinsic corresponds to the <c> VPERMILPS </c> instruction.
Expand Down
24 changes: 19 additions & 5 deletions clang/lib/Interpreter/IncrementalParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@ IncrementalParser::IncrementalParser(Interpreter &Interp,
if (Err)
return;
CI->ExecuteAction(*Act);

if (getCodeGen())
CachedInCodeGenModule = GenModule();

std::unique_ptr<ASTConsumer> IncrConsumer =
std::make_unique<IncrementalASTConsumer>(Interp, CI->takeASTConsumer());
CI->setASTConsumer(std::move(IncrConsumer));
Expand All @@ -224,11 +228,8 @@ IncrementalParser::IncrementalParser(Interpreter &Interp,
return; // PTU.takeError();
}

if (CodeGenerator *CG = getCodeGen()) {
std::unique_ptr<llvm::Module> M(CG->ReleaseModule());
CG->StartModule("incr_module_" + std::to_string(PTUs.size()),
M->getContext());
PTU->TheModule = std::move(M);
if (getCodeGen()) {
PTU->TheModule = GenModule();
assert(PTU->TheModule && "Failed to create initial PTU");
}
}
Expand Down Expand Up @@ -364,6 +365,19 @@ IncrementalParser::Parse(llvm::StringRef input) {
std::unique_ptr<llvm::Module> IncrementalParser::GenModule() {
static unsigned ID = 0;
if (CodeGenerator *CG = getCodeGen()) {
// Clang's CodeGen is designed to work with a single llvm::Module. In many
// cases for convenience various CodeGen parts have a reference to the
// llvm::Module (TheModule or Module) which does not change when a new
// module is pushed. However, the execution engine wants to take ownership
// of the module which does not map well to CodeGen's design. To work this
// around we created an empty module to make CodeGen happy. We should make
// sure it always stays empty.
assert((!CachedInCodeGenModule ||
(CachedInCodeGenModule->empty() &&
CachedInCodeGenModule->global_empty() &&
CachedInCodeGenModule->alias_empty() &&
CachedInCodeGenModule->ifunc_empty())) &&
"CodeGen wrote to a readonly module");
std::unique_ptr<llvm::Module> M(CG->ReleaseModule());
CG->StartModule("incr_module_" + std::to_string(ID++), M->getContext());
return M;
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Interpreter/IncrementalParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <memory>
namespace llvm {
class LLVMContext;
class Module;
} // namespace llvm

namespace clang {
Expand Down Expand Up @@ -57,6 +58,10 @@ class IncrementalParser {
/// of code.
std::list<PartialTranslationUnit> PTUs;

/// When CodeGen is created the first llvm::Module gets cached in many places
/// and we must keep it alive.
std::unique_ptr<llvm::Module> CachedInCodeGenModule;

IncrementalParser();

public:
Expand Down
36 changes: 32 additions & 4 deletions clang/lib/Lex/LiteralSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
bool isFixedPointConstant = isFixedPointLiteral();
bool isFPConstant = isFloatingLiteral();
bool HasSize = false;
bool DoubleUnderscore = false;

// Loop over all of the characters of the suffix. If we see something bad,
// we break out of the loop.
Expand Down Expand Up @@ -1117,6 +1118,31 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
if (isImaginary) break; // Cannot be repeated.
isImaginary = true;
continue; // Success.
case '_':
if (isFPConstant)
break; // Invalid for floats
if (HasSize)
break;
if (DoubleUnderscore)
break; // Cannot be repeated.
if (LangOpts.CPlusPlus && s + 2 < ThisTokEnd &&
s[1] == '_') { // s + 2 < ThisTokEnd to ensure some character exists
// after __
DoubleUnderscore = true;
s += 2; // Skip both '_'
if (s + 1 < ThisTokEnd &&
(*s == 'u' || *s == 'U')) { // Ensure some character after 'u'/'U'
isUnsigned = true;
++s;
}
if (s + 1 < ThisTokEnd &&
((*s == 'w' && *(++s) == 'b') || (*s == 'W' && *(++s) == 'B'))) {
isBitInt = true;
HasSize = true;
continue;
}
}
break;
case 'w':
case 'W':
if (isFPConstant)
Expand All @@ -1127,9 +1153,9 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
// wb and WB are allowed, but a mixture of cases like Wb or wB is not. We
// explicitly do not support the suffix in C++ as an extension because a
// library-based UDL that resolves to a library type may be more
// appropriate there.
if (!LangOpts.CPlusPlus && ((s[0] == 'w' && s[1] == 'b') ||
(s[0] == 'W' && s[1] == 'B'))) {
// appropriate there. The same rules apply for __wb/__WB.
if ((!LangOpts.CPlusPlus || DoubleUnderscore) && s + 1 < ThisTokEnd &&
((s[0] == 'w' && s[1] == 'b') || (s[0] == 'W' && s[1] == 'B'))) {
isBitInt = true;
HasSize = true;
++s; // Skip both characters (2nd char skipped on continue).
Expand Down Expand Up @@ -1241,7 +1267,9 @@ bool NumericLiteralParser::isValidUDSuffix(const LangOptions &LangOpts,
return false;

// By C++11 [lex.ext]p10, ud-suffixes starting with an '_' are always valid.
if (Suffix[0] == '_')
// Suffixes starting with '__' (double underscore) are for use by
// the implementation.
if (Suffix.starts_with("_") && !Suffix.starts_with("__"))
return true;

// In C++11, there are no library suffixes.
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/Lex/PPExpressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,11 +333,11 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
: diag::ext_cxx23_size_t_suffix
: diag::err_cxx23_size_t_suffix);

// 'wb/uwb' literals are a C23 feature. We explicitly do not support the
// suffix in C++ as an extension because a library-based UDL that resolves
// to a library type may be more appropriate there.
// 'wb/uwb' literals are a C23 feature.
// '__wb/__uwb' are a C++ extension.
if (Literal.isBitInt)
PP.Diag(PeekTok, PP.getLangOpts().C23
PP.Diag(PeekTok, PP.getLangOpts().CPlusPlus ? diag::ext_cxx_bitint_suffix
: PP.getLangOpts().C23
? diag::warn_c23_compat_bitint_suffix
: diag::ext_c23_bitint_suffix);

Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Parse/ParseCXXInlineMethods.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,8 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
// to be re-used for method bodies as well.
ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope |
Scope::CompoundStmtScope);
Sema::FPFeaturesStateRAII SaveFPFeatures(Actions);

Actions.ActOnStartOfFunctionDef(getCurScope(), LM.D);

if (Tok.is(tok::kw_try)) {
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2222,7 +2222,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
}

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

if (Tok.is(tok::kw_requires))
ParseTrailingRequiresClause(D);
Expand Down Expand Up @@ -2469,7 +2469,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
ParseDeclarator(D);

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

if (!D.isInvalidType()) {
// C++2a [dcl.decl]p1
Expand Down Expand Up @@ -7699,7 +7699,7 @@ void Parser::ParseParameterDeclarationClause(
// Parse GNU attributes, if present.
MaybeParseGNUAttributes(ParmDeclarator);
if (getLangOpts().HLSL)
MaybeParseHLSLSemantics(DS.getAttributes());
MaybeParseHLSLAnnotations(DS.getAttributes());

if (Tok.is(tok::kw_requires)) {
// User tried to define a requires clause in a parameter declaration,
Expand Down
18 changes: 8 additions & 10 deletions clang/lib/Parse/ParseHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd) {
SourceLocation IdentifierLoc = ConsumeToken();

ParsedAttributes Attrs(AttrFactory);
MaybeParseHLSLSemantics(Attrs, nullptr);
MaybeParseHLSLAnnotations(Attrs, nullptr);

ParseScope BufferScope(this, Scope::DeclScope);
BalancedDelimiterTracker T(*this, tok::l_brace);
Expand Down Expand Up @@ -118,12 +118,10 @@ static void fixSeparateAttrArgAndNumber(StringRef ArgStr, SourceLocation ArgLoc,
Slot = IdentifierLoc::create(Ctx, ArgLoc, PP.getIdentifierInfo(FixedArg));
}

void Parser::ParseHLSLSemantics(ParsedAttributes &Attrs,
SourceLocation *EndLoc) {
// FIXME: HLSLSemantic is shared for Semantic and resource binding which is
// confusing. Need a better name to avoid misunderstanding. Issue
// https://github.com/llvm/llvm-project/issues/57882
assert(Tok.is(tok::colon) && "Not a HLSL Semantic");
void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs,
SourceLocation *EndLoc) {

assert(Tok.is(tok::colon) && "Not a HLSL Annotation");
ConsumeToken();

IdentifierInfo *II = nullptr;
Expand All @@ -141,7 +139,7 @@ void Parser::ParseHLSLSemantics(ParsedAttributes &Attrs,
if (EndLoc)
*EndLoc = Tok.getLocation();
ParsedAttr::Kind AttrKind =
ParsedAttr::getParsedKind(II, nullptr, ParsedAttr::AS_HLSLSemantic);
ParsedAttr::getParsedKind(II, nullptr, ParsedAttr::AS_HLSLAnnotation);

ArgsVector ArgExprs;
switch (AttrKind) {
Expand Down Expand Up @@ -192,10 +190,10 @@ void Parser::ParseHLSLSemantics(ParsedAttributes &Attrs,
case ParsedAttr::AT_HLSLSV_DispatchThreadID:
break;
default:
llvm_unreachable("invalid HLSL Semantic");
llvm_unreachable("invalid HLSL Annotation");
break;
}

Attrs.addNew(II, Loc, nullptr, SourceLocation(), ArgExprs.data(),
ArgExprs.size(), ParsedAttr::Form::HLSLSemantic());
ArgExprs.size(), ParsedAttr::Form::HLSLAnnotation());
}
1 change: 1 addition & 0 deletions clang/lib/Parse/ParseObjc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3736,6 +3736,7 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
ParseScope BodyScope(this, (parseMethod ? Scope::ObjCMethodScope : 0) |
Scope::FnScope | Scope::DeclScope |
Scope::CompoundStmtScope);
Sema::FPFeaturesStateRAII SaveFPFeatures(Actions);

// Tell the actions module that we have entered a method or c-function definition
// with the specified Declarator for the method/function.
Expand Down
87 changes: 70 additions & 17 deletions clang/lib/Parse/ParseOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -632,16 +632,54 @@ Parser::ParseOpenACCClauseList(OpenACCDirectiveKind DirKind) {
return Clauses;
}

ExprResult Parser::ParseOpenACCIntExpr(OpenACCDirectiveKind DK,
OpenACCClauseKind CK,
SourceLocation Loc) {
ExprResult ER =
getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression());
Parser::OpenACCIntExprParseResult
Parser::ParseOpenACCIntExpr(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
SourceLocation Loc) {
ExprResult ER = ParseAssignmentExpression();

// If the actual parsing failed, we don't know the state of the parse, so
// don't try to continue.
if (!ER.isUsable())
return ER;
return {ER, OpenACCParseCanContinue::Cannot};

// Parsing can continue after the initial assignment expression parsing, so
// even if there was a typo, we can continue.
ER = getActions().CorrectDelayedTyposInExpr(ER);
if (!ER.isUsable())
return {ER, OpenACCParseCanContinue::Can};

return {getActions().OpenACC().ActOnIntExpr(DK, CK, Loc, ER.get()),
OpenACCParseCanContinue::Can};
}

bool Parser::ParseOpenACCIntExprList(OpenACCDirectiveKind DK,
OpenACCClauseKind CK, SourceLocation Loc,
llvm::SmallVectorImpl<Expr *> &IntExprs) {
OpenACCIntExprParseResult CurResult = ParseOpenACCIntExpr(DK, CK, Loc);

if (!CurResult.first.isUsable() &&
CurResult.second == OpenACCParseCanContinue::Cannot) {
SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
Parser::StopBeforeMatch);
return true;
}

IntExprs.push_back(CurResult.first.get());

while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
ExpectAndConsume(tok::comma);

CurResult = ParseOpenACCIntExpr(DK, CK, Loc);

return getActions().OpenACC().ActOnIntExpr(DK, CK, Loc, ER.get());
if (!CurResult.first.isUsable() &&
CurResult.second == OpenACCParseCanContinue::Cannot) {
SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
Parser::StopBeforeMatch);
return true;
}
IntExprs.push_back(CurResult.first.get());
}
return false;
}

bool Parser::ParseOpenACCClauseVarList(OpenACCClauseKind Kind) {
Expand Down Expand Up @@ -761,7 +799,7 @@ bool Parser::ParseOpenACCGangArg(SourceLocation GangLoc) {
ConsumeToken();
return ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,
OpenACCClauseKind::Gang, GangLoc)
.isInvalid();
.first.isInvalid();
}

if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Num, getCurToken()) &&
Expand All @@ -773,7 +811,7 @@ bool Parser::ParseOpenACCGangArg(SourceLocation GangLoc) {
// This is just the 'num' case where 'num' is optional.
return ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,
OpenACCClauseKind::Gang, GangLoc)
.isInvalid();
.first.isInvalid();
}

bool Parser::ParseOpenACCGangArgList(SourceLocation GangLoc) {
Expand Down Expand Up @@ -946,13 +984,25 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
}
break;
}
case OpenACCClauseKind::NumGangs:
case OpenACCClauseKind::NumGangs: {
llvm::SmallVector<Expr *> IntExprs;

if (ParseOpenACCIntExprList(OpenACCDirectiveKind::Invalid,
OpenACCClauseKind::NumGangs, ClauseLoc,
IntExprs)) {
Parens.skipToEnd();
return OpenACCCanContinue();
}
ParsedClause.setIntExprDetails(std::move(IntExprs));
break;
}
case OpenACCClauseKind::NumWorkers:
case OpenACCClauseKind::DeviceNum:
case OpenACCClauseKind::DefaultAsync:
case OpenACCClauseKind::VectorLength: {
ExprResult IntExpr = ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,
ClauseKind, ClauseLoc);
ClauseKind, ClauseLoc)
.first;
if (IntExpr.isInvalid()) {
Parens.skipToEnd();
return OpenACCCanContinue();
Expand Down Expand Up @@ -1017,7 +1067,8 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
: OpenACCSpecialTokenKind::Num,
ClauseKind);
ExprResult IntExpr = ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,
ClauseKind, ClauseLoc);
ClauseKind, ClauseLoc)
.first;
if (IntExpr.isInvalid()) {
Parens.skipToEnd();
return OpenACCCanContinue();
Expand Down Expand Up @@ -1081,11 +1132,13 @@ bool Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
// Consume colon.
ConsumeToken();

ExprResult IntExpr = ParseOpenACCIntExpr(
IsDirective ? OpenACCDirectiveKind::Wait
: OpenACCDirectiveKind::Invalid,
IsDirective ? OpenACCClauseKind::Invalid : OpenACCClauseKind::Wait,
Loc);
ExprResult IntExpr =
ParseOpenACCIntExpr(IsDirective ? OpenACCDirectiveKind::Wait
: OpenACCDirectiveKind::Invalid,
IsDirective ? OpenACCClauseKind::Invalid
: OpenACCClauseKind::Wait,
Loc)
.first;
if (IntExpr.isInvalid())
return true;

Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Parse/ParseTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -733,7 +733,12 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
// we introduce the type parameter into the local scope.
SourceLocation EqualLoc;
ParsedType DefaultArg;
std::optional<DelayTemplateIdDestructionRAII> DontDestructTemplateIds;
if (TryConsumeToken(tok::equal, EqualLoc)) {
// The default argument might contain a lambda declaration; avoid destroying
// parsed template ids at the end of that declaration because they can be
// used in a type constraint later.
DontDestructTemplateIds.emplace(*this, /*DelayTemplateIdDestruction=*/true);
// The default argument may declare template parameters, notably
// if it contains a generic lambda, so we need to increase
// the template depth as these parameters would not be instantiated
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Parse/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1497,6 +1497,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
return Actions.ActOnFinishFunctionBody(Res, nullptr, false);
}

Sema::FPFeaturesStateRAII SaveFPFeatures(Actions);

if (Tok.is(tok::kw_try))
return ParseFunctionTryBlock(Res, BodyScope);

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/MultiplexExternalSemaSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ void MultiplexExternalSemaSource::AddSource(ExternalSemaSource *Source) {
// ExternalASTSource.
//===----------------------------------------------------------------------===//

Decl *MultiplexExternalSemaSource::GetExternalDecl(uint32_t ID) {
Decl *MultiplexExternalSemaSource::GetExternalDecl(Decl::DeclID ID) {
for(size_t i = 0; i < Sources.size(); ++i)
if (Decl *Result = Sources[i]->GetExternalDecl(ID))
return Result;
Expand Down
33 changes: 29 additions & 4 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7953,6 +7953,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
// For variadic functions, we may have more args than parameters.
// For some K&R functions, we may have less args than parameters.
const auto N = std::min<unsigned>(Proto->getNumParams(), Args.size());
bool AnyScalableArgsOrRet = Proto->getReturnType()->isSizelessVectorType();
for (unsigned ArgIdx = 0; ArgIdx < N; ++ArgIdx) {
// Args[ArgIdx] can be null in malformed code.
if (const Expr *Arg = Args[ArgIdx]) {
Expand All @@ -7966,6 +7967,8 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
checkAIXMemberAlignment((Arg->getExprLoc()), Arg);

QualType ParamTy = Proto->getParamType(ArgIdx);
if (ParamTy->isSizelessVectorType())
AnyScalableArgsOrRet = true;
QualType ArgTy = Arg->getType();
CheckArgAlignment(Arg->getExprLoc(), FDecl, std::to_string(ArgIdx + 1),
ArgTy, ParamTy);
Expand All @@ -7986,6 +7989,23 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
}
}

// If the call requires a streaming-mode change and has scalable vector
// arguments or return values, then warn the user that the streaming and
// non-streaming vector lengths may be different.
const auto *CallerFD = dyn_cast<FunctionDecl>(CurContext);
if (CallerFD && (!FD || !FD->getBuiltinID()) && AnyScalableArgsOrRet) {
bool IsCalleeStreaming =
ExtInfo.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask;
bool IsCalleeStreamingCompatible =
ExtInfo.AArch64SMEAttributes &
FunctionType::SME_PStateSMCompatibleMask;
ArmStreamingType CallerFnType = getArmStreamingFnType(CallerFD);
if (!IsCalleeStreamingCompatible &&
(CallerFnType == ArmStreamingCompatible ||
((CallerFnType == ArmStreaming) ^ IsCalleeStreaming)))
Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming);
}

FunctionType::ArmStateValue CalleeArmZAState =
FunctionType::getArmZAState(ExtInfo.AArch64SMEAttributes);
FunctionType::ArmStateValue CalleeArmZT0State =
Expand All @@ -7994,7 +8014,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
CalleeArmZT0State != FunctionType::ARM_None) {
bool CallerHasZAState = false;
bool CallerHasZT0State = false;
if (const auto *CallerFD = dyn_cast<FunctionDecl>(CurContext)) {
if (CallerFD) {
auto *Attr = CallerFD->getAttr<ArmNewAttr>();
if (Attr && Attr->isNewZA())
CallerHasZAState = true;
Expand Down Expand Up @@ -12759,10 +12779,15 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// In this case, the expression could be printed using a different
// specifier, but we've decided that the specifier is probably correct
// and we should cast instead. Just use the normal warning message.

unsigned Diag =
IsScopedEnum
? diag::warn_format_conversion_argument_type_mismatch_pedantic
: diag::warn_format_conversion_argument_type_mismatch;

EmitFormatDiagnostic(
S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
<< AT.getRepresentativeTypeName(S.Context) << ExprTy << IsEnum
<< E->getSourceRange(),
S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy
<< IsEnum << E->getSourceRange(),
E->getBeginLoc(), /*IsStringLocation*/ false, SpecRange, Hints);
}
}
Expand Down
7 changes: 2 additions & 5 deletions clang/lib/Sema/SemaCoroutine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -817,13 +817,10 @@ ExprResult Sema::BuildOperatorCoawaitLookupExpr(Scope *S, SourceLocation Loc) {

assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous");
const auto &Functions = Operators.asUnresolvedSet();
bool IsOverloaded =
Functions.size() > 1 ||
(Functions.size() == 1 && isa<FunctionTemplateDecl>(*Functions.begin()));
Expr *CoawaitOp = UnresolvedLookupExpr::Create(
Context, /*NamingClass*/ nullptr, NestedNameSpecifierLoc(),
DeclarationNameInfo(OpName, Loc), /*RequiresADL*/ true, IsOverloaded,
Functions.begin(), Functions.end());
DeclarationNameInfo(OpName, Loc), /*RequiresADL*/ true, Functions.begin(),
Functions.end(), /*KnownDependent=*/false);
assert(CoawaitOp);
return CoawaitOp;
}
Expand Down
35 changes: 32 additions & 3 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1240,8 +1240,8 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
Result.suppressDiagnostics();
return NameClassification::OverloadSet(UnresolvedLookupExpr::Create(
Context, Result.getNamingClass(), SS.getWithLocInContext(Context),
Result.getLookupNameInfo(), ADL, Result.isOverloadedResult(),
Result.begin(), Result.end()));
Result.getLookupNameInfo(), ADL, Result.begin(), Result.end(),
/*KnownDependent=*/false));
}

ExprResult
Expand Down Expand Up @@ -12408,12 +12408,22 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
}

// Check if the function definition uses any AArch64 SME features without
// having the '+sme' feature enabled.
// having the '+sme' feature enabled and warn user if sme locally streaming
// function returns or uses arguments with VL-based types.
if (DeclIsDefn) {
const auto *Attr = NewFD->getAttr<ArmNewAttr>();
bool UsesSM = NewFD->hasAttr<ArmLocallyStreamingAttr>();
bool UsesZA = Attr && Attr->isNewZA();
bool UsesZT0 = Attr && Attr->isNewZT0();

if (NewFD->hasAttr<ArmLocallyStreamingAttr>()) {
if (NewFD->getReturnType()->isSizelessVectorType() ||
llvm::any_of(NewFD->parameters(), [](ParmVarDecl *P) {
return P->getOriginalType()->isSizelessVectorType();
}))
Diag(NewFD->getLocation(),
diag::warn_sme_locally_streaming_has_vl_args_returns);
}
if (const auto *FPT = NewFD->getType()->getAs<FunctionProtoType>()) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
UsesSM |=
Expand Down Expand Up @@ -15889,6 +15899,11 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
FD->setInvalidDecl();
return D;
}

// Some function attributes (like OptimizeNoneAttr) need actions before
// parsing body started.
applyFunctionAttributesBeforeParsingBody(D);

// We want to attach documentation to original Decl (which might be
// a function template).
ActOnDocumentableDecl(D);
Expand All @@ -15900,6 +15915,20 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
return D;
}

void Sema::applyFunctionAttributesBeforeParsingBody(Decl *FD) {
if (!FD || FD->isInvalidDecl())
return;
if (auto *TD = dyn_cast<FunctionTemplateDecl>(FD))
FD = TD->getTemplatedDecl();
if (FD && FD->hasAttr<OptimizeNoneAttr>()) {
FPOptionsOverride FPO;
FPO.setDisallowOptimizations();
CurFPFeatures.applyChanges(FPO);
FpPragmaStack.CurrentValue =
CurFPFeatures.getChangesFrom(FPOptions(LangOpts));
}
}

/// Given the set of return statements within a function body,
/// compute the variables that are subject to the named return value
/// optimization.
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1302,7 +1302,7 @@ static bool checkTupleLikeDecomposition(Sema &S,
// in the associated namespaces.
Expr *Get = UnresolvedLookupExpr::Create(
S.Context, nullptr, NestedNameSpecifierLoc(), SourceLocation(),
DeclarationNameInfo(GetDN, Loc), /*RequiresADL*/ true, &Args,
DeclarationNameInfo(GetDN, Loc), /*RequiresADL=*/true, &Args,
UnresolvedSetIterator(), UnresolvedSetIterator(),
/*KnownDependent=*/false);

Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaDeclObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,10 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
}
}
}

// Some function attributes (like OptimizeNoneAttr) need actions before
// parsing body started.
applyFunctionAttributesBeforeParsingBody(D);
}

namespace {
Expand Down
45 changes: 14 additions & 31 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2918,26 +2918,9 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
// to get this right here so that we don't end up making a
// spuriously dependent expression if we're inside a dependent
// instance method.
if (getLangOpts().CPlusPlus && !R.empty() &&
(*R.begin())->isCXXClassMember()) {
bool MightBeImplicitMember;
if (!IsAddressOfOperand)
MightBeImplicitMember = true;
else if (!SS.isEmpty())
MightBeImplicitMember = false;
else if (R.isOverloadedResult())
MightBeImplicitMember = false;
else if (R.isUnresolvableResult())
MightBeImplicitMember = true;
else
MightBeImplicitMember = isa<FieldDecl>(R.getFoundDecl()) ||
isa<IndirectFieldDecl>(R.getFoundDecl()) ||
isa<MSPropertyDecl>(R.getFoundDecl());

if (MightBeImplicitMember)
return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc,
R, TemplateArgs, S);
}
if (isPotentialImplicitMemberAccess(SS, R, IsAddressOfOperand))
return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs,
S);

if (TemplateArgs || TemplateKWLoc.isValid()) {

Expand Down Expand Up @@ -3471,12 +3454,10 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
// we've picked a target.
R.suppressDiagnostics();

UnresolvedLookupExpr *ULE
= UnresolvedLookupExpr::Create(Context, R.getNamingClass(),
SS.getWithLocInContext(Context),
R.getLookupNameInfo(),
NeedsADL, R.isOverloadedResult(),
R.begin(), R.end());
UnresolvedLookupExpr *ULE = UnresolvedLookupExpr::Create(
Context, R.getNamingClass(), SS.getWithLocInContext(Context),
R.getLookupNameInfo(), NeedsADL, R.begin(), R.end(),
/*KnownDependent=*/false);

return ULE;
}
Expand Down Expand Up @@ -4156,11 +4137,13 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
// 'wb/uwb' literals are a C23 feature. We support _BitInt as a type in C++,
// but we do not currently support the suffix in C++ mode because it's not
// entirely clear whether WG21 will prefer this suffix to return a library
// type such as std::bit_int instead of returning a _BitInt.
if (Literal.isBitInt && !getLangOpts().CPlusPlus)
PP.Diag(Tok.getLocation(), getLangOpts().C23
? diag::warn_c23_compat_bitint_suffix
: diag::ext_c23_bitint_suffix);
// type such as std::bit_int instead of returning a _BitInt. '__wb/__uwb'
// literals are a C++ extension.
if (Literal.isBitInt)
PP.Diag(Tok.getLocation(),
getLangOpts().CPlusPlus ? diag::ext_cxx_bitint_suffix
: getLangOpts().C23 ? diag::warn_c23_compat_bitint_suffix
: diag::ext_c23_bitint_suffix);

// Get the value in the widest-possible width. What is "widest" depends on
// whether the literal is a bit-precise integer or not. For a bit-precise
Expand Down
61 changes: 32 additions & 29 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1416,26 +1416,42 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit,
}

ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
/// C++ 9.3.2: In the body of a non-static member function, the keyword this
/// is a non-lvalue expression whose value is the address of the object for
/// which the function is called.
// C++20 [expr.prim.this]p1:
// The keyword this names a pointer to the object for which an
// implicit object member function is invoked or a non-static
// data member's initializer is evaluated.
QualType ThisTy = getCurrentThisType();

if (ThisTy.isNull()) {
DeclContext *DC = getFunctionLevelDeclContext();
if (CheckCXXThisType(Loc, ThisTy))
return ExprError();

if (const auto *Method = dyn_cast<CXXMethodDecl>(DC);
Method && Method->isExplicitObjectMemberFunction()) {
return Diag(Loc, diag::err_invalid_this_use) << 1;
}
return BuildCXXThisExpr(Loc, ThisTy, /*IsImplicit=*/false);
}

if (isLambdaCallWithExplicitObjectParameter(CurContext))
return Diag(Loc, diag::err_invalid_this_use) << 1;
bool Sema::CheckCXXThisType(SourceLocation Loc, QualType Type) {
if (!Type.isNull())
return false;

return Diag(Loc, diag::err_invalid_this_use) << 0;
// C++20 [expr.prim.this]p3:
// If a declaration declares a member function or member function template
// of a class X, the expression this is a prvalue of type
// "pointer to cv-qualifier-seq X" wherever X is the current class between
// the optional cv-qualifier-seq and the end of the function-definition,
// member-declarator, or declarator. It shall not appear within the
// declaration of either a static member function or an explicit object
// member function of the current class (although its type and value
// category are defined within such member functions as they are within
// an implicit object member function).
DeclContext *DC = getFunctionLevelDeclContext();
if (const auto *Method = dyn_cast<CXXMethodDecl>(DC);
Method && Method->isExplicitObjectMemberFunction()) {
Diag(Loc, diag::err_invalid_this_use) << 1;
} else if (isLambdaCallWithExplicitObjectParameter(CurContext)) {
Diag(Loc, diag::err_invalid_this_use) << 1;
} else {
Diag(Loc, diag::err_invalid_this_use) << 0;
}

return BuildCXXThisExpr(Loc, ThisTy, /*IsImplicit=*/false);
return true;
}

Expr *Sema::BuildCXXThisExpr(SourceLocation Loc, QualType Type,
Expand Down Expand Up @@ -8644,21 +8660,8 @@ static ExprResult attemptRecovery(Sema &SemaRef,

// Detect and handle the case where the decl might be an implicit
// member.
bool MightBeImplicitMember;
if (!Consumer.isAddressOfOperand())
MightBeImplicitMember = true;
else if (!NewSS.isEmpty())
MightBeImplicitMember = false;
else if (R.isOverloadedResult())
MightBeImplicitMember = false;
else if (R.isUnresolvableResult())
MightBeImplicitMember = true;
else
MightBeImplicitMember = isa<FieldDecl>(ND) ||
isa<IndirectFieldDecl>(ND) ||
isa<MSPropertyDecl>(ND);

if (MightBeImplicitMember)
if (SemaRef.isPotentialImplicitMemberAccess(
NewSS, R, Consumer.isAddressOfOperand()))
return SemaRef.BuildPossibleImplicitMemberExpr(
NewSS, /*TemplateKWLoc*/ SourceLocation(), R,
/*TemplateArgs*/ nullptr, /*S*/ nullptr);
Expand Down
72 changes: 57 additions & 15 deletions clang/lib/Sema/SemaExprMember.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ enum IMAKind {
/// The reference is a contextually-permitted abstract member reference.
IMA_Abstract,

/// Whether the context is static is dependent on the enclosing template (i.e.
/// in a dependent class scope explicit specialization).
IMA_Dependent,

/// The reference may be to an unresolved using declaration and the
/// context is not an instance method.
IMA_Unresolved_StaticOrExplicitContext,
Expand Down Expand Up @@ -92,14 +96,25 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,

DeclContext *DC = SemaRef.getFunctionLevelDeclContext();

bool isStaticOrExplicitContext =
SemaRef.CXXThisTypeOverride.isNull() &&
(!isa<CXXMethodDecl>(DC) || cast<CXXMethodDecl>(DC)->isStatic() ||
cast<CXXMethodDecl>(DC)->isExplicitObjectMemberFunction());
bool couldInstantiateToStatic = false;
bool isStaticOrExplicitContext = SemaRef.CXXThisTypeOverride.isNull();

if (R.isUnresolvableResult())
if (auto *MD = dyn_cast<CXXMethodDecl>(DC)) {
if (MD->isImplicitObjectMemberFunction()) {
isStaticOrExplicitContext = false;
// A dependent class scope function template explicit specialization
// that is neither declared 'static' nor with an explicit object
// parameter could instantiate to a static or non-static member function.
couldInstantiateToStatic = MD->getDependentSpecializationInfo();
}
}

if (R.isUnresolvableResult()) {
if (couldInstantiateToStatic)
return IMA_Dependent;
return isStaticOrExplicitContext ? IMA_Unresolved_StaticOrExplicitContext
: IMA_Unresolved;
}

// Collect all the declaring classes of instance members we find.
bool hasNonInstance = false;
Expand All @@ -124,6 +139,9 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
if (Classes.empty())
return IMA_Static;

if (couldInstantiateToStatic)
return IMA_Dependent;

// C++11 [expr.prim.general]p12:
// An id-expression that denotes a non-static data member or non-static
// member function of a class can only be used:
Expand Down Expand Up @@ -264,21 +282,37 @@ static void diagnoseInstanceReference(Sema &SemaRef,
}
}

bool Sema::isPotentialImplicitMemberAccess(const CXXScopeSpec &SS,
LookupResult &R,
bool IsAddressOfOperand) {
if (!getLangOpts().CPlusPlus)
return false;
else if (R.empty() || !R.begin()->isCXXClassMember())
return false;
else if (!IsAddressOfOperand)
return true;
else if (!SS.isEmpty())
return false;
else if (R.isOverloadedResult())
return false;
else if (R.isUnresolvableResult())
return true;
else
return isa<FieldDecl, IndirectFieldDecl, MSPropertyDecl>(R.getFoundDecl());
}

/// Builds an expression which might be an implicit member expression.
ExprResult Sema::BuildPossibleImplicitMemberExpr(
const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
UnresolvedLookupExpr *AsULE) {
switch (ClassifyImplicitMemberAccess(*this, R)) {
const TemplateArgumentListInfo *TemplateArgs, const Scope *S) {
switch (IMAKind Classification = ClassifyImplicitMemberAccess(*this, R)) {
case IMA_Instance:
return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, true, S);

case IMA_Mixed:
case IMA_Mixed_Unrelated:
case IMA_Unresolved:
return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, false,
S);

return BuildImplicitMemberExpr(
SS, TemplateKWLoc, R, TemplateArgs,
/*IsKnownInstance=*/Classification == IMA_Instance, S);
case IMA_Field_Uneval_Context:
Diag(R.getNameLoc(), diag::warn_cxx98_compat_non_static_member_use)
<< R.getLookupNameInfo().getName();
Expand All @@ -288,8 +322,16 @@ ExprResult Sema::BuildPossibleImplicitMemberExpr(
case IMA_Mixed_StaticOrExplicitContext:
case IMA_Unresolved_StaticOrExplicitContext:
if (TemplateArgs || TemplateKWLoc.isValid())
return BuildTemplateIdExpr(SS, TemplateKWLoc, R, false, TemplateArgs);
return AsULE ? AsULE : BuildDeclarationNameExpr(SS, R, false);
return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*RequiresADL=*/false,
TemplateArgs);
return BuildDeclarationNameExpr(SS, R, /*NeedsADL=*/false,
/*AcceptInvalidDecl=*/false);
case IMA_Dependent:
R.suppressDiagnostics();
return UnresolvedLookupExpr::Create(
Context, R.getNamingClass(), SS.getWithLocInContext(Context),
TemplateKWLoc, R.getLookupNameInfo(), /*RequiresADL=*/false,
TemplateArgs, R.begin(), R.end(), /*KnownDependent=*/true);

case IMA_Error_StaticOrExplicitContext:
case IMA_Error_Unrelated:
Expand Down
35 changes: 35 additions & 0 deletions clang/lib/Sema/SemaOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind,
default:
return false;
}
case OpenACCClauseKind::NumGangs:
case OpenACCClauseKind::NumWorkers:
case OpenACCClauseKind::VectorLength:
switch (DirectiveKind) {
Expand Down Expand Up @@ -230,6 +231,40 @@ SemaOpenACC::ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses,
getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
Clause.getConditionExpr(), Clause.getEndLoc());
}
case OpenACCClauseKind::NumGangs: {
// Restrictions only properly implemented on 'compute' constructs, and
// 'compute' constructs are the only construct that can do anything with
// this yet, so skip/treat as unimplemented in this case.
if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
break;

// There is no prose in the standard that says duplicates aren't allowed,
// but this diagnostic is present in other compilers, as well as makes
// sense.
if (checkAlreadyHasClauseOfKind(*this, ExistingClauses, Clause))
return nullptr;

if (Clause.getIntExprs().empty())
Diag(Clause.getBeginLoc(), diag::err_acc_num_gangs_num_args)
<< /*NoArgs=*/0;

unsigned MaxArgs =
(Clause.getDirectiveKind() == OpenACCDirectiveKind::Parallel ||
Clause.getDirectiveKind() == OpenACCDirectiveKind::ParallelLoop)
? 3
: 1;
if (Clause.getIntExprs().size() > MaxArgs)
Diag(Clause.getBeginLoc(), diag::err_acc_num_gangs_num_args)
<< /*NoArgs=*/1 << Clause.getDirectiveKind() << MaxArgs
<< Clause.getIntExprs().size();

// Create the AST node for the clause even if the number of expressions is
// incorrect.
return OpenACCNumGangsClause::Create(
getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
Clause.getIntExprs(), Clause.getEndLoc());
break;
}
case OpenACCClauseKind::NumWorkers: {
// Restrictions only properly implemented on 'compute' constructs, and
// 'compute' constructs are the only construct that can do anything with
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19354,7 +19354,7 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
return UnresolvedLookupExpr::Create(
SemaRef.Context, /*NamingClass=*/nullptr,
ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), ReductionId,
/*ADL=*/true, /*Overloaded=*/true, ResSet.begin(), ResSet.end());
/*ADL=*/true, ResSet.begin(), ResSet.end(), /*KnownDependent=*/false);
}
// Lookup inside the classes.
// C++ [over.match.oper]p3:
Expand Down Expand Up @@ -22220,7 +22220,7 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S,
return UnresolvedLookupExpr::Create(
SemaRef.Context, /*NamingClass=*/nullptr,
MapperIdScopeSpec.getWithLocInContext(SemaRef.Context), MapperId,
/*ADL=*/false, /*Overloaded=*/true, URS.begin(), URS.end());
/*ADL=*/false, URS.begin(), URS.end(), /*KnownDependent=*/false);
}
SourceLocation Loc = MapperId.getLoc();
// [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions
Expand Down
10 changes: 2 additions & 8 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14261,20 +14261,14 @@ ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn,
OverloadResult, AllowTypoCorrection);
}

static bool IsOverloaded(const UnresolvedSetImpl &Functions) {
return Functions.size() > 1 ||
(Functions.size() == 1 &&
isa<FunctionTemplateDecl>((*Functions.begin())->getUnderlyingDecl()));
}

ExprResult Sema::CreateUnresolvedLookupExpr(CXXRecordDecl *NamingClass,
NestedNameSpecifierLoc NNSLoc,
DeclarationNameInfo DNI,
const UnresolvedSetImpl &Fns,
bool PerformADL) {
return UnresolvedLookupExpr::Create(Context, NamingClass, NNSLoc, DNI,
PerformADL, IsOverloaded(Fns),
Fns.begin(), Fns.end());
PerformADL, Fns.begin(), Fns.end(),
/*KnownDependent=*/false);
}

ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaStmtAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
SetHints(LoopHintAttr::Unroll, LoopHintAttr::Disable);
} else if (PragmaName == "unroll") {
// #pragma unroll N
if (ValueExpr) {
if (ValueExpr && !ValueExpr->isValueDependent()) {
llvm::APSInt ValueAPS;
ExprResult R = S.VerifyIntegerConstantExpression(ValueExpr, &ValueAPS);
assert(!R.isInvalid() && "unroll count value must be a valid value, it's "
Expand Down
27 changes: 14 additions & 13 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2962,19 +2962,6 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
Context.getCanonicalTemplateArgument(
Context.getInjectedTemplateArg(NewParam));
}
// Substitute new template parameters into requires-clause if present.
Expr *RequiresClause =
transformRequireClause(SemaRef, F, TemplateArgsForBuildingFPrime);
// FIXME: implement the is_deducible constraint per C++
// [over.match.class.deduct]p3.3:
// ... and a constraint that is satisfied if and only if the arguments
// of A are deducible (see below) from the return type.
auto *FPrimeTemplateParamList = TemplateParameterList::Create(
Context, AliasTemplate->getTemplateParameters()->getTemplateLoc(),
AliasTemplate->getTemplateParameters()->getLAngleLoc(),
FPrimeTemplateParams,
AliasTemplate->getTemplateParameters()->getRAngleLoc(),
/*RequiresClause=*/RequiresClause);

// To form a deduction guide f' from f, we leverage clang's instantiation
// mechanism, we construct a template argument list where the template
Expand Down Expand Up @@ -3020,6 +3007,20 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
F, TemplateArgListForBuildingFPrime, AliasTemplate->getLocation(),
Sema::CodeSynthesisContext::BuildingDeductionGuides)) {
auto *GG = cast<CXXDeductionGuideDecl>(FPrime);
// Substitute new template parameters into requires-clause if present.
Expr *RequiresClause =
transformRequireClause(SemaRef, F, TemplateArgsForBuildingFPrime);
// FIXME: implement the is_deducible constraint per C++
// [over.match.class.deduct]p3.3:
// ... and a constraint that is satisfied if and only if the arguments
// of A are deducible (see below) from the return type.
auto *FPrimeTemplateParamList = TemplateParameterList::Create(
Context, AliasTemplate->getTemplateParameters()->getTemplateLoc(),
AliasTemplate->getTemplateParameters()->getLAngleLoc(),
FPrimeTemplateParams,
AliasTemplate->getTemplateParameters()->getRAngleLoc(),
/*RequiresClause=*/RequiresClause);

buildDeductionGuide(SemaRef, AliasTemplate, FPrimeTemplateParamList,
GG->getCorrespondingConstructor(),
GG->getExplicitSpecifier(), GG->getTypeSourceInfo(),
Expand Down
5 changes: 1 addition & 4 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2502,10 +2502,7 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
assert(Arg.getKind() == TemplateArgument::Type &&
"unexpected nontype template argument kind in template rewrite");
QualType NewT = Arg.getAsType();
assert(isa<TemplateTypeParmType>(NewT) &&
"type parm not rewritten to type parm");
auto NewTL = TLB.push<TemplateTypeParmTypeLoc>(NewT);
NewTL.setNameLoc(TL.getNameLoc());
TLB.pushTrivial(SemaRef.Context, NewT, TL.getNameLoc());
return NewT;
}

Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5101,6 +5101,14 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
EnterExpressionEvaluationContext EvalContext(
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);

Qualifiers ThisTypeQuals;
CXXRecordDecl *ThisContext = nullptr;
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) {
ThisContext = Method->getParent();
ThisTypeQuals = Method->getMethodQualifiers();
}
CXXThisScopeRAII ThisScope(*this, ThisContext, ThisTypeQuals);

// Introduce a new scope where local variable instantiations will be
// recorded, unless we're actually a member function within a local
// class, in which case we need to merge our results with the parent
Expand Down
8 changes: 5 additions & 3 deletions clang/lib/Sema/SemaTemplateVariadic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1085,9 +1085,11 @@ ExprResult Sema::ActOnPackIndexingExpr(Scope *S, Expr *PackExpression,
SourceLocation RSquareLoc) {
bool isParameterPack = ::isParameterPack(PackExpression);
if (!isParameterPack) {
CorrectDelayedTyposInExpr(IndexExpr);
Diag(PackExpression->getBeginLoc(), diag::err_expected_name_of_pack)
<< PackExpression;
if (!PackExpression->containsErrors()) {
CorrectDelayedTyposInExpr(IndexExpr);
Diag(PackExpression->getBeginLoc(), diag::err_expected_name_of_pack)
<< PackExpression;
}
return ExprError();
}
ExprResult Res =
Expand Down
126 changes: 88 additions & 38 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,9 @@ class TreeTransform {
ParenExpr *PE, DependentScopeDeclRefExpr *DRE, bool IsAddressOfOperand,
TypeSourceInfo **RecoveryTSI);

ExprResult TransformUnresolvedLookupExpr(UnresolvedLookupExpr *E,
bool IsAddressOfOperand);

StmtResult TransformOMPExecutableDirective(OMPExecutableDirective *S);

// FIXME: We use LLVM_ATTRIBUTE_NOINLINE because inlining causes a ridiculous
Expand Down Expand Up @@ -3320,12 +3323,13 @@ class TreeTransform {

/// Build a new C++ "this" expression.
///
/// By default, builds a new "this" expression without performing any
/// semantic analysis. Subclasses may override this routine to provide
/// different behavior.
/// By default, performs semantic analysis to build a new "this" expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildCXXThisExpr(SourceLocation ThisLoc,
QualType ThisType,
bool isImplicit) {
if (getSema().CheckCXXThisType(ThisLoc, ThisType))
return ExprError();
return getSema().BuildCXXThisExpr(ThisLoc, ThisType, isImplicit);
}

Expand Down Expand Up @@ -4759,8 +4763,6 @@ class TemplateArgumentLocInventIterator {
const TemplateArgumentLoc *operator->() const { return &Arg; }
};

TemplateArgumentLocInventIterator() { }

explicit TemplateArgumentLocInventIterator(TreeTransform<Derived> &Self,
InputIterator Iter)
: Self(Self), Iter(Iter) { }
Expand Down Expand Up @@ -10429,12 +10431,11 @@ TreeTransform<Derived>::TransformOMPReductionClause(OMPReductionClause *C) {
cast<NamedDecl>(getDerived().TransformDecl(E->getExprLoc(), D));
Decls.addDecl(InstD, InstD->getAccess());
}
UnresolvedReductions.push_back(
UnresolvedLookupExpr::Create(
UnresolvedReductions.push_back(UnresolvedLookupExpr::Create(
SemaRef.Context, /*NamingClass=*/nullptr,
ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context),
NameInfo, /*ADL=*/true, ULE->isOverloaded(),
Decls.begin(), Decls.end()));
ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), NameInfo,
/*ADL=*/true, Decls.begin(), Decls.end(),
/*KnownDependent=*/false));
} else
UnresolvedReductions.push_back(nullptr);
}
Expand Down Expand Up @@ -10480,7 +10481,8 @@ OMPClause *TreeTransform<Derived>::TransformOMPTaskReductionClause(
UnresolvedReductions.push_back(UnresolvedLookupExpr::Create(
SemaRef.Context, /*NamingClass=*/nullptr,
ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), NameInfo,
/*ADL=*/true, ULE->isOverloaded(), Decls.begin(), Decls.end()));
/*ADL=*/true, Decls.begin(), Decls.end(),
/*KnownDependent=*/false));
} else
UnresolvedReductions.push_back(nullptr);
}
Expand Down Expand Up @@ -10525,7 +10527,8 @@ TreeTransform<Derived>::TransformOMPInReductionClause(OMPInReductionClause *C) {
UnresolvedReductions.push_back(UnresolvedLookupExpr::Create(
SemaRef.Context, /*NamingClass=*/nullptr,
ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), NameInfo,
/*ADL=*/true, ULE->isOverloaded(), Decls.begin(), Decls.end()));
/*ADL=*/true, Decls.begin(), Decls.end(),
/*KnownDependent=*/false));
} else
UnresolvedReductions.push_back(nullptr);
}
Expand Down Expand Up @@ -10706,8 +10709,8 @@ bool transformOMPMappableExprListClause(
UnresolvedMappers.push_back(UnresolvedLookupExpr::Create(
TT.getSema().Context, /*NamingClass=*/nullptr,
MapperIdScopeSpec.getWithLocInContext(TT.getSema().Context),
MapperIdInfo, /*ADL=*/true, ULE->isOverloaded(), Decls.begin(),
Decls.end()));
MapperIdInfo, /*ADL=*/true, Decls.begin(), Decls.end(),
/*KnownDependent=*/false));
} else {
UnresolvedMappers.push_back(nullptr);
}
Expand Down Expand Up @@ -11159,6 +11162,32 @@ void OpenACCClauseTransform<Derived>::VisitSelfClause(
ParsedClause.getEndLoc());
}

template <typename Derived>
void OpenACCClauseTransform<Derived>::VisitNumGangsClause(
const OpenACCNumGangsClause &C) {
llvm::SmallVector<Expr *> InstantiatedIntExprs;

for (Expr *CurIntExpr : C.getIntExprs()) {
ExprResult Res = Self.TransformExpr(CurIntExpr);

if (!Res.isUsable())
return;

Res = Self.getSema().OpenACC().ActOnIntExpr(OpenACCDirectiveKind::Invalid,
C.getClauseKind(),
C.getBeginLoc(), Res.get());
if (!Res.isUsable())
return;

InstantiatedIntExprs.push_back(Res.get());
}

ParsedClause.setIntExprDetails(InstantiatedIntExprs);
NewClause = OpenACCNumGangsClause::Create(
Self.getSema().getASTContext(), ParsedClause.getBeginLoc(),
ParsedClause.getLParenLoc(), ParsedClause.getIntExprs(),
ParsedClause.getEndLoc());
}
template <typename Derived>
void OpenACCClauseTransform<Derived>::VisitNumWorkersClause(
const OpenACCNumWorkersClause &C) {
Expand Down Expand Up @@ -11467,7 +11496,11 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformAddressOfOperand(Expr *E) {
if (DependentScopeDeclRefExpr *DRE = dyn_cast<DependentScopeDeclRefExpr>(E))
return getDerived().TransformDependentScopeDeclRefExpr(DRE, true, nullptr);
return getDerived().TransformDependentScopeDeclRefExpr(
DRE, /*IsAddressOfOperand=*/true, nullptr);
else if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E))
return getDerived().TransformUnresolvedLookupExpr(
ULE, /*IsAddressOfOperand=*/true);
else
return getDerived().TransformExpr(E);
}
Expand Down Expand Up @@ -12910,6 +12943,19 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
ArraySize = NewArraySize.get();
}

// Per C++0x [expr.new]p5, the type being constructed may be a
// typedef of an array type.
QualType AllocType = AllocTypeInfo->getType();
if (ArraySize && E->isTypeDependent()) {
if (const ConstantArrayType *Array =
SemaRef.Context.getAsConstantArrayType(AllocType)) {
ArraySize = IntegerLiteral::Create(SemaRef.Context, Array->getSize(),
SemaRef.Context.getSizeType(),
E->getBeginLoc());
AllocType = Array->getElementType();
}
}

// Transform the placement arguments (if any).
bool ArgumentChanged = false;
SmallVector<Expr*, 8> PlacementArgs;
Expand Down Expand Up @@ -12971,7 +13017,6 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
return E;
}

QualType AllocType = AllocTypeInfo->getType();
if (!ArraySize) {
// If no array size was specified, but the new expression was
// instantiated with an array type (e.g., "new T" where T is
Expand Down Expand Up @@ -13174,10 +13219,16 @@ bool TreeTransform<Derived>::TransformOverloadExprDecls(OverloadExpr *Old,
return false;
}

template<typename Derived>
template <typename Derived>
ExprResult TreeTransform<Derived>::TransformUnresolvedLookupExpr(
UnresolvedLookupExpr *Old) {
return TransformUnresolvedLookupExpr(Old, /*IsAddressOfOperand=*/false);
}

template <typename Derived>
ExprResult
TreeTransform<Derived>::TransformUnresolvedLookupExpr(
UnresolvedLookupExpr *Old) {
TreeTransform<Derived>::TransformUnresolvedLookupExpr(UnresolvedLookupExpr *Old,
bool IsAddressOfOperand) {
LookupResult R(SemaRef, Old->getName(), Old->getNameLoc(),
Sema::LookupOrdinaryName);

Expand Down Expand Up @@ -13209,26 +13260,8 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
R.setNamingClass(NamingClass);
}

// Rebuild the template arguments, if any.
SourceLocation TemplateKWLoc = Old->getTemplateKeywordLoc();

// If we have neither explicit template arguments, nor the template keyword,
// it's a normal declaration name or member reference.
if (!Old->hasExplicitTemplateArgs() && !TemplateKWLoc.isValid()) {
NamedDecl *D = R.getAsSingle<NamedDecl>();
// In a C++11 unevaluated context, an UnresolvedLookupExpr might refer to an
// instance member. In other contexts, BuildPossibleImplicitMemberExpr will
// give a good diagnostic.
if (D && D->isCXXInstanceMember()) {
return SemaRef.BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, R,
/*TemplateArgs=*/nullptr,
/*Scope=*/nullptr);
}

return getDerived().RebuildDeclarationNameExpr(SS, R, Old->requiresADL());
}

// If we have template arguments, rebuild them, then rebuild the
// templateid expression.
TemplateArgumentListInfo TransArgs(Old->getLAngleLoc(), Old->getRAngleLoc());
if (Old->hasExplicitTemplateArgs() &&
getDerived().TransformTemplateArguments(Old->getTemplateArgs(),
Expand All @@ -13238,6 +13271,23 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
return ExprError();
}

// An UnresolvedLookupExpr can refer to a class member. This occurs e.g. when
// a non-static data member is named in an unevaluated operand, or when
// a member is named in a dependent class scope function template explicit
// specialization that is neither declared static nor with an explicit object
// parameter.
if (SemaRef.isPotentialImplicitMemberAccess(SS, R, IsAddressOfOperand))
return SemaRef.BuildPossibleImplicitMemberExpr(
SS, TemplateKWLoc, R,
Old->hasExplicitTemplateArgs() ? &TransArgs : nullptr,
/*S=*/nullptr);

// If we have neither explicit template arguments, nor the template keyword,
// it's a normal declaration name or member reference.
if (!Old->hasExplicitTemplateArgs() && !TemplateKWLoc.isValid())
return getDerived().RebuildDeclarationNameExpr(SS, R, Old->requiresADL());

// If we have template arguments, then rebuild the template-id expression.
return getDerived().RebuildTemplateIdExpr(SS, TemplateKWLoc, R,
Old->requiresADL(), &TransArgs);
}
Expand Down
Loading