2 changes: 2 additions & 0 deletions clang/lib/Frontend/FrontendActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,8 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
return "BuildingDeductionGuides";
case CodeSynthesisContext::TypeAliasTemplateInstantiation:
return "TypeAliasTemplateInstantiation";
case CodeSynthesisContext::PartialOrderingTTP:
return "PartialOrderingTTP";
}
return "";
}
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Frontend/TextDiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1252,10 +1252,10 @@ highlightLines(StringRef FileData, unsigned StartLineNumber,
for (unsigned I = 0; I <= Spelling.size(); ++I) {
// This line is done.
if (I == Spelling.size() || isVerticalWhitespace(Spelling[I])) {
SmallVector<TextDiagnostic::StyleRange> &LineRanges =
SnippetRanges[L - StartLineNumber];

if (L >= StartLineNumber) {
SmallVector<TextDiagnostic::StyleRange> &LineRanges =
SnippetRanges[L - StartLineNumber];

if (L == TokenStartLine) // First line
appendStyle(LineRanges, T, StartCol, LineLength);
else if (L == TokenEndLine) // Last line
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/FrontendTool/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@ set(link_libs
clangRewriteFrontend
)

set(deps)

if(CLANG_ENABLE_CIR)
list(APPEND link_libs
clangCIRFrontendAction
MLIRIR
)
endif()

if(CLANG_ENABLE_ARCMT)
list(APPEND link_libs
clangARCMigrate
Expand All @@ -29,7 +38,13 @@ add_clang_library(clangFrontendTool

DEPENDS
ClangDriverOptions
${deps}

LINK_LIBS
${link_libs}
)

if(CLANG_ENABLE_CIR)
target_include_directories(clangFrontendTool PRIVATE ${LLVM_MAIN_SRC_DIR}/../mlir/include)
target_include_directories(clangFrontendTool PRIVATE ${CMAKE_BINARY_DIR}/tools/mlir/include)
endif()
16 changes: 16 additions & 0 deletions clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@
#include "llvm/Support/BuryPointer.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/ErrorHandling.h"

#if CLANG_ENABLE_CIR
#include "clang/CIR/FrontendAction/CIRGenAction.h"
#endif

using namespace clang;
using namespace llvm::opt;

Expand All @@ -42,6 +47,13 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
StringRef Action("unknown");
(void)Action;

unsigned UseCIR = CI.getFrontendOpts().UseClangIRPipeline;
frontend::ActionKind Act = CI.getFrontendOpts().ProgramAction;
bool EmitsCIR = Act == EmitCIR;

if (!UseCIR && EmitsCIR)
llvm::report_fatal_error("-emit-cir and only valid when using -fclangir");

switch (CI.getFrontendOpts().ProgramAction) {
case ASTDeclList: return std::make_unique<ASTDeclListAction>();
case ASTDump: return std::make_unique<ASTDumpAction>();
Expand All @@ -54,7 +66,11 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
case EmitAssembly: return std::make_unique<EmitAssemblyAction>();
case EmitBC: return std::make_unique<EmitBCAction>();
case EmitCIR:
#if CLANG_ENABLE_CIR
return std::make_unique<::cir::EmitCIRAction>();
#else
llvm_unreachable("CIR suppport not built into clang");
#endif
case EmitHTML: return std::make_unique<HTMLPrintAction>();
case EmitLLVM: return std::make_unique<EmitLLVMAction>();
case EmitLLVMOnly: return std::make_unique<EmitLLVMOnlyAction>();
Expand Down
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
20 changes: 20 additions & 0 deletions clang/lib/Parse/ParseOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3080,6 +3080,18 @@ OMPClause *Parser::ParseOpenMPSizesClause() {
OpenLoc, CloseLoc);
}

OMPClause *Parser::ParseOpenMPPermutationClause() {
SourceLocation ClauseNameLoc, OpenLoc, CloseLoc;
SmallVector<Expr *> ArgExprs;
if (ParseOpenMPExprListClause(OMPC_permutation, ClauseNameLoc, OpenLoc,
CloseLoc, ArgExprs,
/*ReqIntConst=*/true))
return nullptr;

return Actions.OpenMP().ActOnOpenMPPermutationClause(ArgExprs, ClauseNameLoc,
OpenLoc, CloseLoc);
}

OMPClause *Parser::ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind) {
SourceLocation Loc = Tok.getLocation();
ConsumeAnyToken();
Expand Down Expand Up @@ -3377,6 +3389,14 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,

Clause = ParseOpenMPSizesClause();
break;
case OMPC_permutation:
if (!FirstClause) {
Diag(Tok, diag::err_omp_more_one_clause)
<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;
ErrorFound = true;
}
Clause = ParseOpenMPPermutationClause();
break;
case OMPC_uses_allocators:
Clause = ParseOpenMPUsesAllocatorClause(DKind);
break;
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
28 changes: 28 additions & 0 deletions clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2777,3 +2777,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);
}
51 changes: 40 additions & 11 deletions clang/lib/Sema/SemaAvailability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1005,25 +1005,54 @@ bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) {
return true;
}

struct ExtractedAvailabilityExpr {
const ObjCAvailabilityCheckExpr *E = nullptr;
bool isNegated = false;
};

ExtractedAvailabilityExpr extractAvailabilityExpr(const Expr *IfCond) {
const auto *E = IfCond;
bool IsNegated = false;
while (true) {
E = E->IgnoreParens();
if (const auto *AE = dyn_cast<ObjCAvailabilityCheckExpr>(E)) {
return ExtractedAvailabilityExpr{AE, IsNegated};
}

const auto *UO = dyn_cast<UnaryOperator>(E);
if (!UO || UO->getOpcode() != UO_LNot) {
return ExtractedAvailabilityExpr{};
}
E = UO->getSubExpr();
IsNegated = !IsNegated;
}
}

bool DiagnoseUnguardedAvailability::TraverseIfStmt(IfStmt *If) {
VersionTuple CondVersion;
if (auto *E = dyn_cast<ObjCAvailabilityCheckExpr>(If->getCond())) {
CondVersion = E->getVersion();

// If we're using the '*' case here or if this check is redundant, then we
// use the enclosing version to check both branches.
if (CondVersion.empty() || CondVersion <= AvailabilityStack.back())
return TraverseStmt(If->getThen()) && TraverseStmt(If->getElse());
} else {
ExtractedAvailabilityExpr IfCond = extractAvailabilityExpr(If->getCond());
if (!IfCond.E) {
// This isn't an availability checking 'if', we can just continue.
return Base::TraverseIfStmt(If);
}

VersionTuple CondVersion = IfCond.E->getVersion();
// If we're using the '*' case here or if this check is redundant, then we
// use the enclosing version to check both branches.
if (CondVersion.empty() || CondVersion <= AvailabilityStack.back()) {
return TraverseStmt(If->getThen()) && TraverseStmt(If->getElse());
}

auto *Guarded = If->getThen();
auto *Unguarded = If->getElse();
if (IfCond.isNegated) {
std::swap(Guarded, Unguarded);
}

AvailabilityStack.push_back(CondVersion);
bool ShouldContinue = TraverseStmt(If->getThen());
bool ShouldContinue = TraverseStmt(Guarded);
AvailabilityStack.pop_back();

return ShouldContinue && TraverseStmt(If->getElse());
return ShouldContinue && TraverseStmt(Unguarded);
}

} // end anonymous namespace
Expand Down
29 changes: 17 additions & 12 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.getInnermost()
: ArrayRef<TemplateArgument>{};
? TemplateArgsLists.getOutermost()
: ArrayRef<TemplateArgument> {};
Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
Sema::InstantiatingTemplate::ConstraintsCheck{},
const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange);
Expand Down Expand Up @@ -834,6 +834,7 @@ 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 @@ -909,13 +910,15 @@ 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) {
static unsigned
CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND,
bool SkipForSpecialization = false) {
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
ND, ND->getLexicalDeclContext(), /*Final=*/false,
/*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true,
/*ForConstraintInstantiation=*/true);
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true, SkipForSpecialization);
return MLTAL.getNumLevels();
}

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

if (MLTAL.getNumSubstitutedLevels() == 0)
return ConstrExpr;
Expand Down Expand Up @@ -1064,16 +1068,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(FTD && "Non-function templates don't need to be checked");
assert(FD->getDescribedFunctionTemplate() &&
"Non-function templates don't need to be checked");

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

unsigned OldTemplateDepth = FTD->getTemplateParameters()->getDepth();
unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
for (const Expr *Constraint : ACs)
if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth,
Constraint))
Expand Down Expand Up @@ -1520,6 +1524,7 @@ 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 @@ -1800,8 +1805,8 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
return false;
}

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

for (size_t I = 0; I != AC1.size() && I != AC2.size(); ++I) {
if (Depth2 > Depth1) {
Expand Down
31 changes: 17 additions & 14 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, NewTemplate->getTemplateParameters(),
OldTemplate, OldTemplate->getTemplateParameters(),
/*Complain=*/true, TPL_TemplateMatch))
if (NewTemplate &&
!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
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, IsMemberSpecialization);
IsPartialSpecialization);
if (Res.isInvalid())
return nullptr;
NewVD = cast<VarDecl>(Res.get());
Expand All @@ -7682,10 +7682,6 @@ 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 @@ -8063,6 +8059,12 @@ 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 @@ -9869,8 +9871,6 @@ 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,7 +12028,10 @@ 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) {
if (IsMemberSpecialization &&
NewTemplateDecl->getInstantiatedFromMemberTemplate()) {
NewTemplateDecl->setMemberSpecialization();
assert(OldTemplateDecl->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 @@ -17090,8 +17093,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.drop_back(),
isMemberSpecialization, SkipBody);
/*FriendLoc*/ SourceLocation(), TemplateParameterLists.size() - 1,
TemplateParameterLists.data(), 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.drop_back(),
IsMemberSpecialization)
FriendLoc, TempParamLists.size() - 1,
TempParamLists.data())
.get();
} else {
// The "template<>" header is extraneous.
Expand Down
12 changes: 11 additions & 1 deletion 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
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8429,7 +8429,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
QualType ObjectType;
QualType T;
TypeLocBuilder TLB;
if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc))
if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc) ||
DS.getTypeSpecType() == DeclSpec::TST_error)
return ExprError();

switch (DS.getTypeSpecType()) {
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
2 changes: 2 additions & 0 deletions 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
4 changes: 3 additions & 1 deletion clang/lib/Sema/SemaLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3666,7 +3666,9 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
TemplateArgumentLoc Arg(TemplateArgument(StringLit), StringLit);
if (CheckTemplateArgument(
Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(),
0, SugaredChecked, CanonicalChecked, CTAK_Specified) ||
0, SugaredChecked, CanonicalChecked, CTAK_Specified,
/*PartialOrdering=*/false,
/*MatchedPackOnParmToNonPackOnArg=*/nullptr) ||
Trap.hasErrorOccurred())
IsTemplate = false;
}
Expand Down
87 changes: 85 additions & 2 deletions clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14956,7 +14956,9 @@ StmtResult SemaOpenMP::ActOnOpenMPInterchangeDirective(
return StmtError();

// interchange without permutation clause swaps two loops.
constexpr size_t NumLoops = 2;
const OMPPermutationClause *PermutationClause =
OMPExecutableDirective::getSingleClause<OMPPermutationClause>(Clauses);
size_t NumLoops = PermutationClause ? PermutationClause->getNumLoops() : 2;

// Verify and diagnose loop nest.
SmallVector<OMPLoopBasedDirective::HelperExprs, 4> LoopHelpers(NumLoops);
Expand All @@ -14971,6 +14973,12 @@ StmtResult SemaOpenMP::ActOnOpenMPInterchangeDirective(
return OMPInterchangeDirective::Create(Context, StartLoc, EndLoc, Clauses,
NumLoops, AStmt, nullptr, nullptr);

// An invalid expression in the permutation clause is set to nullptr in
// ActOnOpenMPPermutationClause.
if (PermutationClause &&
llvm::is_contained(PermutationClause->getArgsRefs(), nullptr))
return StmtError();

assert(LoopHelpers.size() == NumLoops &&
"Expecting loop iteration space dimensionaly to match number of "
"affected loops");
Expand All @@ -14979,7 +14987,44 @@ StmtResult SemaOpenMP::ActOnOpenMPInterchangeDirective(
"affected loops");

// Decode the permutation clause.
constexpr uint64_t Permutation[] = {1, 0};
SmallVector<uint64_t, 2> Permutation;
if (!PermutationClause) {
Permutation = {1, 0};
} else {
ArrayRef<Expr *> PermArgs = PermutationClause->getArgsRefs();
llvm::BitVector Flags(PermArgs.size());
for (Expr *PermArg : PermArgs) {
std::optional<llvm::APSInt> PermCstExpr =
PermArg->getIntegerConstantExpr(Context);
if (!PermCstExpr)
continue;
uint64_t PermInt = PermCstExpr->getZExtValue();
assert(1 <= PermInt && PermInt <= NumLoops &&
"Must be a permutation; diagnostic emitted in "
"ActOnOpenMPPermutationClause");
if (Flags[PermInt - 1]) {
SourceRange ExprRange(PermArg->getBeginLoc(), PermArg->getEndLoc());
Diag(PermArg->getExprLoc(),
diag::err_omp_interchange_permutation_value_repeated)
<< PermInt << ExprRange;
continue;
}
Flags[PermInt - 1] = true;

Permutation.push_back(PermInt - 1);
}

if (Permutation.size() != NumLoops)
return StmtError();
}

// Nothing to transform with trivial permutation.
if (NumLoops <= 1 || llvm::all_of(llvm::enumerate(Permutation), [](auto P) {
auto [Idx, Arg] = P;
return Idx == Arg;
}))
return OMPInterchangeDirective::Create(Context, StartLoc, EndLoc, Clauses,
NumLoops, AStmt, AStmt, nullptr);

// Find the affected loops.
SmallVector<Stmt *> LoopStmts(NumLoops, nullptr);
Expand Down Expand Up @@ -16111,6 +16156,44 @@ OMPClause *SemaOpenMP::ActOnOpenMPSizesClause(ArrayRef<Expr *> SizeExprs,
SanitizedSizeExprs);
}

OMPClause *SemaOpenMP::ActOnOpenMPPermutationClause(ArrayRef<Expr *> PermExprs,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
size_t NumLoops = PermExprs.size();
SmallVector<Expr *> SanitizedPermExprs;
llvm::append_range(SanitizedPermExprs, PermExprs);

for (Expr *&PermExpr : SanitizedPermExprs) {
// Skip if template-dependent or already sanitized, e.g. during a partial
// template instantiation.
if (!PermExpr || PermExpr->isInstantiationDependent())
continue;

llvm::APSInt PermVal;
ExprResult PermEvalExpr = SemaRef.VerifyIntegerConstantExpression(
PermExpr, &PermVal, Sema::AllowFold);
bool IsValid = PermEvalExpr.isUsable();
if (IsValid)
PermExpr = PermEvalExpr.get();

if (IsValid && (PermVal < 1 || NumLoops < PermVal)) {
SourceRange ExprRange(PermEvalExpr.get()->getBeginLoc(),
PermEvalExpr.get()->getEndLoc());
Diag(PermEvalExpr.get()->getExprLoc(),
diag::err_omp_interchange_permutation_value_range)
<< NumLoops << ExprRange;
IsValid = false;
}

if (!PermExpr->isInstantiationDependent() && !IsValid)
PermExpr = nullptr;
}

return OMPPermutationClause::Create(getASTContext(), StartLoc, LParenLoc,
EndLoc, SanitizedPermExprs);
}

OMPClause *SemaOpenMP::ActOnOpenMPFullClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return OMPFullClause::Create(getASTContext(), StartLoc, EndLoc);
Expand Down
50 changes: 32 additions & 18 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6864,7 +6864,8 @@ void Sema::AddOverloadCandidate(
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
bool PartialOverloading, bool AllowExplicit, bool AllowExplicitConversions,
ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions,
OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction) {
OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction,
bool HasMatchedPackOnParmToNonPackOnArg) {
const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
assert(Proto && "Functions without a prototype cannot be overloaded");
Expand All @@ -6883,7 +6884,8 @@ void Sema::AddOverloadCandidate(
AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(),
Expr::Classification::makeSimpleLValue(), Args,
CandidateSet, SuppressUserConversions,
PartialOverloading, EarlyConversions, PO);
PartialOverloading, EarlyConversions, PO,
HasMatchedPackOnParmToNonPackOnArg);
return;
}
// We treat a constructor like a non-member function, since its object
Expand Down Expand Up @@ -6926,6 +6928,8 @@ void Sema::AddOverloadCandidate(
CandidateSet.getRewriteInfo().getRewriteKind(Function, PO);
Candidate.IsADLCandidate = IsADLCandidate;
Candidate.ExplicitCallArguments = Args.size();
Candidate.HasMatchedPackOnParmToNonPackOnArg =
HasMatchedPackOnParmToNonPackOnArg;

// Explicit functions are not actually candidates at all if we're not
// allowing them in this context, but keep them around so we can point
Expand Down Expand Up @@ -7453,16 +7457,13 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType,
}
}

void
Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
Expr::Classification ObjectClassification,
ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
bool SuppressUserConversions,
bool PartialOverloading,
ConversionSequenceList EarlyConversions,
OverloadCandidateParamOrder PO) {
void Sema::AddMethodCandidate(
CXXMethodDecl *Method, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
Expr::Classification ObjectClassification, ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
bool PartialOverloading, ConversionSequenceList EarlyConversions,
OverloadCandidateParamOrder PO, bool HasMatchedPackOnParmToNonPackOnArg) {
const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>());
assert(Proto && "Methods without a prototype cannot be overloaded");
Expand Down Expand Up @@ -7493,6 +7494,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
Candidate.TookAddressOfOverload =
CandidateSet.getKind() == OverloadCandidateSet::CSK_AddressOfOverloadSet;
Candidate.ExplicitCallArguments = Args.size();
Candidate.HasMatchedPackOnParmToNonPackOnArg =
HasMatchedPackOnParmToNonPackOnArg;

bool IgnoreExplicitObject =
(Method->isExplicitObjectMemberFunction() &&
Expand Down Expand Up @@ -7663,8 +7666,8 @@ void Sema::AddMethodTemplateCandidate(
ConversionSequenceList Conversions;
if (TemplateDeductionResult Result = DeduceTemplateArguments(
MethodTmpl, ExplicitTemplateArgs, Args, Specialization, Info,
PartialOverloading, /*AggregateDeductionCandidate=*/false, ObjectType,
ObjectClassification,
PartialOverloading, /*AggregateDeductionCandidate=*/false,
/*PartialOrdering=*/false, ObjectType, ObjectClassification,
[&](ArrayRef<QualType> ParamTypes) {
return CheckNonDependentConversions(
MethodTmpl, ParamTypes, Args, CandidateSet, Conversions,
Expand Down Expand Up @@ -7702,7 +7705,8 @@ void Sema::AddMethodTemplateCandidate(
AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl,
ActingContext, ObjectType, ObjectClassification, Args,
CandidateSet, SuppressUserConversions, PartialOverloading,
Conversions, PO);
Conversions, PO,
Info.hasMatchedPackOnParmToNonPackOnArg());
}

/// Determine whether a given function template has a simple explicit specifier
Expand Down Expand Up @@ -7748,6 +7752,7 @@ void Sema::AddTemplateOverloadCandidate(
if (TemplateDeductionResult Result = DeduceTemplateArguments(
FunctionTemplate, ExplicitTemplateArgs, Args, Specialization, Info,
PartialOverloading, AggregateCandidateDeduction,
/*PartialOrdering=*/false,
/*ObjectType=*/QualType(),
/*ObjectClassification=*/Expr::Classification(),
[&](ArrayRef<QualType> ParamTypes) {
Expand Down Expand Up @@ -7788,7 +7793,8 @@ void Sema::AddTemplateOverloadCandidate(
Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions,
PartialOverloading, AllowExplicit,
/*AllowExplicitConversions=*/false, IsADLCandidate, Conversions, PO,
Info.AggregateDeductionCandidateHasMismatchedArity);
Info.AggregateDeductionCandidateHasMismatchedArity,
Info.hasMatchedPackOnParmToNonPackOnArg());
}

bool Sema::CheckNonDependentConversions(
Expand Down Expand Up @@ -7910,7 +7916,8 @@ void Sema::AddConversionCandidate(
CXXConversionDecl *Conversion, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, Expr *From, QualType ToType,
OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
bool AllowExplicit, bool AllowResultConversion) {
bool AllowExplicit, bool AllowResultConversion,
bool HasMatchedPackOnParmToNonPackOnArg) {
assert(!Conversion->getDescribedFunctionTemplate() &&
"Conversion function templates use AddTemplateConversionCandidate");
QualType ConvType = Conversion->getConversionType().getNonReferenceType();
Expand Down Expand Up @@ -7955,6 +7962,8 @@ void Sema::AddConversionCandidate(
Candidate.FinalConversion.setAllToTypes(ToType);
Candidate.Viable = true;
Candidate.ExplicitCallArguments = 1;
Candidate.HasMatchedPackOnParmToNonPackOnArg =
HasMatchedPackOnParmToNonPackOnArg;

// Explicit functions are not actually candidates at all if we're not
// allowing them in this context, but keep them around so we can point
Expand Down Expand Up @@ -8156,7 +8165,8 @@ void Sema::AddTemplateConversionCandidate(
assert(Specialization && "Missing function template specialization?");
AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType,
CandidateSet, AllowObjCConversionOnExplicit,
AllowExplicit, AllowResultConversion);
AllowExplicit, AllowResultConversion,
Info.hasMatchedPackOnParmToNonPackOnArg());
}

void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
Expand Down Expand Up @@ -10509,6 +10519,10 @@ bool clang::isBetterOverloadCandidate(
isa<CXXConstructorDecl>(Cand2.Function))
return isa<CXXConstructorDecl>(Cand1.Function);

if (Cand1.HasMatchedPackOnParmToNonPackOnArg !=
Cand2.HasMatchedPackOnParmToNonPackOnArg)
return Cand2.HasMatchedPackOnParmToNonPackOnArg;

// -- F1 is a non-template function and F2 is a function template
// specialization, or, if not that,
bool Cand1IsSpecialization = Cand1.Function &&
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
312 changes: 156 additions & 156 deletions clang/lib/Sema/SemaTemplate.cpp

Large diffs are not rendered by default.

492 changes: 355 additions & 137 deletions clang/lib/Sema/SemaTemplateDeduction.cpp

Large diffs are not rendered by default.

66 changes: 47 additions & 19 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> InnerArgsForBuildingRC(
SmallVector<TemplateArgument> TemplateArgsForBuildingRC(
F->getTemplateParameters()->size());
// Transform the transformed template args
MultiLevelTemplateArgumentList Args;
Expand All @@ -778,30 +778,33 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
NamedDecl *TP = F->getTemplateParameters()->getParam(Index);
MultiLevelTemplateArgumentList Args;
Args.setKind(TemplateSubstitutionKind::Rewrite);
Args.addOuterTemplateArguments(InnerArgsForBuildingRC);
Args.addOuterTemplateArguments(TemplateArgsForBuildingRC);
// 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(InnerArgsForBuildingRC[Index].isNull());
InnerArgsForBuildingRC[Index] = Context.getInjectedTemplateArg(NewParam);
assert(TemplateArgsForBuildingRC[Index].isNull());
TemplateArgsForBuildingRC[Index] =
Context.getInjectedTemplateArg(NewParam);
continue;
}
TemplateArgumentLoc Input =
SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{});
TemplateArgumentLoc Output;
if (!SemaRef.SubstTemplateArgument(Input, Args, Output)) {
assert(InnerArgsForBuildingRC[Index].isNull() &&
assert(TemplateArgsForBuildingRC[Index].isNull() &&
"InstantiatedArgs must be null before setting");
InnerArgsForBuildingRC[Index] = Output.getArgument();
TemplateArgsForBuildingRC[Index] = Output.getArgument();
}
}

// A list of template arguments for transforming the require-clause using
// the transformed template arguments as the template argument list of F.
//
// 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);
// 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 @@ -824,15 +827,25 @@ 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.
MultiLevelTemplateArgumentList ArgsForBuildingRC =
SemaRef.getTemplateInstantiationArgs(F, F->getLexicalDeclContext(),
/*Final=*/false,
/*Innermost=*/InnerArgsForBuildingRC,
/*RelativeToPrimary=*/true,
/*ForConstraintInstantiation=*/true);
ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
// 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);
}

ExprResult E = SemaRef.SubstExpr(RC, ArgsForBuildingRC);
if (E.isInvalid())
Expand Down Expand Up @@ -1215,10 +1228,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
819 changes: 426 additions & 393 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp

Large diffs are not rendered by default.

71 changes: 14 additions & 57 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#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 @@ -231,7 +230,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 @@ -4686,36 +4688,6 @@ 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 @@ -4733,10 +4705,12 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
//
// template<typename T>
// A<T> Foo(int a = A<T>::FooImpl());
MultiLevelTemplateArgumentList TemplateArgs =
getTemplateInstantiationArgs(Pattern, Pattern->getLexicalDeclContext(),
/*Final=*/false, Innermost,
/*RelativeToPrimary=*/true);
MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
FD, FD->getLexicalDeclContext(),
/*Final=*/false, /*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true, /*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/false, /*SkipForSpecialization=*/false,
/*ForDefaultArgumentSubstitution=*/true);

if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
return true;
Expand Down Expand Up @@ -4777,7 +4751,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 @@ -5224,26 +5198,9 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
RebuildTypeSourceInfoForDefaultSpecialMembers();
SetDeclDefaulted(Function, PatternDecl->getLocation());
} else {
DeclContext *DC = Function;
MultiLevelTemplateArgumentList TemplateArgs;
if (auto *Primary = Function->getPrimaryTemplate();
Primary &&
!isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function)) {
auto It = llvm::find_if(Primary->redecls(),
[](const RedeclarableTemplateDecl *RTD) {
return cast<FunctionTemplateDecl>(RTD)
->isCompatibleWithDefinition();
});
assert(It != Primary->redecls().end() &&
"Should't get here without a definition");
DC = (*It)->getLexicalDeclContext();
if (Function->getTemplateSpecializationKind() !=
TSK_ExplicitSpecialization)
TemplateArgs.addOuterTemplateArguments(
Function, Function->getTemplateSpecializationArgs()->asArray(),
/*Final=*/false);
}
getTemplateInstantiationArgs(TemplateArgs, /*D=*/nullptr, DC);
MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
Function, Function->getLexicalDeclContext(), /*Final=*/false,
/*Innermost=*/std::nullopt, false, PatternDecl);

// Substitute into the qualifier; we can get a substitution failure here
// through evil use of alias templates.
Expand Down
35 changes: 35 additions & 0 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -1760,6 +1760,15 @@ class TreeTransform {
EndLoc);
}

/// Build a new OpenMP 'permutation' clause.
OMPClause *RebuildOMPPermutationClause(ArrayRef<Expr *> PermExprs,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
return getSema().OpenMP().ActOnOpenMPPermutationClause(PermExprs, StartLoc,
LParenLoc, EndLoc);
}

/// Build a new OpenMP 'full' clause.
OMPClause *RebuildOMPFullClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
Expand Down Expand Up @@ -10279,6 +10288,32 @@ OMPClause *TreeTransform<Derived>::TransformOMPSizesClause(OMPSizesClause *C) {
C->getLParenLoc(), C->getEndLoc());
}

template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPPermutationClause(OMPPermutationClause *C) {
SmallVector<Expr *> TransformedArgs;
TransformedArgs.reserve(C->getNumLoops());
bool Changed = false;
for (Expr *E : C->getArgsRefs()) {
if (!E) {
TransformedArgs.push_back(nullptr);
continue;
}

ExprResult T = getDerived().TransformExpr(E);
if (T.isInvalid())
return nullptr;
if (E != T.get())
Changed = true;
TransformedArgs.push_back(T.get());
}

if (!Changed && !getDerived().AlwaysRebuild())
return C;
return RebuildOMPPermutationClause(TransformedArgs, C->getBeginLoc(),
C->getLParenLoc(), C->getEndLoc());
}

template <typename Derived>
OMPClause *TreeTransform<Derived>::TransformOMPFullClause(OMPFullClause *C) {
if (!getDerived().AlwaysRebuild())
Expand Down
14 changes: 12 additions & 2 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10003,8 +10003,7 @@ void ASTReader::finishPendingActions() {

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

Expand Down Expand Up @@ -10605,6 +10604,11 @@ OMPClause *OMPClauseReader::readClause() {
C = OMPSizesClause::CreateEmpty(Context, NumSizes);
break;
}
case llvm::omp::OMPC_permutation: {
unsigned NumLoops = Record.readInt();
C = OMPPermutationClause::CreateEmpty(Context, NumLoops);
break;
}
case llvm::omp::OMPC_full:
C = OMPFullClause::CreateEmpty(Context);
break;
Expand Down Expand Up @@ -10993,6 +10997,12 @@ void OMPClauseReader::VisitOMPSizesClause(OMPSizesClause *C) {
C->setLParenLoc(Record.readSourceLocation());
}

void OMPClauseReader::VisitOMPPermutationClause(OMPPermutationClause *C) {
for (Expr *&E : C->getArgsRefs())
E = Record.readSubExpr();
C->setLParenLoc(Record.readSourceLocation());
}

void OMPClauseReader::VisitOMPFullClause(OMPFullClause *C) {}

void OMPClauseReader::VisitOMPPartialClause(OMPPartialClause *C) {
Expand Down
19 changes: 9 additions & 10 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1087,7 +1087,6 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FD->setHasImplicitReturnZero(FunctionDeclBits.getNextBit());
FD->setIsMultiVersion(FunctionDeclBits.getNextBit());
FD->setLateTemplateParsed(FunctionDeclBits.getNextBit());
FD->setInstantiatedFromMemberTemplate(FunctionDeclBits.getNextBit());
FD->setFriendConstraintRefersToEnclosingTemplate(
FunctionDeclBits.getNextBit());
FD->setUsesSEHTry(FunctionDeclBits.getNextBit());
Expand Down Expand Up @@ -2417,13 +2416,11 @@ 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->getCommonPtrInternal()) {
CanonD->setCommonPtr(CanonD->newCommon(Reader.getContext()));
if (!CanonD->Common) {
CanonD->Common = CanonD->newCommon(Reader.getContext());
Reader.PendingDefinitions.insert(CanonD);
}
D->setCommonPtr(CanonD->getCommonPtrInternal());
if (Record.readInt())
D->setMemberSpecialization();
D->Common = CanonD->Common;

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

Expand Down Expand Up @@ -2563,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>());
readDeclAs<ClassTemplatePartialSpecializationDecl>());
D->InstantiatedFromMember.setInt(Record.readInt());
}
}

Expand Down Expand Up @@ -2661,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 @@ -2889,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->setCommonPtr(D->getCanonicalDecl()->getCommonPtrInternal());
D->Common = D->getCanonicalDecl()->Common;
}

/// "Cast" to type T, asserting if we don't have an implicit conversion.
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7188,6 +7188,13 @@ void OMPClauseWriter::VisitOMPSizesClause(OMPSizesClause *C) {
Record.AddSourceLocation(C->getLParenLoc());
}

void OMPClauseWriter::VisitOMPPermutationClause(OMPPermutationClause *C) {
Record.push_back(C->getNumLoops());
for (Expr *Size : C->getArgsRefs())
Record.AddStmt(Size);
Record.AddSourceLocation(C->getLParenLoc());
}

void OMPClauseWriter::VisitOMPFullClause(OMPFullClause *C) {}

void OMPClauseWriter::VisitOMPPartialClause(OMPPartialClause *C) {
Expand Down
20 changes: 11 additions & 9 deletions clang/lib/Serialization/ASTWriterDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ void ASTDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) {
}

void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
static_assert(DeclContext::NumFunctionDeclBits == 45,
static_assert(DeclContext::NumFunctionDeclBits == 44,
"You need to update the serializer after you change the "
"FunctionDeclBits");

Expand Down Expand Up @@ -732,7 +732,6 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
FunctionDeclBits.addBit(D->hasImplicitReturnZero());
FunctionDeclBits.addBit(D->isMultiVersion());
FunctionDeclBits.addBit(D->isLateTemplateParsed());
FunctionDeclBits.addBit(D->isInstantiatedFromMemberTemplate());
FunctionDeclBits.addBit(D->FriendConstraintRefersToEnclosingTemplate());
FunctionDeclBits.addBit(D->usesSEHTry());
Record.push_back(FunctionDeclBits);
Expand Down Expand Up @@ -1714,13 +1713,14 @@ 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,10 +1806,11 @@ void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(

VisitClassTemplateSpecializationDecl(D);

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

Code = serialization::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION;
}
Expand Down Expand Up @@ -1873,11 +1874,12 @@ 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->isFirstDecl())
if (D->getPreviousDecl() == nullptr) {
Record.AddDeclRef(D->getInstantiatedFromMember());
Record.push_back(D->isMemberSpecialization());
}

Code = serialization::DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION;
}
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
4 changes: 4 additions & 0 deletions clang/test/AST/ByteCode/codegen.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s -fexperimental-new-constant-interpreter | FileCheck %s

#ifdef __SIZEOF_INT128__
// CHECK: @PR11705 = global i128 0
__int128_t PR11705 = (__int128_t)&PR11705;
#endif

int arr[2];
// CHECK: @pastEnd = constant ptr getelementptr (i8, ptr @arr, i64 8)
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
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
36 changes: 36 additions & 0 deletions clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,20 @@ class ObjectWithMutatingDestructor {
Number n;
};

class BaseType {
public:
BaseType() : n(0) { }
BaseType(int v) : n(v) { }
BaseType(const char*);
private:
Number n;
};

class SomeType : public BaseType {
public:
using BaseType::BaseType;
};

class RefCounted {
public:
void ref() const;
Expand Down Expand Up @@ -336,6 +350,8 @@ class RefCounted {
unsigned trivial60() { return ObjectWithNonTrivialDestructor { 5 }.value(); }
unsigned trivial61() { return DerivedNumber('7').value(); }
void trivial62() { WTFReportBacktrace(); }
SomeType trivial63() { return SomeType(0); }
SomeType trivial64() { return SomeType(); }

static RefCounted& singleton() {
static RefCounted s_RefCounted;
Expand Down Expand Up @@ -425,6 +441,7 @@ class RefCounted {
unsigned nonTrivial21() { return Number("123").value(); }
unsigned nonTrivial22() { return ComplexNumber(123, "456").real().value(); }
unsigned nonTrivial23() { return DerivedNumber("123").value(); }
SomeType nonTrivial24() { return SomeType("123"); }

static unsigned s_v;
unsigned v { 0 };
Expand Down Expand Up @@ -515,6 +532,8 @@ class UnrelatedClass {
getFieldTrivial().trivial60(); // no-warning
getFieldTrivial().trivial61(); // no-warning
getFieldTrivial().trivial62(); // no-warning
getFieldTrivial().trivial63(); // no-warning
getFieldTrivial().trivial64(); // no-warning

RefCounted::singleton().trivial18(); // no-warning
RefCounted::singleton().someFunction(); // no-warning
Expand Down Expand Up @@ -587,7 +606,11 @@ class UnrelatedClass {
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial23();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial24();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
}

void setField(RefCounted*);
};

class UnrelatedClass2 {
Expand All @@ -598,11 +621,24 @@ class UnrelatedClass2 {
RefCounted &getFieldTrivialRecursively() { return getFieldTrivial().getFieldTrivial(); }
RefCounted *getFieldTrivialTernary() { return Field ? Field->getFieldTernary() : nullptr; }

template<typename T, typename ... AdditionalArgs>
void callSetField(T&& item, AdditionalArgs&&... args)
{
item.setField(std::forward<AdditionalArgs>(args)...);
}

template<typename T, typename ... AdditionalArgs>
void callSetField2(T&& item, AdditionalArgs&&... args)
{
item.setField(std::move<AdditionalArgs>(args)...);
}

void test() {
getFieldTrivialRecursively().trivial1(); // no-warning
getFieldTrivialTernary()->trivial2(); // no-warning
getFieldTrivialRecursively().someFunction();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
callSetField(getFieldTrivial(), refCountedObj()); // no-warning
}
};

Expand Down
5 changes: 5 additions & 0 deletions clang/test/CIR/hello.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s | FileCheck --allow-empty %s

// just confirm that we don't crash
// CHECK-NOT: *
void foo() {}
2 changes: 2 additions & 0 deletions clang/test/CIR/lit.local.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
if not config.root.clang_enable_cir:
config.unsupported = True
122 changes: 121 additions & 1 deletion clang/test/CXX/special/class.temporary/p6.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,80 @@ template void default_arg_dependent_context2<int>();
template void default_arg_dependent_context3<int>();
} // namespace default_arg

namespace default_init {
template <class T>
struct DepA {
T arr[1];
~DepA() {}
};

template <class T>
struct DepB {
int x;
const DepA<T> &a = DepA<T>{{0}};
~DepB() {}
const int *begin() { return a.arr; }
const int *end() { return &a.arr[1]; }
};

template <typename T>
void default_init1_dependent() {
// CHECK-CXX23: void @_ZN7P2718R012default_init23default_init1_dependentINS0_4DepBIiEEEEvv()
// CHECK-CXX23-LABEL: for.cond.cleanup:
// CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init4DepBIiED1Ev(
// CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init4DepAIiED1Ev(
for (auto &&x : T{0}) {}
}

template <typename T>
void default_init2_dependent() {
// CHECK-CXX23: void @_ZN7P2718R012default_init23default_init2_dependentINS0_4DepBIiEEEEvv()
// CHECK-CXX23-LABEL: for.cond.cleanup:
// CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init4DepBIiED1Ev(
// CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init4DepAIiED1Ev(
for (auto &&x : T{0}.a.arr) {}
}

template void default_init1_dependent<DepB<int>>();
template void default_init2_dependent<DepB<int>>();
} // namespace default_init

// -- Examples from https://wg21.link/p2718r0
extern void block_scope_begin_function();
extern void block_scope_end_function();
namespace std_examples {
using T = std::list<int>;
const T& f1(const T& t) { return t; }
const T& f2(T t) { return t; }
T g();
void foo() {
// CHECK-CXX23: define {{.*}} void @_ZN7P2718R012std_examples3fooEv()
// CHECK-CXX23: call void @_ZN7P2718R026block_scope_begin_functionEv
block_scope_begin_function();
{
// CHECK-CXX23-NEXT: call void @_ZN7P2718R012std_examples1gEv
// CHECK-CXX23-NEXT: call {{.*}} @_ZN7P2718R012std_examples2f1ERKSt4listIiE
// CHECK-CXX23: for.cond.cleanup:
// CHECK-CXX23-NEXT: call void @_ZNSt4listIiED1Ev
for (auto e : f1(g())) {} // OK, lifetime of return value of g() extended
}
// CHECK-CXX23: call void @_ZN7P2718R024block_scope_end_functionEv
block_scope_end_function();

// The lifetime of temporary returned by g() in this case will not be extended.
// CHECK-CXX23: call void @_ZN7P2718R026block_scope_begin_functionEv
block_scope_begin_function();
{
// CHECK-CXX23-NEXT: call void @_ZN7P2718R012std_examples1gEv
// CHECK-CXX23-NEXT: call {{.*}} @_ZN7P2718R012std_examples2f2ESt4listIiE
// CHECK-CXX23-NEXT: call void @_ZNSt4listIiED1Ev
for (auto e : f2(g())) {} // undefined behavior
}
// CHECK-CXX23: call void @_ZN7P2718R024block_scope_end_functionEv
block_scope_end_function();
}
} // namespace std_examples

namespace basic {
using T = std::list<int>;
const T& f1(const T& t) { return t; }
Expand Down Expand Up @@ -579,5 +653,51 @@ void default_arg3() {
for (auto e : C(0, C(0, C(0, C())))) {}
}
} // namespace default_arg
} // namespace P2718R0

namespace default_init {
struct X {
int x;
~X() {}
};

struct Y {
int y;
const X &x = X{1};
~Y() {}
};

struct A {
int arr[1];
const Y &y = Y{1};
~A() {}
};

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

void default_init1() {
// CHECK-CXX23: void @_ZN7P2718R012default_init13default_init1Ev()
// CHECK-CXX23-LABEL: for.cond.cleanup:
// CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1BD1Ev(
// CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1AD1Ev(
// CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1YD1Ev(
// CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1XD1Ev(
for (auto &&x : B{0}) {}
}

void default_init2() {
// CHECK-CXX23: void @_ZN7P2718R012default_init13default_init2Ev()
// CHECK-CXX23-LABEL: for.cond.cleanup:
// CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1BD1Ev(
// CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1AD1Ev(
// CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1YD1Ev(
// CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1XD1Ev(
for (auto &&x : B{0}.a.arr) {}
}
} // namespace default_init
} // namespace P2718R0
31 changes: 18 additions & 13 deletions clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

template <class T> struct eval; // expected-note 3{{template is declared here}}

template <template <class, class...> class TT, class T1, class... Rest>
template <template <class, class...> class TT, class T1, class... Rest>
struct eval<TT<T1, Rest...>> { };

template <class T1> struct A;
template <class T1, class T2> struct B;
template <int N> struct C;
template <class T1, int N> struct D;
template <class T1> struct A;
template <class T1, class T2> struct B;
template <int N> struct C;
template <class T1, int N> struct D;
template <class T1, class T2, int N = 17> struct E;

eval<A<int>> eA;
Expand All @@ -17,27 +17,32 @@ eval<C<17>> eC; // expected-error{{implicit instantiation of undefined template
eval<D<int, 17>> eD; // expected-error{{implicit instantiation of undefined template 'eval<D<int, 17>>'}}
eval<E<int, float>> eE; // expected-error{{implicit instantiation of undefined template 'eval<E<int, float>>}}

template<template <int ...N> class TT> struct X0 { }; // expected-note{{previous non-type template parameter with type 'int' is here}}
template<
template <int ...N> // expected-error{{deduced non-type template argument does not have the same type as the corresponding template parameter ('int' vs 'long')}}
class TT // expected-note {{previous template template parameter is here}}
> struct X0 { };

template<int I, int J, int ...Rest> struct X0a;
template<int ...Rest> struct X0b;
template<int I, long J> struct X0c; // expected-note{{template non-type parameter has a different type 'long' in template argument}}
template<int I, long J> struct X0c; // expected-note{{template parameter is declared here}}

X0<X0a> inst_x0a;
X0<X0b> inst_x0b;
X0<X0c> inst_x0c; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}}
X0<X0c> inst_x0c; // expected-note{{template template argument has different template parameters than its corresponding template template parameter}}

template<typename T,
template <T ...N> class TT> // expected-note{{previous non-type template parameter with type 'short' is here}}
struct X1 { };
template<typename T,
template <T ...N> // expected-error{{deduced non-type template argument does not have the same type as the corresponding template parameter ('short' vs 'long')}}
class TT // expected-note {{previous template template parameter is here}}
> struct X1 { };
template<int I, int J, int ...Rest> struct X1a;
template<long I, long ...Rest> struct X1b;
template<short I, short J> struct X1c;
template<short I, long J> struct X1d; // expected-note{{template non-type parameter has a different type 'long' in template argument}}
template<short I, long J> struct X1d; // expected-note{{template parameter is declared here}}

X1<int, X1a> inst_x1a;
X1<long, X1b> inst_x1b;
X1<short, X1c> inst_x1c;
X1<short, X1d> inst_x1d; // expected-error{{template template argument has different template parameters than its corresponding template template paramete}}
X1<short, X1d> inst_x1d; // expected-note{{template template argument has different template parameters than its corresponding template template parameter}}

template <int> class X2; // expected-note{{template is declared here}} \
// expected-note{{template is declared here}}
Expand Down
175 changes: 0 additions & 175 deletions clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp

This file was deleted.

21 changes: 11 additions & 10 deletions clang/test/CXX/temp/temp.param/p12.cpp
Original file line number Diff line number Diff line change
@@ -1,39 +1,40 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
template<typename> struct Y1; // expected-note{{too few template parameters in template template argument}}
// RUN: %clang_cc1 -fsyntax-only -verify %s
template<typename> struct Y1; // expected-note{{template is declared here}}
template<typename, int> struct Y2;

// C++ [temp.param]p12:
template<class T1,
template<class T1,
class T2 = int> // expected-note{{previous default template argument defined here}}
class B3;
template<class T1, typename T2> class B3;
template<class T1,
template<class T1,
typename T2 = float> // expected-error{{template parameter redefines default argument}}
class B3;

template<template<class, int> class,
template<template<class, int> class,
template<class> class = Y1> // expected-note{{previous default template argument defined here}}
class B3t;

template<template<class, int> class, template<class> class> class B3t;

template<template<class, int> class,
template<template<class, int> class,
template<class> class = Y1> // expected-error{{template parameter redefines default argument}}
class B3t;

template<int N,
template<int N,
int M = 5> // expected-note{{previous default template argument defined here}}
class B3n;

template<int N, int M> class B3n;

template<int N,
template<int N,
int M = 7> // expected-error{{template parameter redefines default argument}}
class B3n;

// Check validity of default arguments
template<template<class, int> class // expected-note{{previous template template parameter is here}}
= Y1> // expected-error{{template template argument has different template parameters than its corresponding template template parameter}}
template<template<class, int> class =// expected-note {{previous template template parameter is here}}
Y1> // expected-error{{too many template arguments for class template 'Y1'}}
// expected-note@-1 {{template template argument has different template parameters than its corresponding template template parameter}}
class C1 {};

C1<> c1; // expected-note{{while checking a default template argument}}
178 changes: 0 additions & 178 deletions clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp

This file was deleted.

9 changes: 9 additions & 0 deletions clang/test/CodeGen/X86/sse-builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -948,6 +948,15 @@ void test_constexpr() {
constexpr __m128 v_mm_movelh_ps = _mm_movelh_ps(k1, k2);
static_assert(v_mm_movelh_ps[0] == +1.0f && v_mm_movelh_ps[1] == +0.0f && v_mm_movelh_ps[2] == +8.0f && v_mm_movelh_ps[3] == +4.0f);

constexpr __m128 v_mm_cvtsi32_ss = _mm_cvtsi32_ss(k1, 42);
static_assert(v_mm_cvtsi32_ss[0] == 42.0f && v_mm_cvtsi32_ss[1] == +0.0f && v_mm_cvtsi32_ss[2] == +2.0f && v_mm_cvtsi32_ss[3] == +4.0f);

constexpr __m128 v_mm_cvt_si2ss = _mm_cvt_si2ss(k2, -99);
static_assert(v_mm_cvt_si2ss[0] == -99.0f && v_mm_cvt_si2ss[1] == +4.0f && v_mm_cvt_si2ss[2] == +2.0f && v_mm_cvt_si2ss[3] == +1.0f);

constexpr __m128 v_mm_cvtsi64_ss = _mm_cvtsi64_ss(k3, 555);
static_assert(v_mm_cvtsi64_ss[0] == 555.0f && v_mm_cvtsi64_ss[1] == -5.0f && v_mm_cvtsi64_ss[2] == +6.0f && v_mm_cvtsi64_ss[3] == +7.0f);

static_assert(_mm_cvtss_f32(k2) == +8.0f);
}

Expand Down
95 changes: 95 additions & 0 deletions clang/test/CodeGen/X86/sse2-builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -1783,11 +1783,106 @@ __m128i test_mm_xor_si128(__m128i A, __m128i B) {
#if defined(__cplusplus) && (__cplusplus >= 201103L)

void test_constexpr() {
constexpr __m128d kd1 {+2.0,-1.0};
constexpr __m128d kd2 {-4.0,-2.0};
constexpr __m128d kd3 {-0.0,+0.0};

constexpr __m128 kf1 {-1.0f,+2.0f,-3.0f,+4.0f};

constexpr __m64 km1 {0x00000080FFFFFFF0ULL}; // -16,+128
constexpr __m128i ki1 {0x00000010FFFFFFF8ULL, 0x00000001FFFFFFFFULL}; // -8,+16,-1,1

constexpr __m128d v_mm_set_sd = _mm_set_sd(1.0);
static_assert(v_mm_set_sd[0] == +1.0 && v_mm_set_sd[1] == +0.0);

constexpr __m128d v_mm_set1_pd = _mm_set1_pd(2.0);
static_assert(v_mm_set1_pd[0] == +2.0 && v_mm_set1_pd[1] == +2.0);

constexpr __m128d v_mm_set_pd1 = _mm_set_pd1(-2.0);
static_assert(v_mm_set_pd1[0] == -2.0 && v_mm_set_pd1[1] == -2.0);

constexpr __m128d v_mm_set_pd = _mm_set_pd(+2.0, +3.0);
static_assert(v_mm_set_pd[0] == +3.0 && v_mm_set_pd[1] == +2.0);

constexpr __m128d v_mm_setr_pd = _mm_setr_pd(+2.0, +3.0);
static_assert(v_mm_setr_pd[0] == +2.0 && v_mm_setr_pd[1] == +3.0);

constexpr __m128d v_mm_setzero_pd = _mm_setzero_pd();
static_assert(v_mm_setzero_pd[0] == +0.0 && v_mm_setzero_pd[1] == +0.0);

constexpr __m128i v_mm_setzero_si128 = _mm_setzero_si128();
static_assert(v_mm_setzero_si128[0] == 0x0000000000000000ULL && v_mm_setzero_si128[1] == 0x0000000000000000ULL);

constexpr __m128d v_mm_add_sd = _mm_add_sd(kd1, kd2);
static_assert(v_mm_add_sd[0] == -2.0 && v_mm_add_sd[1] == -1.0);

constexpr __m128d v_mm_add_pd = _mm_add_pd(kd1, kd2);
static_assert(v_mm_add_pd[0] == -2.0 && v_mm_add_pd[1] == -3.0);

constexpr __m128d v_mm_sub_sd = _mm_sub_sd(kd1, kd2);
static_assert(v_mm_sub_sd[0] == +6.0 && v_mm_sub_sd[1] == -1.0);

constexpr __m128d v_mm_sub_pd = _mm_sub_pd(kd1, kd2);
static_assert(v_mm_sub_pd[0] == +6.0 && v_mm_sub_pd[1] == +1.0);

constexpr __m128d v_mm_mul_sd = _mm_mul_sd(kd1, kd2);
static_assert(v_mm_mul_sd[0] == -8.0 && v_mm_mul_sd[1] == -1.0);

constexpr __m128d v_mm_mul_pd = _mm_mul_pd(kd1, kd2);
static_assert(v_mm_mul_pd[0] == -8.0 && v_mm_mul_pd[1] == +2.0);

constexpr __m128d v_mm_div_sd = _mm_div_sd(kd1, kd2);
static_assert(v_mm_div_sd[0] == -0.5 && v_mm_div_sd[1] == -1.0);

constexpr __m128d v_mm_div_pd = _mm_div_pd(kd1, kd2);
static_assert(v_mm_div_pd[0] == -0.5 && v_mm_div_pd[1] == +0.5);

constexpr __m128d v_mm_and_pd = _mm_and_pd(kd1, kd3);
static_assert(v_mm_and_pd[0] == +0.0 && v_mm_and_pd[1] == +0.0);

constexpr __m128d v_mm_andnot_pd = _mm_andnot_pd(kd1, kd3);
static_assert(v_mm_andnot_pd[0] == -0.0 && v_mm_andnot_pd[1] == +0.0);

constexpr __m128d v_mm_or_pd = _mm_or_pd(kd1, kd3);
static_assert(v_mm_or_pd[0] == -2.0 && v_mm_or_pd[1] == -1.0);

constexpr __m128d v_mm_xor_pd = _mm_xor_pd(kd2, kd3);
static_assert(v_mm_xor_pd[0] == +4.0 && v_mm_xor_pd[1] == -2.0);

constexpr __m128d v_mm_cvtps_pd = _mm_cvtps_pd(kf1);
static_assert(v_mm_cvtps_pd[0] == -1.0 && v_mm_cvtps_pd[1] == +2.0);

constexpr __m128d v_mm_cvtepi32_pd = _mm_cvtepi32_pd(ki1);
static_assert(v_mm_cvtepi32_pd[0] == -8.0 && v_mm_cvtepi32_pd[1] == +16.0);

constexpr __m128 v_mm_cvtepi32_ps = _mm_cvtepi32_ps(ki1);
static_assert(v_mm_cvtepi32_ps[0] == -8.0f && v_mm_cvtepi32_ps[1] == +16.0f && v_mm_cvtepi32_ps[2] == -1.0f && v_mm_cvtepi32_ps[3] == +1.0f);

constexpr __m128d v_mm_cvtsi32_sd = _mm_cvtsi32_sd(kd1, 8);
static_assert(v_mm_cvtsi32_sd[0] == +8.0 && v_mm_cvtsi32_sd[1] == -1.0);

constexpr __m128d v_mm_cvtss_sd = _mm_cvtss_sd(kd2, kf1);
static_assert(v_mm_cvtss_sd[0] == -1.0 && v_mm_cvtss_sd[1] == -2.0);

constexpr __m128d v_mm_cvtpi32_pd = _mm_cvtpi32_pd(km1);
static_assert(v_mm_cvtpi32_pd[0] == -16.0 && v_mm_cvtpi32_pd[1] == 128.0);

static_assert(_mm_cvtsd_f64(kd2) == -4.0);

constexpr __m128d v_mm_move_sd = _mm_move_sd(kd1, kd2);
static_assert(v_mm_move_sd[0] == -4.0 && v_mm_move_sd[1] == -1.0);

constexpr __m128d v_mm_unpackhi_pd = _mm_unpackhi_pd(kd1, kd2);
static_assert(v_mm_unpackhi_pd[0] == -1.0f && v_mm_unpackhi_pd[1] == -2.0f);

constexpr __m128d v_mm_unpacklo_pd = _mm_unpacklo_pd(kd1, kd2);
static_assert(v_mm_unpacklo_pd[0] == +2.0f && v_mm_unpacklo_pd[1] == -4.0f);

constexpr __m128 v_mm_castpd_ps = _mm_castpd_ps(kd3);
static_assert(v_mm_castpd_ps[0] == -0.0f && v_mm_castpd_ps[1] == +0.0f && v_mm_castpd_ps[2] == +0.0f && v_mm_castpd_ps[3] == +0.0f);

constexpr __m128i v_mm_castpd_si128 = _mm_castpd_si128(kd3);
static_assert(v_mm_castpd_si128[0] == 0x8000000000000000ULL && v_mm_castpd_si128[1] == 0x0000000000000000ULL);
}

#endif
Loading