22 changes: 21 additions & 1 deletion clang/lib/AST/Interp/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -634,12 +634,23 @@ static bool interp__builtin_addressof(InterpState &S, CodePtr OpPC,
return true;
}

static bool interp__builtin_move(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame, const Function *Func,
const CallExpr *Call) {

PrimType ArgT = S.getContext().classify(Call->getArg(0)).value_or(PT_Ptr);

TYPE_SWITCH(ArgT, const T &Arg = S.Stk.peek<T>(); S.Stk.push<T>(Arg););

return Func->getDecl()->isConstexpr();
}

bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
const CallExpr *Call) {
InterpFrame *Frame = S.Current;
APValue Dummy;

std::optional<PrimType> ReturnT = S.getContext().classify(Call->getType());
std::optional<PrimType> ReturnT = S.getContext().classify(Call);

// If classify failed, we assume void.
assert(ReturnT || Call->getType()->isVoidType());
Expand Down Expand Up @@ -848,6 +859,15 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
return false;
break;

case Builtin::BIas_const:
case Builtin::BIforward:
case Builtin::BIforward_like:
case Builtin::BImove:
case Builtin::BImove_if_noexcept:
if (!interp__builtin_move(S, OpPC, Frame, F, Call))
return false;
break;

default:
return false;
}
Expand Down
10 changes: 8 additions & 2 deletions clang/lib/AST/Interp/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,14 @@ class Pointer {

/// Returns the type of the innermost field.
QualType getType() const {
if (inPrimitiveArray() && Offset != Base)
return getFieldDesc()->getType()->getAsArrayTypeUnsafe()->getElementType();
if (inPrimitiveArray() && Offset != Base) {
// Unfortunately, complex types are not array types in clang, but they are
// for us.
if (const auto *AT = getFieldDesc()->getType()->getAsArrayTypeUnsafe())
return AT->getElementType();
if (const auto *CT = getFieldDesc()->getType()->getAs<ComplexType>())
return CT->getElementType();
}
return getFieldDesc()->getType();
}

Expand Down
33 changes: 32 additions & 1 deletion clang/lib/AST/JSONNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ void JSONNodeDumper::Visit(const Type *T) {
return;

JOS.attribute("kind", (llvm::Twine(T->getTypeClassName()) + "Type").str());
JOS.attribute("type", createQualType(QualType(T, 0), /*Desugar*/ false));
JOS.attribute("type", createQualType(QualType(T, 0), /*Desugar=*/false));
attributeOnlyIfTrue("containsErrors", T->containsErrors());
attributeOnlyIfTrue("isDependent", T->isDependentType());
attributeOnlyIfTrue("isInstantiationDependent",
Expand All @@ -96,6 +96,21 @@ void JSONNodeDumper::Visit(QualType T) {
JOS.attribute("qualifiers", T.split().Quals.getAsString());
}

void JSONNodeDumper::Visit(TypeLoc TL) {
if (TL.isNull())
return;
JOS.attribute("kind",
(llvm::Twine(TL.getTypeLocClass() == TypeLoc::Qualified
? "Qualified"
: TL.getTypePtr()->getTypeClassName()) +
"TypeLoc")
.str());
JOS.attribute("type",
createQualType(QualType(TL.getType()), /*Desugar=*/false));
JOS.attributeObject("range",
[TL, this] { writeSourceRange(TL.getSourceRange()); });
}

void JSONNodeDumper::Visit(const Decl *D) {
JOS.attribute("id", createPointerRepresentation(D));

Expand Down Expand Up @@ -223,6 +238,22 @@ void JSONNodeDumper::Visit(const APValue &Value, QualType Ty) {
JOS.attribute("value", OS.str());
}

void JSONNodeDumper::Visit(const ConceptReference *CR) {
JOS.attribute("kind", "ConceptReference");
JOS.attribute("id", createPointerRepresentation(CR->getNamedConcept()));
if (const auto *Args = CR->getTemplateArgsAsWritten()) {
JOS.attributeArray("templateArgsAsWritten", [Args, this] {
for (const TemplateArgumentLoc &TAL : Args->arguments())
JOS.object(
[&TAL, this] { Visit(TAL.getArgument(), TAL.getSourceRange()); });
});
}
JOS.attributeObject("loc",
[CR, this] { writeSourceLocation(CR->getLocation()); });
JOS.attributeObject("range",
[CR, this] { writeSourceRange(CR->getSourceRange()); });
}

void JSONNodeDumper::writeIncludeStack(PresumedLoc Loc, bool JustFirst) {
if (Loc.isInvalid())
return;
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/OpenMPClause.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1957,6 +1957,8 @@ void OMPClausePrinter::VisitOMPRelaxedClause(OMPRelaxedClause *) {
OS << "relaxed";
}

void OMPClausePrinter::VisitOMPWeakClause(OMPWeakClause *) { OS << "weak"; }

void OMPClausePrinter::VisitOMPThreadsClause(OMPThreadsClause *) {
OS << "threads";
}
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/StmtProfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,8 @@ void OMPClauseProfiler::VisitOMPReleaseClause(const OMPReleaseClause *) {}

void OMPClauseProfiler::VisitOMPRelaxedClause(const OMPRelaxedClause *) {}

void OMPClauseProfiler::VisitOMPWeakClause(const OMPWeakClause *) {}

void OMPClauseProfiler::VisitOMPThreadsClause(const OMPThreadsClause *) {}

void OMPClauseProfiler::VisitOMPSIMDClause(const OMPSIMDClause *) {}
Expand Down
34 changes: 30 additions & 4 deletions clang/lib/AST/TextNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "clang/AST/LocInfoType.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Specifiers.h"
Expand Down Expand Up @@ -240,6 +241,27 @@ void TextNodeDumper::Visit(QualType T) {
OS << " " << T.split().Quals.getAsString();
}

void TextNodeDumper::Visit(TypeLoc TL) {
if (!TL) {
ColorScope Color(OS, ShowColors, NullColor);
OS << "<<<NULL>>>";
return;
}

{
ColorScope Color(OS, ShowColors, TypeColor);
OS << (TL.getTypeLocClass() == TypeLoc::Qualified
? "Qualified"
: TL.getType()->getTypeClassName())
<< "TypeLoc";
}
dumpSourceRange(TL.getSourceRange());
OS << ' ';
dumpBareType(TL.getType(), /*Desugar=*/false);

TypeLocVisitor<TextNodeDumper>::Visit(TL);
}

void TextNodeDumper::Visit(const Decl *D) {
if (!D) {
ColorScope Color(OS, ShowColors, NullColor);
Expand Down Expand Up @@ -1801,11 +1823,8 @@ void TextNodeDumper::VisitAutoType(const AutoType *T) {
OS << " decltype(auto)";
if (!T->isDeduced())
OS << " undeduced";
if (T->isConstrained()) {
if (T->isConstrained())
dumpDeclRef(T->getTypeConstraintConcept());
for (const auto &Arg : T->getTypeConstraintArguments())
VisitTemplateArgument(Arg);
}
}

void TextNodeDumper::VisitDeducedTemplateSpecializationType(
Expand Down Expand Up @@ -1838,6 +1857,13 @@ void TextNodeDumper::VisitPackExpansionType(const PackExpansionType *T) {
OS << " expansions " << *N;
}

void TextNodeDumper::VisitTypeLoc(TypeLoc TL) {
// By default, add extra Type details with no extra loc info.
TypeVisitor<TextNodeDumper>::Visit(TL.getTypePtr());
}
// FIXME: override behavior for TypeLocs that have interesting location
// information, such as the qualifier in ElaboratedTypeLoc.

void TextNodeDumper::VisitLabelDecl(const LabelDecl *D) { dumpName(D); }

void TextNodeDumper::VisitTypedefDecl(const TypedefDecl *D) {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2264,7 +2264,7 @@ printTo(raw_ostream &OS, ArrayRef<TA> Args, const PrintingPolicy &Policy,
// If this is the first argument and its string representation
// begins with the global scope specifier ('::foo'), add a space
// to avoid printing the diagraph '<:'.
if (FirstArg && !ArgString.empty() && ArgString[0] == ':')
if (FirstArg && ArgString.starts_with(":"))
OS << ' ';

OS << ArgString;
Expand Down
18 changes: 9 additions & 9 deletions clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ class HTMLLogger : public Logger {
llvm::raw_string_ostream JStringStream{JSON};
llvm::json::OStream JOS{JStringStream, /*Indent=*/2};

const ControlFlowContext *CFG;
const ControlFlowContext *CFC;
// Timeline of iterations of CFG block visitation.
std::vector<Iteration> Iters;
// Indexes in `Iters` of the iterations for each block.
Expand All @@ -176,15 +176,15 @@ class HTMLLogger : public Logger {

public:
explicit HTMLLogger(StreamFactory Streams) : Streams(std::move(Streams)) {}
void beginAnalysis(const ControlFlowContext &CFG,
void beginAnalysis(const ControlFlowContext &CFC,
TypeErasedDataflowAnalysis &A) override {
OS = Streams();
this->CFG = &CFG;
this->CFC = &CFC;
*OS << llvm::StringRef(HTMLLogger_html).split("<?INJECT?>").first;

BlockConverged.resize(CFG.getCFG().getNumBlockIDs());
BlockConverged.resize(CFC.getCFG().getNumBlockIDs());

const auto &D = CFG.getDecl();
const auto &D = CFC.getDecl();
const auto &SM = A.getASTContext().getSourceManager();
*OS << "<title>";
if (const auto *ND = dyn_cast<NamedDecl>(&D))
Expand Down Expand Up @@ -345,15 +345,15 @@ class HTMLLogger : public Logger {
// tokens are associated with, and even which BB element (so that clicking
// can select the right element).
void writeCode() {
const auto &AST = CFG->getDecl().getASTContext();
const auto &AST = CFC->getDecl().getASTContext();
bool Invalid = false;

// Extract the source code from the original file.
// Pretty-printing from the AST would probably be nicer (no macros or
// indentation to worry about), but we need the boundaries of particular
// AST nodes and the printer doesn't provide this.
auto Range = clang::Lexer::makeFileCharRange(
CharSourceRange::getTokenRange(CFG->getDecl().getSourceRange()),
CharSourceRange::getTokenRange(CFC->getDecl().getSourceRange()),
AST.getSourceManager(), AST.getLangOpts());
if (Range.isInvalid())
return;
Expand Down Expand Up @@ -419,7 +419,7 @@ class HTMLLogger : public Logger {
// Construct one TokenInfo per character in a flat array.
// This is inefficient (chars in a token all have the same info) but simple.
std::vector<TokenInfo> State(Code.size());
for (const auto *Block : CFG->getCFG()) {
for (const auto *Block : CFC->getCFG()) {
unsigned EltIndex = 0;
for (const auto& Elt : *Block) {
++EltIndex;
Expand Down Expand Up @@ -480,7 +480,7 @@ class HTMLLogger : public Logger {
// out to `dot` to turn it into an SVG.
void writeCFG() {
*OS << "<template data-copy='cfg'>\n";
if (auto SVG = renderSVG(buildCFGDot(CFG->getCFG())))
if (auto SVG = renderSVG(buildCFGDot(CFC->getCFG())))
*OS << *SVG;
else
*OS << "Can't draw CFG: " << toString(SVG.takeError());
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/Analysis/FlowSensitive/HTMLLogger.css
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ section h2 {
}
#timeline {
min-width: max-content;
counter-reset: entry_counter;
}
#timeline .entry .counter::before {
counter-increment: entry_counter;
content: counter(entry_counter) ":";
}
#timeline .entry .counter {
display: inline-block;
min-width: 2em; /* Enough space for two digits and a colon */
text-align: right;
}
#timeline .entry.hover {
background-color: #aaa;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Analysis/FlowSensitive/HTMLLogger.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
<header>Timeline</header>
<template data-for="entry in timeline">
<div id="{{entry.block}}:{{entry.iter}}" data-bb="{{entry.block}}" class="entry">
<span class="counter"></span>
{{entry.block}}
<template data-if="entry.post_visit">(post-visit)</template>
<template data-if="!entry.post_visit">({{entry.iter}})</template>
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Analysis/FlowSensitive/Transfer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,13 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {

copyRecord(*LocSrc, *LocDst, Env);
Env.setStorageLocation(*S, *LocDst);
return;
}

// CXXOperatorCallExpr can be prvalues. Call `VisitCallExpr`() to create
// a `RecordValue` for them so that `Environment::getResultObjectLocation()`
// can return a value.
VisitCallExpr(S);
}

void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) {
Expand Down
44 changes: 42 additions & 2 deletions clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,6 @@ void AArch64TargetInfo::getTargetDefinesARMV83A(const LangOptions &Opts,
MacroBuilder &Builder) const {
Builder.defineMacro("__ARM_FEATURE_COMPLEX", "1");
Builder.defineMacro("__ARM_FEATURE_JCVT", "1");
Builder.defineMacro("__ARM_FEATURE_PAUTH", "1");
// Also include the Armv8.2 defines
getTargetDefinesARMV82A(Opts, Builder);
}
Expand Down Expand Up @@ -387,6 +386,11 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,

Builder.defineMacro("__ARM_ALIGN_MAX_STACK_PWR", "4");

// These macros are set when Clang can parse declarations with these
// attributes.
Builder.defineMacro("__ARM_STATE_ZA", "1");
Builder.defineMacro("__ARM_STATE_ZT0", "1");

// 0xe implies support for half, single and double precision operations.
if (FPU & FPUMode)
Builder.defineMacro("__ARM_FP", "0xE");
Expand Down Expand Up @@ -431,6 +435,17 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasSVE2 && HasSVE2SM4)
Builder.defineMacro("__ARM_FEATURE_SVE2_SM4", "1");

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

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

if (HasCRC)
Builder.defineMacro("__ARM_FEATURE_CRC32", "1");

Expand Down Expand Up @@ -466,6 +481,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasPAuth)
Builder.defineMacro("__ARM_FEATURE_PAUTH", "1");

if (HasPAuthLR)
Builder.defineMacro("__ARM_FEATURE_PAUTH_LR", "1");

if (HasUnaligned)
Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1");

Expand Down Expand Up @@ -517,6 +535,7 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
// 0: Protection using the A key
// 1: Protection using the B key
// 2: Protection including leaf functions
// 3: Protection using PC as a diversifier
unsigned Value = 0;

if (Opts.isSignReturnAddressWithAKey())
Expand All @@ -527,6 +546,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
if (Opts.isSignReturnAddressScopeAll())
Value |= (1 << 2);

if (Opts.BranchProtectionPAuthLR)
Value |= (1 << 3);

Builder.defineMacro("__ARM_FEATURE_PAC_DEFAULT", std::to_string(Value));
}

Expand Down Expand Up @@ -686,6 +708,7 @@ bool AArch64TargetInfo::hasFeature(StringRef Feature) const {
.Case("sve2-sha3", FPU & SveMode && HasSVE2SHA3)
.Case("sve2-sm4", FPU & SveMode && HasSVE2SM4)
.Case("sme", HasSME)
.Case("sme2", HasSME2)
.Case("sme-f64f64", HasSMEF64F64)
.Case("sme-i16i64", HasSMEI16I64)
.Case("sme-fa64", HasSMEFA64)
Expand Down Expand Up @@ -806,6 +829,12 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasBFloat16 = true;
HasFullFP16 = true;
}
if (Feature == "+sme2") {
HasSME = true;
HasSME2 = true;
HasBFloat16 = true;
HasFullFP16 = true;
}
if (Feature == "+sme-f64f64") {
HasSME = true;
HasSMEF64F64 = true;
Expand Down Expand Up @@ -966,6 +995,10 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasGCS = true;
if (Feature == "+rcpc3")
HasRCPC3 = true;
if (Feature == "+pauth-lr") {
HasPAuthLR = true;
HasPAuth = true;
}
}

// Check features that are manually disabled by command line options.
Expand Down Expand Up @@ -1164,6 +1197,8 @@ TargetInfo::BuiltinVaListKind AArch64TargetInfo::getBuiltinVaListKind() const {
}

const char *const AArch64TargetInfo::GCCRegNames[] = {
// clang-format off

// 32-bit Integer registers
"w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9", "w10", "w11",
"w12", "w13", "w14", "w15", "w16", "w17", "w18", "w19", "w20", "w21", "w22",
Expand Down Expand Up @@ -1200,7 +1235,12 @@ const char *const AArch64TargetInfo::GCCRegNames[] = {

// SVE predicate-as-counter registers
"pn0", "pn1", "pn2", "pn3", "pn4", "pn5", "pn6", "pn7", "pn8",
"pn9", "pn10", "pn11", "pn12", "pn13", "pn14", "pn15"
"pn9", "pn10", "pn11", "pn12", "pn13", "pn14", "pn15",

// SME registers
"za", "zt0",

// clang-format on
};

ArrayRef<const char *> AArch64TargetInfo::getGCCRegNames() const {
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Basic/Targets/AArch64.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
bool HasCCDP = false;
bool HasFRInt3264 = false;
bool HasSME = false;
bool HasSME2 = false;
bool HasSMEF64F64 = false;
bool HasSMEI16I64 = false;
bool HasSB = false;
Expand All @@ -84,6 +85,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
bool HasGCS = false;
bool HasRCPC3 = false;
bool HasSMEFA64 = false;
bool HasPAuthLR = false;

const llvm::AArch64::ArchInfo *ArchInfo = &llvm::AArch64::ARMV8A;

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Basic/Targets/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ bool RISCVTargetInfo::validateAsmConstraint(
// An address that is held in a general-purpose register.
Info.setAllowsMemory();
return true;
case 'S': // A symbolic address
case 's':
case 'S': // A symbol or label reference with a constant offset
Info.setAllowsRegister();
return true;
case 'v':
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Basic/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ bool X86TargetInfo::initFeatureMap(
// Postpone AVX10 features handling after AVX512 settled.
UpdatedAVX10FeaturesVec.push_back(Feature);
continue;
} else if (!HasAVX512F && Feature.substr(0, 7) == "+avx512") {
} else if (!HasAVX512F && StringRef(Feature).starts_with("+avx512")) {
HasAVX512F = true;
LastAVX512 = Feature;
} else if (HasAVX512F && Feature == "-avx512f") {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ static bool initTargetOptions(DiagnosticsEngine &Diags,
LangOptions::FPModeKind::FPM_FastHonorPragmas);
Options.ApproxFuncFPMath = LangOpts.ApproxFunc;

Options.BBAddrMap = CodeGenOpts.BBAddrMap;
Options.BBSections =
llvm::StringSwitch<llvm::BasicBlockSection>(CodeGenOpts.BBSections)
.Case("all", llvm::BasicBlockSection::All)
Expand Down
6 changes: 2 additions & 4 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10676,10 +10676,8 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
llvm::FunctionType::get(StructType::get(CGM.Int64Ty, CGM.Int64Ty), {},
false),
"__arm_sme_state"));
auto Attrs =
AttributeList()
.addFnAttribute(getLLVMContext(), "aarch64_pstate_sm_compatible")
.addFnAttribute(getLLVMContext(), "aarch64_pstate_za_preserved");
auto Attrs = AttributeList().addFnAttribute(getLLVMContext(),
"aarch64_pstate_sm_compatible");
CI->setAttributes(Attrs);
CI->setCallingConv(
llvm::CallingConv::
Expand Down
16 changes: 8 additions & 8 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1774,14 +1774,14 @@ static void AddAttributesFromFunctionProtoType(ASTContext &Ctx,
FuncAttrs.addAttribute("aarch64_pstate_sm_compatible");

// ZA
if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_Out ||
FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_InOut)
FuncAttrs.addAttribute("aarch64_pstate_za_shared");
if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_Preserves ||
FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_In) {
FuncAttrs.addAttribute("aarch64_pstate_za_shared");
FuncAttrs.addAttribute("aarch64_pstate_za_preserved");
}
if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_Preserves)
FuncAttrs.addAttribute("aarch64_preserves_za");
if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_In)
FuncAttrs.addAttribute("aarch64_in_za");
if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_Out)
FuncAttrs.addAttribute("aarch64_out_za");
if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_InOut)
FuncAttrs.addAttribute("aarch64_inout_za");

// ZT0
if (FunctionType::getArmZT0State(SMEBits) == FunctionType::ARM_Preserves)
Expand Down
6 changes: 2 additions & 4 deletions clang/lib/CodeGen/CGObjCMac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5038,12 +5038,10 @@ std::string CGObjCCommonMac::GetSectionName(StringRef Section,
return ("__DATA," + Section + "," + MachOAttributes).str();
}
case llvm::Triple::ELF:
assert(Section.substr(0, 2) == "__" &&
"expected the name to begin with __");
assert(Section.starts_with("__") && "expected the name to begin with __");
return Section.substr(2).str();
case llvm::Triple::COFF:
assert(Section.substr(0, 2) == "__" &&
"expected the name to begin with __");
assert(Section.starts_with("__") && "expected the name to begin with __");
return ("." + Section.substr(2) + "$B").str();
case llvm::Triple::Wasm:
case llvm::Triple::GOFF:
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CGStmtOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6546,6 +6546,9 @@ void CodeGenFunction::EmitOMPAtomicDirective(const OMPAtomicDirective &S) {
// Find first clause (skip seq_cst|acq_rel|aqcuire|release|relaxed clause,
// if it is first).
OpenMPClauseKind K = C->getClauseKind();
// TBD
if (K == OMPC_weak)
return;
if (K == OMPC_seq_cst || K == OMPC_acq_rel || K == OMPC_acquire ||
K == OMPC_release || K == OMPC_relaxed || K == OMPC_hint)
continue;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2414,7 +2414,7 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,

if (auto *Attr = D->getAttr<ArmNewAttr>()) {
if (Attr->isNewZA())
B.addAttribute("aarch64_pstate_za_new");
B.addAttribute("aarch64_new_za");
if (Attr->isNewZT0())
B.addAttribute("aarch64_new_zt0");
}
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/CodeGen/CodeGenPGO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ static llvm::cl::opt<bool>
llvm::cl::desc("Enable value profiling"),
llvm::cl::Hidden, llvm::cl::init(false));

extern llvm::cl::opt<bool> SystemHeadersCoverage;

using namespace clang;
using namespace CodeGen;

Expand Down Expand Up @@ -1022,7 +1024,7 @@ bool CodeGenPGO::skipRegionMappingForDecl(const Decl *D) {
// Don't map the functions in system headers.
const auto &SM = CGM.getContext().getSourceManager();
auto Loc = D->getBody()->getBeginLoc();
return SM.isInSystemHeader(Loc);
return !SystemHeadersCoverage && SM.isInSystemHeader(Loc);
}

void CodeGenPGO::emitCounterRegionMapping(const Decl *D) {
Expand Down
8 changes: 5 additions & 3 deletions clang/lib/CodeGen/CoverageMappingGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ static llvm::cl::opt<bool> EmptyLineCommentCoverage(
"disable it on test)"),
llvm::cl::init(true), llvm::cl::Hidden);

static llvm::cl::opt<bool> SystemHeadersCoverage(
llvm::cl::opt<bool> SystemHeadersCoverage(
"system-headers-coverage",
llvm::cl::desc("Enable collecting coverage from system headers"),
llvm::cl::init(false), llvm::cl::Hidden);
Expand Down Expand Up @@ -1812,8 +1812,10 @@ struct CounterCoverageMappingBuilder
assert(S->isConstexpr());

// evaluate constant condition...
const auto *E = cast<ConstantExpr>(S->getCond());
const bool isTrue = E->getResultAsAPSInt().getExtValue();
const bool isTrue =
S->getCond()
->EvaluateKnownConstInt(CVM.getCodeGenModule().getContext())
.getBoolValue();

extendRegion(S);

Expand Down
14 changes: 10 additions & 4 deletions clang/lib/Driver/ToolChains/AMDGPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -486,10 +486,16 @@ void RocmInstallationDetector::detectHIPRuntime() {
return newpath;
};
// If HIP version file can be found and parsed, use HIP version from there.
for (const auto &VersionFilePath :
{Append(SharePath, "hip", "version"),
Append(ParentSharePath, "hip", "version"),
Append(BinPath, ".hipVersion")}) {
std::vector<SmallString<0>> VersionFilePaths = {
Append(SharePath, "hip", "version"),
InstallPath != D.SysRoot + "/usr/local"
? Append(ParentSharePath, "hip", "version")
: SmallString<0>(),
Append(BinPath, ".hipVersion")};

for (const auto &VersionFilePath : VersionFilePaths) {
if (VersionFilePath.empty())
continue;
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile =
FS.getBufferForFile(VersionFilePath);
if (!VersionFile)
Expand Down
17 changes: 16 additions & 1 deletion clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2705,7 +2705,7 @@ static StringRef EnumComplexRangeToStr(LangOptions::ComplexRangeKind Range) {
static void EmitComplexRangeDiag(const Driver &D,
LangOptions::ComplexRangeKind Range1,
LangOptions::ComplexRangeKind Range2) {
if (Range1 != LangOptions::ComplexRangeKind::CX_Full)
if (Range1 != Range2 && Range1 != LangOptions::ComplexRangeKind::CX_None)
D.Diag(clang::diag::warn_drv_overriding_option)
<< EnumComplexRangeToStr(Range1) << EnumComplexRangeToStr(Range2);
}
Expand Down Expand Up @@ -3940,6 +3940,10 @@ static bool RenderModulesOptions(Compilation &C, const Driver &D,
Args.ClaimAllArgs(options::OPT_fmodules_disable_diagnostic_validation);
}

// FIXME: We provisionally don't check ODR violations for decls in the global
// module fragment.
CmdArgs.push_back("-fskip-odr-check-in-gmf");

// Claim `-fmodule-output` and `-fmodule-output=` to avoid unused warnings.
Args.ClaimAllArgs(options::OPT_fmodule_output);
Args.ClaimAllArgs(options::OPT_fmodule_output_EQ);
Expand Down Expand Up @@ -5940,6 +5944,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-ffunction-sections");
}

if (Arg *A = Args.getLastArg(options::OPT_fbasic_block_address_map,
options::OPT_fno_basic_block_address_map)) {
if (Triple.isX86() && Triple.isOSBinFormatELF()) {
if (A->getOption().matches(options::OPT_fbasic_block_address_map))
A->render(Args, CmdArgs);
} else {
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << TripleStr;
}
}

if (Arg *A = Args.getLastArg(options::OPT_fbasic_block_sections_EQ)) {
StringRef Val = A->getValue();
if (Triple.isX86() && Triple.isOSBinFormatELF()) {
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Driver/ToolChains/HIPAMD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA,
if (IsThinLTO)
LldArgs.push_back(Args.MakeArgString("-plugin-opt=-force-import-all"));

for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
LldArgs.push_back(
Args.MakeArgString(Twine("-plugin-opt=") + A->getValue(0)));
}

if (C.getDriver().isSaveTempsEnabled())
LldArgs.push_back("-save-temps");

Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Driver/ToolChains/MinGW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,10 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("thumb2pe");
break;
case llvm::Triple::aarch64:
CmdArgs.push_back("arm64pe");
if (TC.getEffectiveTriple().isWindowsArm64EC())
CmdArgs.push_back("arm64ecpe");
else
CmdArgs.push_back("arm64pe");
break;
default:
D.Diag(diag::err_target_unknown_triple) << TC.getEffectiveTriple().str();
Expand Down
23 changes: 1 addition & 22 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -504,22 +504,6 @@ struct ScalarEnumerationTraits<FormatStyle::QualifierAlignmentStyle> {
}
};

template <>
struct MappingTraits<
FormatStyle::SpaceBeforeParensCustom::AfterPlacementOperatorStyle> {
static void
mapping(IO &IO,
FormatStyle::SpaceBeforeParensCustom::AfterPlacementOperatorStyle
&Value) {
IO.enumCase(Value, "Always",
FormatStyle::SpaceBeforeParensCustom::APO_Always);
IO.enumCase(Value, "Never",
FormatStyle::SpaceBeforeParensCustom::APO_Never);
IO.enumCase(Value, "Leave",
FormatStyle::SpaceBeforeParensCustom::APO_Leave);
}
};

template <> struct MappingTraits<FormatStyle::RawStringFormat> {
static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) {
IO.mapOptional("Language", Format.Language);
Expand Down Expand Up @@ -1388,12 +1372,9 @@ static void expandPresetsSpaceBeforeParens(FormatStyle &Expanded) {
return;
// Reset all flags
Expanded.SpaceBeforeParensOptions = {};
Expanded.SpaceBeforeParensOptions.AfterPlacementOperator = true;

switch (Expanded.SpaceBeforeParens) {
case FormatStyle::SBPO_Never:
Expanded.SpaceBeforeParensOptions.AfterPlacementOperator =
FormatStyle::SpaceBeforeParensCustom::APO_Never;
break;
case FormatStyle::SBPO_ControlStatements:
Expanded.SpaceBeforeParensOptions.AfterControlStatements = true;
Expanded.SpaceBeforeParensOptions.AfterForeachMacros = true;
Expand All @@ -1405,8 +1386,6 @@ static void expandPresetsSpaceBeforeParens(FormatStyle &Expanded) {
case FormatStyle::SBPO_NonEmptyParentheses:
Expanded.SpaceBeforeParensOptions.BeforeNonEmptyParentheses = true;
break;
case FormatStyle::SBPO_Always:
break;
default:
break;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Format/FormatTokenLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1420,7 +1420,7 @@ void FormatTokenLexer::readRawToken(FormatToken &Tok) {
// For formatting, treat unterminated string literals like normal string
// literals.
if (Tok.is(tok::unknown)) {
if (!Tok.TokenText.empty() && Tok.TokenText[0] == '"') {
if (Tok.TokenText.starts_with("\"")) {
Tok.Tok.setKind(tok::string_literal);
Tok.IsUnterminatedLiteral = true;
} else if (Style.isJavaScript() && Tok.TokenText == "''") {
Expand Down
9 changes: 1 addition & 8 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4274,14 +4274,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
Left.isOneOf(tok::kw_new, tok::kw_delete) &&
Right.isNot(TT_OverloadedOperatorLParen) &&
!(Line.MightBeFunctionDecl && Left.is(TT_FunctionDeclarationName))) {
if (Style.SpaceBeforeParensOptions.AfterPlacementOperator ==
FormatStyle::SpaceBeforeParensCustom::APO_Always ||
(Style.SpaceBeforeParensOptions.AfterPlacementOperator ==
FormatStyle::SpaceBeforeParensCustom::APO_Leave &&
Right.hasWhitespaceBefore())) {
return true;
}
return false;
return Style.SpaceBeforeParensOptions.AfterPlacementOperator;
}
if (Line.Type == LT_ObjCDecl)
return true;
Expand Down
10 changes: 3 additions & 7 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1760,8 +1760,8 @@ void UnwrappedLineParser::parseStructuralElement(
break;
}
case tok::kw_enum:
// Ignore if this is part of "template <enum ...".
if (Previous && Previous->is(tok::less)) {
// Ignore if this is part of "template <enum ..." or "... -> enum".
if (Previous && Previous->isOneOf(tok::less, tok::arrow)) {
nextToken();
break;
}
Expand Down Expand Up @@ -3446,18 +3446,14 @@ bool clang::format::UnwrappedLineParser::parseRequires() {
return false;
}
break;
case tok::r_paren:
case tok::pipepipe:
FormatTok = Tokens->setPosition(StoredPosition);
parseRequiresClause(RequiresToken);
return true;
case tok::eof:
// Break out of the loop.
Lookahead = 50;
break;
case tok::coloncolon:
LastWasColonColon = true;
break;
case tok::kw_decltype:
case tok::identifier:
if (FoundType && !LastWasColonColon && OpenAngles == 0) {
FormatTok = Tokens->setPosition(StoredPosition);
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Frontend/FrontendActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -826,8 +826,7 @@ void DumpModuleInfoAction::ExecuteAction() {
auto &FileMgr = CI.getFileManager();
auto Buffer = FileMgr.getBufferForFile(getCurrentFile());
StringRef Magic = (*Buffer)->getMemBufferRef().getBuffer();
bool IsRaw = (Magic.size() >= 4 && Magic[0] == 'C' && Magic[1] == 'P' &&
Magic[2] == 'C' && Magic[3] == 'H');
bool IsRaw = Magic.starts_with("CPCH");
Out << " Module format: " << (IsRaw ? "raw" : "obj") << "\n";

Preprocessor &PP = CI.getPreprocessor();
Expand Down
45 changes: 45 additions & 0 deletions clang/lib/Lex/Lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,51 @@ tok::ObjCKeywordKind Token::getObjCKeywordID() const {
return specId ? specId->getObjCKeywordID() : tok::objc_not_keyword;
}

/// Determine whether the token kind starts a simple-type-specifier.
bool Token::isSimpleTypeSpecifier(const LangOptions &LangOpts) const {
switch (getKind()) {
case tok::annot_typename:
case tok::annot_decltype:
case tok::annot_pack_indexing_type:
return true;

case tok::kw_short:
case tok::kw_long:
case tok::kw___int64:
case tok::kw___int128:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw_void:
case tok::kw_char:
case tok::kw_int:
case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
case tok::kw___bf16:
case tok::kw__Float16:
case tok::kw___float128:
case tok::kw___ibm128:
case tok::kw_wchar_t:
case tok::kw_bool:
case tok::kw__Bool:
case tok::kw__Accum:
case tok::kw__Fract:
case tok::kw__Sat:
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
#include "clang/Basic/TransformTypeTraits.def"
case tok::kw___auto_type:
case tok::kw_char16_t:
case tok::kw_char32_t:
case tok::kw_typeof:
case tok::kw_decltype:
case tok::kw_char8_t:
return getIdentifierInfo()->isKeyword(LangOpts);

default:
return false;
}
}

//===----------------------------------------------------------------------===//
// Lexer Class Implementation
//===----------------------------------------------------------------------===//
Expand Down
97 changes: 84 additions & 13 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1916,9 +1916,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
case tok::kw_export:
ProhibitAttributes(DeclAttrs);
ProhibitAttributes(DeclSpecAttrs);
SingleDecl =
ParseDeclarationStartingWithTemplate(Context, DeclEnd, DeclAttrs);
break;
return ParseDeclarationStartingWithTemplate(Context, DeclEnd, DeclAttrs);
case tok::kw_inline:
// Could be the start of an inline namespace. Allowed as an ext in C++03.
if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_namespace)) {
Expand Down Expand Up @@ -1994,8 +1992,9 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(
ParsingDeclSpec DS(*this);
DS.takeAttributesFrom(DeclSpecAttrs);

ParsedTemplateInfo TemplateInfo;
DeclSpecContext DSContext = getDeclSpecContextFromDeclaratorContext(Context);
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, DSContext);
ParseDeclarationSpecifiers(DS, TemplateInfo, AS_none, DSContext);

// If we had a free-standing type definition with a missing semicolon, we
// may get this far before the problem becomes obvious.
Expand Down Expand Up @@ -2027,7 +2026,7 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(
if (DeclSpecStart)
DS.SetRangeStart(*DeclSpecStart);

return ParseDeclGroup(DS, Context, DeclAttrs, &DeclEnd, FRI);
return ParseDeclGroup(DS, Context, DeclAttrs, TemplateInfo, &DeclEnd, FRI);
}

/// Returns true if this might be the start of a declarator, or a common typo
Expand Down Expand Up @@ -2184,6 +2183,7 @@ void Parser::SkipMalformedDecl() {
Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
DeclaratorContext Context,
ParsedAttributes &Attrs,
ParsedTemplateInfo &TemplateInfo,
SourceLocation *DeclEnd,
ForRangeInit *FRI) {
// Parse the first declarator.
Expand All @@ -2193,8 +2193,19 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
ParsedAttributes LocalAttrs(AttrFactory);
LocalAttrs.takeAllFrom(Attrs);
ParsingDeclarator D(*this, DS, LocalAttrs, Context);
if (TemplateInfo.TemplateParams)
D.setTemplateParameterLists(*TemplateInfo.TemplateParams);

bool IsTemplateSpecOrInst =
(TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation ||
TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization);
SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst);

ParseDeclarator(D);

if (IsTemplateSpecOrInst)
SAC.done();

// Bail out if the first declarator didn't seem well-formed.
if (!D.hasName() && !D.mayOmitIdentifier()) {
SkipMalformedDecl();
Expand Down Expand Up @@ -2262,15 +2273,54 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// need to handle the file scope definition case.
if (Context == DeclaratorContext::File) {
if (isStartOfFunctionDefinition(D)) {
// C++23 [dcl.typedef] p1:
// The typedef specifier shall not be [...], and it shall not be
// used in the decl-specifier-seq of a parameter-declaration nor in
// the decl-specifier-seq of a function-definition.
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
Diag(Tok, diag::err_function_declared_typedef);

// Recover by treating the 'typedef' as spurious.
// If the user intended to write 'typename', we should have already
// suggested adding it elsewhere. In any case, recover by ignoring
// 'typedef' and suggest removing it.
Diag(DS.getStorageClassSpecLoc(),
diag::err_function_declared_typedef)
<< FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
DS.ClearStorageClassSpecs();
}
Decl *TheDecl = nullptr;

if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
if (D.getName().getKind() != UnqualifiedIdKind::IK_TemplateId) {
// If the declarator-id is not a template-id, issue a diagnostic
// and recover by ignoring the 'template' keyword.
Diag(Tok, diag::err_template_defn_explicit_instantiation) << 0;
TheDecl = ParseFunctionDefinition(D, ParsedTemplateInfo(),
&LateParsedAttrs);
} else {
SourceLocation LAngleLoc =
PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
Diag(D.getIdentifierLoc(),
diag::err_explicit_instantiation_with_definition)
<< SourceRange(TemplateInfo.TemplateLoc)
<< FixItHint::CreateInsertion(LAngleLoc, "<>");

// Recover as if it were an explicit specialization.
TemplateParameterLists FakedParamLists;
FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc,
std::nullopt, LAngleLoc, nullptr));

TheDecl = ParseFunctionDefinition(
D,
ParsedTemplateInfo(&FakedParamLists,
/*isSpecialization=*/true,
/*lastParameterListWasEmpty=*/true),
&LateParsedAttrs);
}
} else {
TheDecl =
ParseFunctionDefinition(D, TemplateInfo, &LateParsedAttrs);
}

Decl *TheDecl = ParseFunctionDefinition(D, ParsedTemplateInfo(),
&LateParsedAttrs);
return Actions.ConvertDeclToDeclGroup(TheDecl);
}

Expand Down Expand Up @@ -2360,8 +2410,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
}

SmallVector<Decl *, 8> DeclsInGroup;
Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(
D, ParsedTemplateInfo(), FRI);
Decl *FirstDecl =
ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo, FRI);
if (LateParsedAttrs.size() > 0)
ParseLexedAttributeList(LateParsedAttrs, FirstDecl, true, false);
D.complete(FirstDecl);
Expand All @@ -2384,6 +2434,16 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
break;
}

// C++23 [temp.pre]p5:
// In a template-declaration, explicit specialization, or explicit
// instantiation the init-declarator-list in the declaration shall
// contain at most one declarator.
if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
D.isFirstDeclarator()) {
Diag(CommaLoc, diag::err_multiple_template_declarators)
<< TemplateInfo.Kind;
}

// Parse the next declarator.
D.clear();
D.setCommaLoc(CommaLoc);
Expand Down Expand Up @@ -2413,7 +2473,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// declarator requires-clause
if (Tok.is(tok::kw_requires))
ParseTrailingRequiresClause(D);
Decl *ThisDecl = ParseDeclarationAfterDeclarator(D);
Decl *ThisDecl = ParseDeclarationAfterDeclarator(D, TemplateInfo);
D.complete(ThisDecl);
if (ThisDecl)
DeclsInGroup.push_back(ThisDecl);
Expand Down Expand Up @@ -6526,6 +6586,17 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
/*ObjectHasErrors=*/false, EnteringContext);
}

// C++23 [basic.scope.namespace]p1:
// For each non-friend redeclaration or specialization whose target scope
// is or is contained by the scope, the portion after the declarator-id,
// class-head-name, or enum-head-name is also included in the scope.
// C++23 [basic.scope.class]p1:
// For each non-friend redeclaration or specialization whose target scope
// is or is contained by the scope, the portion after the declarator-id,
// class-head-name, or enum-head-name is also included in the scope.
//
// FIXME: We should not be doing this for friend declarations; they have
// their own special lookup semantics specified by [basic.lookup.unqual]p6.
if (D.getCXXScopeSpec().isValid()) {
if (Actions.ShouldEnterDeclaratorScope(getCurScope(),
D.getCXXScopeSpec()))
Expand Down
35 changes: 31 additions & 4 deletions clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2855,7 +2855,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
}

// static_assert-declaration. A templated static_assert declaration is
// diagnosed in Parser::ParseSingleDeclarationAfterTemplate.
// diagnosed in Parser::ParseDeclarationAfterTemplate.
if (!TemplateInfo.Kind &&
Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {
SourceLocation DeclEnd;
Expand All @@ -2868,9 +2868,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
"Nested template improperly parsed?");
ObjCDeclContextSwitch ObjCDC(*this);
SourceLocation DeclEnd;
return DeclGroupPtrTy::make(
DeclGroupRef(ParseTemplateDeclarationOrSpecialization(
DeclaratorContext::Member, DeclEnd, AccessAttrs, AS)));
return ParseTemplateDeclarationOrSpecialization(DeclaratorContext::Member,
DeclEnd, AccessAttrs, AS);
}

// Handle: member-declaration ::= '__extension__' member-declaration
Expand Down Expand Up @@ -3279,6 +3278,16 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
break;
}

// C++23 [temp.pre]p5:
// In a template-declaration, explicit specialization, or explicit
// instantiation the init-declarator-list in the declaration shall
// contain at most one declarator.
if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
DeclaratorInfo.isFirstDeclarator()) {
Diag(CommaLoc, diag::err_multiple_template_declarators)
<< TemplateInfo.Kind;
}

// Parse the next declarator.
DeclaratorInfo.clear();
VS.clear();
Expand Down Expand Up @@ -4228,6 +4237,24 @@ void Parser::ParseTrailingRequiresClause(Declarator &D) {

SourceLocation RequiresKWLoc = ConsumeToken();

// C++23 [basic.scope.namespace]p1:
// For each non-friend redeclaration or specialization whose target scope
// is or is contained by the scope, the portion after the declarator-id,
// class-head-name, or enum-head-name is also included in the scope.
// C++23 [basic.scope.class]p1:
// For each non-friend redeclaration or specialization whose target scope
// is or is contained by the scope, the portion after the declarator-id,
// class-head-name, or enum-head-name is also included in the scope.
//
// FIXME: We should really be calling ParseTrailingRequiresClause in
// ParseDirectDeclarator, when we are already in the declarator scope.
// This would also correctly suppress access checks for specializations
// and explicit instantiations, which we currently do not do.
CXXScopeSpec &SS = D.getCXXScopeSpec();
DeclaratorScopeObj DeclScopeObj(*this, SS);
if (SS.isValid() && Actions.ShouldEnterDeclaratorScope(getCurScope(), SS))
DeclScopeObj.EnterDeclaratorScope();

ExprResult TrailingRequiresClause;
ParseScope ParamScope(this, Scope::DeclScope |
Scope::FunctionDeclarationScope |
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 @@ -1609,7 +1609,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
if (TryAnnotateTypeOrScopeToken())
return ExprError();

if (!Actions.isSimpleTypeSpecifier(Tok))
if (!Tok.isSimpleTypeSpecifier(getLangOpts()))
// We are trying to parse a simple-type-specifier but might not get such
// a token after error recovery.
return ExprError();
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Parse/ParseObjc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2971,7 +2971,7 @@ bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
tok::annot_cxxscope))
TryAnnotateTypeOrScopeToken();

if (!Actions.isSimpleTypeSpecifier(Tok)) {
if (!Tok.isSimpleTypeSpecifier(getLangOpts())) {
// objc-receiver:
// expression
// Make sure any typos in the receiver are corrected or diagnosed, so that
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Parse/ParseOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3314,6 +3314,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_acquire:
case OMPC_release:
case OMPC_relaxed:
case OMPC_weak:
case OMPC_threads:
case OMPC_simd:
case OMPC_nogroup:
Expand Down
206 changes: 40 additions & 166 deletions clang/lib/Parse/ParseTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,19 @@ unsigned Parser::ReenterTemplateScopes(MultiParseScope &S, Decl *D) {

/// Parse a template declaration, explicit instantiation, or
/// explicit specialization.
Decl *Parser::ParseDeclarationStartingWithTemplate(
DeclaratorContext Context, SourceLocation &DeclEnd,
ParsedAttributes &AccessAttrs, AccessSpecifier AS) {
Parser::DeclGroupPtrTy
Parser::ParseDeclarationStartingWithTemplate(DeclaratorContext Context,
SourceLocation &DeclEnd,
ParsedAttributes &AccessAttrs) {
ObjCDeclContextSwitch ObjCDC(*this);

if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) {
return ParseExplicitInstantiation(Context, SourceLocation(), ConsumeToken(),
DeclEnd, AccessAttrs, AS);
DeclEnd, AccessAttrs,
AccessSpecifier::AS_none);
}
return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AccessAttrs,
AS);
AccessSpecifier::AS_none);
}

/// Parse a template declaration or an explicit specialization.
Expand All @@ -73,7 +75,7 @@ Decl *Parser::ParseDeclarationStartingWithTemplate(
///
/// explicit-specialization: [ C++ temp.expl.spec]
/// 'template' '<' '>' declaration
Decl *Parser::ParseTemplateDeclarationOrSpecialization(
Parser::DeclGroupPtrTy Parser::ParseTemplateDeclarationOrSpecialization(
DeclaratorContext Context, SourceLocation &DeclEnd,
ParsedAttributes &AccessAttrs, AccessSpecifier AS) {
assert(Tok.isOneOf(tok::kw_export, tok::kw_template) &&
Expand Down Expand Up @@ -161,17 +163,16 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization(
TemplateParams, RAngleLoc, OptionalRequiresClauseConstraintER.get()));
} while (Tok.isOneOf(tok::kw_export, tok::kw_template));

ParsedTemplateInfo TemplateInfo(&ParamLists, isSpecialization,
LastParamListWasEmpty);

// Parse the actual template declaration.
if (Tok.is(tok::kw_concept))
return ParseConceptDefinition(
ParsedTemplateInfo(&ParamLists, isSpecialization,
LastParamListWasEmpty),
DeclEnd);

return ParseSingleDeclarationAfterTemplate(
Context,
ParsedTemplateInfo(&ParamLists, isSpecialization, LastParamListWasEmpty),
ParsingTemplateParams, DeclEnd, AccessAttrs, AS);
return Actions.ConvertDeclToDeclGroup(
ParseConceptDefinition(TemplateInfo, DeclEnd));

return ParseDeclarationAfterTemplate(
Context, TemplateInfo, ParsingTemplateParams, DeclEnd, AccessAttrs, AS);
}

/// Parse a single declaration that declares a template,
Expand All @@ -184,8 +185,8 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization(
/// declaration. Will be AS_none for namespace-scope declarations.
///
/// \returns the new declaration.
Decl *Parser::ParseSingleDeclarationAfterTemplate(
DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo,
Parser::DeclGroupPtrTy Parser::ParseDeclarationAfterTemplate(
DeclaratorContext Context, ParsedTemplateInfo &TemplateInfo,
ParsingDeclRAIIObject &DiagsFromTParams, SourceLocation &DeclEnd,
ParsedAttributes &AccessAttrs, AccessSpecifier AS) {
assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
Expand All @@ -196,37 +197,29 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
Diag(Tok.getLocation(), diag::err_templated_invalid_declaration)
<< TemplateInfo.getSourceRange();
// Parse the static_assert declaration to improve error recovery.
return ParseStaticAssertDeclaration(DeclEnd);
return Actions.ConvertDeclToDeclGroup(
ParseStaticAssertDeclaration(DeclEnd));
}

if (Context == DeclaratorContext::Member) {
// We are parsing a member template.
DeclGroupPtrTy D = ParseCXXClassMemberDeclaration(
AS, AccessAttrs, TemplateInfo, &DiagsFromTParams);
// We are parsing a member template.
if (Context == DeclaratorContext::Member)
return ParseCXXClassMemberDeclaration(AS, AccessAttrs, TemplateInfo,
&DiagsFromTParams);

if (!D || !D.get().isSingleDecl())
return nullptr;
return D.get().getSingleDecl();
}

ParsedAttributes prefixAttrs(AttrFactory);
ParsedAttributes DeclAttrs(AttrFactory);
ParsedAttributes DeclSpecAttrs(AttrFactory);

// GNU attributes are applied to the declaration specification while the
// standard attributes are applied to the declaration. We parse the two
// attribute sets into different containters so we can apply them during
// the regular parsing process.
while (MaybeParseCXX11Attributes(prefixAttrs) ||
while (MaybeParseCXX11Attributes(DeclAttrs) ||
MaybeParseGNUAttributes(DeclSpecAttrs))
;

if (Tok.is(tok::kw_using)) {
auto usingDeclPtr = ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd,
prefixAttrs);
if (!usingDeclPtr || !usingDeclPtr.get().isSingleDecl())
return nullptr;
return usingDeclPtr.get().getSingleDecl();
}
if (Tok.is(tok::kw_using))
return ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd,
DeclAttrs);

// Parse the declaration specifiers, stealing any diagnostics from
// the template parameters.
Expand All @@ -239,7 +232,7 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
getDeclSpecContextFromDeclaratorContext(Context));

if (Tok.is(tok::semi)) {
ProhibitAttributes(prefixAttrs);
ProhibitAttributes(DeclAttrs);
DeclEnd = ConsumeToken();
RecordDecl *AnonRecord = nullptr;
Decl *Decl = Actions.ParsedFreeStandingDeclSpec(
Expand All @@ -252,133 +245,17 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
assert(!AnonRecord &&
"Anonymous unions/structs should not be valid with template");
DS.complete(Decl);
return Decl;
return Actions.ConvertDeclToDeclGroup(Decl);
}

if (DS.hasTagDefinition())
Actions.ActOnDefinedDeclarationSpecifier(DS.getRepAsDecl());

// Move the attributes from the prefix into the DS.
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
ProhibitAttributes(prefixAttrs);

// Parse the declarator.
ParsingDeclarator DeclaratorInfo(*this, DS, prefixAttrs,
(DeclaratorContext)Context);
if (TemplateInfo.TemplateParams)
DeclaratorInfo.setTemplateParameterLists(*TemplateInfo.TemplateParams);

// Turn off usual access checking for template specializations and
// instantiations.
// C++20 [temp.spec] 13.9/6.
// This disables the access checking rules for function template explicit
// instantiation and explicit specialization:
// - parameter-list;
// - template-argument-list;
// - noexcept-specifier;
// - dynamic-exception-specifications (deprecated in C++11, removed since
// C++17).
bool IsTemplateSpecOrInst =
(TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation ||
TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization);
SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst);

ParseDeclarator(DeclaratorInfo);

if (IsTemplateSpecOrInst)
SAC.done();

// Error parsing the declarator?
if (!DeclaratorInfo.hasName()) {
SkipMalformedDecl();
return nullptr;
}

LateParsedAttrList LateParsedAttrs(true);
if (DeclaratorInfo.isFunctionDeclarator()) {
if (Tok.is(tok::kw_requires)) {
CXXScopeSpec &ScopeSpec = DeclaratorInfo.getCXXScopeSpec();
DeclaratorScopeObj DeclScopeObj(*this, ScopeSpec);
if (ScopeSpec.isValid() &&
Actions.ShouldEnterDeclaratorScope(getCurScope(), ScopeSpec))
DeclScopeObj.EnterDeclaratorScope();
ParseTrailingRequiresClause(DeclaratorInfo);
}

MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
}

if (DeclaratorInfo.isFunctionDeclarator() &&
isStartOfFunctionDefinition(DeclaratorInfo)) {
ProhibitAttributes(DeclAttrs);

// Function definitions are only allowed at file scope and in C++ classes.
// The C++ inline method definition case is handled elsewhere, so we only
// need to handle the file scope definition case.
if (Context != DeclaratorContext::File) {
Diag(Tok, diag::err_function_definition_not_allowed);
SkipMalformedDecl();
return nullptr;
}

if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
// Recover by ignoring the 'typedef'. This was probably supposed to be
// the 'typename' keyword, which we should have already suggested adding
// if it's appropriate.
Diag(DS.getStorageClassSpecLoc(), diag::err_function_declared_typedef)
<< FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
DS.ClearStorageClassSpecs();
}

if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
if (DeclaratorInfo.getName().getKind() !=
UnqualifiedIdKind::IK_TemplateId) {
// If the declarator-id is not a template-id, issue a diagnostic and
// recover by ignoring the 'template' keyword.
Diag(Tok, diag::err_template_defn_explicit_instantiation) << 0;
return ParseFunctionDefinition(DeclaratorInfo, ParsedTemplateInfo(),
&LateParsedAttrs);
} else {
SourceLocation LAngleLoc
= PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
Diag(DeclaratorInfo.getIdentifierLoc(),
diag::err_explicit_instantiation_with_definition)
<< SourceRange(TemplateInfo.TemplateLoc)
<< FixItHint::CreateInsertion(LAngleLoc, "<>");

// Recover as if it were an explicit specialization.
TemplateParameterLists FakedParamLists;
FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc,
std::nullopt, LAngleLoc, nullptr));

return ParseFunctionDefinition(
DeclaratorInfo, ParsedTemplateInfo(&FakedParamLists,
/*isSpecialization=*/true,
/*lastParameterListWasEmpty=*/true),
&LateParsedAttrs);
}
}
return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo,
&LateParsedAttrs);
}

// Parse this declaration.
Decl *ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo,
TemplateInfo);

if (Tok.is(tok::comma)) {
Diag(Tok, diag::err_multiple_template_declarators)
<< (int)TemplateInfo.Kind;
SkipUntil(tok::semi);
return ThisDecl;
}

// Eat the semi colon after the declaration.
ExpectAndConsumeSemi(diag::err_expected_semi_declaration);
if (LateParsedAttrs.size() > 0)
ParseLexedAttributeList(LateParsedAttrs, ThisDecl, true, false);
DeclaratorInfo.complete(ThisDecl);
return ThisDecl;
return ParseDeclGroup(DS, Context, DeclAttrs, TemplateInfo, &DeclEnd);
}

/// \brief Parse a single declaration that declares a concept.
Expand Down Expand Up @@ -1686,19 +1563,16 @@ bool Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs,
/// 'extern' [opt] 'template' declaration
///
/// Note that the 'extern' is a GNU extension and C++11 feature.
Decl *Parser::ParseExplicitInstantiation(DeclaratorContext Context,
SourceLocation ExternLoc,
SourceLocation TemplateLoc,
SourceLocation &DeclEnd,
ParsedAttributes &AccessAttrs,
AccessSpecifier AS) {
Parser::DeclGroupPtrTy Parser::ParseExplicitInstantiation(
DeclaratorContext Context, SourceLocation ExternLoc,
SourceLocation TemplateLoc, SourceLocation &DeclEnd,
ParsedAttributes &AccessAttrs, AccessSpecifier AS) {
// This isn't really required here.
ParsingDeclRAIIObject
ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent);

return ParseSingleDeclarationAfterTemplate(
Context, ParsedTemplateInfo(ExternLoc, TemplateLoc),
ParsingTemplateParams, DeclEnd, AccessAttrs, AS);
ParsedTemplateInfo TemplateInfo(ExternLoc, TemplateLoc);
return ParseDeclarationAfterTemplate(
Context, TemplateInfo, ParsingTemplateParams, DeclEnd, AccessAttrs, AS);
}

SourceRange Parser::ParsedTemplateInfo::getSourceRange() const {
Expand Down
9 changes: 5 additions & 4 deletions clang/lib/Parse/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1040,8 +1040,8 @@ Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
diag::warn_cxx98_compat_extern_template :
diag::ext_extern_template) << SourceRange(ExternLoc, TemplateLoc);
SourceLocation DeclEnd;
return Actions.ConvertDeclToDeclGroup(ParseExplicitInstantiation(
DeclaratorContext::File, ExternLoc, TemplateLoc, DeclEnd, Attrs));
return ParseExplicitInstantiation(DeclaratorContext::File, ExternLoc,
TemplateLoc, DeclEnd, Attrs);
}
goto dont_know;

Expand Down Expand Up @@ -1143,9 +1143,10 @@ Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal(
DS.SetRangeEnd(DeclSpecAttrs.Range.getEnd());
DS.takeAttributesFrom(DeclSpecAttrs);

ParsedTemplateInfo TemplateInfo;
MaybeParseMicrosoftAttributes(DS.getAttributes());
// Parse the common declaration-specifiers piece.
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS,
ParseDeclarationSpecifiers(DS, TemplateInfo, AS,
DeclSpecContext::DSC_top_level);

// If we had a free-standing type definition with a missing semicolon, we
Expand Down Expand Up @@ -1241,7 +1242,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal(
return Actions.ConvertDeclToDeclGroup(TheDecl);
}

return ParseDeclGroup(DS, DeclaratorContext::File, Attrs);
return ParseDeclGroup(DS, DeclaratorContext::File, Attrs, TemplateInfo);
}

Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition(
Expand Down
135 changes: 116 additions & 19 deletions clang/lib/Rewrite/HTMLRewrite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
using namespace clang;

using namespace clang;
using namespace llvm;
using namespace html;

/// HighlightRange - Highlight a range in the source code with the specified
/// start/end tags. B/E must be in the same file. This ensures that
Expand Down Expand Up @@ -104,6 +106,32 @@ void html::HighlightRange(RewriteBuffer &RB, unsigned B, unsigned E,
}
}

namespace clang::html {
struct RelexRewriteCache {
// These structs mimic input arguments of HighlightRange().
struct Highlight {
SourceLocation B, E;
std::string StartTag, EndTag;
bool IsTokenRange;
};
struct RawHighlight {
unsigned B, E;
std::string StartTag, EndTag;
};

// SmallVector isn't appropriate because these vectors are almost never small.
using HighlightList = std::vector<Highlight>;
using RawHighlightList = std::vector<RawHighlight>;

DenseMap<FileID, RawHighlightList> SyntaxHighlights;
DenseMap<FileID, HighlightList> MacroHighlights;
};
} // namespace clang::html

html::RelexRewriteCacheRef html::instantiateRelexRewriteCache() {
return std::make_shared<RelexRewriteCache>();
}

void html::EscapeText(Rewriter &R, FileID FID,
bool EscapeSpaces, bool ReplaceTabs) {

Expand Down Expand Up @@ -442,13 +470,18 @@ input.spoilerhider:checked + label + .spoiler{
/// information about keywords, macro expansions etc. This uses the macro
/// table state from the end of the file, so it won't be perfectly perfect,
/// but it will be reasonably close.
void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
RewriteBuffer &RB = R.getEditBuffer(FID);
static void SyntaxHighlightImpl(
Rewriter &R, FileID FID, const Preprocessor &PP,
llvm::function_ref<void(RewriteBuffer &, unsigned, unsigned, const char *,
const char *, const char *)>
HighlightRangeCallback) {

RewriteBuffer &RB = R.getEditBuffer(FID);
const SourceManager &SM = PP.getSourceManager();
llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(FID);
const char *BufferStart = FromFile.getBuffer().data();

Lexer L(FID, FromFile, SM, PP.getLangOpts());
const char *BufferStart = L.getBuffer().data();

// Inform the preprocessor that we want to retain comments as tokens, so we
// can highlight them.
Expand All @@ -475,13 +508,13 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {

// If this is a pp-identifier, for a keyword, highlight it as such.
if (Tok.isNot(tok::identifier))
HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart,
"<span class='keyword'>", "</span>");
HighlightRangeCallback(RB, TokOffs, TokOffs + TokLen, BufferStart,
"<span class='keyword'>", "</span>");
break;
}
case tok::comment:
HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart,
"<span class='comment'>", "</span>");
HighlightRangeCallback(RB, TokOffs, TokOffs + TokLen, BufferStart,
"<span class='comment'>", "</span>");
break;
case tok::utf8_string_literal:
// Chop off the u part of u8 prefix
Expand All @@ -498,8 +531,8 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
[[fallthrough]];
case tok::string_literal:
// FIXME: Exclude the optional ud-suffix from the highlighted range.
HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart,
"<span class='string_literal'>", "</span>");
HighlightRangeCallback(RB, TokOffs, TokOffs + TokLen, BufferStart,
"<span class='string_literal'>", "</span>");
break;
case tok::hash: {
// If this is a preprocessor directive, all tokens to end of line are too.
Expand All @@ -516,8 +549,8 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
}

// Find end of line. This is a hack.
HighlightRange(RB, TokOffs, TokEnd, BufferStart,
"<span class='directive'>", "</span>");
HighlightRangeCallback(RB, TokOffs, TokEnd, BufferStart,
"<span class='directive'>", "</span>");

// Don't skip the next token.
continue;
Expand All @@ -527,12 +560,43 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
L.LexFromRawLexer(Tok);
}
}
void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP,
RelexRewriteCacheRef Cache) {
RewriteBuffer &RB = R.getEditBuffer(FID);
const SourceManager &SM = PP.getSourceManager();
llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(FID);
const char *BufferStart = FromFile.getBuffer().data();

if (Cache) {
auto CacheIt = Cache->SyntaxHighlights.find(FID);
if (CacheIt != Cache->SyntaxHighlights.end()) {
for (const RelexRewriteCache::RawHighlight &H : CacheIt->second) {
HighlightRange(RB, H.B, H.E, BufferStart, H.StartTag.data(),
H.EndTag.data());
}
return;
}
}

// "Every time you would call HighlightRange, cache the inputs as well."
auto HighlightRangeCallback = [&](RewriteBuffer &RB, unsigned B, unsigned E,
const char *BufferStart,
const char *StartTag, const char *EndTag) {
HighlightRange(RB, B, E, BufferStart, StartTag, EndTag);

if (Cache)
Cache->SyntaxHighlights[FID].push_back({B, E, StartTag, EndTag});
};

SyntaxHighlightImpl(R, FID, PP, HighlightRangeCallback);
}

static void HighlightMacrosImpl(
Rewriter &R, FileID FID, const Preprocessor &PP,
llvm::function_ref<void(Rewriter &, SourceLocation, SourceLocation,
const char *, const char *, bool)>
HighlightRangeCallback) {

/// HighlightMacros - This uses the macro table state from the end of the
/// file, to re-expand macros and insert (into the HTML) information about the
/// macro expansions. This won't be perfectly perfect, but it will be
/// reasonably close.
void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) {
// Re-lex the raw token stream into a token buffer.
const SourceManager &SM = PP.getSourceManager();
std::vector<Token> TokenStream;
Expand Down Expand Up @@ -659,11 +723,44 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) {
// get highlighted.
Expansion = "<span class='macro_popup'>" + Expansion + "</span></span>";

HighlightRange(R, LLoc.getBegin(), LLoc.getEnd(), "<span class='macro'>",
Expansion.c_str(), LLoc.isTokenRange());
HighlightRangeCallback(R, LLoc.getBegin(), LLoc.getEnd(),
"<span class='macro'>", Expansion.c_str(),
LLoc.isTokenRange());
}

// Restore the preprocessor's old state.
TmpPP.setDiagnostics(*OldDiags);
TmpPP.setPragmasEnabled(PragmasPreviouslyEnabled);
}

/// HighlightMacros - This uses the macro table state from the end of the
/// file, to re-expand macros and insert (into the HTML) information about the
/// macro expansions. This won't be perfectly perfect, but it will be
/// reasonably close.
void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor &PP,
RelexRewriteCacheRef Cache) {
if (Cache) {
auto CacheIt = Cache->MacroHighlights.find(FID);
if (CacheIt != Cache->MacroHighlights.end()) {
for (const RelexRewriteCache::Highlight &H : CacheIt->second) {
HighlightRange(R, H.B, H.E, H.StartTag.data(), H.EndTag.data(),
H.IsTokenRange);
}
return;
}
}

// "Every time you would call HighlightRange, cache the inputs as well."
auto HighlightRangeCallback = [&](Rewriter &R, SourceLocation B,
SourceLocation E, const char *StartTag,
const char *EndTag, bool isTokenRange) {
HighlightRange(R, B, E, StartTag, EndTag, isTokenRange);

if (Cache) {
Cache->MacroHighlights[FID].push_back(
{B, E, StartTag, EndTag, isTokenRange});
}
};

HighlightMacrosImpl(R, FID, PP, HighlightRangeCallback);
}
20 changes: 10 additions & 10 deletions clang/lib/Sema/SemaConcept.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -661,11 +661,12 @@ Sema::SetupConstraintCheckingTemplateArgumentsAndScope(
// Collect the list of template arguments relative to the 'primary' template.
// We need the entire list, since the constraint is completely uninstantiated
// at this point.
MLTAL = getTemplateInstantiationArgs(FD, FD->getLexicalDeclContext(),
/*Final=*/false, /*Innermost=*/nullptr,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true);
MLTAL =
getTemplateInstantiationArgs(FD, FD->getLexicalDeclContext(),
/*Final=*/false, /*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true);
if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope))
return std::nullopt;

Expand Down Expand Up @@ -740,7 +741,8 @@ static unsigned
CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND,
bool SkipForSpecialization = false) {
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
ND, ND->getLexicalDeclContext(), /*Final=*/false, /*Innermost=*/nullptr,
ND, ND->getLexicalDeclContext(), /*Final=*/false,
/*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true, SkipForSpecialization);
Expand Down Expand Up @@ -780,7 +782,7 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
const Expr *ConstrExpr) {
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
DeclInfo.getDecl(), DeclInfo.getLexicalDeclContext(), /*Final=*/false,
/*Innermost=*/nullptr,
/*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true,
/*SkipForSpecialization*/ false);
Expand Down Expand Up @@ -1279,11 +1281,9 @@ substituteParameterMappings(Sema &S, NormalizedConstraint &N,

static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
const ConceptSpecializationExpr *CSE) {
TemplateArgumentList TAL{TemplateArgumentList::OnStack,
CSE->getTemplateArguments()};
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
CSE->getNamedConcept(), CSE->getNamedConcept()->getLexicalDeclContext(),
/*Final=*/false, &TAL,
/*Final=*/false, CSE->getTemplateArguments(),
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true);
Expand Down
45 changes: 0 additions & 45 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,51 +127,6 @@ class TypeNameValidatorCCC final : public CorrectionCandidateCallback {

} // end anonymous namespace

/// Determine whether the token kind starts a simple-type-specifier.
bool Sema::isSimpleTypeSpecifier(const Token &Tok) const {
switch (Tok.getKind()) {
case tok::annot_typename:
case tok::annot_decltype:
case tok::annot_pack_indexing_type:
return true;

case tok::kw_short:
case tok::kw_long:
case tok::kw___int64:
case tok::kw___int128:
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw_void:
case tok::kw_char:
case tok::kw_int:
case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
case tok::kw___bf16:
case tok::kw__Float16:
case tok::kw___float128:
case tok::kw___ibm128:
case tok::kw_wchar_t:
case tok::kw_bool:
case tok::kw__Bool:
case tok::kw__Accum:
case tok::kw__Fract:
case tok::kw__Sat:
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
#include "clang/Basic/TransformTypeTraits.def"
case tok::kw___auto_type:
case tok::kw_char16_t:
case tok::kw_char32_t:
case tok::kw_typeof:
case tok::kw_decltype:
case tok::kw_char8_t:
return Tok.getIdentifierInfo()->isKeyword(getLangOpts());

default:
return false;
}
}

namespace {
enum class UnqualifiedTypeNameLookupResult {
NotFound,
Expand Down
18 changes: 8 additions & 10 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19528,16 +19528,6 @@ static bool captureInLambda(LambdaScopeInfo *LSI, ValueDecl *Var,
ByRef = (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByref);
}

BindingDecl *BD = dyn_cast<BindingDecl>(Var);
// FIXME: We should support capturing structured bindings in OpenMP.
if (!Invalid && BD && S.LangOpts.OpenMP) {
if (BuildAndDiagnose) {
S.Diag(Loc, diag::err_capture_binding_openmp) << Var;
S.Diag(Var->getLocation(), diag::note_entity_declared_at) << Var;
}
Invalid = true;
}

if (BuildAndDiagnose && S.Context.getTargetInfo().getTriple().isWasm() &&
CaptureType.getNonReferenceType().isWebAssemblyReferenceType()) {
S.Diag(Loc, diag::err_wasm_ca_reference) << 0;
Expand Down Expand Up @@ -19879,6 +19869,14 @@ bool Sema::tryCaptureVariable(
// just break here. Similarly, global variables that are captured in a
// target region should not be captured outside the scope of the region.
if (RSI->CapRegionKind == CR_OpenMP) {
// FIXME: We should support capturing structured bindings in OpenMP.
if (isa<BindingDecl>(Var)) {
if (BuildAndDiagnose) {
Diag(ExprLoc, diag::err_capture_binding_openmp) << Var;
Diag(Var->getLocation(), diag::note_entity_declared_at) << Var;
}
return true;
}
OpenMPClauseKind IsOpenMPPrivateDecl = isOpenMPPrivateDecl(
Var, RSI->OpenMPLevel, RSI->OpenMPCaptureLevel);
// If the variable is private (i.e. not captured) and has variably
Expand Down
4 changes: 1 addition & 3 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9113,9 +9113,7 @@ Sema::BuildExprRequirement(

auto *Param = cast<TemplateTypeParmDecl>(TPL->getParam(0));

TemplateArgumentList TAL(TemplateArgumentList::OnStack, Args);
MultiLevelTemplateArgumentList MLTAL(Param, TAL.asArray(),
/*Final=*/false);
MultiLevelTemplateArgumentList MLTAL(Param, Args, /*Final=*/false);
MLTAL.addOuterRetainedLevels(TPL->getDepth());
const TypeConstraint *TC = Param->getTypeConstraint();
assert(TC && "Type Constraint cannot be null here");
Expand Down
33 changes: 32 additions & 1 deletion clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12708,9 +12708,11 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
}
break;
}
case OMPC_weak:
case OMPC_fail: {
if (!EncounteredAtomicKinds.contains(OMPC_compare)) {
Diag(C->getBeginLoc(), diag::err_omp_atomic_fail_no_compare)
Diag(C->getBeginLoc(), diag::err_omp_atomic_no_compare)
<< getOpenMPClauseName(C->getClauseKind())
<< SourceRange(C->getBeginLoc(), C->getEndLoc());
return StmtError();
}
Expand Down Expand Up @@ -13202,6 +13204,27 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
E = Checker.getE();
D = Checker.getD();
CE = Checker.getCond();
// The weak clause may only appear if the resulting atomic operation is
// an atomic conditional update for which the comparison tests for
// equality. It was not possible to do this check in
// OpenMPAtomicCompareChecker::checkStmt() as the check for OMPC_weak
// could not be performed (Clauses are not available).
auto *It = find_if(Clauses, [](OMPClause *C) {
return C->getClauseKind() == llvm::omp::Clause::OMPC_weak;
});
if (It != Clauses.end()) {
auto *Cond = dyn_cast<BinaryOperator>(CE);
if (Cond->getOpcode() != BO_EQ) {
ErrorInfo.Error = Checker.ErrorTy::NotAnAssignment;
ErrorInfo.ErrorLoc = Cond->getExprLoc();
ErrorInfo.NoteLoc = Cond->getOperatorLoc();
ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Cond->getSourceRange();

Diag(ErrorInfo.ErrorLoc, diag::err_omp_atomic_weak_no_equality)
<< ErrorInfo.ErrorRange;
return StmtError();
}
}
// We reuse IsXLHSInRHSPart to tell if it is in the form 'x ordop expr'.
IsXLHSInRHSPart = Checker.isXBinopExpr();
}
Expand Down Expand Up @@ -17593,6 +17616,9 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_relaxed:
Res = ActOnOpenMPRelaxedClause(StartLoc, EndLoc);
break;
case OMPC_weak:
Res = ActOnOpenMPWeakClause(StartLoc, EndLoc);
break;
case OMPC_threads:
Res = ActOnOpenMPThreadsClause(StartLoc, EndLoc);
break;
Expand Down Expand Up @@ -17781,6 +17807,11 @@ OMPClause *Sema::ActOnOpenMPRelaxedClause(SourceLocation StartLoc,
return new (Context) OMPRelaxedClause(StartLoc, EndLoc);
}

OMPClause *Sema::ActOnOpenMPWeakClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return new (Context) OMPWeakClause(StartLoc, EndLoc);
}

OMPClause *Sema::ActOnOpenMPThreadsClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return new (Context) OMPThreadsClause(StartLoc, EndLoc);
Expand Down
64 changes: 32 additions & 32 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4843,9 +4843,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
// the set of specializations, based on the closest partial specialization
// that it represents. That is,
VarDecl *InstantiationPattern = Template->getTemplatedDecl();
TemplateArgumentList TemplateArgList(TemplateArgumentList::OnStack,
CanonicalConverted);
TemplateArgumentList *InstantiationArgs = &TemplateArgList;
const TemplateArgumentList *PartialSpecArgs = nullptr;
bool AmbiguousPartialSpec = false;
typedef PartialSpecMatchResult MatchResult;
SmallVector<MatchResult, 4> Matched;
Expand All @@ -4866,7 +4864,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
TemplateDeductionInfo Info(FailedCandidates.getLocation());

if (TemplateDeductionResult Result =
DeduceTemplateArguments(Partial, TemplateArgList, Info)) {
DeduceTemplateArguments(Partial, CanonicalConverted, Info)) {
// Store the failed-deduction information for use in diagnostics, later.
// TODO: Actually use the failed-deduction info?
FailedCandidates.addCandidate().set(
Expand Down Expand Up @@ -4919,7 +4917,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,

// Instantiate using the best variable template partial specialization.
InstantiationPattern = Best->Partial;
InstantiationArgs = Best->Args;
PartialSpecArgs = Best->Args;
} else {
// -- If no match is found, the instantiation is generated
// from the primary template.
Expand All @@ -4931,7 +4929,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
// in DoMarkVarDeclReferenced().
// FIXME: LateAttrs et al.?
VarTemplateSpecializationDecl *Decl = BuildVarTemplateInstantiation(
Template, InstantiationPattern, *InstantiationArgs, TemplateArgs,
Template, InstantiationPattern, PartialSpecArgs, TemplateArgs,
CanonicalConverted, TemplateNameLoc /*, LateAttrs, StartingScope*/);
if (!Decl)
return true;
Expand All @@ -4952,7 +4950,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,

if (VarTemplatePartialSpecializationDecl *D =
dyn_cast<VarTemplatePartialSpecializationDecl>(InstantiationPattern))
Decl->setInstantiationOf(D, InstantiationArgs);
Decl->setInstantiationOf(D, PartialSpecArgs);

checkSpecializationReachability(TemplateNameLoc, Decl);

Expand Down Expand Up @@ -6257,8 +6255,6 @@ bool Sema::CheckTemplateArgumentList(
TemplateArgs = std::move(NewArgs);

if (!PartialTemplateArgs) {
TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack,
CanonicalConverted);
// Setup the context/ThisScope for the case where we are needing to
// re-instantiate constraints outside of normal instantiation.
DeclContext *NewContext = Template->getDeclContext();
Expand All @@ -6278,7 +6274,7 @@ bool Sema::CheckTemplateArgumentList(
CXXThisScopeRAII(*this, RD, ThisQuals, RD != nullptr);

MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
Template, NewContext, /*Final=*/false, &StackTemplateArgs,
Template, NewContext, /*Final=*/false, CanonicalConverted,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConceptInstantiation=*/true);
Expand Down Expand Up @@ -7417,9 +7413,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (ArgResult.isInvalid())
return ExprError();

// Prior to C++20, enforce restrictions on possible template argument
// values.
if (!getLangOpts().CPlusPlus20 && Value.isLValue()) {
if (Value.isLValue()) {
APValue::LValueBase Base = Value.getLValueBase();
auto *VD = const_cast<ValueDecl *>(Base.dyn_cast<const ValueDecl *>());
// For a non-type template-parameter of pointer or reference type,
// the value of the constant expression shall not refer to
assert(ParamType->isPointerType() || ParamType->isReferenceType() ||
Expand All @@ -7428,33 +7424,37 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// -- a string literal
// -- the result of a typeid expression, or
// -- a predefined __func__ variable
APValue::LValueBase Base = Value.getLValueBase();
auto *VD = const_cast<ValueDecl *>(Base.dyn_cast<const ValueDecl *>());
if (Base &&
(!VD ||
isa<LifetimeExtendedTemporaryDecl, UnnamedGlobalConstantDecl>(VD))) {
Diag(Arg->getBeginLoc(), diag::err_template_arg_not_decl_ref)
<< Arg->getSourceRange();
return ExprError();
}
// -- a subobject [until C++20]
if (Value.hasLValuePath() && Value.getLValuePath().size() == 1 &&
VD && VD->getType()->isArrayType() &&

if (Value.hasLValuePath() && Value.getLValuePath().size() == 1 && VD &&
VD->getType()->isArrayType() &&
Value.getLValuePath()[0].getAsArrayIndex() == 0 &&
!Value.isLValueOnePastTheEnd() && ParamType->isPointerType()) {
// Per defect report (no number yet):
// ... other than a pointer to the first element of a complete array
// object.
} else if (!Value.hasLValuePath() || Value.getLValuePath().size() ||
Value.isLValueOnePastTheEnd()) {
Diag(StartLoc, diag::err_non_type_template_arg_subobject)
<< Value.getAsString(Context, ParamType);
return ExprError();
SugaredConverted = TemplateArgument(VD, ParamType);
CanonicalConverted = TemplateArgument(
cast<ValueDecl>(VD->getCanonicalDecl()), CanonParamType);
return ArgResult.get();
}

// -- a subobject [until C++20]
if (!getLangOpts().CPlusPlus20) {
if (!Value.hasLValuePath() || Value.getLValuePath().size() ||
Value.isLValueOnePastTheEnd()) {
Diag(StartLoc, diag::err_non_type_template_arg_subobject)
<< Value.getAsString(Context, ParamType);
return ExprError();
}
assert((VD || !ParamType->isReferenceType()) &&
"null reference should not be a constant expression");
assert((!VD || !ParamType->isNullPtrType()) &&
"non-null value of type nullptr_t?");
}
assert((VD || !ParamType->isReferenceType()) &&
"null reference should not be a constant expression");
assert((!VD || !ParamType->isNullPtrType()) &&
"non-null value of type nullptr_t?");
}

if (Value.isAddrLabelDiff())
Expand Down Expand Up @@ -9778,8 +9778,8 @@ bool Sema::CheckFunctionTemplateSpecialization(
// specialization, with the template arguments from the previous
// specialization.
// Take copies of (semantic and syntactic) template argument lists.
const TemplateArgumentList* TemplArgs = new (Context)
TemplateArgumentList(Specialization->getTemplateSpecializationArgs());
const TemplateArgumentList *TemplArgs = TemplateArgumentList::CreateCopy(
Context, Specialization->getTemplateSpecializationArgs()->asArray());
FD->setFunctionTemplateSpecialization(
Specialization->getPrimaryTemplate(), TemplArgs, /*InsertPos=*/nullptr,
SpecInfo->getTemplateSpecializationKind(),
Expand Down
70 changes: 29 additions & 41 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2514,17 +2514,6 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
return Sema::TDK_Success;
}

static Sema::TemplateDeductionResult
DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
const TemplateArgumentList &ParamList,
const TemplateArgumentList &ArgList,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
return DeduceTemplateArguments(S, TemplateParams, ParamList.asArray(),
ArgList.asArray(), Info, Deduced,
/*NumberOfArgumentsMustMatch=*/false);
}

/// Determine whether two template arguments are the same.
static bool isSameTemplateArg(ASTContext &Context,
TemplateArgument X,
Expand Down Expand Up @@ -2945,21 +2934,22 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template,
llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
Template->getAssociatedConstraints(AssociatedConstraints);

bool NeedsReplacement = DeducedArgsNeedReplacement(Template);
TemplateArgumentList DeducedTAL{TemplateArgumentList::OnStack,
CanonicalDeducedArgs};
std::optional<ArrayRef<TemplateArgument>> Innermost;
// If we don't need to replace the deduced template arguments,
// we can add them immediately as the inner-most argument list.
if (!DeducedArgsNeedReplacement(Template))
Innermost = CanonicalDeducedArgs;

MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
Template, Template->getDeclContext(), /*Final=*/false,
/*InnerMost=*/NeedsReplacement ? nullptr : &DeducedTAL,
Template, Template->getDeclContext(), /*Final=*/false, Innermost,
/*RelativeToPrimary=*/true, /*Pattern=*/
nullptr, /*ForConstraintInstantiation=*/true);

// getTemplateInstantiationArgs picks up the non-deduced version of the
// template args when this is a variable template partial specialization and
// not class-scope explicit specialization, so replace with Deduced Args
// instead of adding to inner-most.
if (NeedsReplacement)
if (!Innermost)
MLTAL.replaceInnermostTemplateArguments(Template, CanonicalDeducedArgs);

if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
Expand All @@ -2980,7 +2970,7 @@ static std::enable_if_t<IsPartialSpecialization<T>::value,
Sema::TemplateDeductionResult>
FinishTemplateArgumentDeduction(
Sema &S, T *Partial, bool IsPartialOrdering,
const TemplateArgumentList &TemplateArgs,
ArrayRef<TemplateArgument> TemplateArgs,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
TemplateDeductionInfo &Info) {
// Unevaluated SFINAE context.
Expand Down Expand Up @@ -3073,7 +3063,7 @@ FinishTemplateArgumentDeduction(
// FIXME: Factor out duplication with partial specialization version above.
static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
Sema &S, TemplateDecl *Template, bool PartialOrdering,
const TemplateArgumentList &TemplateArgs,
ArrayRef<TemplateArgument> TemplateArgs,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
TemplateDeductionInfo &Info) {
// Unevaluated SFINAE context.
Expand Down Expand Up @@ -3122,7 +3112,7 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
/// partial specialization per C++ [temp.class.spec.match].
Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
const TemplateArgumentList &TemplateArgs,
ArrayRef<TemplateArgument> TemplateArgs,
TemplateDeductionInfo &Info) {
if (Partial->isInvalidDecl())
return TDK_Invalid;
Expand All @@ -3144,11 +3134,10 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,

SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(Partial->getTemplateParameters()->size());
if (TemplateDeductionResult Result
= ::DeduceTemplateArguments(*this,
Partial->getTemplateParameters(),
Partial->getTemplateArgs(),
TemplateArgs, Info, Deduced))
if (TemplateDeductionResult Result = ::DeduceTemplateArguments(
*this, Partial->getTemplateParameters(),
Partial->getTemplateArgs().asArray(), TemplateArgs, Info, Deduced,
/*NumberOfArgumentsMustMatch=*/false))
return Result;

SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
Expand All @@ -3174,7 +3163,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
/// partial specialization per C++ [temp.class.spec.match].
Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial,
const TemplateArgumentList &TemplateArgs,
ArrayRef<TemplateArgument> TemplateArgs,
TemplateDeductionInfo &Info) {
if (Partial->isInvalidDecl())
return TDK_Invalid;
Expand All @@ -3197,8 +3186,9 @@ Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial,
SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(Partial->getTemplateParameters()->size());
if (TemplateDeductionResult Result = ::DeduceTemplateArguments(
*this, Partial->getTemplateParameters(), Partial->getTemplateArgs(),
TemplateArgs, Info, Deduced))
*this, Partial->getTemplateParameters(),
Partial->getTemplateArgs().asArray(), TemplateArgs, Info, Deduced,
/*NumberOfArgumentsMustMatch=*/false))
return Result;

SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
Expand Down Expand Up @@ -3427,15 +3417,15 @@ Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments(
// specification.
SmallVector<QualType, 4> ExceptionStorage;
if (getLangOpts().CPlusPlus17 &&
SubstExceptionSpec(Function->getLocation(), EPI.ExceptionSpec,
ExceptionStorage,
getTemplateInstantiationArgs(
FunctionTemplate, nullptr, /*Final=*/true,
/*Innermost=*/SugaredExplicitArgumentList,
/*RelativeToPrimary=*/false,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/false,
/*SkipForSpecialization=*/true)))
SubstExceptionSpec(
Function->getLocation(), EPI.ExceptionSpec, ExceptionStorage,
getTemplateInstantiationArgs(
FunctionTemplate, nullptr, /*Final=*/true,
/*Innermost=*/SugaredExplicitArgumentList->asArray(),
/*RelativeToPrimary=*/false,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/false,
/*SkipForSpecialization=*/true)))
return TDK_SubstitutionFailure;

*FunctionType = BuildFunctionType(ResultType, ParamTypes,
Expand Down Expand Up @@ -5802,10 +5792,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2,
bool AtLeastAsSpecialized;
S.runWithSufficientStackSpace(Info.getLocation(), [&] {
AtLeastAsSpecialized = !FinishTemplateArgumentDeduction(
S, P2, /*IsPartialOrdering=*/true,
TemplateArgumentList(TemplateArgumentList::OnStack,
TST1->template_arguments()),
Deduced, Info);
S, P2, /*IsPartialOrdering=*/true, TST1->template_arguments(), Deduced,
Info);
});
return AtLeastAsSpecialized;
}
Expand Down
24 changes: 8 additions & 16 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ Response HandleGenericDeclContext(const Decl *CurDecl) {

MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
const NamedDecl *ND, const DeclContext *DC, bool Final,
const TemplateArgumentList *Innermost, bool RelativeToPrimary,
std::optional<ArrayRef<TemplateArgument>> Innermost, bool RelativeToPrimary,
const FunctionDecl *Pattern, bool ForConstraintInstantiation,
bool SkipForSpecialization) {
assert((ND || DC) && "Can't find arguments for a decl if one isn't provided");
Expand All @@ -352,8 +352,8 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
CurDecl = Decl::castFromDeclContext(DC);

if (Innermost) {
Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND),
Innermost->asArray(), Final);
Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND), *Innermost,
Final);
// Populate placeholder template arguments for TemplateTemplateParmDecls.
// This is essential for the case e.g.
//
Expand Down Expand Up @@ -3049,7 +3049,6 @@ bool Sema::SubstDefaultArgument(
// default argument expression appears.
ContextRAII SavedContext(*this, FD);
std::unique_ptr<LocalInstantiationScope> LIS;
MultiLevelTemplateArgumentList NewTemplateArgs = TemplateArgs;

if (ForCallExpr) {
// When instantiating a default argument due to use in a call expression,
Expand All @@ -3062,19 +3061,11 @@ bool Sema::SubstDefaultArgument(
/*ForDefinition*/ false);
if (addInstantiatedParametersToScope(FD, PatternFD, *LIS, TemplateArgs))
return true;
if (FD->isOutOfLine()) {
TemplateArgumentList *CurrentTemplateArgumentList =
TemplateArgumentList::CreateCopy(getASTContext(),
TemplateArgs.getInnermost());
NewTemplateArgs = getTemplateInstantiationArgs(
FD, FD->getDeclContext(), /*Final=*/false,
CurrentTemplateArgumentList, /*RelativeToPrimary=*/true);
}
}

runWithSufficientStackSpace(Loc, [&] {
Result = SubstInitializer(PatternExpr, NewTemplateArgs,
/*DirectInit*/ false);
Result = SubstInitializer(PatternExpr, TemplateArgs,
/*DirectInit*/false);
});
}
if (Result.isInvalid())
Expand Down Expand Up @@ -3665,7 +3656,8 @@ bool Sema::usesPartialOrExplicitSpecialization(
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
TemplateDeductionInfo Info(Loc);
if (!DeduceTemplateArguments(PartialSpecs[I],
ClassTemplateSpec->getTemplateArgs(), Info))
ClassTemplateSpec->getTemplateArgs().asArray(),
Info))
return true;
}

Expand Down Expand Up @@ -3710,7 +3702,7 @@ getPatternForClassTemplateSpecialization(
ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I];
TemplateDeductionInfo Info(FailedCandidates.getLocation());
if (Sema::TemplateDeductionResult Result = S.DeduceTemplateArguments(
Partial, ClassTemplateSpec->getTemplateArgs(), Info)) {
Partial, ClassTemplateSpec->getTemplateArgs().asArray(), Info)) {
// Store the failed-deduction information for use in diagnostics, later.
// TODO: Actually use the failed-deduction info?
FailedCandidates.addCandidate().set(
Expand Down
27 changes: 15 additions & 12 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4656,9 +4656,10 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
//
// template<typename T>
// A<T> Foo(int a = A<T>::FooImpl());
MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
FD, FD->getLexicalDeclContext(), /*Final=*/false, nullptr,
/*RelativeToPrimary=*/true);
MultiLevelTemplateArgumentList TemplateArgs =
getTemplateInstantiationArgs(FD, FD->getLexicalDeclContext(),
/*Final=*/false, /*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true);

if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
return true;
Expand Down Expand Up @@ -4696,9 +4697,10 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
Sema::ContextRAII savedContext(*this, Decl);
LocalInstantiationScope Scope(*this);

MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
Decl, Decl->getLexicalDeclContext(), /*Final=*/false, nullptr,
/*RelativeToPrimary*/ true);
MultiLevelTemplateArgumentList TemplateArgs =
getTemplateInstantiationArgs(Decl, Decl->getLexicalDeclContext(),
/*Final=*/false, /*Innermost=*/std::nullopt,
/*RelativeToPrimary*/ true);

// FIXME: We can't use getTemplateInstantiationPattern(false) in general
// here, because for a non-defining friend declaration in a class template,
Expand Down Expand Up @@ -5140,8 +5142,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
SetDeclDefaulted(Function, PatternDecl->getLocation());
} else {
MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
Function, Function->getLexicalDeclContext(), /*Final=*/false, nullptr,
false, PatternDecl);
Function, Function->getLexicalDeclContext(), /*Final=*/false,
/*Innermost=*/std::nullopt, false, PatternDecl);

// Substitute into the qualifier; we can get a substitution failure here
// through evil use of alias templates.
Expand Down Expand Up @@ -5211,7 +5213,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,

VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
VarTemplateDecl *VarTemplate, VarDecl *FromVar,
const TemplateArgumentList &TemplateArgList,
const TemplateArgumentList *PartialSpecArgs,
const TemplateArgumentListInfo &TemplateArgsInfo,
SmallVectorImpl<TemplateArgument> &Converted,
SourceLocation PointOfInstantiation, LateInstantiatedAttrVec *LateAttrs,
Expand All @@ -5236,14 +5238,15 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
MultiLevelTemplateArgumentList MultiLevelList;
if (auto *PartialSpec =
dyn_cast<VarTemplatePartialSpecializationDecl>(FromVar)) {
assert(PartialSpecArgs);
IsMemberSpec = PartialSpec->isMemberSpecialization();
MultiLevelList.addOuterTemplateArguments(
PartialSpec, TemplateArgList.asArray(), /*Final=*/false);
PartialSpec, PartialSpecArgs->asArray(), /*Final=*/false);
} else {
assert(VarTemplate == FromVar->getDescribedVarTemplate());
IsMemberSpec = VarTemplate->isMemberSpecialization();
MultiLevelList.addOuterTemplateArguments(
VarTemplate, TemplateArgList.asArray(), /*Final=*/false);
MultiLevelList.addOuterTemplateArguments(VarTemplate, Converted,
/*Final=*/false);
}
if (!IsMemberSpec)
FromVar = FromVar->getFirstDecl();
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -10075,6 +10075,12 @@ TreeTransform<Derived>::TransformOMPRelaxedClause(OMPRelaxedClause *C) {
return C;
}

template <typename Derived>
OMPClause *TreeTransform<Derived>::TransformOMPWeakClause(OMPWeakClause *C) {
// No need to rebuild this clause, no template-dependent parameters.
return C;
}

template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPThreadsClause(OMPThreadsClause *C) {
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9759,7 +9759,7 @@ void ASTReader::finishPendingActions() {
!NonConstDefn->isLateTemplateParsed() &&
// We only perform ODR checks for decls not in the explicit
// global module fragment.
!isFromExplicitGMF(FD) &&
!shouldSkipCheckingODR(FD) &&
FD->getODRHash() != NonConstDefn->getODRHash()) {
if (!isa<CXXMethodDecl>(FD)) {
PendingFunctionOdrMergeFailures[FD].push_back(NonConstDefn);
Expand Down Expand Up @@ -10349,6 +10349,9 @@ OMPClause *OMPClauseReader::readClause() {
case llvm::omp::OMPC_relaxed:
C = new (Context) OMPRelaxedClause();
break;
case llvm::omp::OMPC_weak:
C = new (Context) OMPWeakClause();
break;
case llvm::omp::OMPC_threads:
C = new (Context) OMPThreadsClause();
break;
Expand Down Expand Up @@ -10747,6 +10750,8 @@ void OMPClauseReader::VisitOMPReleaseClause(OMPReleaseClause *) {}

void OMPClauseReader::VisitOMPRelaxedClause(OMPRelaxedClause *) {}

void OMPClauseReader::VisitOMPWeakClause(OMPWeakClause *) {}

void OMPClauseReader::VisitOMPThreadsClause(OMPThreadsClause *) {}

void OMPClauseReader::VisitOMPSIMDClause(OMPSIMDClause *) {}
Expand Down
Loading