157 changes: 112 additions & 45 deletions clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1313,6 +1313,44 @@ llvm::DIType *CGDebugInfo::CreateType(const BlockPointerType *Ty,
return DBuilder.createPointerType(EltTy, Size);
}

static llvm::SmallVector<TemplateArgument>
GetTemplateArgs(const TemplateDecl *TD, const TemplateSpecializationType *Ty) {
assert(Ty->isTypeAlias());
// TemplateSpecializationType doesn't know if its template args are
// being substituted into a parameter pack. We can find out if that's
// the case now by inspecting the TypeAliasTemplateDecl template
// parameters. Insert Ty's template args into SpecArgs, bundling args
// passed to a parameter pack into a TemplateArgument::Pack. It also
// doesn't know the value of any defaulted args, so collect those now
// too.
SmallVector<TemplateArgument> SpecArgs;
ArrayRef SubstArgs = Ty->template_arguments();
for (const NamedDecl *Param : TD->getTemplateParameters()->asArray()) {
// If Param is a parameter pack, pack the remaining arguments.
if (Param->isParameterPack()) {
SpecArgs.push_back(TemplateArgument(SubstArgs));
break;
}

// Skip defaulted args.
// FIXME: Ideally, we wouldn't do this. We can read the default values
// for each parameter. However, defaulted arguments which are dependent
// values or dependent types can't (easily?) be resolved here.
if (SubstArgs.empty()) {
// If SubstArgs is now empty (we're taking from it each iteration) and
// this template parameter isn't a pack, then that should mean we're
// using default values for the remaining template parameters (after
// which there may be an empty pack too which we will ignore).
break;
}

// Take the next argument.
SpecArgs.push_back(SubstArgs.front());
SubstArgs = SubstArgs.drop_front();
}
return SpecArgs;
}

llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty,
llvm::DIFile *Unit) {
assert(Ty->isTypeAlias());
Expand All @@ -1332,6 +1370,31 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty,
auto PP = getPrintingPolicy();
Ty->getTemplateName().print(OS, PP, TemplateName::Qualified::None);

SourceLocation Loc = AliasDecl->getLocation();

if (CGM.getCodeGenOpts().DebugTemplateAlias) {
auto ArgVector = ::GetTemplateArgs(TD, Ty);
TemplateArgs Args = {TD->getTemplateParameters(), ArgVector};

// FIXME: Respect DebugTemplateNameKind::Mangled, e.g. by using GetName.
// Note we can't use GetName without additional work: TypeAliasTemplateDecl
// doesn't have instantiation information, so
// TypeAliasTemplateDecl::getNameForDiagnostic wouldn't have access to the
// template args.
std::string Name;
llvm::raw_string_ostream OS(Name);
TD->getNameForDiagnostic(OS, PP, /*Qualified=*/false);
if (CGM.getCodeGenOpts().getDebugSimpleTemplateNames() !=
llvm::codegenoptions::DebugTemplateNamesKind::Simple ||
!HasReconstitutableArgs(Args.Args))
printTemplateArgumentList(OS, Args.Args, PP);

llvm::DIDerivedType *AliasTy = DBuilder.createTemplateAlias(
Src, Name, getOrCreateFile(Loc), getLineNumber(Loc),
getDeclContextDescriptor(AliasDecl), CollectTemplateParams(Args, Unit));
return AliasTy;
}

// Disable PrintCanonicalTypes here because we want
// the DW_AT_name to benefit from the TypePrinter's ability
// to skip defaulted template arguments.
Expand All @@ -1343,8 +1406,6 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty,
PP.PrintCanonicalTypes = false;
printTemplateArgumentList(OS, Ty->template_arguments(), PP,
TD->getTemplateParameters());

SourceLocation Loc = AliasDecl->getLocation();
return DBuilder.createTypedef(Src, OS.str(), getOrCreateFile(Loc),
getLineNumber(Loc),
getDeclContextDescriptor(AliasDecl));
Expand Down Expand Up @@ -5363,6 +5424,54 @@ static bool IsReconstitutableType(QualType QT) {
return T.Reconstitutable;
}

bool CGDebugInfo::HasReconstitutableArgs(
ArrayRef<TemplateArgument> Args) const {
return llvm::all_of(Args, [&](const TemplateArgument &TA) {
switch (TA.getKind()) {
case TemplateArgument::Template:
// Easy to reconstitute - the value of the parameter in the debug
// info is the string name of the template. The template name
// itself won't benefit from any name rebuilding, but that's a
// representational limitation - maybe DWARF could be
// changed/improved to use some more structural representation.
return true;
case TemplateArgument::Declaration:
// Reference and pointer non-type template parameters point to
// variables, functions, etc and their value is, at best (for
// variables) represented as an address - not a reference to the
// DWARF describing the variable/function/etc. This makes it hard,
// possibly impossible to rebuild the original name - looking up
// the address in the executable file's symbol table would be
// needed.
return false;
case TemplateArgument::NullPtr:
// These could be rebuilt, but figured they're close enough to the
// declaration case, and not worth rebuilding.
return false;
case TemplateArgument::Pack:
// A pack is invalid if any of the elements of the pack are
// invalid.
return HasReconstitutableArgs(TA.getPackAsArray());
case TemplateArgument::Integral:
// Larger integers get encoded as DWARF blocks which are a bit
// harder to parse back into a large integer, etc - so punting on
// this for now. Re-parsing the integers back into APInt is
// probably feasible some day.
return TA.getAsIntegral().getBitWidth() <= 64 &&
IsReconstitutableType(TA.getIntegralType());
case TemplateArgument::StructuralValue:
return false;
case TemplateArgument::Type:
return IsReconstitutableType(TA.getAsType());
case TemplateArgument::Expression:
return IsReconstitutableType(TA.getAsExpr()->getType());
default:
llvm_unreachable("Other, unresolved, template arguments should "
"not be seen here");
}
});
}

std::string CGDebugInfo::GetName(const Decl *D, bool Qualified) const {
std::string Name;
llvm::raw_string_ostream OS(Name);
Expand All @@ -5389,49 +5498,7 @@ std::string CGDebugInfo::GetName(const Decl *D, bool Qualified) const {
} else if (auto *VD = dyn_cast<VarDecl>(ND)) {
Args = GetTemplateArgs(VD);
}
std::function<bool(ArrayRef<TemplateArgument>)> HasReconstitutableArgs =
[&](ArrayRef<TemplateArgument> Args) {
return llvm::all_of(Args, [&](const TemplateArgument &TA) {
switch (TA.getKind()) {
case TemplateArgument::Template:
// Easy to reconstitute - the value of the parameter in the debug
// info is the string name of the template. (so the template name
// itself won't benefit from any name rebuilding, but that's a
// representational limitation - maybe DWARF could be
// changed/improved to use some more structural representation)
return true;
case TemplateArgument::Declaration:
// Reference and pointer non-type template parameters point to
// variables, functions, etc and their value is, at best (for
// variables) represented as an address - not a reference to the
// DWARF describing the variable/function/etc. This makes it hard,
// possibly impossible to rebuild the original name - looking up the
// address in the executable file's symbol table would be needed.
return false;
case TemplateArgument::NullPtr:
// These could be rebuilt, but figured they're close enough to the
// declaration case, and not worth rebuilding.
return false;
case TemplateArgument::Pack:
// A pack is invalid if any of the elements of the pack are invalid.
return HasReconstitutableArgs(TA.getPackAsArray());
case TemplateArgument::Integral:
// Larger integers get encoded as DWARF blocks which are a bit
// harder to parse back into a large integer, etc - so punting on
// this for now. Re-parsing the integers back into APInt is probably
// feasible some day.
return TA.getAsIntegral().getBitWidth() <= 64 &&
IsReconstitutableType(TA.getIntegralType());
case TemplateArgument::StructuralValue:
return false;
case TemplateArgument::Type:
return IsReconstitutableType(TA.getAsType());
default:
llvm_unreachable("Other, unresolved, template arguments should "
"not be seen here");
}
});
};

// A conversion operator presents complications/ambiguity if there's a
// conversion to class template that is itself a template, eg:
// template<typename T>
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CGDebugInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,8 @@ class CGDebugInfo {
llvm::DIType *WrappedType;
};

std::string GetName(const Decl*, bool Qualified = false) const;
bool HasReconstitutableArgs(ArrayRef<TemplateArgument> Args) const;
std::string GetName(const Decl *, bool Qualified = false) const;

/// Build up structure info for the byref. See \a BuildByRefType.
BlockByRefType EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4632,6 +4632,21 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T,
}
}

// Emit DW_TAG_template_alias for template aliases? True by default for SCE.
bool UseDebugTemplateAlias =
DebuggerTuning == llvm::DebuggerKind::SCE && RequestedDWARFVersion >= 5;
if (const auto *DebugTemplateAlias = Args.getLastArg(
options::OPT_gtemplate_alias, options::OPT_gno_template_alias)) {
// DW_TAG_template_alias is only supported from DWARFv5 but if a user
// asks for it we should let them have it (if the target supports it).
if (checkDebugInfoOption(DebugTemplateAlias, Args, D, TC)) {
const auto &Opt = DebugTemplateAlias->getOption();
UseDebugTemplateAlias = Opt.matches(options::OPT_gtemplate_alias);
}
}
if (UseDebugTemplateAlias)
CmdArgs.push_back("-gtemplate-alias");

if (const Arg *A = Args.getLastArg(options::OPT_gsrc_hash_EQ)) {
StringRef v = A->getValue();
CmdArgs.push_back(Args.MakeArgString("-gsrc-hash=" + v));
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1556,6 +1556,9 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
llvm::DICompileUnit::DebugNameTableKind::Default))
GenerateArg(Consumer, OPT_gpubnames);

if (Opts.DebugTemplateAlias)
GenerateArg(Consumer, OPT_gtemplate_alias);

auto TNK = Opts.getDebugSimpleTemplateNames();
if (TNK != llvm::codegenoptions::DebugTemplateNamesKind::Full) {
if (TNK == llvm::codegenoptions::DebugTemplateNamesKind::Simple)
Expand Down Expand Up @@ -1827,6 +1830,8 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.BinutilsVersion =
std::string(Args.getLastArgValue(OPT_fbinutils_version_EQ));

Opts.DebugTemplateAlias = Args.hasArg(OPT_gtemplate_alias);

Opts.DebugNameTable = static_cast<unsigned>(
Args.hasArg(OPT_ggnu_pubnames)
? llvm::DICompileUnit::DebugNameTableKind::GNU
Expand Down
58 changes: 41 additions & 17 deletions clang/lib/Parse/ParseOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -632,10 +632,16 @@ Parser::ParseOpenACCClauseList(OpenACCDirectiveKind DirKind) {
return Clauses;
}

ExprResult Parser::ParseOpenACCIntExpr() {
// FIXME: this is required to be an integer expression (or dependent), so we
// should ensure that is the case by passing this to SEMA here.
return getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression());
ExprResult Parser::ParseOpenACCIntExpr(OpenACCDirectiveKind DK,
OpenACCClauseKind CK,
SourceLocation Loc) {
ExprResult ER =
getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression());

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

return getActions().OpenACC().ActOnIntExpr(DK, CK, Loc, ER.get());
}

bool Parser::ParseOpenACCClauseVarList(OpenACCClauseKind Kind) {
Expand Down Expand Up @@ -739,7 +745,7 @@ bool Parser::ParseOpenACCSizeExprList() {
/// [num:]int-expr
/// dim:int-expr
/// static:size-expr
bool Parser::ParseOpenACCGangArg() {
bool Parser::ParseOpenACCGangArg(SourceLocation GangLoc) {

if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Static, getCurToken()) &&
NextToken().is(tok::colon)) {
Expand All @@ -753,7 +759,9 @@ bool Parser::ParseOpenACCGangArg() {
NextToken().is(tok::colon)) {
ConsumeToken();
ConsumeToken();
return ParseOpenACCIntExpr().isInvalid();
return ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,
OpenACCClauseKind::Gang, GangLoc)
.isInvalid();
}

if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Num, getCurToken()) &&
Expand All @@ -763,11 +771,13 @@ bool Parser::ParseOpenACCGangArg() {
// Fallthrough to the 'int-expr' handling for when 'num' is omitted.
}
// This is just the 'num' case where 'num' is optional.
return ParseOpenACCIntExpr().isInvalid();
return ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,
OpenACCClauseKind::Gang, GangLoc)
.isInvalid();
}

bool Parser::ParseOpenACCGangArgList() {
if (ParseOpenACCGangArg()) {
bool Parser::ParseOpenACCGangArgList(SourceLocation GangLoc) {
if (ParseOpenACCGangArg(GangLoc)) {
SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
Parser::StopBeforeMatch);
return false;
Expand All @@ -776,7 +786,7 @@ bool Parser::ParseOpenACCGangArgList() {
while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
ExpectAndConsume(tok::comma);

if (ParseOpenACCGangArg()) {
if (ParseOpenACCGangArg(GangLoc)) {
SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,
Parser::StopBeforeMatch);
return false;
Expand Down Expand Up @@ -941,11 +951,19 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
case OpenACCClauseKind::DeviceNum:
case OpenACCClauseKind::DefaultAsync:
case OpenACCClauseKind::VectorLength: {
ExprResult IntExpr = ParseOpenACCIntExpr();
ExprResult IntExpr = ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,
ClauseKind, ClauseLoc);
if (IntExpr.isInvalid()) {
Parens.skipToEnd();
return OpenACCCanContinue();
}

// TODO OpenACC: as we implement the 'rest' of the above, this 'if' should
// be removed leaving just the 'setIntExprDetails'.
if (ClauseKind == OpenACCClauseKind::NumWorkers ||
ClauseKind == OpenACCClauseKind::VectorLength)
ParsedClause.setIntExprDetails(IntExpr.get());

break;
}
case OpenACCClauseKind::DType:
Expand Down Expand Up @@ -998,7 +1016,8 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
? OpenACCSpecialTokenKind::Length
: OpenACCSpecialTokenKind::Num,
ClauseKind);
ExprResult IntExpr = ParseOpenACCIntExpr();
ExprResult IntExpr = ParseOpenACCIntExpr(OpenACCDirectiveKind::Invalid,
ClauseKind, ClauseLoc);
if (IntExpr.isInvalid()) {
Parens.skipToEnd();
return OpenACCCanContinue();
Expand All @@ -1014,13 +1033,14 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
break;
}
case OpenACCClauseKind::Gang:
if (ParseOpenACCGangArgList()) {
if (ParseOpenACCGangArgList(ClauseLoc)) {
Parens.skipToEnd();
return OpenACCCanContinue();
}
break;
case OpenACCClauseKind::Wait:
if (ParseOpenACCWaitArgument()) {
if (ParseOpenACCWaitArgument(ClauseLoc,
/*IsDirective=*/false)) {
Parens.skipToEnd();
return OpenACCCanContinue();
}
Expand Down Expand Up @@ -1052,7 +1072,7 @@ ExprResult Parser::ParseOpenACCAsyncArgument() {
/// In this section and throughout the specification, the term wait-argument
/// means:
/// [ devnum : int-expr : ] [ queues : ] async-argument-list
bool Parser::ParseOpenACCWaitArgument() {
bool Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
// [devnum : int-expr : ]
if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::DevNum, Tok) &&
NextToken().is(tok::colon)) {
Expand All @@ -1061,7 +1081,11 @@ bool Parser::ParseOpenACCWaitArgument() {
// Consume colon.
ConsumeToken();

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

Expand Down Expand Up @@ -1245,7 +1269,7 @@ Parser::OpenACCDirectiveParseInfo Parser::ParseOpenACCDirective() {
break;
case OpenACCDirectiveKind::Wait:
// OpenACC has an optional paren-wrapped 'wait-argument'.
if (ParseOpenACCWaitArgument())
if (ParseOpenACCWaitArgument(StartLoc, /*IsDirective=*/true))
T.skipToEnd();
else
T.consumeClose();
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17522,6 +17522,12 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
if (Converted.isInvalid())
return Converted;
E = Converted.get();
// The 'explicit' case causes us to get a RecoveryExpr. Give up here so we
// don't try to evaluate it later. We also don't want to return the
// RecoveryExpr here, as it results in this call succeeding, thus callers of
// this function will attempt to use 'Value'.
if (isa<RecoveryExpr>(E))
return ExprError();
if (!E->getType()->isIntegralOrUnscopedEnumerationType())
return ExprError();
} else if (!E->getType()->isIntegralOrUnscopedEnumerationType()) {
Expand Down
140 changes: 140 additions & 0 deletions clang/lib/Sema/SemaOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "clang/Sema/SemaOpenACC.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/OpenACCKinds.h"
#include "clang/Sema/Sema.h"
#include "llvm/Support/Casting.h"

Expand Down Expand Up @@ -90,6 +91,17 @@ bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind,
default:
return false;
}
case OpenACCClauseKind::NumWorkers:
case OpenACCClauseKind::VectorLength:
switch (DirectiveKind) {
case OpenACCDirectiveKind::Parallel:
case OpenACCDirectiveKind::Kernels:
case OpenACCDirectiveKind::ParallelLoop:
case OpenACCDirectiveKind::KernelsLoop:
return true;
default:
return false;
}
default:
// Do nothing so we can go to the 'unimplemented' diagnostic instead.
return true;
Expand Down Expand Up @@ -218,6 +230,44 @@ SemaOpenACC::ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses,
getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
Clause.getConditionExpr(), Clause.getEndLoc());
}
case OpenACCClauseKind::NumWorkers: {
// Restrictions only properly implemented on 'compute' constructs, and
// 'compute' constructs are the only construct that can do anything with
// this yet, so skip/treat as unimplemented in this case.
if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
break;

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

assert(Clause.getIntExprs().size() == 1 &&
"Invalid number of expressions for NumWorkers");
return OpenACCNumWorkersClause::Create(
getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
Clause.getIntExprs()[0], Clause.getEndLoc());
}
case OpenACCClauseKind::VectorLength: {
// Restrictions only properly implemented on 'compute' constructs, and
// 'compute' constructs are the only construct that can do anything with
// this yet, so skip/treat as unimplemented in this case.
if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
break;

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

assert(Clause.getIntExprs().size() == 1 &&
"Invalid number of expressions for VectorLength");
return OpenACCVectorLengthClause::Create(
getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
Clause.getIntExprs()[0], Clause.getEndLoc());
}
default:
break;
}
Expand Down Expand Up @@ -248,6 +298,96 @@ void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K,
}
}

ExprResult SemaOpenACC::ActOnIntExpr(OpenACCDirectiveKind DK,
OpenACCClauseKind CK, SourceLocation Loc,
Expr *IntExpr) {

assert(((DK != OpenACCDirectiveKind::Invalid &&
CK == OpenACCClauseKind::Invalid) ||
(DK == OpenACCDirectiveKind::Invalid &&
CK != OpenACCClauseKind::Invalid)) &&
"Only one of directive or clause kind should be provided");

class IntExprConverter : public Sema::ICEConvertDiagnoser {
OpenACCDirectiveKind DirectiveKind;
OpenACCClauseKind ClauseKind;
Expr *IntExpr;

public:
IntExprConverter(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
Expr *IntExpr)
: ICEConvertDiagnoser(/*AllowScopedEnumerations=*/false,
/*Suppress=*/false,
/*SuppressConversion=*/true),
DirectiveKind(DK), ClauseKind(CK), IntExpr(IntExpr) {}

bool match(QualType T) override {
// OpenACC spec just calls this 'integer expression' as having an
// 'integer type', so fall back on C99's 'integer type'.
return T->isIntegerType();
}
SemaBase::SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
QualType T) override {
if (ClauseKind != OpenACCClauseKind::Invalid)
return S.Diag(Loc, diag::err_acc_int_expr_requires_integer) <<
/*Clause=*/0 << ClauseKind << T;

return S.Diag(Loc, diag::err_acc_int_expr_requires_integer) <<
/*Directive=*/1 << DirectiveKind << T;
}

SemaBase::SemaDiagnosticBuilder
diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) override {
return S.Diag(Loc, diag::err_acc_int_expr_incomplete_class_type)
<< T << IntExpr->getSourceRange();
}

SemaBase::SemaDiagnosticBuilder
diagnoseExplicitConv(Sema &S, SourceLocation Loc, QualType T,
QualType ConvTy) override {
return S.Diag(Loc, diag::err_acc_int_expr_explicit_conversion)
<< T << ConvTy;
}

SemaBase::SemaDiagnosticBuilder noteExplicitConv(Sema &S,
CXXConversionDecl *Conv,
QualType ConvTy) override {
return S.Diag(Conv->getLocation(), diag::note_acc_int_expr_conversion)
<< ConvTy->isEnumeralType() << ConvTy;
}

SemaBase::SemaDiagnosticBuilder
diagnoseAmbiguous(Sema &S, SourceLocation Loc, QualType T) override {
return S.Diag(Loc, diag::err_acc_int_expr_multiple_conversions) << T;
}

SemaBase::SemaDiagnosticBuilder
noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override {
return S.Diag(Conv->getLocation(), diag::note_acc_int_expr_conversion)
<< ConvTy->isEnumeralType() << ConvTy;
}

SemaBase::SemaDiagnosticBuilder
diagnoseConversion(Sema &S, SourceLocation Loc, QualType T,
QualType ConvTy) override {
llvm_unreachable("conversion functions are permitted");
}
} IntExprDiagnoser(DK, CK, IntExpr);

ExprResult IntExprResult = SemaRef.PerformContextualImplicitConversion(
Loc, IntExpr, IntExprDiagnoser);
if (IntExprResult.isInvalid())
return ExprError();

IntExpr = IntExprResult.get();
if (!IntExpr->isTypeDependent() && !IntExpr->getType()->isIntegerType())
return ExprError();

// TODO OpenACC: Do we want to perform usual unary conversions here? When
// doing codegen we might find that is necessary, but skip it for now.
return IntExpr;
}

bool SemaOpenACC::ActOnStartStmtDirective(OpenACCDirectiveKind K,
SourceLocation StartLoc) {
return diagnoseConstructAppertainment(*this, K, StartLoc, /*IsStmt=*/true);
Expand Down
13 changes: 8 additions & 5 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6563,11 +6563,14 @@ diagnoseNoViableConversion(Sema &SemaRef, SourceLocation Loc, Expr *&From,
HadMultipleCandidates);
if (Result.isInvalid())
return true;
// Record usage of conversion in an implicit cast.
From = ImplicitCastExpr::Create(SemaRef.Context, Result.get()->getType(),
CK_UserDefinedConversion, Result.get(),
nullptr, Result.get()->getValueKind(),
SemaRef.CurFPFeatureOverrides());

// Replace the conversion with a RecoveryExpr, so we don't try to
// instantiate it later, but can further diagnose here.
Result = SemaRef.CreateRecoveryExpr(From->getBeginLoc(), From->getEndLoc(),
From, Result.get()->getType());
if (Result.isInvalid())
return true;
From = Result.get();
}
return false;
}
Expand Down
46 changes: 46 additions & 0 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -11158,6 +11158,52 @@ void OpenACCClauseTransform<Derived>::VisitSelfClause(
ParsedClause.getLParenLoc(), ParsedClause.getConditionExpr(),
ParsedClause.getEndLoc());
}

template <typename Derived>
void OpenACCClauseTransform<Derived>::VisitNumWorkersClause(
const OpenACCNumWorkersClause &C) {
Expr *IntExpr = const_cast<Expr *>(C.getIntExpr());
assert(IntExpr && "num_workers clause constructed with invalid int expr");

ExprResult Res = Self.TransformExpr(IntExpr);
if (!Res.isUsable())
return;

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

ParsedClause.setIntExprDetails(Res.get());
NewClause = OpenACCNumWorkersClause::Create(
Self.getSema().getASTContext(), ParsedClause.getBeginLoc(),
ParsedClause.getLParenLoc(), ParsedClause.getIntExprs()[0],
ParsedClause.getEndLoc());
}

template <typename Derived>
void OpenACCClauseTransform<Derived>::VisitVectorLengthClause(
const OpenACCVectorLengthClause &C) {
Expr *IntExpr = const_cast<Expr *>(C.getIntExpr());
assert(IntExpr && "vector_length clause constructed with invalid int expr");

ExprResult Res = Self.TransformExpr(IntExpr);
if (!Res.isUsable())
return;

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

ParsedClause.setIntExprDetails(Res.get());
NewClause = OpenACCVectorLengthClause::Create(
Self.getSema().getASTContext(), ParsedClause.getBeginLoc(),
ParsedClause.getLParenLoc(), ParsedClause.getIntExprs()[0],
ParsedClause.getEndLoc());
}
} // namespace
template <typename Derived>
OpenACCClause *TreeTransform<Derived>::TransformOpenACCClause(
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 @@ -11786,6 +11786,18 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() {
return OpenACCSelfClause::Create(getContext(), BeginLoc, LParenLoc,
CondExpr, EndLoc);
}
case OpenACCClauseKind::NumWorkers: {
SourceLocation LParenLoc = readSourceLocation();
Expr *IntExpr = readSubExpr();
return OpenACCNumWorkersClause::Create(getContext(), BeginLoc, LParenLoc,
IntExpr, EndLoc);
}
case OpenACCClauseKind::VectorLength: {
SourceLocation LParenLoc = readSourceLocation();
Expr *IntExpr = readSubExpr();
return OpenACCVectorLengthClause::Create(getContext(), BeginLoc, LParenLoc,
IntExpr, EndLoc);
}
case OpenACCClauseKind::Finalize:
case OpenACCClauseKind::IfPresent:
case OpenACCClauseKind::Seq:
Expand Down Expand Up @@ -11814,9 +11826,7 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() {
case OpenACCClauseKind::Reduction:
case OpenACCClauseKind::Collapse:
case OpenACCClauseKind::Bind:
case OpenACCClauseKind::VectorLength:
case OpenACCClauseKind::NumGangs:
case OpenACCClauseKind::NumWorkers:
case OpenACCClauseKind::DeviceNum:
case OpenACCClauseKind::DefaultAsync:
case OpenACCClauseKind::DeviceType:
Expand Down
18 changes: 14 additions & 4 deletions clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5014,7 +5014,7 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {

if (!ModularCodegenDecls.empty())
Stream.EmitRecord(MODULAR_CODEGEN_DECLS, ModularCodegenDecls);

// Write the record containing tentative definitions.
RecordData TentativeDefinitions;
AddLazyVectorEmiitedDecls(*this, SemaRef.TentativeDefinitions,
Expand Down Expand Up @@ -5135,7 +5135,7 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {
}
if (!UndefinedButUsed.empty())
Stream.EmitRecord(UNDEFINED_BUT_USED, UndefinedButUsed);

// Write all delete-expressions that we would like to
// analyze later in AST.
RecordData DeleteExprsToAnalyze;
Expand Down Expand Up @@ -7657,6 +7657,18 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
AddStmt(const_cast<Expr *>(SC->getConditionExpr()));
return;
}
case OpenACCClauseKind::NumWorkers: {
const auto *NWC = cast<OpenACCNumWorkersClause>(C);
writeSourceLocation(NWC->getLParenLoc());
AddStmt(const_cast<Expr *>(NWC->getIntExpr()));
return;
}
case OpenACCClauseKind::VectorLength: {
const auto *NWC = cast<OpenACCVectorLengthClause>(C);
writeSourceLocation(NWC->getLParenLoc());
AddStmt(const_cast<Expr *>(NWC->getIntExpr()));
return;
}
case OpenACCClauseKind::Finalize:
case OpenACCClauseKind::IfPresent:
case OpenACCClauseKind::Seq:
Expand Down Expand Up @@ -7685,9 +7697,7 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
case OpenACCClauseKind::Reduction:
case OpenACCClauseKind::Collapse:
case OpenACCClauseKind::Bind:
case OpenACCClauseKind::VectorLength:
case OpenACCClauseKind::NumGangs:
case OpenACCClauseKind::NumWorkers:
case OpenACCClauseKind::DeviceNum:
case OpenACCClauseKind::DefaultAsync:
case OpenACCClauseKind::DeviceType:
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CodeGenCXX/debug-info-alias.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang -g -std=c++11 -S -emit-llvm %s -o - | FileCheck %s
// RUN: %clang -g -gno-template-alias -std=c++11 -S -emit-llvm %s -o - | FileCheck %s

template<typename T>
struct foo {
Expand Down
38 changes: 38 additions & 0 deletions clang/test/CodeGenCXX/defaulted-template-alias.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// RUN: %clang_cc1 -triple x86_64-unk-unk -o - -emit-llvm -debug-info-kind=standalone -gtemplate-alias %s -gsimple-template-names=simple \
// RUN: | FileCheck %s

//// Check that -gtemplate-alias causes DW_TAG_template_alias emission for
//// template aliases with default parameter values. See template-alias.cpp for
//// more template alias tests.
//// FIXME: We currently do not emit defaulted arguments.

template<typename T>
struct X {
char m;
};

template<typename T>
struct Y {
char n;
};

template <typename NonDefault, template <typename C> class T = Y, int I = 5, typename... Ts>
using A = X<NonDefault>;

//// We should be able to emit type alias metadata which describes all the
//// values, including the defaulted parameters and empty parameter pack.
A<int> a;

// CHECK: !DIDerivedType(tag: DW_TAG_template_alias, name: "A", file: ![[#]], line: [[#]], baseType: ![[baseType:[0-9]+]], extraData: ![[extraData:[0-9]+]])
// CHECK: ![[baseType]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "X",
// CHECK: ![[int:[0-9]+]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
// CHECK: ![[extraData]] = !{![[NonDefault:[0-9]+]]}
// CHECK: ![[NonDefault]] = !DITemplateTypeParameter(name: "NonDefault", type: ![[int]])

//// FIXME: Ideally, we would describe the deafulted args, like this:
// : ![[extraData]] = !{![[NonDefault:[0-9]+]], ![[T:[0-9]+]], ![[I:[0-9]+]], ![[Ts:[0-9]+]]}
// : ![[NonDefault]] = !DITemplateTypeParameter(name: "NonDefault", type: ![[int]])
// : ![[T]] = !DITemplateValueParameter(tag: DW_TAG_GNU_template_template_param, name: "T", defaulted: true, value: !"Y")
// : ![[I]] = !DITemplateValueParameter(name: "I", type: ![[int]], defaulted: true, value: i32 5)
// : ![[Ts]] = !DITemplateValueParameter(tag: DW_TAG_GNU_template_parameter_pack, name: "Ts", value: ![[types:[0-9]+]])
// : ![[types]] = !{}
47 changes: 47 additions & 0 deletions clang/test/CodeGenCXX/template-alias.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// RUN: %clang_cc1 -triple x86_64-unk-unk -o - -emit-llvm -debug-info-kind=standalone -gtemplate-alias %s -gsimple-template-names=simple \
// RUN: | FileCheck %s --check-prefixes=ALIAS-SIMPLE,ALIAS-ALL

// RUN: %clang_cc1 -triple x86_64-unk-unk -o - -emit-llvm -debug-info-kind=standalone -gtemplate-alias %s -gsimple-template-names=mangled \
// RUN: | FileCheck %s --check-prefixes=ALIAS-MANGLED,ALIAS-ALL

// RUN: %clang_cc1 -triple x86_64-unk-unk -o - -emit-llvm -debug-info-kind=standalone -gtemplate-alias %s \
// RUN: | FileCheck %s --check-prefixes=ALIAS-FULL,ALIAS-ALL

// RUN: %clang_cc1 -triple x86_64-unk-unk -o - -emit-llvm -debug-info-kind=standalone %s \
// RUN: | FileCheck %s --check-prefixes=TYPEDEF


//// Check that -gtemplate-alias causes DW_TAG_template_alias emission for
//// template aliases, and that respects gsimple-template-names.
////
//// Test type and value template parameters.

template<typename Y, int Z>
struct X {
Y m1 = Z;
};

template<typename B, int C>
using A = X<B, C>;

A<int, 5> a;


// ALIAS-SIMPLE: !DIDerivedType(tag: DW_TAG_template_alias, name: "A", file: ![[#]], line: [[#]], baseType: ![[baseType:[0-9]+]], extraData: ![[extraData:[0-9]+]])
// ALIAS-SIMPLE: ![[baseType]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "X",

// FIXME: Mangled name is wrong (not a regression).
// ALIAS-MANGLED: !DIDerivedType(tag: DW_TAG_template_alias, name: "A<int, 5>", file: ![[#]], line: [[#]], baseType: ![[baseType:[0-9]+]], extraData: ![[extraData:[0-9]+]])
// ALIAS-MANGLED: ![[baseType]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "_STN|X|<int, 5>",

// ALIAS-FULL: !DIDerivedType(tag: DW_TAG_template_alias, name: "A<int, 5>", file: ![[#]], line: [[#]], baseType: ![[baseType:[0-9]+]], extraData: ![[extraData:[0-9]+]])
// ALIAS-FULL: ![[baseType]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "X<int, 5>",

// ALIAS-ALL: ![[int:[0-9]+]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
// ALIAS-ALL: ![[extraData]] = !{![[B:[0-9]+]], ![[C:[0-9]+]]}
// ALIAS-ALL: ![[B]] = !DITemplateTypeParameter(name: "B", type: ![[int]])
// ALIAS-ALL: ![[C]] = !DITemplateValueParameter(name: "C", type: ![[int]], value: i32 5)

// TYPEDEF: !DIDerivedType(tag: DW_TAG_typedef, name: "A<int, 5>", file: ![[#]], line: [[#]], baseType: ![[baseType:[0-9]+]])
// TYPEDEF: ![[baseType]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "X<int, 5>",
// TYPEDEF: ![[int:[0-9]+]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
25 changes: 25 additions & 0 deletions clang/test/CodeGenCXX/variadic-template-alias.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// RUN: %clang_cc1 -triple x86_64-unk-unk -o - -emit-llvm -debug-info-kind=standalone -gtemplate-alias %s -gsimple-template-names=simple \
// RUN: | FileCheck %s

//// Check that -gtemplate-alias causes DW_TAG_template_alias emission for
//// variadic template aliases. See template-alias.cpp for more template alias
//// tests.

template<typename Y, int Z>
struct X {
Y m1 = Z;
};

template<int I, typename... Ts>
using A = X<Ts..., I>;

A<5, int> a;

// CHECK: !DIDerivedType(tag: DW_TAG_template_alias, name: "A", file: ![[#]], line: [[#]], baseType: ![[baseType:[0-9]+]], extraData: ![[extraData:[0-9]+]])
// CHECK: ![[baseType]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "X",
// CHECK: ![[int:[0-9]+]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
// CHECK: ![[extraData]] = !{![[I:[0-9]+]], ![[Ts:[0-9]+]]}
// CHECK: ![[I]] = !DITemplateValueParameter(name: "I", type: ![[int]], value: i32 5)
// CHECK: ![[Ts]] = !DITemplateValueParameter(tag: DW_TAG_GNU_template_parameter_pack, name: "Ts", value: ![[types:[0-9]+]])
// CHECK: ![[types]] = !{![[int_template_param:[0-9]+]]}
// CHECK: ![[int_template_param]] = !DITemplateTypeParameter(type: ![[int]])
10 changes: 10 additions & 0 deletions clang/test/Driver/debug-options.c
Original file line number Diff line number Diff line change
Expand Up @@ -465,3 +465,13 @@
// MANGLED_TEMP_NAMES: error: unknown argument '-gsimple-template-names=mangled'; did you mean '-Xclang -gsimple-template-names=mangled'
// RUN: %clang -### -target x86_64 -c -g %s 2>&1 | FileCheck --check-prefix=FULL_TEMP_NAMES --implicit-check-not=debug-forward-template-params %s
// FULL_TEMP_NAMES-NOT: -gsimple-template-names

//// Test -g[no-]template-alias (enabled by default with SCE debugger tuning and DWARFv5).
// RUN: %clang -### -target x86_64 -c -gdwarf-5 -gsce %s 2>&1 | FileCheck %s --check-prefixes=TEMPLATE-ALIAS
// RUN: %clang -### -target x86_64 -c -gdwarf-4 -gsce %s 2>&1 | FileCheck %s --check-prefixes=NO-TEMPLATE-ALIAS
// RUN: %clang -### -target x86_64 -c -gdwarf-5 -gsce -gtemplate-alias %s 2>&1 | FileCheck %s --check-prefixes=TEMPLATE-ALIAS
// RUN: %clang -### -target x86_64 -c -gdwarf-5 -gsce -gno-template-alias %s 2>&1 | FileCheck %s --check-prefixes=NO-TEMPLATE-ALIAS
// RUN: %clang -### -target x86_64 -c -gdwarf-5 -gtemplate-alias %s 2>&1 | FileCheck %s --check-prefixes=TEMPLATE-ALIAS
// RUN: %clang -### -target x86_64 -c -gdwarf-5 -gtemplate-alias -gno-template-alias %s 2>&1 | FileCheck %s --check-prefixes=NO-TEMPLATE-ALIAS
// TEMPLATE-ALIAS: "-gtemplate-alias"
// NO-TEMPLATE-ALIAS-NOT: "-gtemplate-alias"
2 changes: 1 addition & 1 deletion clang/test/InstallAPI/binary-attributes.test
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
; RUN: -current_version 1.2.3 -compatibility_version 1 \
; RUN: -allowable_client Foo -allowable_client Bar \
; RUN: -o tmp.tbd --verify-against=%t/Simple 2>&1 | FileCheck -check-prefix=ALLOWABLE %s
; ALLOWABLE: error: allowable client missing from binary file: 'Foo [ x86_64 ]'
; ALLOWABLE: error: allowable client missing from binary file: '{{Foo|Bar}} [ x86_64 ]'

; RUN: not clang-installapi -target x86_64-apple-macos10.12 \
; RUN: -install_name /System/Library/Frameworks/Simple.framework/Versions/A/Simple \
Expand Down
4 changes: 2 additions & 2 deletions clang/test/InstallAPI/rpath.test
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
; RUN: --verify-mode=Pedantic 2>&1 | FileCheck %s --check-prefix=MISSING
; RUN: llvm-readtapi --compare %t/RPath_warnings.tbd %t/expected_no_rpaths.tbd

; MISSING: warning: runpath search paths missing from installAPI option: '@loader_path/../../../SharedFrameworks/ [ x86_64 arm64 ]'
; MISSING: warning: runpath search paths missing from installAPI option: '@loader_path/../../PrivateFrameworks/ [ x86_64 arm64 ]'
; MISSING-DAG: warning: runpath search paths missing from installAPI option: '@loader_path/../../../SharedFrameworks/ [ x86_64 arm64 ]'
; MISSING-DAG: warning: runpath search paths missing from installAPI option: '@loader_path/../../PrivateFrameworks/ [ x86_64 arm64 ]'

; RUN: clang-installapi --filetype=tbd-v5 \
; RUN: -target arm64-apple-macos13.0 -target x86_64-apple-macos13.0 \
Expand Down
4 changes: 0 additions & 4 deletions clang/test/ParserOpenACC/parse-clauses.c
Original file line number Diff line number Diff line change
Expand Up @@ -893,11 +893,9 @@ void IntExprParsing() {
#pragma acc parallel vector_length(5, 4)
{}

// expected-warning@+1{{OpenACC clause 'vector_length' not yet implemented, clause ignored}}
#pragma acc parallel vector_length(5)
{}

// expected-warning@+1{{OpenACC clause 'vector_length' not yet implemented, clause ignored}}
#pragma acc parallel vector_length(returns_int())
{}

Expand Down Expand Up @@ -943,11 +941,9 @@ void IntExprParsing() {
#pragma acc parallel num_workers(5, 4)
{}

// expected-warning@+1{{OpenACC clause 'num_workers' not yet implemented, clause ignored}}
#pragma acc parallel num_workers(5)
{}

// expected-warning@+1{{OpenACC clause 'num_workers' not yet implemented, clause ignored}}
#pragma acc parallel num_workers(returns_int())
{}

Expand Down
2 changes: 0 additions & 2 deletions clang/test/ParserOpenACC/parse-clauses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,9 @@ void templ() {
#pragma acc loop collapse(T::value)
for(;;){}

// expected-warning@+1{{OpenACC clause 'vector_length' not yet implemented, clause ignored}}
#pragma acc parallel vector_length(T::value)
for(;;){}

// expected-warning@+1{{OpenACC clause 'vector_length' not yet implemented, clause ignored}}
#pragma acc parallel vector_length(I)
for(;;){}

Expand Down
15 changes: 15 additions & 0 deletions clang/test/SemaCXX/explicit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,3 +266,18 @@ namespace PR18777 {
struct S { explicit operator bool() const; } s;
int *p = new int(s); // expected-error {{no viable conversion}}
}

namespace DoubleDiags {
struct ExplicitConvert{
explicit operator int();//#DOUBLE_DIAG_OP_INT
} EC;
template<typename T>
void Template(){
// expected-error@+2{{switch condition type 'struct ExplicitConvert' requires explicit conversion to 'int'}}
// expected-note@#DOUBLE_DIAG_OP_INT{{conversion to integral type 'int'}}
switch(EC){}
};
void Inst() {
Template<int>();
}
}
304 changes: 304 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-intexpr-clause-ast.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s

// Test this with PCH.
// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s
// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s

#ifndef PCH_HELPER
#define PCH_HELPER

int some_int();
short some_short();
long some_long();
enum E{};
E some_enum();

struct CorrectConvert {
operator int();
} Convert;


void NormalUses() {
// CHECK: FunctionDecl{{.*}}NormalUses
// CHECK-NEXT: CompoundStmt

#pragma acc parallel num_workers(some_int())
while(true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: num_workers clause
// CHECK-NEXT: CallExpr{{.*}}'int'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'int (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'int ()' lvalue Function{{.*}} 'some_int' 'int ()'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc kernels num_workers(some_short())
while(true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}kernels
// CHECK-NEXT: num_workers clause
// CHECK-NEXT: CallExpr{{.*}}'short'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'short (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'short ()' lvalue Function{{.*}} 'some_short' 'short ()'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc parallel num_workers(some_long())
while(true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: num_workers clause
// CHECK-NEXT: CallExpr{{.*}}'long'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'long (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'long ()' lvalue Function{{.*}} 'some_long' 'long ()'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc parallel num_workers(some_enum())
while(true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: num_workers clause
// CHECK-NEXT: CallExpr{{.*}}'E'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'E (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'E ()' lvalue Function{{.*}} 'some_enum' 'E ()'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc kernels num_workers(Convert)
while(true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}kernels
// CHECK-NEXT: num_workers clause
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' <UserDefinedConversion>
// CHECK-NEXT: CXXMemberCallExpr{{.*}}'int'
// CHECK-NEXT: MemberExpr{{.*}} '<bound member function type>' .operator int
// CHECK-NEXT: DeclRefExpr{{.*}} 'struct CorrectConvert':'CorrectConvert' lvalue Var
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc kernels vector_length(some_short())
while(true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}kernels
// CHECK-NEXT: vector_length clause
// CHECK-NEXT: CallExpr{{.*}}'short'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'short (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr{{.*}}'short ()' lvalue Function{{.*}} 'some_short' 'short ()'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt
}

template<typename T, typename U>
void TemplUses(T t, U u) {
// CHECK-NEXT: FunctionTemplateDecl
// CHECK-NEXT: TemplateTypeParmDecl{{.*}}typename depth 0 index 0 T
// CHECK-NEXT: TemplateTypeParmDecl{{.*}}typename depth 0 index 1 U
// CHECK-NEXT: FunctionDecl{{.*}} TemplUses 'void (T, U)'
// CHECK-NEXT: ParmVarDecl{{.*}} referenced t 'T'
// CHECK-NEXT: ParmVarDecl{{.*}} referenced u 'U'
// CHECK-NEXT: CompoundStmt

#pragma acc parallel num_workers(t)
while(true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: num_workers clause
// CHECK-NEXT: DeclRefExpr{{.*}} 'T' lvalue ParmVar{{.*}} 't' 'T'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc kernels num_workers(u)
while(true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}kernels
// CHECK-NEXT: num_workers clause
// CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc parallel num_workers(U::value)
while(true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: num_workers clause
// CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'U'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc kernels num_workers(T{})
while(true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}kernels
// CHECK-NEXT: num_workers clause
// CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}} 'T' 'T' list
// CHECK-NEXT: InitListExpr{{.*}} 'void'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc parallel num_workers(U{})
while(true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: num_workers clause
// CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}} 'U' 'U' list
// CHECK-NEXT: InitListExpr{{.*}} 'void'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc kernels num_workers(typename U::IntTy{})
while(true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}kernels
// CHECK-NEXT: num_workers clause
// CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}} 'typename U::IntTy' 'typename U::IntTy' list
// CHECK-NEXT: InitListExpr{{.*}} 'void'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc parallel num_workers(typename U::ShortTy{})
while(true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: num_workers clause
// CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}} 'typename U::ShortTy' 'typename U::ShortTy' list
// CHECK-NEXT: InitListExpr{{.*}} 'void'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc kernels vector_length(u)
while(true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}kernels
// CHECK-NEXT: vector_length clause
// CHECK-NEXT: DeclRefExpr{{.*}} 'U' lvalue ParmVar{{.*}} 'u' 'U'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

#pragma acc parallel vector_length(U::value)
while(true){}
// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: vector_length clause
// CHECK-NEXT: DependentScopeDeclRefExpr{{.*}} '<dependent type>' lvalue
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'U'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// Check the instantiated versions of the above.
// CHECK-NEXT: FunctionDecl{{.*}} used TemplUses 'void (CorrectConvert, HasInt)' implicit_instantiation
// CHECK-NEXT: TemplateArgument type 'CorrectConvert'
// CHECK-NEXT: RecordType{{.*}} 'CorrectConvert'
// CHECK-NEXT: CXXRecord{{.*}} 'CorrectConvert'
// CHECK-NEXT: TemplateArgument type 'HasInt'
// CHECK-NEXT: RecordType{{.*}} 'HasInt'
// CHECK-NEXT: CXXRecord{{.*}} 'HasInt'
// CHECK-NEXT: ParmVarDecl{{.*}} used t 'CorrectConvert'
// CHECK-NEXT: ParmVarDecl{{.*}} used u 'HasInt'
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: num_workers clause
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' <UserDefinedConversion>
// CHECK-NEXT: CXXMemberCallExpr{{.*}}'int'
// CHECK-NEXT: MemberExpr{{.*}} '<bound member function type>' .operator int
// CHECK-NEXT: DeclRefExpr{{.*}} 'CorrectConvert' lvalue ParmVar
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}kernels
// CHECK-NEXT: num_workers clause
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' <UserDefinedConversion>
// CHECK-NEXT: CXXMemberCallExpr{{.*}}'char'
// CHECK-NEXT: MemberExpr{{.*}} '<bound member function type>' .operator char
// CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: num_workers clause
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr{{.*}} 'const int' lvalue Var{{.*}} 'value' 'const int'
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'HasInt'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}kernels
// CHECK-NEXT: num_workers clause
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' <UserDefinedConversion>
// CHECK-NEXT: CXXMemberCallExpr{{.*}}'int'
// CHECK-NEXT: MemberExpr{{.*}} '<bound member function type>' .operator int
// CHECK-NEXT: MaterializeTemporaryExpr{{.*}} 'CorrectConvert' lvalue
// CHECK-NEXT: CXXFunctionalCastExpr{{.*}} 'CorrectConvert' functional cast to struct CorrectConvert <NoOp>
// CHECK-NEXT: InitListExpr{{.*}}'CorrectConvert'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: ExprWithCleanups
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: num_workers clause
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' <UserDefinedConversion>
// CHECK-NEXT: CXXMemberCallExpr{{.*}}'char'
// CHECK-NEXT: MemberExpr{{.*}} '<bound member function type>' .operator char
// CHECK-NEXT: MaterializeTemporaryExpr{{.*}} 'HasInt' lvalue
// CHECK-NEXT: CXXFunctionalCastExpr{{.*}} 'HasInt' functional cast to struct HasInt <NoOp>
// CHECK-NEXT: InitListExpr{{.*}}'HasInt'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: ExprWithCleanups
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}kernels
// CHECK-NEXT: num_workers clause
// CHECK-NEXT: CXXFunctionalCastExpr{{.*}} 'typename HasInt::IntTy':'int' functional cast to typename struct HasInt::IntTy <NoOp>
// CHECK-NEXT: InitListExpr{{.*}}'typename HasInt::IntTy':'int'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: num_workers clause
// CHECK-NEXT: CXXFunctionalCastExpr{{.*}} 'typename HasInt::ShortTy':'short' functional cast to typename struct HasInt::ShortTy <NoOp>
// CHECK-NEXT: InitListExpr{{.*}}'typename HasInt::ShortTy':'short'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}kernels
// CHECK-NEXT: vector_length clause
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'char' <UserDefinedConversion>
// CHECK-NEXT: CXXMemberCallExpr{{.*}}'char'
// CHECK-NEXT: MemberExpr{{.*}} '<bound member function type>' .operator char
// CHECK-NEXT: DeclRefExpr{{.*}} 'HasInt' lvalue ParmVar
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt

// CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
// CHECK-NEXT: vector_length clause
// CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr{{.*}} 'const int' lvalue Var{{.*}} 'value' 'const int'
// CHECK-NEXT: NestedNameSpecifier TypeSpec 'HasInt'
// CHECK-NEXT: WhileStmt
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt
}

struct HasInt {
using IntTy = int;
using ShortTy = short;
static constexpr int value = 1;

operator char();
};

void Inst() {
TemplUses<CorrectConvert, HasInt>({}, {});
}
#endif // PCH_HELPER
33 changes: 33 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-num_workers-clause.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// RUN: %clang_cc1 %s -fopenacc -verify

short getS();

void Test() {
#pragma acc parallel num_workers(1)
while(1);
#pragma acc kernels num_workers(1)
while(1);

// expected-error@+1{{OpenACC 'num_workers' clause is not valid on 'serial' directive}}
#pragma acc serial num_workers(1)
while(1);

struct NotConvertible{} NC;
// expected-error@+1{{OpenACC clause 'num_workers' requires expression of integer type ('struct NotConvertible' invalid)}}
#pragma acc parallel num_workers(NC)
while(1);

#pragma acc kernels num_workers(getS())
while(1);

struct Incomplete *SomeIncomplete;

// expected-error@+1{{OpenACC clause 'num_workers' requires expression of integer type ('struct Incomplete' invalid)}}
#pragma acc kernels num_workers(*SomeIncomplete)
while(1);

enum E{A} SomeE;

#pragma acc kernels num_workers(SomeE)
while(1);
}
133 changes: 133 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-num_workers-clause.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// RUN: %clang_cc1 %s -fopenacc -verify

struct NotConvertible{} NC;
struct Incomplete *SomeIncomplete; // #INCOMPLETE
enum E{} SomeE;
enum class E2{} SomeE2;

struct CorrectConvert {
operator int();
} Convert;

struct ExplicitConvertOnly {
explicit operator int() const; // #EXPL_CONV
} Explicit;

struct AmbiguousConvert{
operator int(); // #AMBIG_INT
operator short(); // #AMBIG_SHORT
operator float();
} Ambiguous;

void Test() {
#pragma acc parallel num_workers(1)
while(1);
#pragma acc kernels num_workers(1)
while(1);

// expected-error@+1{{OpenACC clause 'num_workers' requires expression of integer type ('struct NotConvertible' invalid}}
#pragma acc parallel num_workers(NC)
while(1);

// expected-error@+2{{OpenACC integer expression has incomplete class type 'struct Incomplete'}}
// expected-note@#INCOMPLETE{{forward declaration of 'Incomplete'}}
#pragma acc kernels num_workers(*SomeIncomplete)
while(1);

#pragma acc parallel num_workers(SomeE)
while(1);

// expected-error@+1{{OpenACC clause 'num_workers' requires expression of integer type ('enum E2' invalid}}
#pragma acc kernels num_workers(SomeE2)
while(1);

#pragma acc parallel num_workers(Convert)
while(1);

// expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
#pragma acc kernels num_workers(Explicit)
while(1);

// expected-error@+3{{multiple conversions from expression type 'struct AmbiguousConvert' to an integral type}}
// expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
// expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
#pragma acc parallel num_workers(Ambiguous)
while(1);
}

struct HasInt {
using IntTy = int;
using ShortTy = short;
static constexpr int value = 1;
static constexpr AmbiguousConvert ACValue;
static constexpr ExplicitConvertOnly EXValue;

operator char();
};

template<typename T>
void TestInst() {

// expected-error@+1{{no member named 'Invalid' in 'HasInt'}}
#pragma acc parallel num_workers(HasInt::Invalid)
while (1);

// expected-error@+2{{no member named 'Invalid' in 'HasInt'}}
// expected-note@#INST{{in instantiation of function template specialization 'TestInst<HasInt>' requested here}}
#pragma acc kernels num_workers(T::Invalid)
while (1);

// expected-error@+3{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}}
// expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
// expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
#pragma acc parallel num_workers(HasInt::ACValue)
while (1);

// expected-error@+3{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}}
// expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
// expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
#pragma acc kernels num_workers(T::ACValue)
while (1);

// expected-error@+2{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
#pragma acc parallel num_workers(HasInt::EXValue)
while (1);

// expected-error@+2{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
#pragma acc kernels num_workers(T::EXValue)
while (1);

#pragma acc parallel num_workers(HasInt::value)
while (1);

#pragma acc kernels num_workers(T::value)
while (1);

#pragma acc parallel num_workers(HasInt::IntTy{})
while (1);

#pragma acc kernels num_workers(typename T::ShortTy{})
while (1);

#pragma acc parallel num_workers(HasInt::IntTy{})
while (1);

#pragma acc kernels num_workers(typename T::ShortTy{})
while (1);

HasInt HI{};
T MyT{};

#pragma acc parallel num_workers(HI)
while (1);

#pragma acc kernels num_workers(MyT)
while (1);
}

void Inst() {
TestInst<HasInt>(); // #INST
}
33 changes: 33 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-vector_length-clause.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// RUN: %clang_cc1 %s -fopenacc -verify

short getS();

void Test() {
#pragma acc parallel vector_length(1)
while(1);
#pragma acc kernels vector_length(1)
while(1);

// expected-error@+1{{OpenACC 'vector_length' clause is not valid on 'serial' directive}}
#pragma acc serial vector_length(1)
while(1);

struct NotConvertible{} NC;
// expected-error@+1{{OpenACC clause 'vector_length' requires expression of integer type ('struct NotConvertible' invalid)}}
#pragma acc parallel vector_length(NC)
while(1);

#pragma acc kernels vector_length(getS())
while(1);

struct Incomplete *SomeIncomplete;

// expected-error@+1{{OpenACC clause 'vector_length' requires expression of integer type ('struct Incomplete' invalid)}}
#pragma acc kernels vector_length(*SomeIncomplete)
while(1);

enum E{A} SomeE;

#pragma acc kernels vector_length(SomeE)
while(1);
}
133 changes: 133 additions & 0 deletions clang/test/SemaOpenACC/compute-construct-vector_length-clause.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// RUN: %clang_cc1 %s -fopenacc -verify

struct NotConvertible{} NC;
struct Incomplete *SomeIncomplete; // #INCOMPLETE
enum E{} SomeE;
enum class E2{} SomeE2;

struct CorrectConvert {
operator int();
} Convert;

struct ExplicitConvertOnly {
explicit operator int() const; // #EXPL_CONV
} Explicit;

struct AmbiguousConvert{
operator int(); // #AMBIG_INT
operator short(); // #AMBIG_SHORT
operator float();
} Ambiguous;

void Test() {
#pragma acc parallel vector_length(1)
while(1);
#pragma acc kernels vector_length(1)
while(1);

// expected-error@+1{{OpenACC clause 'vector_length' requires expression of integer type ('struct NotConvertible' invalid}}
#pragma acc parallel vector_length(NC)
while(1);

// expected-error@+2{{OpenACC integer expression has incomplete class type 'struct Incomplete'}}
// expected-note@#INCOMPLETE{{forward declaration of 'Incomplete'}}
#pragma acc kernels vector_length(*SomeIncomplete)
while(1);

#pragma acc parallel vector_length(SomeE)
while(1);

// expected-error@+1{{OpenACC clause 'vector_length' requires expression of integer type ('enum E2' invalid}}
#pragma acc kernels vector_length(SomeE2)
while(1);

#pragma acc parallel vector_length(Convert)
while(1);

// expected-error@+2{{OpenACC integer expression type 'struct ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
#pragma acc kernels vector_length(Explicit)
while(1);

// expected-error@+3{{multiple conversions from expression type 'struct AmbiguousConvert' to an integral type}}
// expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
// expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
#pragma acc parallel vector_length(Ambiguous)
while(1);
}

struct HasInt {
using IntTy = int;
using ShortTy = short;
static constexpr int value = 1;
static constexpr AmbiguousConvert ACValue;
static constexpr ExplicitConvertOnly EXValue;

operator char();
};

template<typename T>
void TestInst() {

// expected-error@+1{{no member named 'Invalid' in 'HasInt'}}
#pragma acc parallel vector_length(HasInt::Invalid)
while (1);

// expected-error@+2{{no member named 'Invalid' in 'HasInt'}}
// expected-note@#INST{{in instantiation of function template specialization 'TestInst<HasInt>' requested here}}
#pragma acc kernels vector_length(T::Invalid)
while (1);

// expected-error@+3{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}}
// expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
// expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
#pragma acc parallel vector_length(HasInt::ACValue)
while (1);

// expected-error@+3{{multiple conversions from expression type 'const AmbiguousConvert' to an integral type}}
// expected-note@#AMBIG_INT{{conversion to integral type 'int'}}
// expected-note@#AMBIG_SHORT{{conversion to integral type 'short'}}
#pragma acc kernels vector_length(T::ACValue)
while (1);

// expected-error@+2{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
#pragma acc parallel vector_length(HasInt::EXValue)
while (1);

// expected-error@+2{{OpenACC integer expression type 'const ExplicitConvertOnly' requires explicit conversion to 'int'}}
// expected-note@#EXPL_CONV{{conversion to integral type 'int'}}
#pragma acc kernels vector_length(T::EXValue)
while (1);

#pragma acc parallel vector_length(HasInt::value)
while (1);

#pragma acc kernels vector_length(T::value)
while (1);

#pragma acc parallel vector_length(HasInt::IntTy{})
while (1);

#pragma acc kernels vector_length(typename T::ShortTy{})
while (1);

#pragma acc parallel vector_length(HasInt::IntTy{})
while (1);

#pragma acc kernels vector_length(typename T::ShortTy{})
while (1);

HasInt HI{};
T MyT{};

#pragma acc parallel vector_length(HI)
while (1);

#pragma acc kernels vector_length(MyT)
while (1);
}

void Inst() {
TestInst<HasInt>(); // #INST
}
8 changes: 8 additions & 0 deletions clang/tools/libclang/CIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2795,6 +2795,14 @@ void OpenACCClauseEnqueue::VisitSelfClause(const OpenACCSelfClause &C) {
if (C.hasConditionExpr())
Visitor.AddStmt(C.getConditionExpr());
}
void OpenACCClauseEnqueue::VisitNumWorkersClause(
const OpenACCNumWorkersClause &C) {
Visitor.AddStmt(C.getIntExpr());
}
void OpenACCClauseEnqueue::VisitVectorLengthClause(
const OpenACCVectorLengthClause &C) {
Visitor.AddStmt(C.getIntExpr());
}
} // namespace

void EnqueueVisitor::EnqueueChildren(const OpenACCClause *C) {
Expand Down
16 changes: 7 additions & 9 deletions libc/docs/dev/config_options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@ hierarchical JSON files. At the top of the hierarchy is a JSON file by name
options which affect all platforms. The default value for the option and a short
description about it listed against each option. For example:

.. code-block::
.. code-block:: json

{
"printf": {
"LIBC_CONF_PRINTF_DISABLE_FLOAT": {
"value": false,
"doc": "Disable printing floating point values in printf and friends."
},
...
}
}
}

Expand All @@ -28,7 +27,7 @@ has a value of ``false``. A platform, say the baremetal platform, can choose
to override this value in its ``config.json`` file in the ``config/baremetal``
directory with the following contents:

.. code-block::
.. code-block:: json

{
"printf": {
Expand Down Expand Up @@ -61,14 +60,13 @@ The value corresponding to each grouping tag is also a dictionary called the
options belonging to that grouping tag. For the ``printf`` tag in the above
example, the option-dictionary is:

.. code-block::
.. code-block:: json

{
"LIBC_CONF_PRINTF_DISABLE_FLOAT": {
"value": false,
"doc":
},
...
}
}

The value corresponding to an option key in the option-dictionary is another
Expand All @@ -86,7 +84,7 @@ Option name format

The option names, or the keys of a option-dictionary, have the following format:

.. code-block::
.. code-block:: none

LIBC_CONF_<UPPER_CASE_TAG_NAME>_<ACTION_INDICATING_THE_INTENDED_SEMANTICS>

Expand Down Expand Up @@ -123,7 +121,7 @@ should convert the CMake config options to appropriate compiler and/or linker
flags. Those compile/link flags can be used in listing the affected targets as
follows:

.. code-block::
.. code-block:: cmake

add_object_library(
...
Expand Down
1 change: 1 addition & 0 deletions libc/docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ stages there is no ABI stability in any form.
c23
ctype
signal
threads

.. toctree::
:hidden:
Expand Down
88 changes: 88 additions & 0 deletions libc/docs/threads.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
.. include:: check.rst

threads.h Functions
===================

.. list-table::
:widths: auto
:align: center
:header-rows: 1

* - Function
- Implemented
- Standard
* - call_once
- |check|
- 7.28.2.1
* - cnd_broadcast
- |check|
- 7.28.3.1
* - cnd_destroy
- |check|
- 7.28.3.2
* - cnd_init
- |check|
- 7.28.3.3
* - cnd_signal
- |check|
- 7.28.3.4
* - cnd_timedwait
-
- 7.28.3.5
* - cnd_wait
- |check|
- 7.28.3.6
* - mtx_destroy
- |check|
- 7.28.4.1
* - mtx_init
- |check|
- 7.28.4.2
* - mtx_lock
- |check|
- 7.28.4.3
* - mtx_timedlock
-
- 7.28.4.4
* - mtx_trylock
-
- 7.28.4.5
* - mtx_unlock
- |check|
- 7.28.4.6
* - thrd_create
- |check|
- 7.28.5.1
* - thrd_current
- |check|
- 7.28.5.2
* - thrd_detach
- |check|
- 7.28.5.3
* - thrd_equal
- |check|
- 7.28.5.4
* - thrd_exit
- |check|
- 7.28.5.5
* - thrd_join
- |check|
- 7.28.5.6
* - thrd_sleep
-
- 7.28.5.7
* - thrd_yield
-
- 7.28.5.8
* - tss_create
- |check|
- 7.28.6.1
* - tss_delete
- |check|
- 7.28.6.2
* - tss_get
- |check|
- 7.28.6.3
* - tss_set
- |check|
- 7.28.6.4
2 changes: 2 additions & 0 deletions libc/src/unistd/linux/pipe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/common.h"
#include "src/__support/macros/sanitizer.h" // for MSAN_UNPOISON
#include "src/errno/libc_errno.h"
#include <sys/syscall.h> // For syscall numbers.

Expand All @@ -23,6 +24,7 @@ LLVM_LIBC_FUNCTION(int, pipe, (int pipefd[2])) {
int ret = LIBC_NAMESPACE::syscall_impl<int>(
SYS_pipe2, reinterpret_cast<long>(pipefd), 0);
#endif
MSAN_UNPOISON(pipefd, sizeof(int) * 2);
if (ret < 0) {
libc_errno = -ret;
return -1;
Expand Down
62 changes: 59 additions & 3 deletions libc/utils/docgen/fenv.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,63 @@
{
"macros": [
"__STDC_VERSION_FENV_H__"
],
"macros": {
"__STDC_VERSION_FENV_H__": {
"defined": "7.6.5"
},
"FE_DIVBYZERO": {
"defined": "7.6.9"
},
"FE_INEXACT": {
"defined": "7.6.9"
},
"FE_INVALID": {
"defined": "7.6.9"
},
"FE_OVERFLOW": {
"defined": "7.6.9"
},
"FE_UNDERFLOW": {
"defined": "7.6.9"
},
"FE_ALL_EXCEPT": {
"defined": "7.6.12"
},
"FE_DFL_MODE": {
"defined": "7.6.11"
},
"FE_DOWNARD": {
"defined": "7.6.13"
},
"FE_TONEAREST": {
"defined": "7.6.13"
},
"FE_TONEARESTFROMZERO": {
"defined": "7.6.13"
},
"FE_TOWARDZERO": {
"defined": "7.6.13"
},
"FE_UPWARD": {
"defined": "7.6.13"
},
"FE_DEC_DOWNWARD": {
"defined": "7.6.14"
},
"FE_DEC_TONEAREST": {
"defined": "7.6.14"
},
"FE_DEC_TONEARESTFROMZERO": {
"defined": "7.6.14"
},
"FE_DEC_TOWARDZERO": {
"defined": "7.6.14"
},
"FE_DEC_UPWARD": {
"defined": "7.6.14"
},
"FE_DFL_ENV": {
"defined": "7.6.17"
}
},
"functions": {
"feclearexcept": {
"defined": "7.6.4.1"
Expand Down
54 changes: 36 additions & 18 deletions libc/utils/docgen/signal.json
Original file line number Diff line number Diff line change
@@ -1,29 +1,47 @@
{
"macros": [
"SIG_DFL",
"SIG_ERR",
"SIG_IGN",
"SIGABRT",
"SIGFPE",
"SIGILL",
"SIGINT",
"SIGSEGV",
"SIGTERM"
],
"macros": {
"SIG_DFL": {
"defined": "7.14.3"
},
"SIG_ERR": {
"defined": "7.14.3"
},
"SIG_IGN": {
"defined": "7.14.3"
},
"SIGABRT": {
"defined": "7.14.3"
},
"SIGFPE": {
"defined": "7.14.3"
},
"SIGILL": {
"defined": "7.14.3"
},
"SIGINT": {
"defined": "7.14.3"
},
"SIGSEGV": {
"defined": "7.14.3"
},
"SIGTERM": {
"defined": "7.14.3"
}
},
"functions": {
"signal": {
"defined": "7.14.1.1"
},
"raise": {
"defined": "7.14.2.1"
},
"kill": null,
"sigaction": null,
"sigaddset": null,
"sigaltstack": null,
"sigdelset": null,
"sigemptyset": null,
"sigfillset": null,
"sigprocmask": null,
"signal": {
"defined": "7.14.1.1"
},
"raise": {
"defined": "7.14.2.1"
}
"sigprocmask": null
}
}
76 changes: 56 additions & 20 deletions libc/utils/docgen/stdbit.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,60 @@
{
"macros": [
"__STDC_VERSION_STDBIT_H__",
"__STDC_ENDIAN_LITTLE__",
"__STDC_ENDIAN_BIG__",
"__STDC_ENDIAN_NATIVE__",
"stdc_leading_zeros",
"stdc_leading_ones",
"stdc_trailing_zeros",
"stdc_trailing_ones",
"stdc_first_leading_zero",
"stdc_first_leading_one",
"stdc_first_trailing_zero",
"stdc_first_trailing_one",
"stdc_count_zeros",
"stdc_count_ones",
"stdc_has_single_bit",
"stdc_bit_width",
"stdc_bit_floor",
"stdc_bit_ceil"
],
"macros": {
"__STDC_VERSION_STDBIT_H__": {
"defined": "7.18.1.2"
},
"__STDC_ENDIAN_LITTLE__": {
"defined": "7.18.2.2"
},
"__STDC_ENDIAN_BIG__": {
"defined": "7.18.2.2"
},
"__STDC_ENDIAN_NATIVE__": {
"defined": "7.18.2.2"
},
"stdc_leading_zeros": {
"defined": "7.18.3.1"
},
"stdc_leading_ones": {
"defined": "7.18.4.1"
},
"stdc_trailing_zeros": {
"defined": "7.18.5.1"
},
"stdc_trailing_ones": {
"defined": "7.18.6.1"
},
"stdc_first_leading_zero": {
"defined": "7.18.7.1"
},
"stdc_first_leading_one": {
"defined": "7.18.8.1"
},
"stdc_first_trailing_zero": {
"defined": "7.18.9.1"
},
"stdc_first_trailing_one": {
"defined": "7.18.10.1"
},
"stdc_count_zeros": {
"defined": "7.18.11.1"
},
"stdc_count_ones": {
"defined": "7.18.12.1"
},
"stdc_has_single_bit": {
"defined": "7.18.13.1"
},
"stdc_bit_width": {
"defined": "7.18.14.1"
},
"stdc_bit_floor": {
"defined": "7.18.15.1"
},
"stdc_bit_ceil": {
"defined": "7.18.16.1"
}
},
"functions": {
"stdc_leading_zeros_uc": {
"defined": "7.18.3"
Expand Down
87 changes: 87 additions & 0 deletions libc/utils/docgen/threads.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{
"macros": {
"ONCE_FLAG_INIT": {
"defined": "7.28.1.3"
},
"TSS_DTOR_ITERATIONS": {
"defined": "7.28.1.3"
}
},
"functions": {
"call_once": {
"defined": "7.28.2.1"
},
"cnd_broadcast": {
"defined": "7.28.3.1"
},
"cnd_destroy": {
"defined": "7.28.3.2"
},
"cnd_init": {
"defined": "7.28.3.3"
},
"cnd_signal": {
"defined": "7.28.3.4"
},
"cnd_timedwait": {
"defined": "7.28.3.5"
},
"cnd_wait": {
"defined": "7.28.3.6"
},
"mtx_destroy": {
"defined": "7.28.4.1"
},
"mtx_init": {
"defined": "7.28.4.2"
},
"mtx_lock": {
"defined": "7.28.4.3"
},
"mtx_timedlock": {
"defined": "7.28.4.4"
},
"mtx_trylock": {
"defined": "7.28.4.5"
},
"mtx_unlock": {
"defined": "7.28.4.6"
},
"thrd_create": {
"defined": "7.28.5.1"
},
"thrd_current": {
"defined": "7.28.5.2"
},
"thrd_detach": {
"defined": "7.28.5.3"
},
"thrd_equal": {
"defined": "7.28.5.4"
},
"thrd_exit": {
"defined": "7.28.5.5"
},
"thrd_join": {
"defined": "7.28.5.6"
},
"thrd_sleep": {
"defined": "7.28.5.7"
},
"thrd_yield": {
"defined": "7.28.5.8"
},
"tss_create": {
"defined": "7.28.6.1"
},
"tss_delete": {
"defined": "7.28.6.2"
},
"tss_get": {
"defined": "7.28.6.3"
},
"tss_set": {
"defined": "7.28.6.4"
}
}
}
32 changes: 16 additions & 16 deletions lld/MachO/ICF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,13 @@ bool ICF::equalsConstant(const ConcatInputSection *ia,
assert(isa<Defined>(sa));
const auto *da = cast<Defined>(sa);
const auto *db = cast<Defined>(sb);
if (!da->isec || !db->isec) {
if (!da->isec() || !db->isec()) {
assert(da->isAbsolute() && db->isAbsolute());
return da->value + ra.addend == db->value + rb.addend;
}
isecA = da->isec;
isecA = da->isec();
valueA = da->value;
isecB = db->isec;
isecB = db->isec();
valueB = db->value;
} else {
isecA = ra.referent.get<InputSection *>();
Expand Down Expand Up @@ -191,10 +191,10 @@ bool ICF::equalsVariable(const ConcatInputSection *ia,
const auto *db = cast<Defined>(rb.referent.get<Symbol *>());
if (da->isAbsolute())
return true;
isecA = dyn_cast<ConcatInputSection>(da->isec);
isecA = dyn_cast<ConcatInputSection>(da->isec());
if (!isecA)
return true; // literal sections were checked in equalsConstant.
isecB = cast<ConcatInputSection>(db->isec);
isecB = cast<ConcatInputSection>(db->isec());
} else {
const auto *sa = ra.referent.get<InputSection *>();
const auto *sb = rb.referent.get<InputSection *>();
Expand All @@ -212,7 +212,7 @@ bool ICF::equalsVariable(const ConcatInputSection *ia,
// info matches. For simplicity, we only handle the case where there are only
// symbols at offset zero within the section (which is typically the case with
// .subsections_via_symbols.)
auto hasUnwind = [](Defined *d) { return d->unwindEntry != nullptr; };
auto hasUnwind = [](Defined *d) { return d->unwindEntry() != nullptr; };
const auto *itA = llvm::find_if(ia->symbols, hasUnwind);
const auto *itB = llvm::find_if(ib->symbols, hasUnwind);
if (itA == ia->symbols.end())
Expand All @@ -221,8 +221,8 @@ bool ICF::equalsVariable(const ConcatInputSection *ia,
return false;
const Defined *da = *itA;
const Defined *db = *itB;
if (da->unwindEntry->icfEqClass[icfPass % 2] !=
db->unwindEntry->icfEqClass[icfPass % 2] ||
if (da->unwindEntry()->icfEqClass[icfPass % 2] !=
db->unwindEntry()->icfEqClass[icfPass % 2] ||
da->value != 0 || db->value != 0)
return false;
auto isZero = [](Defined *d) { return d->value == 0; };
Expand Down Expand Up @@ -289,13 +289,13 @@ void ICF::run() {
for (const Reloc &r : isec->relocs) {
if (auto *sym = r.referent.dyn_cast<Symbol *>()) {
if (auto *defined = dyn_cast<Defined>(sym)) {
if (defined->isec) {
if (defined->isec()) {
if (auto *referentIsec =
dyn_cast<ConcatInputSection>(defined->isec))
dyn_cast<ConcatInputSection>(defined->isec()))
hash += defined->value + referentIsec->icfEqClass[icfPass % 2];
else
hash += defined->isec->kind() +
defined->isec->getOffset(defined->value);
hash += defined->isec()->kind() +
defined->isec()->getOffset(defined->value);
} else {
hash += defined->value;
}
Expand Down Expand Up @@ -368,8 +368,8 @@ void ICF::segregate(size_t begin, size_t end, EqualsFn equals) {

void macho::markSymAsAddrSig(Symbol *s) {
if (auto *d = dyn_cast_or_null<Defined>(s))
if (d->isec)
d->isec->keepUnique = true;
if (d->isec())
d->isec()->keepUnique = true;
}

void macho::markAddrSigSymbols() {
Expand Down Expand Up @@ -430,8 +430,8 @@ void macho::foldIdenticalSections(bool onlyCfStrings) {
if (isFoldable) {
foldable.push_back(isec);
for (Defined *d : isec->symbols)
if (d->unwindEntry)
foldable.push_back(d->unwindEntry);
if (d->unwindEntry())
foldable.push_back(d->unwindEntry());

// Some sections have embedded addends that foil ICF's hashing / equality
// checks. (We can ignore embedded addends when doing ICF because the same
Expand Down
19 changes: 10 additions & 9 deletions lld/MachO/InputFiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1170,7 +1170,7 @@ void ObjFile::registerCompactUnwind(Section &compactUnwindSection) {
continue;
}
add += sym->value;
referentIsec = cast<ConcatInputSection>(sym->isec);
referentIsec = cast<ConcatInputSection>(sym->isec());
} else {
referentIsec =
cast<ConcatInputSection>(r.referent.dyn_cast<InputSection *>());
Expand All @@ -1191,7 +1191,7 @@ void ObjFile::registerCompactUnwind(Section &compactUnwindSection) {
++it;
continue;
}
d->unwindEntry = isec;
d->originalUnwindEntry = isec;
// Now that the symbol points to the unwind entry, we can remove the reloc
// that points from the unwind entry back to the symbol.
//
Expand Down Expand Up @@ -1348,7 +1348,7 @@ targetSymFromCanonicalSubtractor(const InputSection *isec,
}
if (Invert)
std::swap(pcSym, target);
if (pcSym->isec == isec) {
if (pcSym->isec() == isec) {
if (pcSym->value - (Invert ? -1 : 1) * minuend.addend != subtrahend.offset)
fatal("invalid FDE relocation in __eh_frame");
} else {
Expand Down Expand Up @@ -1420,7 +1420,7 @@ void ObjFile::registerEhFrames(Section &ehFrameSection) {
// We already have an explicit relocation for the CIE offset.
cieIsec =
targetSymFromCanonicalSubtractor</*Invert=*/true>(isec, cieOffRelocIt)
->isec;
->isec();
dataOff += sizeof(uint32_t);
} else {
// If we haven't found a relocation, then the CIE offset is most likely
Expand Down Expand Up @@ -1480,15 +1480,15 @@ void ObjFile::registerEhFrames(Section &ehFrameSection) {
// to register the unwind entry under same symbol.
// This is not particularly efficient, but we should run into this case
// infrequently (only when handling the output of `ld -r`).
if (funcSym->isec)
funcSym = findSymbolAtOffset(cast<ConcatInputSection>(funcSym->isec),
if (funcSym->isec())
funcSym = findSymbolAtOffset(cast<ConcatInputSection>(funcSym->isec()),
funcSym->value);
} else {
funcSym = findSymbolAtAddress(sections, funcAddr);
ehRelocator.makePcRel(funcAddrOff, funcSym, target->p2WordSize);
}
// The symbol has been coalesced, or already has a compact unwind entry.
if (!funcSym || funcSym->getFile() != this || funcSym->unwindEntry) {
if (!funcSym || funcSym->getFile() != this || funcSym->unwindEntry()) {
// We must prune unused FDEs for correctness, so we cannot rely on
// -dead_strip being enabled.
isec->live = false;
Expand All @@ -1497,7 +1497,8 @@ void ObjFile::registerEhFrames(Section &ehFrameSection) {

InputSection *lsdaIsec = nullptr;
if (lsdaAddrRelocIt != isec->relocs.end()) {
lsdaIsec = targetSymFromCanonicalSubtractor(isec, lsdaAddrRelocIt)->isec;
lsdaIsec =
targetSymFromCanonicalSubtractor(isec, lsdaAddrRelocIt)->isec();
} else if (lsdaAddrOpt) {
uint64_t lsdaAddr = *lsdaAddrOpt;
Section *sec = findContainingSection(sections, &lsdaAddr);
Expand All @@ -1507,7 +1508,7 @@ void ObjFile::registerEhFrames(Section &ehFrameSection) {
}

fdes[isec] = {funcLength, cie.personalitySymbol, lsdaIsec};
funcSym->unwindEntry = isec;
funcSym->originalUnwindEntry = isec;
ehRelocator.commit();
}

Expand Down
6 changes: 2 additions & 4 deletions lld/MachO/InputSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,8 @@ void ConcatInputSection::foldIdentical(ConcatInputSection *copy) {
copy->live = false;
copy->wasCoalesced = true;
copy->replacement = this;
for (auto &copySym : copy->symbols) {
for (auto &copySym : copy->symbols)
copySym->wasIdenticalCodeFolded = true;
copySym->size = 0;
}

symbols.insert(symbols.end(), copy->symbols.begin(), copy->symbols.end());
copy->symbols.clear();
Expand All @@ -207,7 +205,7 @@ void ConcatInputSection::foldIdentical(ConcatInputSection *copy) {
return;
for (auto it = symbols.begin() + 1; it != symbols.end(); ++it) {
assert((*it)->value == 0);
(*it)->unwindEntry = nullptr;
(*it)->originalUnwindEntry = nullptr;
}
}

Expand Down
17 changes: 12 additions & 5 deletions lld/MachO/MapFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ static MapInfo gatherMapInfo() {
// Only emit the prevailing definition of a symbol. Also, don't emit
// the symbol if it is part of a cstring section (we use the literal
// value instead, similar to ld64)
if (d->isec && d->getFile() == file &&
!isa<CStringInputSection>(d->isec)) {
if (d->isec() && d->getFile() == file &&
!isa<CStringInputSection>(d->isec())) {
isReferencedFile = true;
if (!d->isLive())
info.deadSymbols.push_back(d);
Expand Down Expand Up @@ -155,6 +155,12 @@ static void printNonLazyPointerSection(raw_fd_ostream &os,
target->wordSize, sym->getName().str().data());
}

static uint64_t getSymSizeForMap(Defined *sym) {
if (sym->wasIdenticalCodeFolded)
return 0;
return sym->size;
}

void macho::writeMapFile() {
if (config->mapFile.empty())
return;
Expand Down Expand Up @@ -201,9 +207,10 @@ void macho::writeMapFile() {
auto printIsecArrSyms = [&](const std::vector<ConcatInputSection *> &arr) {
for (const ConcatInputSection *isec : arr) {
for (Defined *sym : isec->symbols) {
if (!(isPrivateLabel(sym->getName()) && sym->size == 0))
if (!(isPrivateLabel(sym->getName()) && getSymSizeForMap(sym) == 0))
os << format("0x%08llX\t0x%08llX\t[%3u] %s\n", sym->getVA(),
sym->size, readerToFileOrdinal[sym->getFile()],
getSymSizeForMap(sym),
readerToFileOrdinal[sym->getFile()],
sym->getName().str().data());
}
}
Expand Down Expand Up @@ -255,7 +262,7 @@ void macho::writeMapFile() {
os << "# \tSize \tFile Name\n";
for (Defined *sym : info.deadSymbols) {
assert(!sym->isLive());
os << format("<<dead>>\t0x%08llX\t[%3u] %s\n", sym->size,
os << format("<<dead>>\t0x%08llX\t[%3u] %s\n", getSymSizeForMap(sym),
readerToFileOrdinal[sym->getFile()],
sym->getName().str().data());
}
Expand Down
10 changes: 5 additions & 5 deletions lld/MachO/MarkLive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,10 @@ void MarkLiveImpl<RecordWhyLive>::addSym(
if (!config->whyLive.empty() && config->whyLive.match(s->getName()))
printWhyLive(s, prev);
if (auto *d = dyn_cast<Defined>(s)) {
if (d->isec)
enqueue(d->isec, d->value, prev);
if (d->unwindEntry)
enqueue(d->unwindEntry, 0, prev);
if (d->isec())
enqueue(d->isec(), d->value, prev);
if (d->unwindEntry())
enqueue(d->unwindEntry(), 0, prev);
}
}

Expand Down Expand Up @@ -179,7 +179,7 @@ void MarkLiveImpl<RecordWhyLive>::markTransitively() {
if (s->isLive()) {
InputSection *referentIsec = nullptr;
if (auto *d = dyn_cast<Defined>(s))
referentIsec = d->isec;
referentIsec = d->isec();
enqueue(isec, 0, makeEntry(referentIsec, nullptr));
}
} else {
Expand Down
36 changes: 18 additions & 18 deletions lld/MachO/ObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,8 @@ static StringRef getReferentString(const Reloc &r) {
if (auto *isec = r.referent.dyn_cast<InputSection *>())
return cast<CStringInputSection>(isec)->getStringRefAtOffset(r.addend);
auto *sym = cast<Defined>(r.referent.get<Symbol *>());
return cast<CStringInputSection>(sym->isec)->getStringRefAtOffset(sym->value +
r.addend);
return cast<CStringInputSection>(sym->isec())
->getStringRefAtOffset(sym->value + r.addend);
}

void ObjcCategoryChecker::parseMethods(const ConcatInputSection *methodsIsec,
Expand Down Expand Up @@ -306,15 +306,15 @@ void ObjcCategoryChecker::parseClass(const Defined *classSym) {
return nullptr;
};

const auto *classIsec = cast<ConcatInputSection>(classSym->isec);
const auto *classIsec = cast<ConcatInputSection>(classSym->isec());

// Parse instance methods.
if (const auto *instanceMethodsIsec = getMethodsIsec(classIsec))
parseMethods(instanceMethodsIsec, classSym, classIsec, MCK_Class,
MK_Instance);

// Class methods are contained in the metaclass.
if (const auto *r = classSym->isec->getRelocAt(classLayout.metaClassOffset))
if (const auto *r = classSym->isec()->getRelocAt(classLayout.metaClassOffset))
if (const auto *classMethodsIsec = getMethodsIsec(
cast<ConcatInputSection>(r->getReferentInputSection())))
parseMethods(classMethodsIsec, classSym, classIsec, MCK_Class, MK_Static);
Expand Down Expand Up @@ -561,9 +561,9 @@ void ObjcCategoryMerger::tryEraseDefinedAtIsecOffset(
if (!sym)
return;

if (auto *cisec = dyn_cast_or_null<ConcatInputSection>(sym->isec))
if (auto *cisec = dyn_cast_or_null<ConcatInputSection>(sym->isec()))
eraseISec(cisec);
else if (auto *csisec = dyn_cast_or_null<CStringInputSection>(sym->isec)) {
else if (auto *csisec = dyn_cast_or_null<CStringInputSection>(sym->isec())) {
uint32_t totalOffset = sym->value + reloc->addend;
StringPiece &piece = csisec->getStringPiece(totalOffset);
piece.live = false;
Expand All @@ -588,7 +588,7 @@ void ObjcCategoryMerger::collectCategoryWriterInfoFromCategory(
assert(catNameSym && "Category does not have a valid name Symbol");

collectSectionWriteInfoFromIsec<CStringSection>(
catNameSym->isec, infoCategoryWriter.catNameInfo);
catNameSym->isec(), infoCategoryWriter.catNameInfo);
}

// Collect writer info from all the category lists (we're assuming they all
Expand All @@ -599,7 +599,7 @@ void ObjcCategoryMerger::collectCategoryWriterInfoFromCategory(
if (Defined *ptrList =
tryGetDefinedAtIsecOffset(catInfo.catBodyIsec, off)) {
collectSectionWriteInfoFromIsec<ConcatOutputSection>(
ptrList->isec, infoCategoryWriter.catPtrListInfo);
ptrList->isec(), infoCategoryWriter.catPtrListInfo);
// we've successfully collected data, so we can break
break;
}
Expand Down Expand Up @@ -627,7 +627,7 @@ void ObjcCategoryMerger::parseProtocolListInfo(const ConcatInputSection *isec,
// platform pointer size, but to simplify implementation we always just read
// the lower 32b which should be good enough.
uint32_t protocolCount = *reinterpret_cast<const uint32_t *>(
ptrListSym->isec->data.data() + listHeaderLayout.structSizeOffset);
ptrListSym->isec()->data.data() + listHeaderLayout.structSizeOffset);

ptrList.structCount += protocolCount;
ptrList.structSize = target->wordSize;
Expand All @@ -636,15 +636,15 @@ void ObjcCategoryMerger::parseProtocolListInfo(const ConcatInputSection *isec,
(protocolCount * target->wordSize) +
/*header(count)*/ protocolListHeaderLayout.totalSize +
/*extra null value*/ target->wordSize;
assert(expectedListSize == ptrListSym->isec->data.size() &&
assert(expectedListSize == ptrListSym->isec()->data.size() &&
"Protocol list does not match expected size");

// Suppress unsuded var warning
(void)expectedListSize;

uint32_t off = protocolListHeaderLayout.totalSize;
for (uint32_t inx = 0; inx < protocolCount; ++inx) {
const Reloc *reloc = ptrListSym->isec->getRelocAt(off);
const Reloc *reloc = ptrListSym->isec()->getRelocAt(off);
assert(reloc && "No reloc found at protocol list offset");

auto *listSym = dyn_cast_or_null<Defined>(reloc->referent.get<Symbol *>());
Expand All @@ -653,7 +653,7 @@ void ObjcCategoryMerger::parseProtocolListInfo(const ConcatInputSection *isec,
ptrList.allPtrs.push_back(listSym);
off += target->wordSize;
}
assert((ptrListSym->isec->getRelocAt(off) == nullptr) &&
assert((ptrListSym->isec()->getRelocAt(off) == nullptr) &&
"expected null terminating protocol");
assert(off + /*extra null value*/ target->wordSize == expectedListSize &&
"Protocol list end offset does not match expected size");
Expand All @@ -678,9 +678,9 @@ void ObjcCategoryMerger::parsePointerListInfo(const ConcatInputSection *isec,
assert(ptrListSym && "Reloc does not have a valid Defined");

uint32_t thisStructSize = *reinterpret_cast<const uint32_t *>(
ptrListSym->isec->data.data() + listHeaderLayout.structSizeOffset);
ptrListSym->isec()->data.data() + listHeaderLayout.structSizeOffset);
uint32_t thisStructCount = *reinterpret_cast<const uint32_t *>(
ptrListSym->isec->data.data() + listHeaderLayout.structCountOffset);
ptrListSym->isec()->data.data() + listHeaderLayout.structCountOffset);
assert(thisStructSize == ptrList.pointersPerStruct * target->wordSize);

assert(!ptrList.structSize || (thisStructSize == ptrList.structSize));
Expand All @@ -690,12 +690,12 @@ void ObjcCategoryMerger::parsePointerListInfo(const ConcatInputSection *isec,

uint32_t expectedListSize =
listHeaderLayout.totalSize + (thisStructSize * thisStructCount);
assert(expectedListSize == ptrListSym->isec->data.size() &&
assert(expectedListSize == ptrListSym->isec()->data.size() &&
"Pointer list does not match expected size");

for (uint32_t off = listHeaderLayout.totalSize; off < expectedListSize;
off += target->wordSize) {
const Reloc *reloc = ptrListSym->isec->getRelocAt(off);
const Reloc *reloc = ptrListSym->isec()->getRelocAt(off);
assert(reloc && "No reloc found at pointer list offset");

auto *listSym = dyn_cast_or_null<Defined>(reloc->referent.get<Symbol *>());
Expand Down Expand Up @@ -1054,7 +1054,7 @@ void ObjcCategoryMerger::createSymbolReference(Defined *refFrom,
r.offset = offset;
r.addend = 0;
r.referent = const_cast<Symbol *>(refTo);
refFrom->isec->relocs.push_back(r);
refFrom->isec()->relocs.push_back(r);
}

void ObjcCategoryMerger::collectAndValidateCategoriesData() {
Expand All @@ -1076,7 +1076,7 @@ void ObjcCategoryMerger::collectAndValidateCategoriesData() {
if (!categorySym->getName().starts_with(objc::symbol_names::category))
continue;

auto *catBodyIsec = dyn_cast<ConcatInputSection>(categorySym->isec);
auto *catBodyIsec = dyn_cast<ConcatInputSection>(categorySym->isec());
assert(catBodyIsec &&
"Category data section is not an ConcatInputSection");

Expand Down
2 changes: 1 addition & 1 deletion lld/MachO/Relocations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ static_assert(sizeof(void *) != 8 || sizeof(Reloc) == 24,
InputSection *Reloc::getReferentInputSection() const {
if (const auto *sym = referent.dyn_cast<Symbol *>()) {
if (const auto *d = dyn_cast<Defined>(sym))
return d->isec;
return d->isec();
return nullptr;
} else {
return referent.get<InputSection *>();
Expand Down
8 changes: 4 additions & 4 deletions lld/MachO/SectionPriorities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ DenseMap<const InputSection *, size_t> CallGraphSort::run() {
// section.
for (Symbol *sym : isec->getFile()->symbols) {
if (auto *d = dyn_cast_or_null<Defined>(sym)) {
if (d->isec == isec)
if (d->isec() == isec)
os << sym->getName() << "\n";
}
}
Expand All @@ -258,7 +258,7 @@ macho::PriorityBuilder::getSymbolPriority(const Defined *sym) {
if (it == priorities.end())
return std::nullopt;
const SymbolPriorityEntry &entry = it->second;
const InputFile *f = sym->isec->getFile();
const InputFile *f = sym->isec()->getFile();
if (!f)
return entry.anyObjectFile;
// We don't use toString(InputFile *) here because it returns the full path
Expand Down Expand Up @@ -287,7 +287,7 @@ void macho::PriorityBuilder::extractCallGraphProfile() {
if (fromSym && toSym &&
(!hasOrderFile ||
(!getSymbolPriority(fromSym) && !getSymbolPriority(toSym))))
callGraphProfile[{fromSym->isec, toSym->isec}] += entry.count;
callGraphProfile[{fromSym->isec(), toSym->isec()}] += entry.count;
}
}
}
Expand Down Expand Up @@ -370,7 +370,7 @@ macho::PriorityBuilder::buildInputSectionPriorities() {
std::optional<size_t> symbolPriority = getSymbolPriority(sym);
if (!symbolPriority)
return;
size_t &priority = sectionPriorities[sym->isec];
size_t &priority = sectionPriorities[sym->isec()];
priority = std::max(priority, *symbolPriority);
};

Expand Down
12 changes: 6 additions & 6 deletions lld/MachO/SymbolTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,14 @@ static void transplantSymbolsAtOffset(InputSection *fromIsec,
// iterator. However, that is typically the case for files that have
// .subsections_via_symbols set.
insertIt = toIsec->symbols.insert(insertIt, d);
d->isec = toIsec;
d->originalIsec = toIsec;
d->value = toOff;
// We don't want to have more than one unwindEntry at a given address, so
// drop the redundant ones. We We can safely drop the unwindEntries of
// the symbols in fromIsec since we will be adding another unwindEntry as
// we finish parsing toIsec's file. (We can assume that toIsec has its
// own unwindEntry because of the ODR.)
d->unwindEntry = nullptr;
d->originalUnwindEntry = nullptr;
}
return true;
});
Expand Down Expand Up @@ -121,16 +121,16 @@ Defined *SymbolTable::addDefined(StringRef name, InputFile *file,
// in ObjFile::parseSymbols() such that extern weak symbols appear
// last, so we don't need to worry about subsequent symbols being
// added to an already-coalesced section.
if (defined->isec)
transplantSymbolsAtOffset(concatIsec, defined->isec,
if (defined->isec())
transplantSymbolsAtOffset(concatIsec, defined->isec(),
/*skip=*/nullptr, value, defined->value);
}
return defined;
}

if (defined->isWeakDef()) {
if (auto concatIsec =
dyn_cast_or_null<ConcatInputSection>(defined->isec)) {
dyn_cast_or_null<ConcatInputSection>(defined->isec())) {
concatIsec->wasCoalesced = true;
if (isec)
transplantSymbolsAtOffset(concatIsec, isec, defined, defined->value,
Expand Down Expand Up @@ -212,7 +212,7 @@ Defined *SymbolTable::addDefined(StringRef name, InputFile *file,
Defined *SymbolTable::aliasDefined(Defined *src, StringRef target,
InputFile *newFile, bool makePrivateExtern) {
bool isPrivateExtern = makePrivateExtern || src->privateExtern;
return addDefined(target, newFile, src->isec, src->value, src->size,
return addDefined(target, newFile, src->isec(), src->value, src->size,
src->isWeakDef(), isPrivateExtern,
src->referencedDynamically, src->noDeadStrip,
src->weakDefCanBeHidden);
Expand Down
34 changes: 19 additions & 15 deletions lld/MachO/Symbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ Defined::Defined(StringRefZ name, InputFile *file, InputSection *isec,
wasIdenticalCodeFolded(false),
referencedDynamically(isReferencedDynamically), noDeadStrip(noDeadStrip),
interposable(interposable), weakDefCanBeHidden(isWeakDefCanBeHidden),
weakDef(isWeakDef), external(isExternal), isec(isec), value(value),
size(size) {
weakDef(isWeakDef), external(isExternal), originalIsec(isec),
value(value), size(size) {
if (isec) {
isec->symbols.push_back(this);
// Maintain sorted order.
Expand All @@ -82,7 +82,7 @@ Defined::Defined(StringRefZ name, InputFile *file, InputSection *isec,
}

bool Defined::isTlv() const {
return !isAbsolute() && isThreadLocalVariables(isec->getFlags());
return !isAbsolute() && isThreadLocalVariables(originalIsec->getFlags());
}

uint64_t Defined::getVA() const {
Expand All @@ -91,7 +91,7 @@ uint64_t Defined::getVA() const {
if (isAbsolute())
return value;

if (!isec->isFinal) {
if (!isec()->isFinal) {
// A target arch that does not use thunks ought never ask for
// the address of a function that has not yet been finalized.
assert(target->usesThunks());
Expand All @@ -102,24 +102,28 @@ uint64_t Defined::getVA() const {
// expedient to return a contrived out-of-range address.
return TargetInfo::outOfRangeVA;
}
return isec->getVA(value);
return isec()->getVA(value);
}

ObjFile *Defined::getObjectFile() const {
return isec ? dyn_cast_or_null<ObjFile>(isec->getFile()) : nullptr;
}

void Defined::canonicalize() {
if (unwindEntry)
unwindEntry = unwindEntry->canonical();
if (isec)
isec = isec->canonical();
return originalIsec ? dyn_cast_or_null<ObjFile>(originalIsec->getFile())
: nullptr;
}

std::string Defined::getSourceLocation() {
if (!isec)
if (!originalIsec)
return {};
return isec->getSourceLocation(value);
return originalIsec->getSourceLocation(value);
}

// Get the canonical InputSection of the symbol.
InputSection *Defined::isec() const {
return originalIsec ? originalIsec->canonical() : nullptr;
}

// Get the canonical unwind entry of the symbol.
ConcatInputSection *Defined::unwindEntry() const {
return originalUnwindEntry ? originalUnwindEntry->canonical() : nullptr;
}

uint64_t DylibSymbol::getVA() const {
Expand Down
17 changes: 11 additions & 6 deletions lld/MachO/Symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ class Defined : public Symbol {
bool isTlv() const override;

bool isExternal() const { return external; }
bool isAbsolute() const { return isec == nullptr; }
bool isAbsolute() const { return originalIsec == nullptr; }

uint64_t getVA() const override;

Expand All @@ -139,9 +139,11 @@ class Defined : public Symbol {

std::string getSourceLocation();

// Ensure this symbol's pointers to InputSections point to their canonical
// copies.
void canonicalize();
// Get the canonical InputSection of the symbol.
InputSection *isec() const;

// Get the canonical unwind entry of the symbol.
ConcatInputSection *unwindEntry() const;

static bool classof(const Symbol *s) { return s->kind() == DefinedKind; }

Expand Down Expand Up @@ -182,14 +184,17 @@ class Defined : public Symbol {
const bool external : 1;

public:
InputSection *isec;
// The native InputSection of the symbol. The symbol may be moved to another
// InputSection in which case originalIsec->canonical() will point to the new
// InputSection
InputSection *originalIsec;
// Contains the offset from the containing subsection. Note that this is
// different from nlist::n_value, which is the absolute address of the symbol.
uint64_t value;
// size is only calculated for regular (non-bitcode) symbols.
uint64_t size;
// This can be a subsection of either __compact_unwind or __eh_frame.
ConcatInputSection *unwindEntry = nullptr;
ConcatInputSection *originalUnwindEntry = nullptr;
};

// This enum does double-duty: as a symbol property, it indicates whether & how
Expand Down
Loading