9 changes: 5 additions & 4 deletions clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,9 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,

if (Args.hasArg(options::OPT_fopenmp_force_usm))
CmdArgs.push_back("-fopenmp-force-usm");
// TODO: OpenMP support isn't "done" yet, so for now we warn that it
// is experimental.
D.Diag(diag::warn_openmp_experimental);

// FIXME: Clang supports a whole bunch more flags here.
break;
Expand Down Expand Up @@ -881,14 +884,12 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,

CmdArgs.push_back(Input.getFilename());

// TODO: Replace flang-new with flang once the new driver replaces the
// throwaway driver
const char *Exec = Args.MakeArgString(D.GetProgramPath("flang-new", TC));
const char *Exec = Args.MakeArgString(D.GetProgramPath("flang", TC));
C.addCommand(std::make_unique<Command>(JA, *this,
ResponseFileSupport::AtFileUTF8(),
Exec, CmdArgs, Inputs, Output));
}

Flang::Flang(const ToolChain &TC) : Tool("flang-new", "flang frontend", TC) {}
Flang::Flang(const ToolChain &TC) : Tool("flang", "flang frontend", TC) {}

Flang::~Flang() {}
103 changes: 55 additions & 48 deletions clang/lib/Headers/emmintrin.h

Large diffs are not rendered by default.

61 changes: 61 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,36 @@ uint64_t3 countbits(uint64_t3);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_popcount)
uint64_t4 countbits(uint64_t4);

//===----------------------------------------------------------------------===//
// degrees builtins
//===----------------------------------------------------------------------===//

/// \fn T degrees(T x)
/// \brief Converts the specified value from radians to degrees.
/// \param x The specified input value.

_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
half degrees(half);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
half2 degrees(half2);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
half3 degrees(half3);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
half4 degrees(half4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
float degrees(float);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
float2 degrees(float2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
float3 degrees(float3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
float4 degrees(float4);

//===----------------------------------------------------------------------===//
// dot product builtins
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -2088,6 +2118,19 @@ int3 sign(int16_t3);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int4 sign(int16_t4);

_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int sign(uint16_t);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int2 sign(uint16_t2);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int3 sign(uint16_t3);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int4 sign(uint16_t4);
#endif

_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
Expand All @@ -2112,6 +2155,15 @@ int3 sign(int3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int4 sign(int4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int sign(uint);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int2 sign(uint2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int3 sign(uint3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int4 sign(uint4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int sign(float);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
Expand All @@ -2130,6 +2182,15 @@ int3 sign(int64_t3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int4 sign(int64_t4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int sign(uint64_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int2 sign(uint64_t2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int3 sign(uint64_t3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int4 sign(uint64_t4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
int sign(double);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign)
Expand Down
15 changes: 6 additions & 9 deletions clang/lib/Headers/xmmintrin.h
Original file line number Diff line number Diff line change
Expand Up @@ -1618,9 +1618,8 @@ _mm_cvtt_ps2pi(__m128 __a)
/// \returns A 128-bit vector of [4 x float] whose lower 32 bits contain the
/// converted value of the second operand. The upper 96 bits are copied from
/// the upper 96 bits of the first operand.
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_cvtsi32_ss(__m128 __a, int __b)
{
static __inline__ __m128 __DEFAULT_FN_ATTRS_CONSTEXPR _mm_cvtsi32_ss(__m128 __a,
int __b) {
__a[0] = __b;
return __a;
}
Expand All @@ -1641,9 +1640,8 @@ _mm_cvtsi32_ss(__m128 __a, int __b)
/// \returns A 128-bit vector of [4 x float] whose lower 32 bits contain the
/// converted value of the second operand. The upper 96 bits are copied from
/// the upper 96 bits of the first operand.
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_cvt_si2ss(__m128 __a, int __b)
{
static __inline__ __m128 __DEFAULT_FN_ATTRS_CONSTEXPR _mm_cvt_si2ss(__m128 __a,
int __b) {
return _mm_cvtsi32_ss(__a, __b);
}

Expand All @@ -1665,9 +1663,8 @@ _mm_cvt_si2ss(__m128 __a, int __b)
/// \returns A 128-bit vector of [4 x float] whose lower 32 bits contain the
/// converted value of the second operand. The upper 96 bits are copied from
/// the upper 96 bits of the first operand.
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_cvtsi64_ss(__m128 __a, long long __b)
{
static __inline__ __m128 __DEFAULT_FN_ATTRS_CONSTEXPR
_mm_cvtsi64_ss(__m128 __a, long long __b) {
__a[0] = __b;
return __a;
}
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Lex/Preprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -902,6 +902,10 @@ void Preprocessor::Lex(Token &Result) {
case tok::r_brace:
StdCXXImportSeqState.handleCloseBrace();
break;
#define PRAGMA_ANNOTATION(X) case tok::annot_##X:
// For `#pragma ...` mimic ';'.
#include "clang/Basic/TokenKinds.def"
#undef PRAGMA_ANNOTATION
// This token is injected to represent the translation of '#include "a.h"'
// into "import a.h;". Mimic the notional ';'.
case tok::annot_module_include:
Expand Down
50 changes: 35 additions & 15 deletions clang/lib/Parse/ParseOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -797,23 +797,26 @@ bool Parser::ParseOpenACCSizeExprList(
/// [num:]int-expr
/// dim:int-expr
/// static:size-expr
bool Parser::ParseOpenACCGangArg(SourceLocation GangLoc) {
Parser::OpenACCGangArgRes Parser::ParseOpenACCGangArg(SourceLocation GangLoc) {

if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Static, getCurToken()) &&
NextToken().is(tok::colon)) {
// 'static' just takes a size-expr, which is an int-expr or an asterisk.
ConsumeToken();
ConsumeToken();
return ParseOpenACCSizeExpr(OpenACCClauseKind::Gang).isInvalid();
ExprResult Res = ParseOpenACCSizeExpr(OpenACCClauseKind::Gang);
return {OpenACCGangKind::Static, Res};
}

if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Dim, getCurToken()) &&
NextToken().is(tok::colon)) {
ConsumeToken();
ConsumeToken();
return ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,
OpenACCClauseKind::Gang, GangLoc)
.first.isInvalid();
// Parse this as a const-expression, and we'll check its integer-ness/value
// in CheckGangExpr.
ExprResult Res =
getActions().CorrectDelayedTyposInExpr(ParseConstantExpression());
return {OpenACCGangKind::Dim, Res};
}

if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Num, getCurToken()) &&
Expand All @@ -822,27 +825,40 @@ bool Parser::ParseOpenACCGangArg(SourceLocation GangLoc) {
ConsumeToken();
// Fallthrough to the 'int-expr' handling for when 'num' is omitted.
}

// This is just the 'num' case where 'num' is optional.
return ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,
OpenACCClauseKind::Gang, GangLoc)
.first.isInvalid();
ExprResult Res = ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,
OpenACCClauseKind::Gang, GangLoc)
.first;
return {OpenACCGangKind::Num, Res};
}

bool Parser::ParseOpenACCGangArgList(SourceLocation GangLoc) {
if (ParseOpenACCGangArg(GangLoc)) {
bool Parser::ParseOpenACCGangArgList(
SourceLocation GangLoc, llvm::SmallVectorImpl<OpenACCGangKind> &GKs,
llvm::SmallVectorImpl<Expr *> &IntExprs) {

Parser::OpenACCGangArgRes Res = ParseOpenACCGangArg(GangLoc);
if (!Res.second.isUsable()) {
SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
Parser::StopBeforeMatch);
return false;
return true;
}

GKs.push_back(Res.first);
IntExprs.push_back(Res.second.get());

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

if (ParseOpenACCGangArg(GangLoc)) {
Res = ParseOpenACCGangArg(GangLoc);
if (!Res.second.isUsable()) {
SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
Parser::StopBeforeMatch);
return false;
return true;
}

GKs.push_back(Res.first);
IntExprs.push_back(Res.second.get());
}
return false;
}
Expand Down Expand Up @@ -1129,12 +1145,16 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
}
break;
}
case OpenACCClauseKind::Gang:
if (ParseOpenACCGangArgList(ClauseLoc)) {
case OpenACCClauseKind::Gang: {
llvm::SmallVector<OpenACCGangKind> GKs;
llvm::SmallVector<Expr *> IntExprs;
if (ParseOpenACCGangArgList(ClauseLoc, GKs, IntExprs)) {
Parens.skipToEnd();
return OpenACCCanContinue();
}
ParsedClause.setGangDetails(std::move(GKs), std::move(IntExprs));
break;
}
case OpenACCClauseKind::Wait: {
OpenACCWaitParseInfo Info =
ParseOpenACCWaitArgument(ClauseLoc,
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Parse/ParseTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,13 +331,17 @@ Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,
if (!TryConsumeToken(tok::equal)) {
Diag(Tok.getLocation(), diag::err_expected) << tok::equal;
SkipUntil(tok::semi);
if (D)
D->setInvalidDecl();
return nullptr;
}

ExprResult ConstraintExprResult =
Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression());
if (ConstraintExprResult.isInvalid()) {
SkipUntil(tok::semi);
if (D)
D->setInvalidDecl();
return nullptr;
}

Expand Down
37 changes: 33 additions & 4 deletions clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2385,18 +2385,19 @@ FunctionScopeInfo *Sema::getEnclosingFunction() const {
return nullptr;
}

LambdaScopeInfo *Sema::getEnclosingLambda() const {
CapturingScopeInfo *Sema::getEnclosingLambdaOrBlock() const {
for (auto *Scope : llvm::reverse(FunctionScopes)) {
if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Scope)) {
if (LSI->Lambda && !LSI->Lambda->Encloses(CurContext) &&
if (auto *CSI = dyn_cast<CapturingScopeInfo>(Scope)) {
auto *LSI = dyn_cast<LambdaScopeInfo>(CSI);
if (LSI && LSI->Lambda && !LSI->Lambda->Encloses(CurContext) &&
LSI->AfterParameterList) {
// We have switched contexts due to template instantiation.
// FIXME: We should swap out the FunctionScopes during code synthesis
// so that we don't need to check for this.
assert(!CodeSynthesisContexts.empty());
return nullptr;
}
return LSI;
return CSI;
}
}
return nullptr;
Expand Down Expand Up @@ -2777,3 +2778,31 @@ bool Sema::isDeclaratorFunctionLike(Declarator &D) {
});
return Result;
}

Attr *Sema::CreateAnnotationAttr(const AttributeCommonInfo &CI, StringRef Annot,
MutableArrayRef<Expr *> Args) {

auto *A = AnnotateAttr::Create(Context, Annot, Args.data(), Args.size(), CI);
if (!ConstantFoldAttrArgs(
CI, MutableArrayRef<Expr *>(A->args_begin(), A->args_end()))) {
return nullptr;
}
return A;
}

Attr *Sema::CreateAnnotationAttr(const ParsedAttr &AL) {
// Make sure that there is a string literal as the annotation's first
// argument.
StringRef Str;
if (!checkStringLiteralArgumentAttr(AL, 0, Str))
return nullptr;

llvm::SmallVector<Expr *, 4> Args;
Args.reserve(AL.getNumArgs() - 1);
for (unsigned Idx = 1; Idx < AL.getNumArgs(); Idx++) {
assert(!AL.isArgIdent(Idx));
Args.push_back(AL.getArgAsExpr(Idx));
}

return CreateAnnotationAttr(AL, Str, Args);
}
29 changes: 12 additions & 17 deletions clang/lib/Sema/SemaConcept.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,8 +585,8 @@ static bool CheckConstraintSatisfaction(

ArrayRef<TemplateArgument> TemplateArgs =
TemplateArgsLists.getNumSubstitutedLevels() > 0
? TemplateArgsLists.getOutermost()
: ArrayRef<TemplateArgument> {};
? TemplateArgsLists.getInnermost()
: ArrayRef<TemplateArgument>{};
Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
Sema::InstantiatingTemplate::ConstraintsCheck{},
const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange);
Expand Down Expand Up @@ -834,7 +834,6 @@ Sema::SetupConstraintCheckingTemplateArgumentsAndScope(
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 @@ -910,15 +909,13 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
// Figure out the to-translation-unit depth for this function declaration for
// the purpose of seeing if they differ by constraints. This isn't the same as
// getTemplateDepth, because it includes already instantiated parents.
static unsigned
CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND,
bool SkipForSpecialization = false) {
static unsigned CalculateTemplateDepthForConstraints(Sema &S,
const NamedDecl *ND) {
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
ND, ND->getLexicalDeclContext(), /*Final=*/false,
/*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true, SkipForSpecialization);
/*ForConstraintInstantiation=*/true);
return MLTAL.getNumLevels();
}

Expand Down Expand Up @@ -957,8 +954,7 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
DeclInfo.getDecl(), DeclInfo.getLexicalDeclContext(), /*Final=*/false,
/*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true,
/*SkipForSpecialization*/ false);
/*ForConstraintInstantiation=*/true);

if (MLTAL.getNumSubstitutedLevels() == 0)
return ConstrExpr;
Expand Down Expand Up @@ -1068,16 +1064,16 @@ bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old,
bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) {
assert(FD->getFriendObjectKind() && "Must be a friend!");

FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate();
// The logic for non-templates is handled in ASTContext::isSameEntity, so we
// don't have to bother checking 'DependsOnEnclosingTemplate' for a
// non-function-template.
assert(FD->getDescribedFunctionTemplate() &&
"Non-function templates don't need to be checked");
assert(FTD && "Non-function templates don't need to be checked");

SmallVector<const Expr *, 3> ACs;
FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs);
FTD->getAssociatedConstraints(ACs);

unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
unsigned OldTemplateDepth = FTD->getTemplateParameters()->getDepth();
for (const Expr *Constraint : ACs)
if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth,
Constraint))
Expand Down Expand Up @@ -1524,7 +1520,6 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
CSE->getNamedConcept(), CSE->getNamedConcept()->getLexicalDeclContext(),
/*Final=*/false, CSE->getTemplateArguments(),
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true);

return substituteParameterMappings(S, N, CSE->getNamedConcept(), MLTAL,
Expand Down Expand Up @@ -1805,8 +1800,8 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
return false;
}

unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1, true);
unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2, true);
unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1);
unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2);

for (size_t I = 0; I != AC1.size() && I != AC2.size(); ++I) {
if (Depth2 > Depth1) {
Expand Down
35 changes: 16 additions & 19 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4510,10 +4510,10 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
adjustDeclContextForDeclaratorDecl(New, Old);

// Ensure the template parameters are compatible.
if (NewTemplate &&
!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
OldTemplate->getTemplateParameters(),
/*Complain=*/true, TPL_TemplateMatch))
if (NewTemplate && !TemplateParameterListsAreEqual(
NewTemplate, NewTemplate->getTemplateParameters(),
OldTemplate, OldTemplate->getTemplateParameters(),
/*Complain=*/true, TPL_TemplateMatch))
return New->setInvalidDecl();

// C++ [class.mem]p1:
Expand Down Expand Up @@ -7663,7 +7663,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
: SourceLocation();
DeclResult Res = ActOnVarTemplateSpecialization(
S, D, TInfo, Previous, TemplateKWLoc, TemplateParams, SC,
IsPartialSpecialization);
IsPartialSpecialization, IsMemberSpecialization);
if (Res.isInvalid())
return nullptr;
NewVD = cast<VarDecl>(Res.get());
Expand All @@ -7682,6 +7682,10 @@ NamedDecl *Sema::ActOnVariableDeclarator(
VarTemplateDecl::Create(Context, DC, D.getIdentifierLoc(), Name,
TemplateParams, NewVD);
NewVD->setDescribedVarTemplate(NewTemplate);
// If we are providing an explicit specialization of a static variable
// template, make a note of that.
if (IsMemberSpecialization)
NewTemplate->setMemberSpecialization();
}

// If this decl has an auto type in need of deduction, make a note of the
Expand Down Expand Up @@ -8059,12 +8063,6 @@ NamedDecl *Sema::ActOnVariableDeclarator(
? TPC_ClassTemplateMember
: TPC_VarTemplate))
NewVD->setInvalidDecl();

// If we are providing an explicit specialization of a static variable
// template, make a note of that.
if (PrevVarTemplate &&
PrevVarTemplate->getInstantiatedFromMemberTemplate())
PrevVarTemplate->setMemberSpecialization();
}
}

Expand Down Expand Up @@ -9871,6 +9869,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD);
FunctionTemplate->setLexicalDeclContext(CurContext);
NewFD->setDescribedFunctionTemplate(FunctionTemplate);
if (isMemberSpecialization)
FunctionTemplate->setMemberSpecialization();

// For source fidelity, store the other template param lists.
if (TemplateParamLists.size() > 1) {
Expand Down Expand Up @@ -12028,10 +12028,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,

// If this is an explicit specialization of a member that is a function
// template, mark it as a member specialization.
if (IsMemberSpecialization &&
NewTemplateDecl->getInstantiatedFromMemberTemplate()) {
NewTemplateDecl->setMemberSpecialization();
assert(OldTemplateDecl->isMemberSpecialization());
if (IsMemberSpecialization) {
// Explicit specializations of a member template do not inherit deleted
// status from the parent member template that they are specializing.
if (OldFD->isDeleted()) {
Expand Down Expand Up @@ -15165,8 +15162,8 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
// we know that references to that pack must also be expanded within the
// lambda scope.
if (New->isParameterPack())
if (auto *LSI = getEnclosingLambda())
LSI->LocalPacks.push_back(New);
if (auto *CSI = getEnclosingLambdaOrBlock())
CSI->LocalPacks.push_back(New);

if (New->getType().hasNonTrivialToPrimitiveDestructCUnion() ||
New->getType().hasNonTrivialToPrimitiveCopyCUnion())
Expand Down Expand Up @@ -17093,8 +17090,8 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
DeclResult Result = CheckClassTemplate(
S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attrs, TemplateParams,
AS, ModulePrivateLoc,
/*FriendLoc*/ SourceLocation(), TemplateParameterLists.size() - 1,
TemplateParameterLists.data(), SkipBody);
/*FriendLoc*/ SourceLocation(), TemplateParameterLists.drop_back(),
isMemberSpecialization, SkipBody);
return Result.get();
} else {
// The "template<>" header is extraneous.
Expand Down
32 changes: 7 additions & 25 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1216,6 +1216,8 @@ static void handlePreferredName(Sema &S, Decl *D, const ParsedAttr &AL) {
}

bool Sema::isValidPointerAttrType(QualType T, bool RefOkay) {
if (T->isDependentType())
return true;
if (RefOkay) {
if (T->isReferenceType())
return true;
Expand Down Expand Up @@ -1284,7 +1286,7 @@ static void handleNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
for (unsigned I = 0, E = getFunctionOrMethodNumParams(D);
I != E && !AnyPointers; ++I) {
QualType T = getFunctionOrMethodParamType(D, I);
if (T->isDependentType() || S.isValidPointerAttrType(T))
if (S.isValidPointerAttrType(T))
AnyPointers = true;
}

Expand Down Expand Up @@ -1409,8 +1411,7 @@ void Sema::AddAllocAlignAttr(Decl *D, const AttributeCommonInfo &CI,
AllocAlignAttr TmpAttr(Context, CI, ParamIdx());
SourceLocation AttrLoc = CI.getLoc();

if (!ResultType->isDependentType() &&
!isValidPointerAttrType(ResultType, /* RefOkay */ true)) {
if (!isValidPointerAttrType(ResultType, /* RefOkay */ true)) {
Diag(AttrLoc, diag::warn_attribute_return_pointers_refs_only)
<< &TmpAttr << CI.getRange() << getFunctionOrMethodResultSourceRange(D);
return;
Expand Down Expand Up @@ -3957,30 +3958,11 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
RD->addAttr(::new (S.Context) TransparentUnionAttr(S.Context, AL));
}

void Sema::AddAnnotationAttr(Decl *D, const AttributeCommonInfo &CI,
StringRef Str, MutableArrayRef<Expr *> Args) {
auto *Attr = AnnotateAttr::Create(Context, Str, Args.data(), Args.size(), CI);
if (ConstantFoldAttrArgs(
CI, MutableArrayRef<Expr *>(Attr->args_begin(), Attr->args_end()))) {
D->addAttr(Attr);
}
}

static void handleAnnotateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// Make sure that there is a string literal as the annotation's first
// argument.
StringRef Str;
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
return;

llvm::SmallVector<Expr *, 4> Args;
Args.reserve(AL.getNumArgs() - 1);
for (unsigned Idx = 1; Idx < AL.getNumArgs(); Idx++) {
assert(!AL.isArgIdent(Idx));
Args.push_back(AL.getArgAsExpr(Idx));
auto *Attr = S.CreateAnnotationAttr(AL);
if (Attr) {
D->addAttr(Attr);
}

S.AddAnnotationAttr(D, AL, Str, Args);
}

static void handleAlignValueAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17416,8 +17416,8 @@ DeclResult Sema::ActOnTemplatedFriendTag(
return CheckClassTemplate(S, TagSpec, TagUseKind::Friend, TagLoc, SS,
Name, NameLoc, Attr, TemplateParams, AS_public,
/*ModulePrivateLoc=*/SourceLocation(),
FriendLoc, TempParamLists.size() - 1,
TempParamLists.data())
FriendLoc, TempParamLists.drop_back(),
IsMemberSpecialization)
.get();
} else {
// The "template<>" header is extraneous.
Expand Down
29 changes: 16 additions & 13 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2470,7 +2470,15 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
LookupCtx ? LookupCtx : (SS.isEmpty() ? CurContext : nullptr);
while (DC) {
if (isa<CXXRecordDecl>(DC)) {
LookupQualifiedName(R, DC);
if (ExplicitTemplateArgs) {
if (LookupTemplateName(
R, S, SS, Context.getRecordType(cast<CXXRecordDecl>(DC)),
/*EnteringContext*/ false, TemplateNameIsRequired,
/*RequiredTemplateKind*/ nullptr, /*AllowTypoCorrection*/ true))
return true;
} else {
LookupQualifiedName(R, DC);
}

if (!R.empty()) {
// Don't give errors about ambiguities in this lookup.
Expand Down Expand Up @@ -5641,6 +5649,8 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
runWithSufficientStackSpace(Loc, [&] {
MarkDeclarationsReferencedInExpr(E, /*SkipLocalVariables=*/false);
});
if (isInLifetimeExtendingContext())
DiscardCleanupsInEvaluationContext();
// C++11 [class.base.init]p7:
// The initialization of each base and member constitutes a
// full-expression.
Expand Down Expand Up @@ -16077,17 +16087,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,

TypeSourceInfo *Sig = GetTypeForDeclarator(ParamInfo);
QualType T = Sig->getType();

// FIXME: We should allow unexpanded parameter packs here, but that would,
// in turn, make the block expression contain unexpanded parameter packs.
if (DiagnoseUnexpandedParameterPack(CaretLoc, Sig, UPPC_Block)) {
// Drop the parameters.
FunctionProtoType::ExtProtoInfo EPI;
EPI.HasTrailingReturn = false;
EPI.TypeQuals.addConst();
T = Context.getFunctionType(Context.DependentTy, std::nullopt, EPI);
Sig = Context.getTrivialTypeSourceInfo(T);
}
DiagnoseUnexpandedParameterPack(CaretLoc, Sig, UPPC_Block);

// GetTypeForDeclarator always produces a function type for a block
// literal signature. Furthermore, it is always a FunctionProtoType
Expand Down Expand Up @@ -16359,7 +16359,8 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
PoppedFunctionScopePtr ScopeRAII = PopFunctionScopeInfo(&WP, BD, BlockTy);

BlockExpr *Result = new (Context) BlockExpr(BD, BlockTy);
BlockExpr *Result = new (Context)
BlockExpr(BD, BlockTy, BSI->ContainsUnexpandedParameterPack);

// If the block isn't obviously global, i.e. it captures anything at
// all, then we need to do a few things in the surrounding context:
Expand All @@ -16382,6 +16383,8 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
if (getCurFunction())
getCurFunction()->addBlock(BD);

// This can happen if the block's return type is deduced, but
// the return expression is invalid.
if (BD->isInvalidDecl())
return CreateRecoveryExpr(Result->getBeginLoc(), Result->getEndLoc(),
{Result}, Result->getType());
Expand Down
28 changes: 17 additions & 11 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -503,17 +503,23 @@ bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS,
const IdentifierInfo *II = Name.Identifier;
ReservedIdentifierStatus Status = II->isReserved(PP.getLangOpts());
SourceLocation Loc = Name.getEndLoc();
if (!PP.getSourceManager().isInSystemHeader(Loc)) {
if (auto Hint = FixItHint::CreateReplacement(
Name.getSourceRange(),
(StringRef("operator\"\"") + II->getName()).str());
isReservedInAllContexts(Status)) {
Diag(Loc, diag::warn_reserved_extern_symbol)
<< II << static_cast<int>(Status) << Hint;
} else {
Diag(Loc, diag::warn_deprecated_literal_operator_id) << II << Hint;
}
}

auto Hint = FixItHint::CreateReplacement(
Name.getSourceRange(),
(StringRef("operator\"\"") + II->getName()).str());

// Only emit this diagnostic if we start with an underscore, else the
// diagnostic for C++11 requiring a space between the quotes and the
// identifier conflicts with this and gets confusing. The diagnostic stating
// this is a reserved name should force the underscore, which gets this
// back.
if (II->isReservedLiteralSuffixId() !=
ReservedLiteralSuffixIdStatus::NotStartsWithUnderscore)
Diag(Loc, diag::warn_deprecated_literal_operator_id) << II << Hint;

if (isReservedInAllContexts(Status))
Diag(Loc, diag::warn_reserved_extern_symbol)
<< II << static_cast<int>(Status) << Hint;
}

if (!SS.isValid())
Expand Down
12 changes: 9 additions & 3 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1708,9 +1708,9 @@ static bool CheckNoDoubleVectors(Sema *S, CallExpr *TheCall) {
return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy,
checkDoubleVector);
}
static bool CheckFloatingOrSignedIntRepresentation(Sema *S, CallExpr *TheCall) {
static bool CheckFloatingOrIntRepresentation(Sema *S, CallExpr *TheCall) {
auto checkAllSignedTypes = [](clang::QualType PassedType) -> bool {
return !PassedType->hasSignedIntegerRepresentation() &&
return !PassedType->hasIntegerRepresentation() &&
!PassedType->hasFloatingRepresentation();
};
return CheckArgsTypesAreCorrect(S, TheCall, S->Context.IntTy,
Expand Down Expand Up @@ -1896,6 +1896,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return true;
break;
}
case Builtin::BI__builtin_hlsl_elementwise_degrees:
case Builtin::BI__builtin_hlsl_elementwise_radians:
case Builtin::BI__builtin_hlsl_elementwise_rsqrt:
case Builtin::BI__builtin_hlsl_elementwise_frac: {
Expand Down Expand Up @@ -1966,7 +1967,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
break;
}
case Builtin::BI__builtin_hlsl_elementwise_sign: {
if (CheckFloatingOrSignedIntRepresentation(&SemaRef, TheCall))
if (CheckFloatingOrIntRepresentation(&SemaRef, TheCall))
return true;
if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall))
return true;
Expand All @@ -1992,6 +1993,11 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return true;
break;
}
case Builtin::BI__builtin_hlsl_wave_get_lane_index: {
if (SemaRef.checkArgCount(TheCall, 0))
return true;
break;
}
case Builtin::BI__builtin_elementwise_acos:
case Builtin::BI__builtin_elementwise_asin:
case Builtin::BI__builtin_elementwise_atan:
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,8 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
SemaRef.currentEvaluationContext().DelayedDefaultInitializationContext =
SemaRef.parentEvaluationContext()
.DelayedDefaultInitializationContext;
SemaRef.currentEvaluationContext().InLifetimeExtendingContext =
SemaRef.parentEvaluationContext().InLifetimeExtendingContext;
DIE = SemaRef.BuildCXXDefaultInitExpr(Loc, Field);
}
if (DIE.isInvalid()) {
Expand Down Expand Up @@ -9951,7 +9953,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
auto SynthesizeAggrGuide = [&](InitListExpr *ListInit) {
auto *Pattern = Template;
while (Pattern->getInstantiatedFromMemberTemplate()) {
if (Pattern->isMemberSpecialization())
if (Pattern->hasMemberSpecialization())
break;
Pattern = Pattern->getInstantiatedFromMemberTemplate();
}
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Sema/SemaLambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2353,7 +2353,10 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
Block->setBody(new (Context) CompoundStmt(ConvLocation));

// Create the block literal expression.
Expr *BuildBlock = new (Context) BlockExpr(Block, Conv->getConversionType());
// TODO: Do we ever get here if we have unexpanded packs in the lambda???
Expr *BuildBlock =
new (Context) BlockExpr(Block, Conv->getConversionType(),
/*ContainsUnexpandedParameterPack=*/false);
ExprCleanupObjects.push_back(Block);
Cleanup.setExprNeedsCleanups(true);

Expand Down
276 changes: 252 additions & 24 deletions clang/lib/Sema/SemaOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,19 @@ bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind,
}
}

case OpenACCClauseKind::Gang: {
switch (DirectiveKind) {
case OpenACCDirectiveKind::Loop:
case OpenACCDirectiveKind::ParallelLoop:
case OpenACCDirectiveKind::SerialLoop:
case OpenACCDirectiveKind::KernelsLoop:
case OpenACCDirectiveKind::Routine:
return true;
default:
return false;
}
}

default:
// Do nothing so we can go to the 'unimplemented' diagnostic instead.
return true;
Expand Down Expand Up @@ -459,6 +472,23 @@ class SemaOpenACCClauseVisitor {
return nullptr;
}

// OpenACC 3.3 2.9:
// A 'gang', 'worker', or 'vector' clause may not appear if a 'seq' clause
// appears.
bool DiagIfSeqClause(SemaOpenACC::OpenACCParsedClause &Clause) {
const auto *Itr =
llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCSeqClause>);

if (Itr != ExistingClauses.end()) {
SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_clause_cannot_combine)
<< Clause.getClauseKind() << (*Itr)->getClauseKind();
SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);

return true;
}
return false;
}

public:
SemaOpenACCClauseVisitor(SemaOpenACC &S,
ArrayRef<const OpenACCClause *> ExistingClauses)
Expand All @@ -470,26 +500,14 @@ class SemaOpenACCClauseVisitor {

OpenACCClause *Visit(SemaOpenACC::OpenACCParsedClause &Clause) {
switch (Clause.getClauseKind()) {
case OpenACCClauseKind::Gang:
case OpenACCClauseKind::Worker:
case OpenACCClauseKind::Vector: {
// TODO OpenACC: These are only implemented enough for the 'seq' diagnostic,
// otherwise treats itself as unimplemented. When we implement these, we
// can remove them from here.

// OpenACC 3.3 2.9:
// A 'gang', 'worker', or 'vector' clause may not appear if a 'seq' clause
// appears.
const auto *Itr =
llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCSeqClause>);

if (Itr != ExistingClauses.end()) {
SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_clause_cannot_combine)
<< Clause.getClauseKind() << (*Itr)->getClauseKind();
SemaRef.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
case OpenACCClauseKind::Worker:
case OpenACCClauseKind::Vector: {
// TODO OpenACC: These are only implemented enough for the 'seq'
// diagnostic, otherwise treats itself as unimplemented. When we
// implement these, we can remove them from here.
DiagIfSeqClause(Clause);
return isNotImplemented();
}
return isNotImplemented();
}

#define VISIT_CLAUSE(CLAUSE_NAME) \
case OpenACCClauseKind::CLAUSE_NAME: \
Expand Down Expand Up @@ -1006,6 +1024,84 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitIndependentClause(
Clause.getEndLoc());
}

OpenACCClause *SemaOpenACCClauseVisitor::VisitGangClause(
SemaOpenACC::OpenACCParsedClause &Clause) {
if (DiagIfSeqClause(Clause))
return nullptr;

// Restrictions only properly implemented on 'loop' constructs, and it is
// the only construct that can do anything with this, so skip/treat as
// unimplemented for the combined constructs.
if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop)
return isNotImplemented();

llvm::SmallVector<OpenACCGangKind> GangKinds;
llvm::SmallVector<Expr *> IntExprs;

// Store the existing locations, so we can do duplicate checking. Index is
// the int-value of the OpenACCGangKind enum.
SourceLocation ExistingElemLoc[3];

for (unsigned I = 0; I < Clause.getIntExprs().size(); ++I) {
OpenACCGangKind GK = Clause.getGangKinds()[I];
ExprResult ER = SemaRef.CheckGangExpr(GK, Clause.getIntExprs()[I]);

if (!ER.isUsable())
continue;

// OpenACC 3.3 2.9.2: When the parent compute construct is a kernels
// construct, the gang clause behaves as follows. ... An argument with no
// keyword or with num keyword is only allowed when num_gangs does not
// appear on the kernels construct.
if (SemaRef.getActiveComputeConstructInfo().Kind ==
OpenACCDirectiveKind::Kernels &&
GK == OpenACCGangKind::Num) {
const auto *Itr =
llvm::find_if(SemaRef.getActiveComputeConstructInfo().Clauses,
llvm::IsaPred<OpenACCNumGangsClause>);

if (Itr != SemaRef.getActiveComputeConstructInfo().Clauses.end()) {
SemaRef.Diag(ER.get()->getBeginLoc(),
diag::err_acc_gang_num_gangs_conflict);
SemaRef.Diag((*Itr)->getBeginLoc(),
diag::note_acc_previous_clause_here);
continue;
}
}

// OpenACC 3.3 2.9: 'gang-arg-list' may have at most one num, one dim, and
// one static argument.
if (ExistingElemLoc[static_cast<unsigned>(GK)].isValid()) {
SemaRef.Diag(ER.get()->getBeginLoc(), diag::err_acc_gang_multiple_elt)
<< static_cast<unsigned>(GK);
SemaRef.Diag(ExistingElemLoc[static_cast<unsigned>(GK)],
diag::note_acc_previous_expr_here);
continue;
}

ExistingElemLoc[static_cast<unsigned>(GK)] = ER.get()->getBeginLoc();
GangKinds.push_back(GK);
IntExprs.push_back(ER.get());
}

// OpenACC 3.3 2.9.2: When the parent compute construct is a kernels
// construct, the gang clause behaves as follows. ... The region of a loop
// with a gang clause may not contain another loop with a gang clause unless
// within a nested compute region.
if (SemaRef.LoopGangClauseOnKernelLoc.isValid()) {
// This handles the 'inner loop' diagnostic, but we cannot set that we're on
// one of these until we get to the end of the construct.
SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_gang_inside_gang);
SemaRef.Diag(SemaRef.LoopGangClauseOnKernelLoc,
diag::note_acc_previous_clause_here);
return nullptr;
}

return OpenACCGangClause::Create(Ctx, Clause.getBeginLoc(),
Clause.getLParenLoc(), GangKinds, IntExprs,
Clause.getEndLoc());
}

OpenACCClause *SemaOpenACCClauseVisitor::VisitSeqClause(
SemaOpenACC::OpenACCParsedClause &Clause) {
// Restrictions only properly implemented on 'loop' constructs, and it is
Expand Down Expand Up @@ -1118,17 +1214,44 @@ SemaOpenACC::AssociatedStmtRAII::AssociatedStmtRAII(
SemaOpenACC &S, OpenACCDirectiveKind DK,
ArrayRef<const OpenACCClause *> UnInstClauses,
ArrayRef<OpenACCClause *> Clauses)
: SemaRef(S), WasInsideComputeConstruct(S.InsideComputeConstruct),
DirKind(DK), LoopRAII(SemaRef, /*PreserveDepth=*/false) {
: SemaRef(S), OldActiveComputeConstructInfo(S.ActiveComputeConstructInfo),
DirKind(DK), OldLoopGangClauseOnKernelLoc(S.LoopGangClauseOnKernelLoc),
LoopRAII(SemaRef, /*PreserveDepth=*/false) {
// Compute constructs end up taking their 'loop'.
if (DirKind == OpenACCDirectiveKind::Parallel ||
DirKind == OpenACCDirectiveKind::Serial ||
DirKind == OpenACCDirectiveKind::Kernels) {
SemaRef.InsideComputeConstruct = true;
SemaRef.ActiveComputeConstructInfo.Kind = DirKind;
SemaRef.ActiveComputeConstructInfo.Clauses = Clauses;
SemaRef.ParentlessLoopConstructs.swap(ParentlessLoopConstructs);

// OpenACC 3.3 2.9.2: When the parent compute construct is a kernels
// construct, the gang clause behaves as follows. ... The region of a loop
// with a gang clause may not contain another loop with a gang clause unless
// within a nested compute region.
//
// Implement the 'unless within a nested compute region' part.
SemaRef.LoopGangClauseOnKernelLoc = {};
} else if (DirKind == OpenACCDirectiveKind::Loop) {
SetCollapseInfoBeforeAssociatedStmt(UnInstClauses, Clauses);
SetTileInfoBeforeAssociatedStmt(UnInstClauses, Clauses);

// OpenACC 3.3 2.9.2: When the parent compute construct is a kernels
// construct, the gang clause behaves as follows. ... The region of a loop
// with a gang clause may not contain another loop with a gang clause unless
// within a nested compute region.
//
// We don't bother doing this when this is a template instantiation, as
// there is no reason to do these checks: the existance of a
// gang/kernels/etc cannot be dependent.
if (SemaRef.getActiveComputeConstructInfo().Kind ==
OpenACCDirectiveKind::Kernels &&
UnInstClauses.empty()) {
// This handles the 'outer loop' part of this.
auto *Itr = llvm::find_if(Clauses, llvm::IsaPred<OpenACCGangClause>);
if (Itr != Clauses.end())
SemaRef.LoopGangClauseOnKernelLoc = (*Itr)->getBeginLoc();
}
}
}

Expand Down Expand Up @@ -1199,7 +1322,9 @@ void SemaOpenACC::AssociatedStmtRAII::SetTileInfoBeforeAssociatedStmt(
}

SemaOpenACC::AssociatedStmtRAII::~AssociatedStmtRAII() {
SemaRef.InsideComputeConstruct = WasInsideComputeConstruct;
SemaRef.ActiveComputeConstructInfo = OldActiveComputeConstructInfo;
SemaRef.LoopGangClauseOnKernelLoc = OldLoopGangClauseOnKernelLoc;

if (DirKind == OpenACCDirectiveKind::Parallel ||
DirKind == OpenACCDirectiveKind::Serial ||
DirKind == OpenACCDirectiveKind::Kernels) {
Expand Down Expand Up @@ -1761,6 +1886,109 @@ ExprResult SemaOpenACC::CheckCollapseLoopCount(Expr *LoopCount) {
ConstantExpr::Create(getASTContext(), LoopCount, APValue{*ICE})};
}

namespace {
ExprResult CheckGangStaticExpr(SemaOpenACC &S, Expr *E) {
if (isa<OpenACCAsteriskSizeExpr>(E))
return E;
return S.ActOnIntExpr(OpenACCDirectiveKind::Invalid, OpenACCClauseKind::Gang,
E->getBeginLoc(), E);
}
} // namespace

ExprResult SemaOpenACC::CheckGangExpr(OpenACCGangKind GK, Expr *E) {
// Gang Expr legality depends on the associated compute construct.
switch (ActiveComputeConstructInfo.Kind) {
case OpenACCDirectiveKind::Invalid:
case OpenACCDirectiveKind::Parallel: {
switch (GK) {
// OpenACC 3.3 2.9.2: When the parent compute construct is a parallel
// construct, or an orphaned loop construct, the gang clause behaves as
// follows. ... The dim argument must be a constant positive integer value
// 1, 2, or 3.
case OpenACCGangKind::Dim: {
if (!E)
return ExprError();
ExprResult Res =
ActOnIntExpr(OpenACCDirectiveKind::Invalid, OpenACCClauseKind::Gang,
E->getBeginLoc(), E);

if (!Res.isUsable())
return Res;

if (Res.get()->isInstantiationDependent())
return Res;

std::optional<llvm::APSInt> ICE =
Res.get()->getIntegerConstantExpr(getASTContext());

if (!ICE || *ICE <= 0 || ICE > 3) {
Diag(Res.get()->getBeginLoc(), diag::err_acc_gang_dim_value)
<< ICE.has_value() << ICE.value_or(llvm::APSInt{}).getExtValue();
return ExprError();
}

return ExprResult{
ConstantExpr::Create(getASTContext(), Res.get(), APValue{*ICE})};
}
// OpenACC 3.3 2.9.2: When the parent compute construct is a parallel
// construct, or an orphaned loop construct, the gang clause behaves as
// follows. ... The num argument is not allowed.
case OpenACCGangKind::Num:
Diag(E->getBeginLoc(), diag::err_acc_gang_arg_invalid)
<< GK
<< (/*orphan/parallel=*/ActiveComputeConstructInfo.Kind ==
OpenACCDirectiveKind::Parallel
? 1
: 0);
return ExprError();
case OpenACCGangKind::Static:
return CheckGangStaticExpr(*this, E);
}
} break;
case OpenACCDirectiveKind::Kernels: {
switch (GK) {
// OpenACC 3.3 2.9.2: When the parent compute construct is a kernels
// construct, the gang clause behaves as follows. ... The dim argument is
// not allowed.
case OpenACCGangKind::Dim:
Diag(E->getBeginLoc(), diag::err_acc_gang_arg_invalid)
<< GK << /*kernels=*/2;
return ExprError();
// OpenACC 3.3 2.9.2: When the parent compute construct is a kernels
// construct, the gang clause behaves as follows. ... An argument with no
// keyword or with num keyword is only allowed when num_gangs does not
// appear on the kernels construct. ... The region of a loop with the gang
// clause may not contain another loop with a gang clause unless within a
// nested compute region.
case OpenACCGangKind::Num:
// This isn't allowed if there is a 'num_gangs' on the kernel construct,
// and makes loop-with-gang-clause ill-formed inside of this 'loop', but
// nothing can be enforced here.
return ExprResult{E};
case OpenACCGangKind::Static:
return CheckGangStaticExpr(*this, E);
}
} break;
case OpenACCDirectiveKind::Serial: {
switch (GK) {
// 'dim' and 'num' don't really make sense on serial, and GCC rejects them
// too, so we disallow them too.
case OpenACCGangKind::Dim:
case OpenACCGangKind::Num:
Diag(E->getBeginLoc(), diag::err_acc_gang_arg_invalid)
<< GK << /*Kernels=*/3;
return ExprError();
case OpenACCGangKind::Static:
return CheckGangStaticExpr(*this, E);
}
}
default:
llvm_unreachable("Non compute construct in active compute construct?");
}

llvm_unreachable("Compute construct directive not handled?");
}

ExprResult SemaOpenACC::CheckTileSizeExpr(Expr *SizeExpr) {
if (!SizeExpr)
return ExprError();
Expand Down Expand Up @@ -2031,7 +2259,7 @@ StmtResult SemaOpenACC::ActOnEndStmtDirective(OpenACCDirectiveKind K,
// If we are in the scope of a compute construct, add this to the list of
// loop constructs that need assigning to the next closing compute
// construct.
if (InsideComputeConstruct)
if (isInComputeConstruct())
ParentlessLoopConstructs.push_back(LoopConstruct);

return LoopConstruct;
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Sema/SemaStmtAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
return handleMSConstexprAttr(S, St, A, Range);
case ParsedAttr::AT_NoConvergent:
return handleNoConvergentAttr(S, St, A, Range);
case ParsedAttr::AT_Annotate:
return S.CreateAnnotationAttr(A);
default:
// N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a
// declaration attribute is not written on a statement, but this code is
Expand Down
193 changes: 92 additions & 101 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1010,8 +1010,8 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename,
Param->setAccess(AS_public);

if (Param->isParameterPack())
if (auto *LSI = getEnclosingLambda())
LSI->LocalPacks.push_back(Param);
if (auto *CSI = getEnclosingLambdaOrBlock())
CSI->LocalPacks.push_back(Param);

if (ParamName) {
maybeDiagnoseTemplateParameterShadow(*this, S, ParamNameLoc, ParamName);
Expand Down Expand Up @@ -1542,8 +1542,8 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
Param->setInvalidDecl();

if (Param->isParameterPack())
if (auto *LSI = getEnclosingLambda())
LSI->LocalPacks.push_back(Param);
if (auto *CSI = getEnclosingLambdaOrBlock())
CSI->LocalPacks.push_back(Param);

if (ParamName) {
maybeDiagnoseTemplateParameterShadow(*this, S, D.getIdentifierLoc(),
Expand Down Expand Up @@ -1593,7 +1593,7 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(
Param->setAccess(AS_public);

if (Param->isParameterPack())
if (auto *LSI = getEnclosingLambda())
if (auto *LSI = getEnclosingLambdaOrBlock())
LSI->LocalPacks.push_back(Param);

// If the template template parameter has a name, then link the identifier
Expand Down Expand Up @@ -1795,8 +1795,9 @@ DeclResult Sema::CheckClassTemplate(
CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams,
AccessSpecifier AS, SourceLocation ModulePrivateLoc,
SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists,
TemplateParameterList **OuterTemplateParamLists, SkipBodyInfo *SkipBody) {
SourceLocation FriendLoc,
ArrayRef<TemplateParameterList *> OuterTemplateParamLists,
bool IsMemberSpecialization, SkipBodyInfo *SkipBody) {
assert(TemplateParams && TemplateParams->size() > 0 &&
"No template parameters");
assert(TUK != TagUseKind::Reference &&
Expand Down Expand Up @@ -1984,19 +1985,6 @@ DeclResult Sema::CheckClassTemplate(
}

if (PrevClassTemplate) {
// Ensure that the template parameter lists are compatible. Skip this check
// for a friend in a dependent context: the template parameter list itself
// could be dependent.
if (!(TUK == TagUseKind::Friend && CurContext->isDependentContext()) &&
!TemplateParameterListsAreEqual(
TemplateCompareNewDeclInfo(SemanticContext ? SemanticContext
: CurContext,
CurContext, KWLoc),
TemplateParams, PrevClassTemplate,
PrevClassTemplate->getTemplateParameters(), /*Complain=*/true,
TPL_TemplateMatch))
return true;

// C++ [temp.class]p4:
// In a redeclaration, partial specialization, explicit
// specialization or explicit instantiation of a class template,
Expand All @@ -2011,30 +1999,6 @@ DeclResult Sema::CheckClassTemplate(
Diag(PrevRecordDecl->getLocation(), diag::note_previous_use);
Kind = PrevRecordDecl->getTagKind();
}

// Check for redefinition of this class template.
if (TUK == TagUseKind::Definition) {
if (TagDecl *Def = PrevRecordDecl->getDefinition()) {
// If we have a prior definition that is not visible, treat this as
// simply making that previous definition visible.
NamedDecl *Hidden = nullptr;
if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
SkipBody->ShouldSkip = true;
SkipBody->Previous = Def;
auto *Tmpl = cast<CXXRecordDecl>(Hidden)->getDescribedClassTemplate();
assert(Tmpl && "original definition of a class template is not a "
"class template?");
makeMergedDefinitionVisible(Hidden);
makeMergedDefinitionVisible(Tmpl);
} else {
Diag(NameLoc, diag::err_redefinition) << Name;
Diag(Def->getLocation(), diag::note_previous_definition);
// FIXME: Would it make sense to try to "forget" the previous
// definition, as part of error recovery?
return true;
}
}
}
} else if (PrevDecl) {
// C++ [temp]p5:
// A class template shall not have the same name as any other
Expand All @@ -2046,23 +2010,6 @@ DeclResult Sema::CheckClassTemplate(
return true;
}

// Check the template parameter list of this declaration, possibly
// merging in the template parameter list from the previous class
// template declaration. Skip this check for a friend in a dependent
// context, because the template parameter list might be dependent.
if (!(TUK == TagUseKind::Friend && CurContext->isDependentContext()) &&
CheckTemplateParameterList(
TemplateParams,
PrevClassTemplate ? GetTemplateParameterList(PrevClassTemplate)
: nullptr,
(SS.isSet() && SemanticContext && SemanticContext->isRecord() &&
SemanticContext->isDependentContext())
? TPC_ClassTemplateMember
: TUK == TagUseKind::Friend ? TPC_FriendClassTemplate
: TPC_ClassTemplate,
SkipBody))
Invalid = true;

if (SS.isSet()) {
// If the name of the template was qualified, we must be defining the
// template out-of-line.
Expand All @@ -2089,10 +2036,8 @@ DeclResult Sema::CheckClassTemplate(
PrevClassTemplate->getTemplatedDecl() : nullptr,
/*DelayTypeCreation=*/true);
SetNestedNameSpecifier(*this, NewClass, SS);
if (NumOuterTemplateParamLists > 0)
NewClass->setTemplateParameterListsInfo(
Context,
llvm::ArrayRef(OuterTemplateParamLists, NumOuterTemplateParamLists));
if (!OuterTemplateParamLists.empty())
NewClass->setTemplateParameterListsInfo(Context, OuterTemplateParamLists);

// Add alignment attributes if necessary; these attributes are checked when
// the ASTContext lays out the structure.
Expand All @@ -2105,7 +2050,10 @@ DeclResult Sema::CheckClassTemplate(
= ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
DeclarationName(Name), TemplateParams,
NewClass);

// If we are providing an explicit specialization of a member that is a
// class template, make a note of that.
if (IsMemberSpecialization)
NewTemplate->setMemberSpecialization();
if (ShouldAddRedecl)
NewTemplate->setPreviousDecl(PrevClassTemplate);

Expand All @@ -2120,12 +2068,6 @@ DeclResult Sema::CheckClassTemplate(
assert(T->isDependentType() && "Class template type is not dependent?");
(void)T;

// If we are providing an explicit specialization of a member that is a
// class template, make a note of that.
if (PrevClassTemplate &&
PrevClassTemplate->getInstantiatedFromMemberTemplate())
PrevClassTemplate->setMemberSpecialization();

// Set the access specifier.
if (!Invalid && TUK != TagUseKind::Friend &&
NewTemplate->getDeclContext()->isRecord())
Expand All @@ -2135,8 +2077,62 @@ DeclResult Sema::CheckClassTemplate(
NewClass->setLexicalDeclContext(CurContext);
NewTemplate->setLexicalDeclContext(CurContext);

if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip))
NewClass->startDefinition();
// Ensure that the template parameter lists are compatible. Skip this check
// for a friend in a dependent context: the template parameter list itself
// could be dependent.
if (ShouldAddRedecl && PrevClassTemplate &&
!TemplateParameterListsAreEqual(
NewTemplate, TemplateParams, PrevClassTemplate,
PrevClassTemplate->getTemplateParameters(),
/*Complain=*/true, TPL_TemplateMatch))
return true;

// Check the template parameter list of this declaration, possibly
// merging in the template parameter list from the previous class
// template declaration. Skip this check for a friend in a dependent
// context, because the template parameter list might be dependent.
if (ShouldAddRedecl &&
CheckTemplateParameterList(
TemplateParams,
PrevClassTemplate ? PrevClassTemplate->getTemplateParameters()
: nullptr,
(SS.isSet() && SemanticContext && SemanticContext->isRecord() &&
SemanticContext->isDependentContext())
? TPC_ClassTemplateMember
: TUK == TagUseKind::Friend ? TPC_FriendClassTemplate
: TPC_ClassTemplate,
SkipBody))
Invalid = true;

if (TUK == TagUseKind::Definition) {
if (PrevClassTemplate) {
// Check for redefinition of this class template.
if (TagDecl *Def =
PrevClassTemplate->getTemplatedDecl()->getDefinition()) {
// If we have a prior definition that is not visible, treat this as
// simply making that previous definition visible.
NamedDecl *Hidden = nullptr;
if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
SkipBody->ShouldSkip = true;
SkipBody->Previous = Def;
auto *Tmpl = cast<CXXRecordDecl>(Hidden)->getDescribedClassTemplate();
assert(Tmpl && "original definition of a class template is not a "
"class template?");
makeMergedDefinitionVisible(Hidden);
makeMergedDefinitionVisible(Tmpl);
} else {
Diag(NameLoc, diag::err_redefinition) << Name;
Diag(Def->getLocation(), diag::note_previous_definition);
// FIXME: Would it make sense to try to "forget" the previous
// definition, as part of error recovery?
return true;
}
}
}

if (!SkipBody || !SkipBody->ShouldSkip)
NewClass->startDefinition();
}

ProcessDeclAttributeList(S, NewClass, Attr);
ProcessAPINotes(NewClass);
Expand Down Expand Up @@ -4133,7 +4129,8 @@ void Sema::CheckDeductionGuideTemplate(FunctionTemplateDecl *TD) {
DeclResult Sema::ActOnVarTemplateSpecialization(
Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous,
SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
StorageClass SC, bool IsPartialSpecialization) {
StorageClass SC, bool IsPartialSpecialization,
bool IsMemberSpecialization) {
// D must be variable template id.
assert(D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId &&
"Variable template specialization is declared with a template id.");
Expand Down Expand Up @@ -4251,17 +4248,16 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
Context, VarTemplate->getDeclContext(), TemplateKWLoc,
TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC,
CanonicalConverted);
// If we are providing an explicit specialization of a member variable
// template specialization, make a note of that.
if (IsMemberSpecialization)
Partial->setMemberSpecialization();
Partial->setTemplateArgsAsWritten(TemplateArgs);

if (!PrevPartial)
VarTemplate->AddPartialSpecialization(Partial, InsertPos);
Specialization = Partial;

// If we are providing an explicit specialization of a member variable
// template specialization, make a note of that.
if (PrevPartial && PrevPartial->getInstantiatedFromMember())
PrevPartial->setMemberSpecialization();

CheckTemplatePartialSpecialization(Partial);
} else {
// Create a new class template specialization declaration node for
Expand Down Expand Up @@ -5776,9 +5772,7 @@ bool Sema::CheckTemplateArgumentList(

MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
Template, NewContext, /*Final=*/false, CanonicalConverted,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConceptInstantiation=*/true);
/*RelativeToPrimary=*/true, /*ForConceptInstantiation=*/true);
if (EnsureTemplateArgumentListConstraints(
Template, MLTAL,
SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) {
Expand Down Expand Up @@ -8467,15 +8461,12 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template)
<< /*class template*/ 0 << (TUK == TagUseKind::Definition)
<< FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc));
return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS,
ClassTemplate->getIdentifier(),
TemplateNameLoc,
Attr,
TemplateParams,
AS_none, /*ModulePrivateLoc=*/SourceLocation(),
/*FriendLoc*/SourceLocation(),
TemplateParameterLists.size() - 1,
TemplateParameterLists.data());
return CheckClassTemplate(
S, TagSpec, TUK, KWLoc, SS, ClassTemplate->getIdentifier(),
TemplateNameLoc, Attr, TemplateParams, AS_none,
/*ModulePrivateLoc=*/SourceLocation(),
/*FriendLoc*/ SourceLocation(), TemplateParameterLists.drop_back(),
isMemberSpecialization);
}

// Create a new class template partial specialization declaration node.
Expand All @@ -8485,6 +8476,11 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
ClassTemplatePartialSpecializationDecl::Create(
Context, Kind, DC, KWLoc, TemplateNameLoc, TemplateParams,
ClassTemplate, CanonicalConverted, CanonType, PrevPartial);

// If we are providing an explicit specialization of a member class
// template specialization, make a note of that.
if (isMemberSpecialization)
Partial->setMemberSpecialization();
Partial->setTemplateArgsAsWritten(TemplateArgs);
SetNestedNameSpecifier(*this, Partial, SS);
if (TemplateParameterLists.size() > 1 && SS.isSet()) {
Expand All @@ -8496,11 +8492,6 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
ClassTemplate->AddPartialSpecialization(Partial, InsertPos);
Specialization = Partial;

// If we are providing an explicit specialization of a member class
// template specialization, make a note of that.
if (PrevPartial && PrevPartial->getInstantiatedFromMember())
PrevPartial->setMemberSpecialization();

CheckTemplatePartialSpecialization(Partial);
} else {
// Create a new class template specialization declaration node for
Expand Down Expand Up @@ -9100,8 +9091,8 @@ bool Sema::CheckFunctionTemplateSpecialization(
TemplateDeductionInfo Info(FailedCandidates.getLocation());
FunctionDecl *Specialization = nullptr;
if (TemplateDeductionResult TDK = DeduceTemplateArguments(
cast<FunctionTemplateDecl>(FunTmpl->getFirstDecl()),
ExplicitTemplateArgs ? &Args : nullptr, FT, Specialization, Info);
FunTmpl, ExplicitTemplateArgs ? &Args : nullptr, FT,
Specialization, Info);
TDK != TemplateDeductionResult::Success) {
// Template argument deduction failed; record why it failed, so
// that we can provide nifty diagnostics.
Expand Down Expand Up @@ -11299,8 +11290,8 @@ class ExplicitSpecializationVisibilityChecker {

template<typename TemplDecl>
void checkTemplate(TemplDecl *TD) {
if (TD->isMemberSpecialization()) {
if (!CheckMemberSpecialization(TD))
if (TD->getMostRecentDecl()->isMemberSpecialization()) {
if (!CheckMemberSpecialization(TD->getMostRecentDecl()))
diagnose(TD->getMostRecentDecl(), false);
}
}
Expand Down
33 changes: 3 additions & 30 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3138,20 +3138,6 @@ template<>
struct IsPartialSpecialization<VarTemplatePartialSpecializationDecl> {
static constexpr bool value = true;
};
template <typename TemplateDeclT>
static bool DeducedArgsNeedReplacement(TemplateDeclT *Template) {
return false;
}
template <>
bool DeducedArgsNeedReplacement<VarTemplatePartialSpecializationDecl>(
VarTemplatePartialSpecializationDecl *Spec) {
return !Spec->isClassScopeExplicitSpecialization();
}
template <>
bool DeducedArgsNeedReplacement<ClassTemplatePartialSpecializationDecl>(
ClassTemplatePartialSpecializationDecl *Spec) {
return !Spec->isClassScopeExplicitSpecialization();
}

template <typename TemplateDeclT>
static TemplateDeductionResult
Expand All @@ -3162,23 +3148,10 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template,
llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
Template->getAssociatedConstraints(AssociatedConstraints);

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,
/*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 (!Innermost)
MLTAL.replaceInnermostTemplateArguments(Template, CanonicalDeducedArgs);
Template, Template->getDeclContext(), /*Final=*/false,
/*Innermost=*/CanonicalDeducedArgs, /*RelativeToPrimary=*/true,
/*ForConstraintInstantiation=*/true);

if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
Info.getLocation(),
Expand Down
66 changes: 34 additions & 32 deletions clang/lib/Sema/SemaTemplateDeductionGuide.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ class ExtractTypeForDeductionGuide
ExtractTypeForDeductionGuide(
Sema &SemaRef,
llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs,
ClassTemplateDecl *NestedPattern,
const MultiLevelTemplateArgumentList *OuterInstantiationArgs)
ClassTemplateDecl *NestedPattern = nullptr,
const MultiLevelTemplateArgumentList *OuterInstantiationArgs = nullptr)
: Base(SemaRef), MaterializedTypedefs(MaterializedTypedefs),
NestedPattern(NestedPattern),
OuterInstantiationArgs(OuterInstantiationArgs) {
Expand Down Expand Up @@ -765,7 +765,7 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
}
// Template arguments used to transform the template arguments in
// DeducedResults.
SmallVector<TemplateArgument> TemplateArgsForBuildingRC(
SmallVector<TemplateArgument> InnerArgsForBuildingRC(
F->getTemplateParameters()->size());
// Transform the transformed template args
MultiLevelTemplateArgumentList Args;
Expand All @@ -778,33 +778,30 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
NamedDecl *TP = F->getTemplateParameters()->getParam(Index);
MultiLevelTemplateArgumentList Args;
Args.setKind(TemplateSubstitutionKind::Rewrite);
Args.addOuterTemplateArguments(TemplateArgsForBuildingRC);
Args.addOuterTemplateArguments(InnerArgsForBuildingRC);
// Rebuild the template parameter with updated depth and index.
NamedDecl *NewParam =
transformTemplateParameter(SemaRef, F->getDeclContext(), TP, Args,
/*NewIndex=*/FirstUndeducedParamIdx,
getDepthAndIndex(TP).first + AdjustDepth);
FirstUndeducedParamIdx += 1;
assert(TemplateArgsForBuildingRC[Index].isNull());
TemplateArgsForBuildingRC[Index] =
Context.getInjectedTemplateArg(NewParam);
assert(InnerArgsForBuildingRC[Index].isNull());
InnerArgsForBuildingRC[Index] = Context.getInjectedTemplateArg(NewParam);
continue;
}
TemplateArgumentLoc Input =
SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{});
TemplateArgumentLoc Output;
if (!SemaRef.SubstTemplateArgument(Input, Args, Output)) {
assert(TemplateArgsForBuildingRC[Index].isNull() &&
assert(InnerArgsForBuildingRC[Index].isNull() &&
"InstantiatedArgs must be null before setting");
TemplateArgsForBuildingRC[Index] = Output.getArgument();
InnerArgsForBuildingRC[Index] = Output.getArgument();
}
}

// A list of template arguments for transforming the require-clause of F.
// It must contain the entire set of template argument lists.
MultiLevelTemplateArgumentList ArgsForBuildingRC;
ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
ArgsForBuildingRC.addOuterTemplateArguments(TemplateArgsForBuildingRC);
// A list of template arguments for transforming the require-clause using
// the transformed template arguments as the template argument list of F.
//
// For 2), if the underlying deduction guide F is nested in a class template,
// we need the entire template argument list, as the constraint AST in the
// require-clause of F remains completely uninstantiated.
Expand All @@ -827,25 +824,15 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
// - The occurrence of U in the function parameter is [depth:0, index:0]
// - The template parameter of U is [depth:0, index:0]
//
// We add the outer template arguments which is [int] to the multi-level arg
// list to ensure that the occurrence U in `C<U>` will be replaced with int
// during the substitution.
//
// NOTE: The underlying deduction guide F is instantiated -- either from an
// explicitly-written deduction guide member, or from a constructor.
// getInstantiatedFromMemberTemplate() can only handle the former case, so we
// check the DeclContext kind.
if (F->getLexicalDeclContext()->getDeclKind() ==
clang::Decl::ClassTemplateSpecialization) {
auto OuterLevelArgs = SemaRef.getTemplateInstantiationArgs(
F, F->getLexicalDeclContext(),
/*Final=*/false, /*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true);
for (auto It : OuterLevelArgs)
ArgsForBuildingRC.addOuterTemplateArguments(It.Args);
}
MultiLevelTemplateArgumentList ArgsForBuildingRC =
SemaRef.getTemplateInstantiationArgs(F, F->getLexicalDeclContext(),
/*Final=*/false,
/*Innermost=*/InnerArgsForBuildingRC,
/*RelativeToPrimary=*/true,
/*ForConstraintInstantiation=*/true);
ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);

ExprResult E = SemaRef.SubstExpr(RC, ArgsForBuildingRC);
if (E.isInvalid())
Expand Down Expand Up @@ -1228,10 +1215,25 @@ FunctionTemplateDecl *DeclareAggregateDeductionGuideForTypeAlias(
getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate).first;
if (!RHSTemplate)
return nullptr;

llvm::SmallVector<TypedefNameDecl *> TypedefDecls;
llvm::SmallVector<QualType> NewParamTypes;
ExtractTypeForDeductionGuide TypeAliasTransformer(SemaRef, TypedefDecls);
for (QualType P : ParamTypes) {
QualType Type = TypeAliasTransformer.TransformType(P);
if (Type.isNull())
return nullptr;
NewParamTypes.push_back(Type);
}

auto *RHSDeductionGuide = SemaRef.DeclareAggregateDeductionGuideFromInitList(
RHSTemplate, ParamTypes, Loc);
RHSTemplate, NewParamTypes, Loc);
if (!RHSDeductionGuide)
return nullptr;

for (TypedefNameDecl *TD : TypedefDecls)
TD->setDeclContext(RHSDeductionGuide->getTemplatedDecl());

return BuildDeductionGuideForTypeAlias(SemaRef, AliasTemplate,
RHSDeductionGuide, Loc);
}
Expand Down
771 changes: 386 additions & 385 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp

Large diffs are not rendered by default.

51 changes: 41 additions & 10 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "TreeTransform.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclVisitor.h"
Expand Down Expand Up @@ -230,7 +231,10 @@ static void instantiateDependentAnnotationAttr(
ActualArgs.insert(ActualArgs.begin(), Args.begin() + 1, Args.end());
std::swap(Args, ActualArgs);
}
S.AddAnnotationAttr(New, *Attr, Str, Args);
auto *AA = S.CreateAnnotationAttr(*Attr, Str, Args);
if (AA) {
New->addAttr(AA);
}
}

static Expr *instantiateDependentFunctionAttrCondition(
Expand Down Expand Up @@ -4685,6 +4689,36 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
ParmVarDecl *Param) {
assert(Param->hasUninstantiatedDefaultArg());

NamedDecl *Pattern = FD;
std::optional<ArrayRef<TemplateArgument>> Innermost;

// C++ [dcl.fct.default]p4
// For non-template functions, default arguments can be added in later
// declarations of a function that inhabit the same scope.
//
// C++ [dcl.fct.default]p6
// Except for member functions of templated classes, the default arguments
// in a member function definition that appears outside of the class
// definition are added to the set of default arguments provided by the
// member function declaration in the class definition; the program is
// ill-formed if a default constructor, copy or move constructor, or copy
// or move assignment operator is so declared. Default arguments for a
// member function of a templated class shall be specified on the initial
// declaration of the member function within the templated class.
//
// We need to collect the template arguments from the context of the function
// where the default argument was defined. For a specialization of a function
// template explicitly specialized for an implicit instantiation of a class
// template, that context is the (implicitly instantiated) declaration in the
// definition of the class template specialization.
if (FD->isCXXClassMember() &&
!isGenericLambdaCallOperatorOrStaticInvokerSpecialization(FD)) {
if (FunctionTemplateDecl *FTD = FD->getPrimaryTemplate()) {
Pattern = FTD->getFirstDecl();
Innermost = FD->getTemplateSpecializationArgs()->asArray();
}
}

// Instantiate the expression.
//
// FIXME: Pass in a correct Pattern argument, otherwise
Expand All @@ -4702,12 +4736,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, /*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true, /*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/false, /*SkipForSpecialization=*/false,
/*ForDefaultArgumentSubstitution=*/true);
MultiLevelTemplateArgumentList TemplateArgs =
getTemplateInstantiationArgs(Pattern, Pattern->getLexicalDeclContext(),
/*Final=*/false, Innermost,
/*RelativeToPrimary=*/true);

if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
return true;
Expand Down Expand Up @@ -4748,7 +4780,7 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
MultiLevelTemplateArgumentList TemplateArgs =
getTemplateInstantiationArgs(Decl, Decl->getLexicalDeclContext(),
/*Final=*/false, /*Innermost=*/std::nullopt,
/*RelativeToPrimary*/ true);
/*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 @@ -5196,8 +5228,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
SetDeclDefaulted(Function, PatternDecl->getLocation());
} else {
MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
Function, Function->getLexicalDeclContext(), /*Final=*/false,
/*Innermost=*/std::nullopt, false, PatternDecl);
Function, Function->getLexicalDeclContext());

// Substitute into the qualifier; we can get a substitution failure here
// through evil use of alias templates.
Expand Down
42 changes: 26 additions & 16 deletions clang/lib/Sema/SemaTemplateVariadic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "llvm/Support/SaveAndRestore.h"
#include <optional>

using namespace clang;
Expand All @@ -36,7 +37,7 @@ namespace {

SmallVectorImpl<UnexpandedParameterPack> &Unexpanded;

bool InLambda = false;
bool InLambdaOrBlock = false;
unsigned DepthLimit = (unsigned)-1;

#ifndef NDEBUG
Expand Down Expand Up @@ -140,7 +141,7 @@ namespace {
/// do not contain unexpanded parameter packs.
bool TraverseStmt(Stmt *S) {
Expr *E = dyn_cast_or_null<Expr>(S);
if ((E && E->containsUnexpandedParameterPack()) || InLambda)
if ((E && E->containsUnexpandedParameterPack()) || InLambdaOrBlock)
return inherited::TraverseStmt(S);

return true;
Expand All @@ -149,7 +150,8 @@ namespace {
/// Suppress traversal into types that do not contain
/// unexpanded parameter packs.
bool TraverseType(QualType T) {
if ((!T.isNull() && T->containsUnexpandedParameterPack()) || InLambda)
if ((!T.isNull() && T->containsUnexpandedParameterPack()) ||
InLambdaOrBlock)
return inherited::TraverseType(T);

return true;
Expand All @@ -160,7 +162,7 @@ namespace {
bool TraverseTypeLoc(TypeLoc TL) {
if ((!TL.getType().isNull() &&
TL.getType()->containsUnexpandedParameterPack()) ||
InLambda)
InLambdaOrBlock)
return inherited::TraverseTypeLoc(TL);

return true;
Expand Down Expand Up @@ -262,20 +264,28 @@ namespace {
if (!Lambda->containsUnexpandedParameterPack())
return true;

bool WasInLambda = InLambda;
SaveAndRestore _(InLambdaOrBlock, true);
unsigned OldDepthLimit = DepthLimit;

InLambda = true;
if (auto *TPL = Lambda->getTemplateParameterList())
DepthLimit = TPL->getDepth();

inherited::TraverseLambdaExpr(Lambda);

InLambda = WasInLambda;
DepthLimit = OldDepthLimit;
return true;
}

/// Analogously for blocks.
bool TraverseBlockExpr(BlockExpr *Block) {
if (!Block->containsUnexpandedParameterPack())
return true;

SaveAndRestore _(InLambdaOrBlock, true);
inherited::TraverseBlockExpr(Block);
return true;
}

/// Suppress traversal within pack expansions in lambda captures.
bool TraverseLambdaCapture(LambdaExpr *Lambda, const LambdaCapture *C,
Expr *Init) {
Expand Down Expand Up @@ -323,11 +333,11 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,

// If we are within a lambda expression and referencing a pack that is not
// declared within the lambda itself, that lambda contains an unexpanded
// parameter pack, and we are done.
// parameter pack, and we are done. Analogously for blocks.
// FIXME: Store 'Unexpanded' on the lambda so we don't need to recompute it
// later.
SmallVector<UnexpandedParameterPack, 4> LambdaParamPackReferences;
if (auto *LSI = getEnclosingLambda()) {
SmallVector<UnexpandedParameterPack, 4> ParamPackReferences;
if (sema::CapturingScopeInfo *CSI = getEnclosingLambdaOrBlock()) {
for (auto &Pack : Unexpanded) {
auto DeclaresThisPack = [&](NamedDecl *LocalPack) {
if (auto *TTPT = Pack.first.dyn_cast<const TemplateTypeParmType *>()) {
Expand All @@ -336,11 +346,11 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
}
return declaresSameEntity(Pack.first.get<NamedDecl *>(), LocalPack);
};
if (llvm::any_of(LSI->LocalPacks, DeclaresThisPack))
LambdaParamPackReferences.push_back(Pack);
if (llvm::any_of(CSI->LocalPacks, DeclaresThisPack))
ParamPackReferences.push_back(Pack);
}

if (LambdaParamPackReferences.empty()) {
if (ParamPackReferences.empty()) {
// Construct in lambda only references packs declared outside the lambda.
// That's OK for now, but the lambda itself is considered to contain an
// unexpanded pack in this case, which will require expansion outside the
Expand All @@ -363,16 +373,16 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
}
// Coumpound-statements outside the lambda are OK for now; we'll check
// for those when we finish handling the lambda.
if (Func == LSI)
if (Func == CSI)
break;
}

if (!EnclosingStmtExpr) {
LSI->ContainsUnexpandedParameterPack = true;
CSI->ContainsUnexpandedParameterPack = true;
return false;
}
} else {
Unexpanded = LambdaParamPackReferences;
Unexpanded = ParamPackReferences;
}
}

Expand Down
23 changes: 23 additions & 0 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -11940,6 +11940,29 @@ void OpenACCClauseTransform<Derived>::VisitTileClause(
ParsedClause.getLParenLoc(), ParsedClause.getIntExprs(),
ParsedClause.getEndLoc());
}
template <typename Derived>
void OpenACCClauseTransform<Derived>::VisitGangClause(
const OpenACCGangClause &C) {
llvm::SmallVector<OpenACCGangKind> TransformedGangKinds;
llvm::SmallVector<Expr *> TransformedIntExprs;

for (unsigned I = 0; I < C.getNumExprs(); ++I) {
ExprResult ER = Self.TransformExpr(const_cast<Expr *>(C.getExpr(I).second));
if (!ER.isUsable())
continue;

ER = Self.getSema().OpenACC().CheckGangExpr(C.getExpr(I).first, ER.get());
if (!ER.isUsable())
continue;
TransformedGangKinds.push_back(C.getExpr(I).first);
TransformedIntExprs.push_back(ER.get());
}

NewClause = OpenACCGangClause::Create(
Self.getSema().getASTContext(), ParsedClause.getBeginLoc(),
ParsedClause.getLParenLoc(), TransformedGangKinds, TransformedIntExprs,
ParsedClause.getEndLoc());
}
} // namespace
template <typename Derived>
OpenACCClause *TreeTransform<Derived>::TransformOpenACCClause(
Expand Down
16 changes: 14 additions & 2 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10003,7 +10003,8 @@ void ASTReader::finishPendingActions() {

auto RTD = cast<RedeclarableTemplateDecl>(D)->getCanonicalDecl();
for (auto *R = getMostRecentExistingDecl(RTD); R; R = R->getPreviousDecl())
cast<RedeclarableTemplateDecl>(R)->Common = RTD->Common;
cast<RedeclarableTemplateDecl>(R)->setCommonPtr(
RTD->getCommonPtrInternal());
}
PendingDefinitions.clear();

Expand Down Expand Up @@ -12326,6 +12327,18 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() {
return OpenACCTileClause::Create(getContext(), BeginLoc, LParenLoc,
SizeExprs, EndLoc);
}
case OpenACCClauseKind::Gang: {
SourceLocation LParenLoc = readSourceLocation();
unsigned NumExprs = readInt();
llvm::SmallVector<OpenACCGangKind> GangKinds;
llvm::SmallVector<Expr *> Exprs;
for (unsigned I = 0; I < NumExprs; ++I) {
GangKinds.push_back(readEnum<OpenACCGangKind>());
Exprs.push_back(readSubExpr());
}
return OpenACCGangClause::Create(getContext(), BeginLoc, LParenLoc,
GangKinds, Exprs, EndLoc);
}

case OpenACCClauseKind::Finalize:
case OpenACCClauseKind::IfPresent:
Expand All @@ -12342,7 +12355,6 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() {
case OpenACCClauseKind::Bind:
case OpenACCClauseKind::DeviceNum:
case OpenACCClauseKind::DefaultAsync:
case OpenACCClauseKind::Gang:
case OpenACCClauseKind::Invalid:
llvm_unreachable("Clause serialization not yet implemented");
}
Expand Down
18 changes: 9 additions & 9 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2416,11 +2416,13 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
// Make sure we've allocated the Common pointer first. We do this before
// VisitTemplateDecl so that getCommonPtr() can be used during initialization.
RedeclarableTemplateDecl *CanonD = D->getCanonicalDecl();
if (!CanonD->Common) {
CanonD->Common = CanonD->newCommon(Reader.getContext());
if (!CanonD->getCommonPtrInternal()) {
CanonD->setCommonPtr(CanonD->newCommon(Reader.getContext()));
Reader.PendingDefinitions.insert(CanonD);
}
D->Common = CanonD->Common;
D->setCommonPtr(CanonD->getCommonPtrInternal());
if (Record.readInt())
D->setMemberSpecialization();

// If this is the first declaration of the template, fill in the information
// for the 'common' pointer.
Expand All @@ -2429,8 +2431,6 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
assert(RTD->getKind() == D->getKind() &&
"InstantiatedFromMemberTemplate kind mismatch");
D->setInstantiatedFromMemberTemplate(RTD);
if (Record.readInt())
D->setMemberSpecialization();
}
}

Expand Down Expand Up @@ -2562,12 +2562,12 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
D->TemplateParams = Params;

RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D);
D->InstantiatedFromMember.setInt(Record.readInt());

// These are read/set from/to the first declaration.
if (ThisDeclID == Redecl.getFirstID()) {
D->InstantiatedFromMember.setPointer(
readDeclAs<ClassTemplatePartialSpecializationDecl>());
D->InstantiatedFromMember.setInt(Record.readInt());
readDeclAs<ClassTemplatePartialSpecializationDecl>());
}
}

Expand Down Expand Up @@ -2660,12 +2660,12 @@ void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl(
D->TemplateParams = Params;

RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);
D->InstantiatedFromMember.setInt(Record.readInt());

// These are read/set from/to the first declaration.
if (ThisDeclID == Redecl.getFirstID()) {
D->InstantiatedFromMember.setPointer(
readDeclAs<VarTemplatePartialSpecializationDecl>());
D->InstantiatedFromMember.setInt(Record.readInt());
}
}

Expand Down Expand Up @@ -2888,7 +2888,7 @@ void ASTDeclReader::mergeRedeclarableTemplate(RedeclarableTemplateDecl *D,
// If we merged the template with a prior declaration chain, merge the
// common pointer.
// FIXME: Actually merge here, don't just overwrite.
D->Common = D->getCanonicalDecl()->Common;
D->setCommonPtr(D->getCanonicalDecl()->getCommonPtrInternal());
}

/// "Cast" to type T, asserting if we don't have an implicit conversion.
Expand Down
11 changes: 10 additions & 1 deletion clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8182,6 +8182,16 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
AddStmt(E);
return;
}
case OpenACCClauseKind::Gang: {
const auto *GC = cast<OpenACCGangClause>(C);
writeSourceLocation(GC->getLParenLoc());
writeUInt32(GC->getNumExprs());
for (unsigned I = 0; I < GC->getNumExprs(); ++I) {
writeEnum(GC->getExpr(I).first);
AddStmt(const_cast<Expr *>(GC->getExpr(I).second));
}
return;
}

case OpenACCClauseKind::Finalize:
case OpenACCClauseKind::IfPresent:
Expand All @@ -8198,7 +8208,6 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
case OpenACCClauseKind::Bind:
case OpenACCClauseKind::DeviceNum:
case OpenACCClauseKind::DefaultAsync:
case OpenACCClauseKind::Gang:
case OpenACCClauseKind::Invalid:
llvm_unreachable("Clause serialization not yet implemented");
}
Expand Down
17 changes: 7 additions & 10 deletions clang/lib/Serialization/ASTWriterDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1713,14 +1713,13 @@ void ASTDeclWriter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
VisitRedeclarable(D);

Record.push_back(D->isMemberSpecialization());

// Emit data to initialize CommonOrPrev before VisitTemplateDecl so that
// getCommonPtr() can be used while this is still initializing.
if (D->isFirstDecl()) {
if (D->isFirstDecl())
// This declaration owns the 'common' pointer, so serialize that data now.
Record.AddDeclRef(D->getInstantiatedFromMemberTemplate());
if (D->getInstantiatedFromMemberTemplate())
Record.push_back(D->isMemberSpecialization());
}

VisitTemplateDecl(D);
Record.push_back(D->getIdentifierNamespace());
Expand Down Expand Up @@ -1806,11 +1805,10 @@ void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(

VisitClassTemplateSpecializationDecl(D);

Record.push_back(D->isMemberSpecialization());
// These are read/set from/to the first declaration.
if (D->getPreviousDecl() == nullptr) {
if (D->isFirstDecl())
Record.AddDeclRef(D->getInstantiatedFromMember());
Record.push_back(D->isMemberSpecialization());
}

Code = serialization::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION;
}
Expand Down Expand Up @@ -1874,12 +1872,11 @@ void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl(
Record.AddTemplateParameterList(D->getTemplateParameters());

VisitVarTemplateSpecializationDecl(D);
Record.push_back(D->isMemberSpecialization());

// These are read/set from/to the first declaration.
if (D->getPreviousDecl() == nullptr) {
if (D->isFirstDecl())
Record.AddDeclRef(D->getInstantiatedFromMember());
Record.push_back(D->isMemberSpecialization());
}

Code = serialization::DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION;
}
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
if (LR->getSymbolicBase() || RR->getSymbolicBase())
return;

if (!B->getLHS()->getType()->isPointerType() ||
!B->getRHS()->getType()->isPointerType())
return;

const auto *ElemLR = dyn_cast<ElementRegion>(LR);
const auto *ElemRR = dyn_cast<ElementRegion>(RR);

Expand Down
5 changes: 5 additions & 0 deletions clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ bool tryToFindPtrOrigin(
if (isSingleton(callee))
return callback(E, true);

if (callee->isInStdNamespace() && safeGetName(callee) == "forward") {
E = call->getArg(0);
continue;
}

if (isPtrConversion(callee)) {
E = call->getArg(0);
continue;
Expand Down
20 changes: 8 additions & 12 deletions clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,14 +177,10 @@ std::optional<bool> isUncounted(const CXXRecordDecl* Class)
return (*IsRefCountable);
}

std::optional<bool> isUncountedPtr(const Type* T)
{
assert(T);

std::optional<bool> isUncountedPtr(const QualType T) {
if (T->isPointerType() || T->isReferenceType()) {
if (auto *CXXRD = T->getPointeeCXXRecordDecl()) {
if (auto *CXXRD = T->getPointeeCXXRecordDecl())
return isUncounted(CXXRD);
}
}
return false;
}
Expand All @@ -208,12 +204,8 @@ std::optional<bool> isGetterOfRefCounted(const CXXMethodDecl* M)
// Ref<T> -> T conversion
// FIXME: Currently allowing any Ref<T> -> whatever cast.
if (isRefType(className)) {
if (auto *maybeRefToRawOperator = dyn_cast<CXXConversionDecl>(M)) {
if (auto *targetConversionType =
maybeRefToRawOperator->getConversionType().getTypePtrOrNull()) {
return isUncountedPtr(targetConversionType);
}
}
if (auto *maybeRefToRawOperator = dyn_cast<CXXConversionDecl>(M))
return isUncountedPtr(maybeRefToRawOperator->getConversionType());
}
}
return false;
Expand Down Expand Up @@ -508,6 +500,10 @@ class TrivialFunctionAnalysisVisitor
return IsFunctionTrivial(CE->getConstructor());
}

bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E) {
return IsFunctionTrivial(E->getConstructor());
}

bool VisitCXXNewExpr(const CXXNewExpr *NE) { return VisitChildren(NE); }

bool VisitImplicitCastExpr(const ImplicitCastExpr *ICE) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ std::optional<bool> isUncounted(const clang::CXXRecordDecl* Class);

/// \returns true if \p T is either a raw pointer or reference to an uncounted
/// class, false if not, std::nullopt if inconclusive.
std::optional<bool> isUncountedPtr(const clang::Type* T);
std::optional<bool> isUncountedPtr(const clang::QualType T);

/// \returns true if Name is a RefPtr, Ref, or its variant, false if not.
bool isRefType(const std::string &Name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,8 @@ class UncountedCallArgsChecker
// continue;

QualType ArgType = (*P)->getType().getCanonicalType();
const auto *TypePtr = ArgType.getTypePtrOrNull();
if (!TypePtr)
continue; // FIXME? Should we bail?

// FIXME: more complex types (arrays, references to raw pointers, etc)
std::optional<bool> IsUncounted = isUncountedPtr(TypePtr);
std::optional<bool> IsUncounted = isUncountedPtr(ArgType);
if (!IsUncounted || !(*IsUncounted))
continue;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ class UncountedLambdaCapturesChecker
for (const LambdaCapture &C : L->captures()) {
if (C.capturesVariable()) {
ValueDecl *CapturedVar = C.getCapturedVar();
if (auto *CapturedVarType = CapturedVar->getType().getTypePtrOrNull()) {
std::optional<bool> IsUncountedPtr = isUncountedPtr(CapturedVarType);
if (IsUncountedPtr && *IsUncountedPtr) {
reportBug(C, CapturedVar, CapturedVarType);
}
QualType CapturedVarQualType = CapturedVar->getType();
if (auto *CapturedVarType = CapturedVarQualType.getTypePtrOrNull()) {
auto IsUncountedPtr = isUncountedPtr(CapturedVarQualType);
if (IsUncountedPtr && *IsUncountedPtr)
reportBug(C, CapturedVar, CapturedVarType);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,11 +199,7 @@ class UncountedLocalVarsChecker
if (shouldSkipVarDecl(V))
return;

const auto *ArgType = V->getType().getTypePtr();
if (!ArgType)
return;

std::optional<bool> IsUncountedPtr = isUncountedPtr(ArgType);
std::optional<bool> IsUncountedPtr = isUncountedPtr(V->getType());
if (IsUncountedPtr && *IsUncountedPtr) {
if (tryToFindPtrOrigin(
Value, /*StopAtFirstRefCountedObj=*/false,
Expand Down
19 changes: 19 additions & 0 deletions clang/test/AST/ByteCode/cxx1z.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify=expected,both %s
// RUN: %clang_cc1 -std=c++17 -verify=ref,both %s

template<typename T, T val> struct A {};
namespace Temp {
struct S { int n; };
constexpr S &addr(S &&s) { return s; }
A<S &, addr({})> a; // both-error {{reference to temporary object}}
A<S *, &addr({})> b; // both-error {{pointer to temporary object}}
A<int &, addr({}).n> c; // both-error {{reference to subobject of temporary object}}
A<int *, &addr({}).n> d; // both-error {{pointer to subobject of temporary object}}
}

char arr[3];
A<const char*, &arr[1]> d; // both-error {{refers to subobject '&arr[1]'}}

void Func() {
A<const char*, __func__> a; // both-error {{pointer to subobject of predefined '__func__' variable}}
}
29 changes: 24 additions & 5 deletions clang/test/AST/ByteCode/new-delete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -552,8 +552,6 @@ namespace DeleteThis {
// both-note {{in call to 'super_secret_double_delete()'}}
}

/// FIXME: This is currently diagnosed, but should work.
/// If the destructor for S is _not_ virtual however, it should fail.
namespace CastedDelete {
struct S {
constexpr S(int *p) : p(p) {}
Expand All @@ -567,11 +565,10 @@ namespace CastedDelete {

constexpr int vdtor_1() {
int a;
delete (S*)new T(&a); // expected-note {{delete of pointer to subobject}}
delete (S*)new T(&a);
return a;
}
static_assert(vdtor_1() == 1); // expected-error {{not an integral constant expression}} \
// expected-note {{in call to}}
static_assert(vdtor_1() == 1);
}

constexpr void use_after_free_2() { // both-error {{never produces a constant expression}}
Expand Down Expand Up @@ -778,6 +775,28 @@ namespace Placement {
static_assert(ok2()== 0);
}

constexpr bool virt_delete(bool global) {
struct A {
virtual constexpr ~A() {}
};
struct B : A {
void operator delete(void *);
constexpr ~B() {}
};

A *p = new B;
if (global)
::delete p;
else
delete p; // both-note {{call to class-specific 'operator delete'}}
return true;
}
static_assert(virt_delete(true));
static_assert(virt_delete(false)); // both-error {{not an integral constant expression}} \
// both-note {{in call to}}



#else
/// Make sure we reject this prior to C++20
constexpr int a() { // both-error {{never produces a constant expression}}
Expand Down
59 changes: 59 additions & 0 deletions clang/test/AST/ast-dump-for-range-lifetime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,4 +449,63 @@ void test13() {
for (auto e : dg<A>().r().g().r().g().r().g())
bar(e);
}

extern "C" void exit(int);

struct A14 {
int arr[1];
~A14() noexcept(false) { throw 42; }
};

struct B14 {
int x;
const A14 &a = A14{{0}};
const int *begin() { return a.arr; }
const int *end() { return &a.arr[1]; }
};

void test14() {
// The ExprWithCleanups in CXXDefaultInitExpr will be ignored.

// CHECK: FunctionDecl {{.*}} test14 'void ()'
// CHECK: -CXXForRangeStmt {{.*}}
// CHECK-NEXT: |-<<<NULL>>>
// CHECK-NEXT: |-DeclStmt {{.*}}
// CHECK-NEXT: | `-VarDecl {{.*}} implicit used __range1 'const int (&)[1]' cinit
// CHECK-NEXT: | `-ExprWithCleanups {{.*}} 'const int[1]' lvalue
// CHECK-NEXT: | `-MemberExpr {{.*}} 'const int[1]' lvalue .arr {{.*}}
// CHECK-NEXT: | `-MemberExpr {{.*}} 'const A14':'const P2718R0::A14' lvalue .a {{.*}}
// CHECK-NEXT: | `-MaterializeTemporaryExpr {{.*}} 'B14':'P2718R0::B14' xvalue extended by Var {{.*}} '__range1' 'const int (&)[1]'
// CHECK-NEXT: | `-CXXFunctionalCastExpr {{.*}} 'B14':'P2718R0::B14' functional cast to B14 <NoOp>
// CHECK-NEXT: | `-InitListExpr {{.*}} 'B14':'P2718R0::B14'
// CHECK-NEXT: | |-IntegerLiteral {{.*}} 'int' 0
// CHECK-NEXT: | `-CXXDefaultInitExpr {{.*}} 'const A14':'const P2718R0::A14' lvalue has rewritten init
// CHECK-NEXT: | `-MaterializeTemporaryExpr {{.*}} 'const A14':'const P2718R0::A14' lvalue extended by Var {{.*}} '__range1' 'const int (&)[1]'
// CHECK-NEXT: | `-ImplicitCastExpr {{.*}} 'const A14':'const P2718R0::A14' <NoOp>
// CHECK-NEXT: | `-CXXFunctionalCastExpr {{.*}} 'A14':'P2718R0::A14' functional cast to A14 <NoOp>
// CHECK-NEXT: | `-CXXBindTemporaryExpr {{.*}} 'A14':'P2718R0::A14' (CXXTemporary {{.*}})
// CHECK-NEXT: | `-InitListExpr {{.*}} 'A14':'P2718R0::A14'
// CHECK-NEXT: | `-InitListExpr {{.*}} 'int[1]'
// CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 0
for (auto &&x : B14{0}.a.arr) { exit(0); }

// CHECK: -CXXForRangeStmt {{.*}}
// CHECK-NEXT: |-<<<NULL>>>
// CHECK-NEXT: |-DeclStmt {{.*}}
// CHECK-NEXT: | `-VarDecl {{.*}} col:19 implicit used __range1 'B14 &&' cinit
// CHECK-NEXT: | `-ExprWithCleanups {{.*}} 'B14':'P2718R0::B14' xvalue
// CHECK-NEXT: | `-MaterializeTemporaryExpr {{.*}} 'B14':'P2718R0::B14' xvalue extended by Var {{.*}} '__range1' 'B14 &&'
// CHECK-NEXT: | `-CXXFunctionalCastExpr {{.*}} 'B14':'P2718R0::B14' functional cast to B14 <NoOp>
// CHECK-NEXT: | `-InitListExpr {{.*}} 'B14':'P2718R0::B14'
// CHECK-NEXT: | |-IntegerLiteral {{.*}} 'int' 0
// CHECK-NEXT: | `-CXXDefaultInitExpr {{.*}} 'const A14':'const P2718R0::A14' lvalue has rewritten init
// CHECK-NEXT: | `-MaterializeTemporaryExpr {{.*}} 'const A14':'const P2718R0::A14' lvalue extended by Var {{.*}} '__range1' 'B14 &&'
// CHECK-NEXT: | `-ImplicitCastExpr {{.*}} 'const A14':'const P2718R0::A14' <NoOp>
// CHECK-NEXT: | `-CXXFunctionalCastExpr {{.*}} 'A14':'P2718R0::A14' functional cast to A14 <NoOp>
// CHECK-NEXT: | `-CXXBindTemporaryExpr {{.*}} 'A14':'P2718R0::A14' (CXXTemporary {{.*}})
// CHECK-NEXT: | `-InitListExpr {{.*}} 'A14':'P2718R0::A14'
// CHECK-NEXT: | `-InitListExpr {{.*}} 'int[1]'
// CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 0
for (auto &&x : B14{0}) { exit(0); }
}
} // namespace P2718R0
82 changes: 82 additions & 0 deletions clang/test/AST/ast-print-openacc-loop-construct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,86 @@ void foo() {
for(;;)
for(;;)
for(;;);

// CHECK: #pragma acc loop gang(dim: 2)
// CHECK-NEXT: for (;;)
// CHECK-NEXT: ;
#pragma acc loop gang(dim:2)
for(;;);

// CHECK: #pragma acc loop gang(static: i)
// CHECK-NEXT: for (;;)
// CHECK-NEXT: ;
#pragma acc loop gang(static:i)
for(;;);

// CHECK: #pragma acc loop gang(static: i) gang(dim: 2)
// CHECK-NEXT: for (;;)
// CHECK-NEXT: ;
#pragma acc loop gang(static:i) gang(dim:2)
for(;;);

// CHECK: #pragma acc parallel
// CHECK-NEXT: #pragma acc loop gang(dim: 2)
// CHECK-NEXT: for (;;)
// CHECK-NEXT: ;
#pragma acc parallel
#pragma acc loop gang(dim:2)
for(;;);

// CHECK: #pragma acc parallel
// CHECK-NEXT: #pragma acc loop gang(static: i)
// CHECK-NEXT: for (;;)
// CHECK-NEXT: ;
#pragma acc parallel
#pragma acc loop gang(static:i)
for(;;);

// CHECK: #pragma acc parallel
// CHECK-NEXT: #pragma acc loop gang(static: i) gang(dim: 2)
// CHECK-NEXT: for (;;)
// CHECK-NEXT: ;
#pragma acc parallel
#pragma acc loop gang(static:i) gang(dim:2)
for(;;);

// CHECK: #pragma acc kernels
// CHECK-NEXT: #pragma acc loop gang(num: i) gang(static: i)
// CHECK-NEXT: for (;;)
// CHECK-NEXT: ;
#pragma acc kernels
#pragma acc loop gang(i) gang(static:i)
for(;;);

// CHECK: #pragma acc kernels
// CHECK-NEXT: #pragma acc loop gang(num: i) gang(static: i)
// CHECK-NEXT: for (;;)
// CHECK-NEXT: ;
#pragma acc kernels
#pragma acc loop gang(num:i) gang(static:i)
for(;;);

// CHECK: #pragma acc serial
// CHECK-NEXT: #pragma acc loop gang(static: i)
// CHECK-NEXT: for (;;)
// CHECK-NEXT: ;
#pragma acc serial
#pragma acc loop gang(static:i)
for(;;);

// CHECK: #pragma acc serial
// CHECK-NEXT: #pragma acc loop gang(static: *)
// CHECK-NEXT: for (;;)
// CHECK-NEXT: ;
#pragma acc serial
#pragma acc loop gang(static:*)
for(;;);

// CHECK: #pragma acc serial
// CHECK-NEXT: #pragma acc loop
// CHECK-NEXT: for (;;)
// CHECK-NEXT: ;
#pragma acc serial
#pragma acc loop gang
for(;;);
}
3 changes: 3 additions & 0 deletions clang/test/AST/attr-print-emit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ class C {
ANNOTATE_ATTR int annotated_attr ANNOTATE_ATTR = 0;
// CHECK: __attribute__((annotate("Annotated"))) int annotated_attr __attribute__((annotate("Annotated"))) = 0;

void increment() { [[clang::annotate("Annotated")]] annotated_attr++; }
// CHECK: {{\[\[}}clang::annotate("Annotated")]] annotated_attr++;

// FIXME: We do not print the attribute as written after the type specifier.
int ANNOTATE_ATTR annotated_attr_fixme = 0;
// CHECK: __attribute__((annotate("Annotated"))) int annotated_attr_fixme = 0;
Expand Down
Loading