34 changes: 21 additions & 13 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2778,26 +2778,34 @@ bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) {
std::optional<PrimType> VarT = classify(VD->getType());

if (Context::shouldBeGloballyIndexed(VD)) {
// We've already seen and initialized this global.
if (P.getGlobal(VD))
return true;

std::optional<unsigned> GlobalIndex = P.createGlobal(VD, Init);

if (!GlobalIndex)
return false;

if (Init) {
auto initGlobal = [&](unsigned GlobalIndex) -> bool {
assert(Init);
DeclScope<Emitter> LocalScope(this, VD);

if (VarT) {
if (!this->visit(Init))
return false;
return this->emitInitGlobal(*VarT, *GlobalIndex, VD);
return this->emitInitGlobal(*VarT, GlobalIndex, VD);
}
return this->visitGlobalInitializer(Init, *GlobalIndex);
return this->visitGlobalInitializer(Init, GlobalIndex);
};

// We've already seen and initialized this global.
if (std::optional<unsigned> GlobalIndex = P.getGlobal(VD)) {
if (P.getPtrGlobal(*GlobalIndex).isInitialized())
return true;

// The previous attempt at initialization might've been unsuccessful,
// so let's try this one.
return Init && initGlobal(*GlobalIndex);
}
return true;

std::optional<unsigned> GlobalIndex = P.createGlobal(VD, Init);

if (!GlobalIndex)
return false;

return !Init || initGlobal(*GlobalIndex);
} else {
VariableScope<Emitter> LocalScope(this);
if (VarT) {
Expand Down
20 changes: 14 additions & 6 deletions clang/lib/AST/Interp/FunctionPointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@ namespace interp {
class FunctionPointer final {
private:
const Function *Func;
bool Valid;

public:
// FIXME: We might want to track the fact that the Function pointer
// has been created from an integer and is most likely garbage anyway.
FunctionPointer(uintptr_t IntVal = 0, const Descriptor *Desc = nullptr)
: Func(reinterpret_cast<const Function *>(IntVal)) {}
FunctionPointer(const Function *Func) : Func(Func), Valid(true) {
assert(Func);
}

FunctionPointer(const Function *Func) : Func(Func) { assert(Func); }
FunctionPointer(uintptr_t IntVal = 0, const Descriptor *Desc = nullptr)
: Func(reinterpret_cast<const Function *>(IntVal)), Valid(false) {}

const Function *getFunction() const { return Func; }
bool isZero() const { return !Func; }
Expand All @@ -37,14 +38,21 @@ class FunctionPointer final {
return APValue(static_cast<Expr *>(nullptr), CharUnits::Zero(), {},
/*OnePastTheEnd=*/false, /*IsNull=*/true);

if (!Valid)
return APValue(static_cast<Expr *>(nullptr),
CharUnits::fromQuantity(getIntegerRepresentation()), {},
/*OnePastTheEnd=*/false, /*IsNull=*/false);

return APValue(Func->getDecl(), CharUnits::Zero(), {},
/*OnePastTheEnd=*/false, /*IsNull=*/false);
}

void print(llvm::raw_ostream &OS) const {
OS << "FnPtr(";
if (Func)
if (Func && Valid)
OS << Func->getName();
else if (Func)
OS << reinterpret_cast<uintptr_t>(Func);
else
OS << "nullptr";
OS << ")";
Expand Down
99 changes: 62 additions & 37 deletions clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,65 @@ static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {
return true;
}

static void diagnoseMissingInitializer(InterpState &S, CodePtr OpPC,
const ValueDecl *VD) {
const SourceInfo &E = S.Current->getSource(OpPC);
S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;
S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange();
}

static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
const ValueDecl *VD);
static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC,
const ValueDecl *D) {
const SourceInfo &E = S.Current->getSource(OpPC);

if (isa<ParmVarDecl>(D)) {
if (S.getLangOpts().CPlusPlus11) {
S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D;
S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange();
} else {
S.FFDiag(E);
}
} else if (const auto *VD = dyn_cast<VarDecl>(D)) {
if (!VD->getType().isConstQualified()) {
diagnoseNonConstVariable(S, OpPC, VD);
return false;
}

// const, but no initializer.
if (!VD->getAnyInitializer()) {
diagnoseMissingInitializer(S, OpPC, VD);
return false;
}
}
return false;
}

static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
const ValueDecl *VD) {
if (!S.getLangOpts().CPlusPlus)
return;

const SourceInfo &Loc = S.Current->getSource(OpPC);
if (const auto *VarD = dyn_cast<VarDecl>(VD);
VarD && VarD->getType().isConstQualified() &&
!VarD->getAnyInitializer()) {
diagnoseMissingInitializer(S, OpPC, VD);
return;
}

if (VD->getType()->isIntegralOrEnumerationType())
if (VD->getType()->isIntegralOrEnumerationType()) {
S.FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD;
else
S.FFDiag(Loc,
S.getLangOpts().CPlusPlus11
? diag::note_constexpr_ltor_non_constexpr
: diag::note_constexpr_ltor_non_integral,
1)
<< VD << VD->getType();
S.Note(VD->getLocation(), diag::note_declared_at);
return;
}

S.FFDiag(Loc,
S.getLangOpts().CPlusPlus11 ? diag::note_constexpr_ltor_non_constexpr
: diag::note_constexpr_ltor_non_integral,
1)
<< VD << VD->getType();
S.Note(VD->getLocation(), diag::note_declared_at);
}

Expand Down Expand Up @@ -202,6 +245,9 @@ bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (!Ptr.isExtern())
return true;

if (Ptr.isInitialized())
return true;

if (!S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus) {
const auto *VD = Ptr.getDeclDesc()->asValueDecl();
diagnoseNonConstVariable(S, OpPC, VD);
Expand Down Expand Up @@ -369,9 +415,15 @@ bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
if (const auto *VD = Ptr.getDeclDesc()->asVarDecl();
VD && VD->hasGlobalStorage()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
S.Note(VD->getLocation(), diag::note_declared_at);
if (VD->getAnyInitializer()) {
S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
S.Note(VD->getLocation(), diag::note_declared_at);
} else {
diagnoseMissingInitializer(S, OpPC, VD);
}
return false;
}

if (!S.checkingPotentialConstantExpression()) {
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
<< AK << /*uninitialized=*/true << S.Current->getRange(OpPC);
Expand Down Expand Up @@ -598,33 +650,6 @@ bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
return true;
}

static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC,
const ValueDecl *D) {
const SourceInfo &E = S.Current->getSource(OpPC);

if (isa<ParmVarDecl>(D)) {
if (S.getLangOpts().CPlusPlus11) {
S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D;
S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange();
} else {
S.FFDiag(E);
}
} else if (const auto *VD = dyn_cast<VarDecl>(D)) {
if (!VD->getType().isConstQualified()) {
diagnoseNonConstVariable(S, OpPC, VD);
return false;
}

// const, but no initializer.
if (!VD->getAnyInitializer()) {
S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;
S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange();
return false;
}
}
return false;
}

/// We aleady know the given DeclRefExpr is invalid for some reason,
/// now figure out why and print appropriate diagnostics.
bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,
bool IsStatic, IsExtern;
if (const auto *Var = dyn_cast<VarDecl>(VD)) {
IsStatic = Context::shouldBeGloballyIndexed(VD);
IsExtern = !Var->getAnyInitializer();
IsExtern = Var->hasExternalStorage();
} else if (isa<UnnamedGlobalConstantDecl, MSGuidDecl>(VD)) {
IsStatic = true;
IsExtern = false;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Basic/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__CCMP__");
if (HasCF)
Builder.defineMacro("__CF__");
// Condition here is aligned with the feature set of mapxf in Options.td
if (HasEGPR && HasPush2Pop2 && HasPPX && HasNDD)
Builder.defineMacro("__APX_F__");

// Each case falls through to the previous one here.
switch (SSELevel) {
Expand Down
9 changes: 5 additions & 4 deletions clang/lib/Parse/ParseTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -805,10 +805,12 @@ NamedDecl *Parser::ParseTemplateTemplateParameter(unsigned Depth,
// identifier, comma, or greater. Provide a fixit if the identifier, comma,
// or greater appear immediately or after 'struct'. In the latter case,
// replace the keyword with 'class'.
bool TypenameKeyword = false;
if (!TryConsumeToken(tok::kw_class)) {
bool Replace = Tok.isOneOf(tok::kw_typename, tok::kw_struct);
const Token &Next = Tok.is(tok::kw_struct) ? NextToken() : Tok;
if (Tok.is(tok::kw_typename)) {
TypenameKeyword = true;
Diag(Tok.getLocation(),
getLangOpts().CPlusPlus17
? diag::warn_cxx14_compat_template_template_param_typename
Expand Down Expand Up @@ -878,10 +880,9 @@ NamedDecl *Parser::ParseTemplateTemplateParameter(unsigned Depth,
}
}

return Actions.ActOnTemplateTemplateParameter(getCurScope(), TemplateLoc,
ParamList, EllipsisLoc,
ParamName, NameLoc, Depth,
Position, EqualLoc, DefaultArg);
return Actions.ActOnTemplateTemplateParameter(
getCurScope(), TemplateLoc, ParamList, TypenameKeyword, EllipsisLoc,
ParamName, NameLoc, Depth, Position, EqualLoc, DefaultArg);
}

/// ParseNonTypeTemplateParameter - Handle the parsing of non-type
Expand Down
13 changes: 6 additions & 7 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6335,16 +6335,15 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
if (TST->isDependentType() && TST->isTypeAlias())
Diag(Loc, diag::ext_alias_template_in_declarative_nns)
<< SpecLoc.getLocalSourceRange();
} else if (T->isDecltypeType()) {
} else if (T->isDecltypeType() || T->getAsAdjusted<PackIndexingType>()) {
// C++23 [expr.prim.id.qual]p2:
// [...] A declarative nested-name-specifier shall not have a
// decltype-specifier.
// computed-type-specifier.
//
// FIXME: This wording appears to be defective as it does not forbid
// declarative nested-name-specifiers with pack-index-specifiers.
// See https://github.com/cplusplus/CWG/issues/499.
Diag(Loc, diag::err_decltype_in_declarator)
<< SpecLoc.getTypeLoc().getSourceRange();
// CWG2858 changed this from 'decltype-specifier' to
// 'computed-type-specifier'.
Diag(Loc, diag::err_computed_type_in_declarative_nns)
<< T->isDecltypeType() << SpecLoc.getTypeLoc().getSourceRange();
}
}
} while ((SpecLoc = SpecLoc.getPrefix()));
Expand Down
24 changes: 9 additions & 15 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1630,26 +1630,20 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
/// ActOnTemplateTemplateParameter - Called when a C++ template template
/// parameter (e.g. T in template <template \<typename> class T> class array)
/// has been parsed. S is the current scope.
NamedDecl *Sema::ActOnTemplateTemplateParameter(Scope* S,
SourceLocation TmpLoc,
TemplateParameterList *Params,
SourceLocation EllipsisLoc,
IdentifierInfo *Name,
SourceLocation NameLoc,
unsigned Depth,
unsigned Position,
SourceLocation EqualLoc,
ParsedTemplateArgument Default) {
NamedDecl *Sema::ActOnTemplateTemplateParameter(
Scope *S, SourceLocation TmpLoc, TemplateParameterList *Params,
bool Typename, SourceLocation EllipsisLoc, IdentifierInfo *Name,
SourceLocation NameLoc, unsigned Depth, unsigned Position,
SourceLocation EqualLoc, ParsedTemplateArgument Default) {
assert(S->isTemplateParamScope() &&
"Template template parameter not in template parameter scope!");

// Construct the parameter object.
bool IsParameterPack = EllipsisLoc.isValid();
TemplateTemplateParmDecl *Param =
TemplateTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(),
NameLoc.isInvalid()? TmpLoc : NameLoc,
Depth, Position, IsParameterPack,
Name, Params);
TemplateTemplateParmDecl *Param = TemplateTemplateParmDecl::Create(
Context, Context.getTranslationUnitDecl(),
NameLoc.isInvalid() ? TmpLoc : NameLoc, Depth, Position, IsParameterPack,
Name, Typename, Params);
Param->setAccess(AS_public);

if (Param->isParameterPack())
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3233,12 +3233,14 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
Param = TemplateTemplateParmDecl::Create(
SemaRef.Context, Owner, D->getLocation(),
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
D->getPosition(), D->getIdentifier(), InstParams, ExpandedParams);
D->getPosition(), D->getIdentifier(), D->wasDeclaredWithTypename(),
InstParams, ExpandedParams);
else
Param = TemplateTemplateParmDecl::Create(
SemaRef.Context, Owner, D->getLocation(),
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
D->getPosition(), D->isParameterPack(), D->getIdentifier(), InstParams);
D->getPosition(), D->isParameterPack(), D->getIdentifier(),
D->wasDeclaredWithTypename(), InstParams);
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
NestedNameSpecifierLoc QualifierLoc =
D->getDefaultArgument().getTemplateQualifierLoc();
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2715,6 +2715,7 @@ void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {

void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
VisitTemplateDecl(D);
D->setDeclaredWithTypename(Record.readBool());
// TemplateParmPosition.
D->setDepth(Record.readInt());
D->setPosition(Record.readInt());
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Serialization/ASTWriterDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1921,6 +1921,7 @@ void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
Record.push_back(D->getNumExpansionTemplateParameters());

VisitTemplateDecl(D);
Record.push_back(D->wasDeclaredWithTypename());
// TemplateParmPosition.
Record.push_back(D->getDepth());
Record.push_back(D->getPosition());
Expand Down
12 changes: 4 additions & 8 deletions clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -542,10 +542,10 @@ namespace {
class CFRetainReleaseChecker : public Checker<check::PreCall> {
mutable APIMisuse BT{this, "null passed to CF memory management function"};
const CallDescriptionSet ModelledCalls = {
{{"CFRetain"}, 1},
{{"CFRelease"}, 1},
{{"CFMakeCollectable"}, 1},
{{"CFAutorelease"}, 1},
{CDM::CLibrary, {"CFRetain"}, 1},
{CDM::CLibrary, {"CFRelease"}, 1},
{CDM::CLibrary, {"CFMakeCollectable"}, 1},
{CDM::CLibrary, {"CFAutorelease"}, 1},
};

public:
Expand All @@ -555,10 +555,6 @@ class CFRetainReleaseChecker : public Checker<check::PreCall> {

void CFRetainReleaseChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
// TODO: Make this check part of CallDescription.
if (!Call.isGlobalCFunction())
return;

// Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
if (!ModelledCalls.contains(Call))
return;
Expand Down
115 changes: 72 additions & 43 deletions clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,82 +87,115 @@ class PthreadLockChecker : public Checker<check::PostCall, check::DeadSymbols,
CheckerKind CheckKind) const;
CallDescriptionMap<FnCheck> PThreadCallbacks = {
// Init.
{{{"pthread_mutex_init"}, 2}, &PthreadLockChecker::InitAnyLock},
{{CDM::CLibrary, {"pthread_mutex_init"}, 2},
&PthreadLockChecker::InitAnyLock},
// TODO: pthread_rwlock_init(2 arguments).
// TODO: lck_mtx_init(3 arguments).
// TODO: lck_mtx_alloc_init(2 arguments) => returns the mutex.
// TODO: lck_rw_init(3 arguments).
// TODO: lck_rw_alloc_init(2 arguments) => returns the mutex.

// Acquire.
{{{"pthread_mutex_lock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
{{{"pthread_rwlock_rdlock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
{{{"pthread_rwlock_wrlock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
{{{"lck_mtx_lock"}, 1}, &PthreadLockChecker::AcquireXNULock},
{{{"lck_rw_lock_exclusive"}, 1}, &PthreadLockChecker::AcquireXNULock},
{{{"lck_rw_lock_shared"}, 1}, &PthreadLockChecker::AcquireXNULock},
{{CDM::CLibrary, {"pthread_mutex_lock"}, 1},
&PthreadLockChecker::AcquirePthreadLock},
{{CDM::CLibrary, {"pthread_rwlock_rdlock"}, 1},
&PthreadLockChecker::AcquirePthreadLock},
{{CDM::CLibrary, {"pthread_rwlock_wrlock"}, 1},
&PthreadLockChecker::AcquirePthreadLock},
{{CDM::CLibrary, {"lck_mtx_lock"}, 1},
&PthreadLockChecker::AcquireXNULock},
{{CDM::CLibrary, {"lck_rw_lock_exclusive"}, 1},
&PthreadLockChecker::AcquireXNULock},
{{CDM::CLibrary, {"lck_rw_lock_shared"}, 1},
&PthreadLockChecker::AcquireXNULock},

// Try.
{{{"pthread_mutex_trylock"}, 1}, &PthreadLockChecker::TryPthreadLock},
{{{"pthread_rwlock_tryrdlock"}, 1}, &PthreadLockChecker::TryPthreadLock},
{{{"pthread_rwlock_trywrlock"}, 1}, &PthreadLockChecker::TryPthreadLock},
{{{"lck_mtx_try_lock"}, 1}, &PthreadLockChecker::TryXNULock},
{{{"lck_rw_try_lock_exclusive"}, 1}, &PthreadLockChecker::TryXNULock},
{{{"lck_rw_try_lock_shared"}, 1}, &PthreadLockChecker::TryXNULock},
{{CDM::CLibrary, {"pthread_mutex_trylock"}, 1},
&PthreadLockChecker::TryPthreadLock},
{{CDM::CLibrary, {"pthread_rwlock_tryrdlock"}, 1},
&PthreadLockChecker::TryPthreadLock},
{{CDM::CLibrary, {"pthread_rwlock_trywrlock"}, 1},
&PthreadLockChecker::TryPthreadLock},
{{CDM::CLibrary, {"lck_mtx_try_lock"}, 1},
&PthreadLockChecker::TryXNULock},
{{CDM::CLibrary, {"lck_rw_try_lock_exclusive"}, 1},
&PthreadLockChecker::TryXNULock},
{{CDM::CLibrary, {"lck_rw_try_lock_shared"}, 1},
&PthreadLockChecker::TryXNULock},

// Release.
{{{"pthread_mutex_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
{{{"pthread_rwlock_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
{{{"lck_mtx_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
{{{"lck_rw_unlock_exclusive"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
{{{"lck_rw_unlock_shared"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
{{{"lck_rw_done"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
{{CDM::CLibrary, {"pthread_mutex_unlock"}, 1},
&PthreadLockChecker::ReleaseAnyLock},
{{CDM::CLibrary, {"pthread_rwlock_unlock"}, 1},
&PthreadLockChecker::ReleaseAnyLock},
{{CDM::CLibrary, {"lck_mtx_unlock"}, 1},
&PthreadLockChecker::ReleaseAnyLock},
{{CDM::CLibrary, {"lck_rw_unlock_exclusive"}, 1},
&PthreadLockChecker::ReleaseAnyLock},
{{CDM::CLibrary, {"lck_rw_unlock_shared"}, 1},
&PthreadLockChecker::ReleaseAnyLock},
{{CDM::CLibrary, {"lck_rw_done"}, 1},
&PthreadLockChecker::ReleaseAnyLock},

// Destroy.
{{{"pthread_mutex_destroy"}, 1}, &PthreadLockChecker::DestroyPthreadLock},
{{{"lck_mtx_destroy"}, 2}, &PthreadLockChecker::DestroyXNULock},
{{CDM::CLibrary, {"pthread_mutex_destroy"}, 1},
&PthreadLockChecker::DestroyPthreadLock},
{{CDM::CLibrary, {"lck_mtx_destroy"}, 2},
&PthreadLockChecker::DestroyXNULock},
// TODO: pthread_rwlock_destroy(1 argument).
// TODO: lck_rw_destroy(2 arguments).
};

CallDescriptionMap<FnCheck> FuchsiaCallbacks = {
// Init.
{{{"spin_lock_init"}, 1}, &PthreadLockChecker::InitAnyLock},
{{CDM::CLibrary, {"spin_lock_init"}, 1},
&PthreadLockChecker::InitAnyLock},

// Acquire.
{{{"spin_lock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
{{{"spin_lock_save"}, 3}, &PthreadLockChecker::AcquirePthreadLock},
{{{"sync_mutex_lock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
{{{"sync_mutex_lock_with_waiter"}, 1},
{{CDM::CLibrary, {"spin_lock"}, 1},
&PthreadLockChecker::AcquirePthreadLock},
{{CDM::CLibrary, {"spin_lock_save"}, 3},
&PthreadLockChecker::AcquirePthreadLock},
{{CDM::CLibrary, {"sync_mutex_lock"}, 1},
&PthreadLockChecker::AcquirePthreadLock},
{{CDM::CLibrary, {"sync_mutex_lock_with_waiter"}, 1},
&PthreadLockChecker::AcquirePthreadLock},

// Try.
{{{"spin_trylock"}, 1}, &PthreadLockChecker::TryFuchsiaLock},
{{{"sync_mutex_trylock"}, 1}, &PthreadLockChecker::TryFuchsiaLock},
{{{"sync_mutex_timedlock"}, 2}, &PthreadLockChecker::TryFuchsiaLock},
{{CDM::CLibrary, {"spin_trylock"}, 1},
&PthreadLockChecker::TryFuchsiaLock},
{{CDM::CLibrary, {"sync_mutex_trylock"}, 1},
&PthreadLockChecker::TryFuchsiaLock},
{{CDM::CLibrary, {"sync_mutex_timedlock"}, 2},
&PthreadLockChecker::TryFuchsiaLock},

// Release.
{{{"spin_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
{{{"spin_unlock_restore"}, 3}, &PthreadLockChecker::ReleaseAnyLock},
{{{"sync_mutex_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
{{CDM::CLibrary, {"spin_unlock"}, 1},
&PthreadLockChecker::ReleaseAnyLock},
{{CDM::CLibrary, {"spin_unlock_restore"}, 3},
&PthreadLockChecker::ReleaseAnyLock},
{{CDM::CLibrary, {"sync_mutex_unlock"}, 1},
&PthreadLockChecker::ReleaseAnyLock},
};

CallDescriptionMap<FnCheck> C11Callbacks = {
// Init.
{{{"mtx_init"}, 2}, &PthreadLockChecker::InitAnyLock},
{{CDM::CLibrary, {"mtx_init"}, 2}, &PthreadLockChecker::InitAnyLock},

// Acquire.
{{{"mtx_lock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
{{CDM::CLibrary, {"mtx_lock"}, 1},
&PthreadLockChecker::AcquirePthreadLock},

// Try.
{{{"mtx_trylock"}, 1}, &PthreadLockChecker::TryC11Lock},
{{{"mtx_timedlock"}, 2}, &PthreadLockChecker::TryC11Lock},
{{CDM::CLibrary, {"mtx_trylock"}, 1}, &PthreadLockChecker::TryC11Lock},
{{CDM::CLibrary, {"mtx_timedlock"}, 2}, &PthreadLockChecker::TryC11Lock},

// Release.
{{{"mtx_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
{{CDM::CLibrary, {"mtx_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},

// Destroy
{{{"mtx_destroy"}, 1}, &PthreadLockChecker::DestroyPthreadLock},
{{CDM::CLibrary, {"mtx_destroy"}, 1},
&PthreadLockChecker::DestroyPthreadLock},
};

ProgramStateRef resolvePossiblyDestroyedMutex(ProgramStateRef state,
Expand Down Expand Up @@ -258,13 +291,9 @@ REGISTER_MAP_WITH_PROGRAMSTATE(DestroyRetVal, const MemRegion *, SymbolRef)

void PthreadLockChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
// An additional umbrella check that all functions modeled by this checker
// are global C functions.
// TODO: Maybe make this the default behavior of CallDescription
// with exactly one identifier?
// FIXME: Try to handle cases when the implementation was inlined rather
// than just giving up.
if (!Call.isGlobalCFunction() || C.wasInlined)
if (C.wasInlined)
return;

if (const FnCheck *Callback = PThreadCallbacks.lookup(Call))
Expand Down
10 changes: 2 additions & 8 deletions clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ class SimpleStreamChecker : public Checker<check::PostCall,
check::PreCall,
check::DeadSymbols,
check::PointerEscape> {
const CallDescription OpenFn{{"fopen"}, 2};
const CallDescription CloseFn{{"fclose"}, 1};
const CallDescription OpenFn{CDM::CLibrary, {"fopen"}, 2};
const CallDescription CloseFn{CDM::CLibrary, {"fclose"}, 1};

const BugType DoubleCloseBugType{this, "Double fclose",
"Unix Stream API Error"};
Expand Down Expand Up @@ -92,9 +92,6 @@ REGISTER_MAP_WITH_PROGRAMSTATE(StreamMap, SymbolRef, StreamState)

void SimpleStreamChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
if (!Call.isGlobalCFunction())
return;

if (!OpenFn.matches(Call))
return;

Expand All @@ -111,9 +108,6 @@ void SimpleStreamChecker::checkPostCall(const CallEvent &Call,

void SimpleStreamChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
if (!Call.isGlobalCFunction())
return;

if (!CloseFn.matches(Call))
return;

Expand Down
69 changes: 35 additions & 34 deletions clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,85 +302,88 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,

private:
CallDescriptionMap<FnDescription> FnDescriptions = {
{{{"fopen"}, 2}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
{{{"fdopen"}, 2}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
{{{"freopen"}, 3},
{{CDM::CLibrary, {"fopen"}, 2},
{nullptr, &StreamChecker::evalFopen, ArgNone}},
{{CDM::CLibrary, {"fdopen"}, 2},
{nullptr, &StreamChecker::evalFopen, ArgNone}},
{{CDM::CLibrary, {"freopen"}, 3},
{&StreamChecker::preFreopen, &StreamChecker::evalFreopen, 2}},
{{{"tmpfile"}, 0}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
{{{"fclose"}, 1},
{{CDM::CLibrary, {"tmpfile"}, 0},
{nullptr, &StreamChecker::evalFopen, ArgNone}},
{{CDM::CLibrary, {"fclose"}, 1},
{&StreamChecker::preDefault, &StreamChecker::evalFclose, 0}},
{{{"fread"}, 4},
{{CDM::CLibrary, {"fread"}, 4},
{&StreamChecker::preRead,
std::bind(&StreamChecker::evalFreadFwrite, _1, _2, _3, _4, true), 3}},
{{{"fwrite"}, 4},
{{CDM::CLibrary, {"fwrite"}, 4},
{&StreamChecker::preWrite,
std::bind(&StreamChecker::evalFreadFwrite, _1, _2, _3, _4, false), 3}},
{{{"fgetc"}, 1},
{{CDM::CLibrary, {"fgetc"}, 1},
{&StreamChecker::preRead,
std::bind(&StreamChecker::evalFgetx, _1, _2, _3, _4, true), 0}},
{{{"fgets"}, 3},
{{CDM::CLibrary, {"fgets"}, 3},
{&StreamChecker::preRead,
std::bind(&StreamChecker::evalFgetx, _1, _2, _3, _4, false), 2}},
{{{"getc"}, 1},
{{CDM::CLibrary, {"getc"}, 1},
{&StreamChecker::preRead,
std::bind(&StreamChecker::evalFgetx, _1, _2, _3, _4, true), 0}},
{{{"fputc"}, 2},
{{CDM::CLibrary, {"fputc"}, 2},
{&StreamChecker::preWrite,
std::bind(&StreamChecker::evalFputx, _1, _2, _3, _4, true), 1}},
{{{"fputs"}, 2},
{{CDM::CLibrary, {"fputs"}, 2},
{&StreamChecker::preWrite,
std::bind(&StreamChecker::evalFputx, _1, _2, _3, _4, false), 1}},
{{{"putc"}, 2},
{{CDM::CLibrary, {"putc"}, 2},
{&StreamChecker::preWrite,
std::bind(&StreamChecker::evalFputx, _1, _2, _3, _4, true), 1}},
{{{"fprintf"}},
{{CDM::CLibrary, {"fprintf"}},
{&StreamChecker::preWrite,
std::bind(&StreamChecker::evalFprintf, _1, _2, _3, _4), 0}},
{{{"vfprintf"}, 3},
{{CDM::CLibrary, {"vfprintf"}, 3},
{&StreamChecker::preWrite,
std::bind(&StreamChecker::evalFprintf, _1, _2, _3, _4), 0}},
{{{"fscanf"}},
{{CDM::CLibrary, {"fscanf"}},
{&StreamChecker::preRead,
std::bind(&StreamChecker::evalFscanf, _1, _2, _3, _4), 0}},
{{{"vfscanf"}, 3},
{{CDM::CLibrary, {"vfscanf"}, 3},
{&StreamChecker::preRead,
std::bind(&StreamChecker::evalFscanf, _1, _2, _3, _4), 0}},
{{{"ungetc"}, 2},
{{CDM::CLibrary, {"ungetc"}, 2},
{&StreamChecker::preWrite,
std::bind(&StreamChecker::evalUngetc, _1, _2, _3, _4), 1}},
{{{"getdelim"}, 4},
{{CDM::CLibrary, {"getdelim"}, 4},
{&StreamChecker::preRead,
std::bind(&StreamChecker::evalGetdelim, _1, _2, _3, _4), 3}},
{{{"getline"}, 3},
{{CDM::CLibrary, {"getline"}, 3},
{&StreamChecker::preRead,
std::bind(&StreamChecker::evalGetdelim, _1, _2, _3, _4), 2}},
{{{"fseek"}, 3},
{{CDM::CLibrary, {"fseek"}, 3},
{&StreamChecker::preFseek, &StreamChecker::evalFseek, 0}},
{{{"fseeko"}, 3},
{{CDM::CLibrary, {"fseeko"}, 3},
{&StreamChecker::preFseek, &StreamChecker::evalFseek, 0}},
{{{"ftell"}, 1},
{{CDM::CLibrary, {"ftell"}, 1},
{&StreamChecker::preWrite, &StreamChecker::evalFtell, 0}},
{{{"ftello"}, 1},
{{CDM::CLibrary, {"ftello"}, 1},
{&StreamChecker::preWrite, &StreamChecker::evalFtell, 0}},
{{{"fflush"}, 1},
{{CDM::CLibrary, {"fflush"}, 1},
{&StreamChecker::preFflush, &StreamChecker::evalFflush, 0}},
{{{"rewind"}, 1},
{{CDM::CLibrary, {"rewind"}, 1},
{&StreamChecker::preDefault, &StreamChecker::evalRewind, 0}},
{{{"fgetpos"}, 2},
{{CDM::CLibrary, {"fgetpos"}, 2},
{&StreamChecker::preWrite, &StreamChecker::evalFgetpos, 0}},
{{{"fsetpos"}, 2},
{{CDM::CLibrary, {"fsetpos"}, 2},
{&StreamChecker::preDefault, &StreamChecker::evalFsetpos, 0}},
{{{"clearerr"}, 1},
{{CDM::CLibrary, {"clearerr"}, 1},
{&StreamChecker::preDefault, &StreamChecker::evalClearerr, 0}},
{{{"feof"}, 1},
{{CDM::CLibrary, {"feof"}, 1},
{&StreamChecker::preDefault,
std::bind(&StreamChecker::evalFeofFerror, _1, _2, _3, _4, ErrorFEof),
0}},
{{{"ferror"}, 1},
{{CDM::CLibrary, {"ferror"}, 1},
{&StreamChecker::preDefault,
std::bind(&StreamChecker::evalFeofFerror, _1, _2, _3, _4, ErrorFError),
0}},
{{{"fileno"}, 1},
{{CDM::CLibrary, {"fileno"}, 1},
{&StreamChecker::preDefault, &StreamChecker::evalFileno, 0}},
};

Expand Down Expand Up @@ -540,8 +543,6 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
const FnDescription *lookupFn(const CallEvent &Call) const {
// Recognize "global C functions" with only integral or pointer arguments
// (and matching name) as stream functions.
if (!Call.isGlobalCFunction())
return nullptr;
for (auto *P : Call.parameters()) {
QualType T = P->getType();
if (!T->isIntegralOrEnumerationType() && !T->isPointerType() &&
Expand Down
35 changes: 17 additions & 18 deletions clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,32 +100,31 @@ class ValistChecker : public Checker<check::PreCall, check::PreStmt<VAArgExpr>,
};

const SmallVector<ValistChecker::VAListAccepter, 15>
ValistChecker::VAListAccepters = {{{{"vfprintf"}, 3}, 2},
{{{"vfscanf"}, 3}, 2},
{{{"vprintf"}, 2}, 1},
{{{"vscanf"}, 2}, 1},
{{{"vsnprintf"}, 4}, 3},
{{{"vsprintf"}, 3}, 2},
{{{"vsscanf"}, 3}, 2},
{{{"vfwprintf"}, 3}, 2},
{{{"vfwscanf"}, 3}, 2},
{{{"vwprintf"}, 2}, 1},
{{{"vwscanf"}, 2}, 1},
{{{"vswprintf"}, 4}, 3},
ValistChecker::VAListAccepters = {{{CDM::CLibrary, {"vfprintf"}, 3}, 2},
{{CDM::CLibrary, {"vfscanf"}, 3}, 2},
{{CDM::CLibrary, {"vprintf"}, 2}, 1},
{{CDM::CLibrary, {"vscanf"}, 2}, 1},
{{CDM::CLibrary, {"vsnprintf"}, 4}, 3},
{{CDM::CLibrary, {"vsprintf"}, 3}, 2},
{{CDM::CLibrary, {"vsscanf"}, 3}, 2},
{{CDM::CLibrary, {"vfwprintf"}, 3}, 2},
{{CDM::CLibrary, {"vfwscanf"}, 3}, 2},
{{CDM::CLibrary, {"vwprintf"}, 2}, 1},
{{CDM::CLibrary, {"vwscanf"}, 2}, 1},
{{CDM::CLibrary, {"vswprintf"}, 4}, 3},
// vswprintf is the wide version of
// vsnprintf, vsprintf has no wide version
{{{"vswscanf"}, 3}, 2}};
{{CDM::CLibrary, {"vswscanf"}, 3}, 2}};

const CallDescription ValistChecker::VaStart({"__builtin_va_start"}, /*Args=*/2,
const CallDescription ValistChecker::VaStart(CDM::CLibrary,
{"__builtin_va_start"}, /*Args=*/2,
/*Params=*/1),
ValistChecker::VaCopy({"__builtin_va_copy"}, 2),
ValistChecker::VaEnd({"__builtin_va_end"}, 1);
ValistChecker::VaCopy(CDM::CLibrary, {"__builtin_va_copy"}, 2),
ValistChecker::VaEnd(CDM::CLibrary, {"__builtin_va_end"}, 1);
} // end anonymous namespace

void ValistChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
if (!Call.isGlobalCFunction())
return;
if (VaStart.matches(Call))
checkVAListStartCall(Call, C, false);
else if (VaCopy.matches(Call))
Expand Down
17 changes: 6 additions & 11 deletions clang/test/AST/Interp/cxx23.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,18 @@

/// FIXME: The new interpreter is missing all the 'control flows through...' diagnostics.

constexpr int f(int n) { // ref20-error {{constexpr function never produces a constant expression}} \
// expected20-error {{constexpr function never produces a constant expression}}
constexpr int f(int n) { // ref20-error {{constexpr function never produces a constant expression}}
static const int m = n; // ref20-note {{control flows through the definition of a static variable}} \
// ref20-warning {{is a C++23 extension}} \
// expected20-warning {{is a C++23 extension}} \
// expected20-note {{declared here}} \
// expected20-warning {{is a C++23 extension}}

return m; // expected20-note {{initializer of 'm' is not a constant expression}}
return m;
}
constexpr int g(int n) { // ref20-error {{constexpr function never produces a constant expression}} \
// expected20-error {{constexpr function never produces a constant expression}}
constexpr int g(int n) { // ref20-error {{constexpr function never produces a constant expression}}
thread_local const int m = n; // ref20-note {{control flows through the definition of a thread_local variable}} \
// ref20-warning {{is a C++23 extension}} \
// expected20-warning {{is a C++23 extension}} \
// expected20-note {{declared here}}
return m; // expected20-note {{initializer of 'm' is not a constant expression}}

// expected20-warning {{is a C++23 extension}}
return m;
}

constexpr int c_thread_local(int n) { // ref20-error {{constexpr function never produces a constant expression}} \
Expand Down
32 changes: 28 additions & 4 deletions clang/test/AST/Interp/records.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++14 -verify=expected,both %s
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify=expected,both %s
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -triple i686 -verify=expected,both %s
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++20 -verify=expected,both %s
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -triple i686 -verify=expected,both %s
// RUN: %clang_cc1 -verify=ref,both %s
// RUN: %clang_cc1 -verify=ref,both -std=c++14 %s
// RUN: %clang_cc1 -verify=ref,both -std=c++17 %s
// RUN: %clang_cc1 -verify=ref,both -std=c++17 -triple i686 %s
// RUN: %clang_cc1 -verify=ref,both -std=c++20 %s
// RUN: %clang_cc1 -verify=ref,both -triple i686 %s

/// Used to crash.
struct Empty {};
Expand Down Expand Up @@ -1285,3 +1285,27 @@ namespace {
}
}
#endif

namespace pr18633 {
struct A1 {
static const int sz;
static const int sz2;
};
const int A1::sz2 = 11;
template<typename T>
void func () {
int arr[A1::sz];
// both-warning@-1 {{variable length arrays in C++ are a Clang extension}}
// both-note@-2 {{initializer of 'sz' is unknown}}
// both-note@-9 {{declared here}}
}
template<typename T>
void func2 () {
int arr[A1::sz2];
}
const int A1::sz = 12;
void func2() {
func<int>();
func2<int>();
}
}
4 changes: 2 additions & 2 deletions clang/test/CXX/dcl.decl/dcl.meaning/p1-0x.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ class foo {
void func();
};

int decltype(foo())::i; // expected-error{{'decltype' cannot be used to name a declaration}}
void decltype(foo())::func() { // expected-error{{'decltype' cannot be used to name a declaration}}
int decltype(foo())::i; // expected-error{{a 'decltype' specifier cannot be used in a declarative nested name specifier}}
void decltype(foo())::func() { // expected-error{{a 'decltype' specifier cannot be used in a declarative nested name specifier}}
}


Expand Down
23 changes: 23 additions & 0 deletions clang/test/CXX/drs/dr28xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,26 @@ void B<int>::g() requires true;
#endif

} // namespace dr2847

namespace dr2858 { // dr2858: 19

#if __cplusplus > 202302L

template<typename... Ts>
struct A {
// FIXME: The nested-name-specifier in the following friend declarations are declarative,
// but we don't treat them as such (yet).
friend void Ts...[0]::f();
template<typename U>
friend void Ts...[0]::g();

friend struct Ts...[0]::B;
// FIXME: The index of the pack-index-specifier is printed as a memory address in the diagnostic.
template<typename U>
friend struct Ts...[0]::C;
// expected-warning-re@-1 {{dependent nested name specifier 'Ts...[{{.*}}]::' for friend template declaration is not supported; ignoring this friend declaration}}
};

#endif

} // namespace dr2858
3 changes: 1 addition & 2 deletions clang/test/CodeGen/X86/avx-shuffle-builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ __m256 test_mm256_permute2f128_ps(__m256 a, __m256 b) {

__m256i test_mm256_permute2f128_si256(__m256i a, __m256i b) {
// CHECK-LABEL: test_mm256_permute2f128_si256
// X64: shufflevector{{.*}}<i32 0, i32 1, i32 4, i32 5>
// X86: shufflevector{{.*}}<i32 0, i32 1, i32 2, i32 3, i32 8, i32 9, i32 10, i32 11>
// CHECK: shufflevector{{.*}}<i32 0, i32 1, i32 4, i32 5>
return _mm256_permute2f128_si256(a, b, 0x20);
}

Expand Down
4 changes: 2 additions & 2 deletions clang/test/CodeGen/ms-intrinsics-other.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ unsigned char test_BitScanForward64(unsigned LONG *Index, unsigned __int64 Mask)
// CHECK: ret i8 [[RESULT]]
// CHECK: [[ISNOTZERO_LABEL]]:
// CHECK: [[INDEX:%[0-9]+]] = tail call i64 @llvm.cttz.i64(i64 %Mask, i1 true)
// CHECK: [[TRUNC_INDEX:%[0-9]+]] = trunc i64 [[INDEX]] to i32
// CHECK: [[TRUNC_INDEX:%[0-9]+]] = trunc nuw nsw i64 [[INDEX]] to i32
// CHECK: store i32 [[TRUNC_INDEX]], ptr %Index, align 4
// CHECK: br label %[[END_LABEL]]

Expand All @@ -102,7 +102,7 @@ unsigned char test_BitScanReverse64(unsigned LONG *Index, unsigned __int64 Mask)
// CHECK: ret i8 [[RESULT]]
// CHECK: [[ISNOTZERO_LABEL]]:
// CHECK: [[REVINDEX:%[0-9]+]] = tail call i64 @llvm.ctlz.i64(i64 %Mask, i1 true)
// CHECK: [[TRUNC_REVINDEX:%[0-9]+]] = trunc i64 [[REVINDEX]] to i32
// CHECK: [[TRUNC_REVINDEX:%[0-9]+]] = trunc nuw nsw i64 [[REVINDEX]] to i32
// CHECK: [[INDEX:%[0-9]+]] = xor i32 [[TRUNC_REVINDEX]], 63
// CHECK: store i32 [[INDEX]], ptr %Index, align 4
// CHECK: br label %[[END_LABEL]]
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CodeGen/ms-intrinsics.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ unsigned char test_BitScanForward64(unsigned long *Index, unsigned __int64 Mask)
// CHECK-ARM-X64: ret i8 [[RESULT]]
// CHECK-ARM-X64: [[ISNOTZERO_LABEL]]:
// CHECK-ARM-X64: [[INDEX:%[0-9]+]] = tail call i64 @llvm.cttz.i64(i64 %Mask, i1 true)
// CHECK-ARM-X64: [[TRUNC_INDEX:%[0-9]+]] = trunc i64 [[INDEX]] to i32
// CHECK-ARM-X64: [[TRUNC_INDEX:%[0-9]+]] = trunc nuw nsw i64 [[INDEX]] to i32
// CHECK-ARM-X64: store i32 [[TRUNC_INDEX]], ptr %Index, align 4
// CHECK-ARM-X64: br label %[[END_LABEL]]

Expand All @@ -204,7 +204,7 @@ unsigned char test_BitScanReverse64(unsigned long *Index, unsigned __int64 Mask)
// CHECK-ARM-X64: ret i8 [[RESULT]]
// CHECK-ARM-X64: [[ISNOTZERO_LABEL]]:
// CHECK-ARM-X64: [[REVINDEX:%[0-9]+]] = tail call i64 @llvm.ctlz.i64(i64 %Mask, i1 true)
// CHECK-ARM-X64: [[TRUNC_REVINDEX:%[0-9]+]] = trunc i64 [[REVINDEX]] to i32
// CHECK-ARM-X64: [[TRUNC_REVINDEX:%[0-9]+]] = trunc nuw nsw i64 [[REVINDEX]] to i32
// CHECK-ARM-X64: [[INDEX:%[0-9]+]] = xor i32 [[TRUNC_REVINDEX]], 63
// CHECK-ARM-X64: store i32 [[INDEX]], ptr %Index, align 4
// CHECK-ARM-X64: br label %[[END_LABEL]]
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CodeGenOpenCL/builtins-amdgcn.cl
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ void test_read_exec_lo(global uint* out) {
// CHECK-LABEL: @test_read_exec_hi(
// CHECK: call i64 @llvm.amdgcn.ballot.i64(i1 true)
// CHECK: lshr i64 [[A:%.*]], 32
// CHECK: trunc i64 [[B:%.*]] to i32
// CHECK: trunc nuw i64 [[B:%.*]] to i32
void test_read_exec_hi(global uint* out) {
*out = __builtin_amdgcn_read_exec_hi();
}
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Headers/__clang_hip_math.hip
Original file line number Diff line number Diff line change
Expand Up @@ -3703,7 +3703,7 @@ extern "C" __device__ BOOL_TYPE test___signbitf(float x) {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[X:%.*]] to i64
// CHECK-NEXT: [[DOTLOBIT:%.*]] = lshr i64 [[TMP0]], 63
// CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[DOTLOBIT]] to i32
// CHECK-NEXT: [[CONV:%.*]] = trunc nuw nsw i64 [[DOTLOBIT]] to i32
// CHECK-NEXT: ret i32 [[CONV]]
//
extern "C" __device__ BOOL_TYPE test___signbit(double x) {
Expand Down
6 changes: 3 additions & 3 deletions clang/test/Parser/cxx-class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ typedef union {
} y;
} bug3177;

// check that we don't consume the token after the access specifier
// check that we don't consume the token after the access specifier
// when it's not a colon
class D {
public // expected-error{{expected ':'}}
int i;
};

// consume the token after the access specifier if it's a semicolon
// consume the token after the access specifier if it's a semicolon
// that was meant to be a colon
class E {
public; // expected-error{{expected ':'}}
Expand Down Expand Up @@ -281,7 +281,7 @@ struct A {} ::PR41192::a; // ok, no missing ';' here expected-warning {{extra q
#if __cplusplus >= 201103L
struct C;
struct D { static C c; };
struct C {} decltype(D())::c; // expected-error {{'decltype' cannot be used to name a declaration}}
struct C {} decltype(D())::c; // expected-error {{a 'decltype' specifier cannot be used in a declarative nested name specifier}}
#endif
}

Expand Down
3 changes: 2 additions & 1 deletion clang/test/Preprocessor/x86_target_features.c
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,8 @@
// RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapx-features=ndd -x c -E -dM -o - %s | FileCheck --check-prefix=NDD %s
// RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapx-features=ccmp -x c -E -dM -o - %s | FileCheck --check-prefix=CCMP %s
// RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapx-features=cf -x c -E -dM -o - %s | FileCheck --check-prefix=CF %s
// RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapxf -x c -E -dM -o - %s | FileCheck --check-prefixes=EGPR,PUSH2POP2,PPX,NDD %s
// RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapxf -x c -E -dM -o - %s | FileCheck --check-prefixes=EGPR,PUSH2POP2,PPX,NDD,APXF %s
// APXF: #define __APX_F__ 1
// CCMP: #define __CCMP__ 1
// CF: #define __CF__ 1
// EGPR: #define __EGPR__ 1
Expand Down
3 changes: 1 addition & 2 deletions clang/unittests/AST/DeclPrinterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1220,8 +1220,7 @@ TEST(DeclPrinter, TestTemplateTemplateParameterWrittenWithTypename) {
ASSERT_TRUE(PrintedDeclCXX17Matches(
"template <template <typename> typename Z> void A();",
functionTemplateDecl(hasName("A")).bind("id"),
"template <template <typename> class Z> void A()"));
// WRONG: We should use typename if the parameter was written with it.
"template <template <typename> typename Z> void A()"));
}

TEST(DeclPrinter, TestTemplateArgumentList1) {
Expand Down
142 changes: 120 additions & 22 deletions clang/unittests/AST/Interp/toAPValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ TEST(ToAPValue, Pointers) {
" A a[3];\n"
"};\n"
"constexpr S d = {{{true, false}, {false, true}, {false, false}}};\n"
"constexpr const bool *b = &d.a[1].z;\n";
"constexpr const bool *b = &d.a[1].z;\n"
"const void *p = (void*)12;\n"
"const void *nullp = (void*)0;\n";

auto AST = tooling::buildASTFromCodeWithArgs(
Code, {"-fexperimental-new-constant-interpreter"});
Expand All @@ -41,20 +43,55 @@ TEST(ToAPValue, Pointers) {
return Prog.getPtrGlobal(*Prog.getGlobal(D));
};

const Pointer &GP = getGlobalPtr("b");
const Pointer &P = GP.deref<Pointer>();
ASSERT_TRUE(P.isLive());
APValue A = P.toAPValue();
ASSERT_TRUE(A.isLValue());
ASSERT_TRUE(A.hasLValuePath());
const auto &Path = A.getLValuePath();
ASSERT_EQ(Path.size(), 3u);
ASSERT_EQ(A.getLValueBase(), getDecl("d"));
{
const Pointer &GP = getGlobalPtr("b");
const Pointer &P = GP.deref<Pointer>();
ASSERT_TRUE(P.isLive());
APValue A = P.toAPValue();
ASSERT_TRUE(A.isLValue());
ASSERT_TRUE(A.hasLValuePath());
const auto &Path = A.getLValuePath();
ASSERT_EQ(Path.size(), 3u);
ASSERT_EQ(A.getLValueBase(), getDecl("d"));
// FIXME: Also test all path elements.
}

{
const ValueDecl *D = getDecl("p");
ASSERT_NE(D, nullptr);
const Pointer &GP = getGlobalPtr("p");
const Pointer &P = GP.deref<Pointer>();
ASSERT_TRUE(P.isIntegralPointer());
APValue A = P.toAPValue();
ASSERT_TRUE(A.isLValue());
ASSERT_TRUE(A.getLValueBase().isNull());
APSInt I;
bool Success = A.toIntegralConstant(I, D->getType(), AST->getASTContext());
ASSERT_TRUE(Success);
ASSERT_EQ(I, 12);
}

{
const ValueDecl *D = getDecl("nullp");
ASSERT_NE(D, nullptr);
const Pointer &GP = getGlobalPtr("nullp");
const Pointer &P = GP.deref<Pointer>();
ASSERT_TRUE(P.isIntegralPointer());
APValue A = P.toAPValue();
ASSERT_TRUE(A.isLValue());
ASSERT_TRUE(A.getLValueBase().isNull());
ASSERT_TRUE(A.isNullPointer());
APSInt I;
bool Success = A.toIntegralConstant(I, D->getType(), AST->getASTContext());
ASSERT_TRUE(Success);
ASSERT_EQ(I, 0);
}
}

TEST(ToAPValue, FunctionPointers) {
constexpr char Code[] = " constexpr bool foo() { return true; }\n"
" constexpr bool (*func)() = foo;\n";
" constexpr bool (*func)() = foo;\n"
" constexpr bool (*nullp)() = nullptr;\n";

auto AST = tooling::buildASTFromCodeWithArgs(
Code, {"-fexperimental-new-constant-interpreter"});
Expand All @@ -76,15 +113,76 @@ TEST(ToAPValue, FunctionPointers) {
return Prog.getPtrGlobal(*Prog.getGlobal(D));
};

const Pointer &GP = getGlobalPtr("func");
const FunctionPointer &FP = GP.deref<FunctionPointer>();
ASSERT_FALSE(FP.isZero());
APValue A = FP.toAPValue();
ASSERT_TRUE(A.hasValue());
ASSERT_TRUE(A.isLValue());
ASSERT_TRUE(A.hasLValuePath());
const auto &Path = A.getLValuePath();
ASSERT_EQ(Path.size(), 0u);
ASSERT_FALSE(A.getLValueBase().isNull());
ASSERT_EQ(A.getLValueBase().dyn_cast<const ValueDecl *>(), getDecl("foo"));
{
const Pointer &GP = getGlobalPtr("func");
const FunctionPointer &FP = GP.deref<FunctionPointer>();
ASSERT_FALSE(FP.isZero());
APValue A = FP.toAPValue();
ASSERT_TRUE(A.hasValue());
ASSERT_TRUE(A.isLValue());
ASSERT_TRUE(A.hasLValuePath());
const auto &Path = A.getLValuePath();
ASSERT_EQ(Path.size(), 0u);
ASSERT_FALSE(A.getLValueBase().isNull());
ASSERT_EQ(A.getLValueBase().dyn_cast<const ValueDecl *>(), getDecl("foo"));
}

{
const ValueDecl *D = getDecl("nullp");
ASSERT_NE(D, nullptr);
const Pointer &GP = getGlobalPtr("nullp");
const auto &P = GP.deref<FunctionPointer>();
APValue A = P.toAPValue();
ASSERT_TRUE(A.isLValue());
ASSERT_TRUE(A.getLValueBase().isNull());
ASSERT_TRUE(A.isNullPointer());
APSInt I;
bool Success = A.toIntegralConstant(I, D->getType(), AST->getASTContext());
ASSERT_TRUE(Success);
ASSERT_EQ(I, 0);
}
}

TEST(ToAPValue, FunctionPointersC) {
// NB: The declaration of func2 is useless, but it makes us register a global
// variable for func.
constexpr char Code[] = "const int (* const func)(int *) = (void*)17;\n"
"const int (*func2)(int *) = func;\n";
auto AST = tooling::buildASTFromCodeWithArgs(
Code, {"-x", "c", "-fexperimental-new-constant-interpreter"});

auto &Ctx = AST->getASTContext().getInterpContext();
Program &Prog = Ctx.getProgram();

auto getDecl = [&](const char *Name) -> const ValueDecl * {
auto Nodes =
match(valueDecl(hasName(Name)).bind("var"), AST->getASTContext());
assert(Nodes.size() == 1);
const auto *D = Nodes[0].getNodeAs<ValueDecl>("var");
assert(D);
return D;
};

auto getGlobalPtr = [&](const char *Name) -> Pointer {
const VarDecl *D = cast<VarDecl>(getDecl(Name));
return Prog.getPtrGlobal(*Prog.getGlobal(D));
};

{
const ValueDecl *D = getDecl("func");
const Pointer &GP = getGlobalPtr("func");
ASSERT_TRUE(GP.isLive());
const FunctionPointer &FP = GP.deref<FunctionPointer>();
ASSERT_FALSE(FP.isZero());
APValue A = FP.toAPValue();
ASSERT_TRUE(A.hasValue());
ASSERT_TRUE(A.isLValue());
const auto &Path = A.getLValuePath();
ASSERT_EQ(Path.size(), 0u);
ASSERT_TRUE(A.getLValueBase().isNull());
APSInt I;
bool Success = A.toIntegralConstant(I, D->getType(), AST->getASTContext());
ASSERT_TRUE(Success);
ASSERT_EQ(I, 17);
}
}
442 changes: 442 additions & 0 deletions flang/docs/DebugGeneration.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions flang/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ on how to get in touch with us and to learn more about the current status.
Character
ComplexOperations
ControlFlowGraph
DebugGeneration
Directives
DoConcurrent
Extensions
Expand Down
29 changes: 29 additions & 0 deletions flang/lib/Lower/OpenMP/ClauseProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,20 @@ bool ClauseProcessor::processDepend(
});
}

bool ClauseProcessor::processHasDeviceAddr(
llvm::SmallVectorImpl<mlir::Value> &operands,
llvm::SmallVectorImpl<mlir::Type> &isDeviceTypes,
llvm::SmallVectorImpl<mlir::Location> &isDeviceLocs,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> &isDeviceSymbols)
const {
return findRepeatableClause<omp::clause::HasDeviceAddr>(
[&](const omp::clause::HasDeviceAddr &devAddrClause,
const Fortran::parser::CharBlock &) {
addUseDeviceClause(converter, devAddrClause.v, operands, isDeviceTypes,
isDeviceLocs, isDeviceSymbols);
});
}

bool ClauseProcessor::processIf(
omp::clause::If::DirectiveNameModifier directiveName,
mlir::Value &result) const {
Expand All @@ -771,6 +785,20 @@ bool ClauseProcessor::processIf(
return found;
}

bool ClauseProcessor::processIsDevicePtr(
llvm::SmallVectorImpl<mlir::Value> &operands,
llvm::SmallVectorImpl<mlir::Type> &isDeviceTypes,
llvm::SmallVectorImpl<mlir::Location> &isDeviceLocs,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> &isDeviceSymbols)
const {
return findRepeatableClause<omp::clause::IsDevicePtr>(
[&](const omp::clause::IsDevicePtr &devPtrClause,
const Fortran::parser::CharBlock &) {
addUseDeviceClause(converter, devPtrClause.v, operands, isDeviceTypes,
isDeviceLocs, isDeviceSymbols);
});
}

bool ClauseProcessor::processLink(
llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const {
return findRepeatableClause<omp::clause::Link>(
Expand Down Expand Up @@ -993,6 +1021,7 @@ bool ClauseProcessor::processUseDevicePtr(
useDeviceLocs, useDeviceSymbols);
});
}

} // namespace omp
} // namespace lower
} // namespace Fortran
12 changes: 12 additions & 0 deletions flang/lib/Lower/OpenMP/ClauseProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ class ClauseProcessor {
bool processDeviceType(mlir::omp::DeclareTargetDeviceType &result) const;
bool processFinal(Fortran::lower::StatementContext &stmtCtx,
mlir::Value &result) const;
bool
processHasDeviceAddr(llvm::SmallVectorImpl<mlir::Value> &operands,
llvm::SmallVectorImpl<mlir::Type> &isDeviceTypes,
llvm::SmallVectorImpl<mlir::Location> &isDeviceLocs,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
&isDeviceSymbols) const;
bool processHint(mlir::IntegerAttr &result) const;
bool processMergeable(mlir::UnitAttr &result) const;
bool processNowait(mlir::UnitAttr &result) const;
Expand Down Expand Up @@ -104,6 +110,12 @@ class ClauseProcessor {
bool processIf(omp::clause::If::DirectiveNameModifier directiveName,
mlir::Value &result) const;
bool
processIsDevicePtr(llvm::SmallVectorImpl<mlir::Value> &operands,
llvm::SmallVectorImpl<mlir::Type> &isDeviceTypes,
llvm::SmallVectorImpl<mlir::Location> &isDeviceLocs,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
&isDeviceSymbols) const;
bool
processLink(llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const;

// This method is used to process a map clause.
Expand Down
22 changes: 17 additions & 5 deletions flang/lib/Lower/OpenMP/OpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1294,6 +1294,11 @@ genTargetOp(Fortran::lower::AbstractConverter &converter,
llvm::SmallVector<mlir::Type> mapSymTypes;
llvm::SmallVector<mlir::Location> mapSymLocs;
llvm::SmallVector<const Fortran::semantics::Symbol *> mapSymbols;
llvm::SmallVector<mlir::Value> devicePtrOperands, deviceAddrOperands;
llvm::SmallVector<mlir::Type> devicePtrTypes, deviceAddrTypes;
llvm::SmallVector<mlir::Location> devicePtrLocs, deviceAddrLocs;
llvm::SmallVector<const Fortran::semantics::Symbol *> devicePtrSymbols,
deviceAddrSymbols;

ClauseProcessor cp(converter, semaCtx, clauseList);
cp.processIf(llvm::omp::Directive::OMPD_target, ifClauseOperand);
Expand All @@ -1303,11 +1308,15 @@ genTargetOp(Fortran::lower::AbstractConverter &converter,
cp.processNowait(nowaitAttr);
cp.processMap(currentLocation, directive, stmtCtx, mapOperands, &mapSymTypes,
&mapSymLocs, &mapSymbols);
cp.processIsDevicePtr(devicePtrOperands, devicePtrTypes, devicePtrLocs,
devicePtrSymbols);
cp.processHasDeviceAddr(deviceAddrOperands, deviceAddrTypes, deviceAddrLocs,
deviceAddrSymbols);

cp.processTODO<clause::Private, clause::Firstprivate, clause::IsDevicePtr,
clause::HasDeviceAddr, clause::Reduction, clause::InReduction,
clause::Allocate, clause::UsesAllocators, clause::Defaultmap>(
currentLocation, llvm::omp::Directive::OMPD_target);
cp.processTODO<clause::Private, clause::Firstprivate, clause::Reduction,
clause::InReduction, clause::Allocate, clause::UsesAllocators,
clause::Defaultmap>(currentLocation,
llvm::omp::Directive::OMPD_target);

// 5.8.1 Implicit Data-Mapping Attribute Rules
// The following code follows the implicit data-mapping rules to map all the
Expand Down Expand Up @@ -1400,7 +1409,8 @@ genTargetOp(Fortran::lower::AbstractConverter &converter,
? nullptr
: mlir::ArrayAttr::get(converter.getFirOpBuilder().getContext(),
dependTypeOperands),
dependOperands, nowaitAttr, mapOperands);
dependOperands, nowaitAttr, devicePtrOperands, deviceAddrOperands,
mapOperands);

genBodyOfTargetOp(converter, semaCtx, eval, genNested, targetOp, mapSymTypes,
mapSymLocs, mapSymbols, currentLocation);
Expand Down Expand Up @@ -2059,6 +2069,8 @@ genOMP(Fortran::lower::AbstractConverter &converter,
!std::get_if<Fortran::parser::OmpClause::Map>(&clause.u) &&
!std::get_if<Fortran::parser::OmpClause::UseDevicePtr>(&clause.u) &&
!std::get_if<Fortran::parser::OmpClause::UseDeviceAddr>(&clause.u) &&
!std::get_if<Fortran::parser::OmpClause::IsDevicePtr>(&clause.u) &&
!std::get_if<Fortran::parser::OmpClause::HasDeviceAddr>(&clause.u) &&
!std::get_if<Fortran::parser::OmpClause::ThreadLimit>(&clause.u) &&
!std::get_if<Fortran::parser::OmpClause::NumTeams>(&clause.u)) {
TODO(clauseLocation, "OpenMP Block construct clause");
Expand Down
78 changes: 72 additions & 6 deletions flang/lib/Lower/OpenMP/ReductionProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "flang/Optimizer/Builder/Todo.h"
#include "flang/Optimizer/Dialect/FIRType.h"
#include "flang/Optimizer/HLFIR/HLFIROps.h"
#include "flang/Optimizer/Support/FatalError.h"
#include "flang/Parser/tools.h"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
#include "llvm/Support/CommandLine.h"
Expand Down Expand Up @@ -391,8 +392,60 @@ static void genCombiner(fir::FirOpBuilder &builder, mlir::Location loc,
TODO(loc, "OpenMP genCombiner for unsupported reduction variable type");
}

static void
createReductionCleanupRegion(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::omp::DeclareReductionOp &reductionDecl) {
mlir::Type redTy = reductionDecl.getType();

mlir::Region &cleanupRegion = reductionDecl.getCleanupRegion();
assert(cleanupRegion.empty());
mlir::Block *block =
builder.createBlock(&cleanupRegion, cleanupRegion.end(), {redTy}, {loc});
builder.setInsertionPointToEnd(block);

auto typeError = [loc]() {
fir::emitFatalError(loc,
"Attempt to create an omp reduction cleanup region "
"for a type that wasn't allocated",
/*genCrashDiag=*/true);
};

mlir::Type valTy = fir::unwrapRefType(redTy);
if (auto boxTy = mlir::dyn_cast_or_null<fir::BaseBoxType>(valTy)) {
mlir::Type innerTy = fir::extractSequenceType(boxTy);
if (!mlir::isa<fir::SequenceType>(innerTy))
typeError();

mlir::Value arg = block->getArgument(0);
arg = builder.loadIfRef(loc, arg);
assert(mlir::isa<fir::BaseBoxType>(arg.getType()));

// Deallocate box
// The FIR type system doesn't nesecarrily know that this is a mutable box
// if we allocated the thread local array on the heap to avoid looped stack
// allocations.
mlir::Value addr =
hlfir::genVariableRawAddress(loc, builder, hlfir::Entity{arg});
mlir::Value isAllocated = builder.genIsNotNullAddr(loc, addr);
fir::IfOp ifOp =
builder.create<fir::IfOp>(loc, isAllocated, /*withElseRegion=*/false);
builder.setInsertionPointToStart(&ifOp.getThenRegion().front());

mlir::Value cast = builder.createConvert(
loc, fir::HeapType::get(fir::dyn_cast_ptrEleTy(addr.getType())), addr);
builder.create<fir::FreeMemOp>(loc, cast);

builder.setInsertionPointAfter(ifOp);
builder.create<mlir::omp::YieldOp>(loc);
return;
}

typeError();
}

static mlir::Value
createReductionInitRegion(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::omp::DeclareReductionOp &reductionDecl,
const ReductionProcessor::ReductionIdentifier redId,
mlir::Type type, bool isByRef) {
mlir::Type ty = fir::unwrapRefType(type);
Expand All @@ -419,11 +472,24 @@ createReductionInitRegion(fir::FirOpBuilder &builder, mlir::Location loc,
// Create the private copy from the initial fir.box:
hlfir::Entity source = hlfir::Entity{builder.getBlock()->getArgument(0)};

// TODO: if the whole reduction is nested inside of a loop, this alloca
// could lead to a stack overflow (the memory is only freed at the end of
// the stack frame). The reduction declare operation needs a deallocation
// region to undo the init region.
hlfir::Entity temp = createStackTempFromMold(loc, builder, source);
// Allocating on the heap in case the whole reduction is nested inside of a
// loop
// TODO: compare performance here to using allocas - this could be made to
// work by inserting stacksave/stackrestore around the reduction in
// openmpirbuilder
auto [temp, needsDealloc] = createTempFromMold(loc, builder, source);
// if needsDealloc isn't statically false, add cleanup region. TODO: always
// do this for allocatable boxes because they might have been re-allocated
// in the body of the loop/parallel region
std::optional<int64_t> cstNeedsDealloc =
fir::getIntIfConstant(needsDealloc);
assert(cstNeedsDealloc.has_value() &&
"createTempFromMold decides this statically");
if (cstNeedsDealloc.has_value() && *cstNeedsDealloc != false) {
auto insPt = builder.saveInsertionPoint();
createReductionCleanupRegion(builder, loc, reductionDecl);
builder.restoreInsertionPoint(insPt);
}

// Put the temporary inside of a box:
hlfir::Entity box = hlfir::genVariableBox(loc, builder, temp);
Expand Down Expand Up @@ -462,7 +528,7 @@ mlir::omp::DeclareReductionOp ReductionProcessor::createDeclareReduction(
builder.setInsertionPointToEnd(&decl.getInitializerRegion().back());

mlir::Value init =
createReductionInitRegion(builder, loc, redId, type, isByRef);
createReductionInitRegion(builder, loc, decl, redId, type, isByRef);
builder.create<mlir::omp::YieldOp>(loc, init);

builder.createBlock(&decl.getReductionRegion(),
Expand Down
43 changes: 42 additions & 1 deletion flang/test/Lower/OpenMP/FIR/target.f90
Original file line number Diff line number Diff line change
Expand Up @@ -506,4 +506,45 @@ subroutine omp_target_parallel_do
!CHECK: omp.terminator
!CHECK: }
!$omp end target parallel do
end subroutine omp_target_parallel_do
end subroutine omp_target_parallel_do

!===============================================================================
! Target `is_device_ptr` clause
!===============================================================================

!CHECK-LABEL: func.func @_QPomp_target_is_device_ptr() {
subroutine omp_target_is_device_ptr
use iso_c_binding, only : c_ptr, c_loc
!CHECK: %[[VAL_0:.*]] = fir.alloca !fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}> {bindc_name = "a", uniq_name = "_QFomp_target_is_device_ptrEa"}
type(c_ptr) :: a
!CHECK: %[[VAL_1:.*]] = fir.alloca i32 {bindc_name = "b", fir.target, uniq_name = "_QFomp_target_is_device_ptrEb"}
integer, target :: b
!CHECK: %[[MAP_0:.*]] = omp.map.info var_ptr(%[[DEV_PTR:.*]] : !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>, !fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>) map_clauses(tofrom) capture(ByRef) -> !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>> {name = "a"}
!CHECK: %[[MAP_1:.*]] = omp.map.info var_ptr(%[[VAL_0:.*]] : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {name = "b"}
!CHECK: %[[MAP_2:.*]] = omp.map.info var_ptr(%[[DEV_PTR:.*]] : !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>, !fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByRef) -> !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>> {name = "a"}
!CHECK: omp.target is_device_ptr(%[[DEV_PTR:.*]] : !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>) map_entries(%[[MAP_0:.*]] -> %[[ARG0:.*]], %[[MAP_1:.*]] -> %[[ARG1:.*]], %[[MAP_2:.*]] -> %[[ARG2:.*]] : !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>, !fir.ref<i32>, !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>) {
!CHECK: ^bb0(%[[ARG0]]: !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>, %[[ARG1]]: !fir.ref<i32>, %[[ARG2]]: !fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>):
!$omp target map(tofrom: a,b) is_device_ptr(a)
!CHECK: {{.*}} = fir.coordinate_of %[[VAL_0:.*]], {{.*}} : (!fir.ref<!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>>, !fir.field) -> !fir.ref<i64>
a = c_loc(b)
!CHECK: omp.terminator
!$omp end target
!CHECK: }
end subroutine omp_target_is_device_ptr

!===============================================================================
! Target `has_device_addr` clause
!===============================================================================

!CHECK-LABEL: func.func @_QPomp_target_has_device_addr() {
subroutine omp_target_has_device_addr
!CHECK: %[[VAL_0:.*]] = fir.alloca !fir.box<!fir.ptr<i32>> {bindc_name = "a", uniq_name = "_QFomp_target_has_device_addrEa"}
integer, pointer :: a
!CHECK: omp.target has_device_addr(%[[VAL_0:.*]] : !fir.ref<!fir.box<!fir.ptr<i32>>>) map_entries({{.*}} -> {{.*}}, {{.*}} -> {{.*}} : !fir.llvm_ptr<!fir.ref<i32>>, !fir.ref<!fir.box<!fir.ptr<i32>>>) {
!$omp target has_device_addr(a)
!CHECK: {{.*}} = fir.load %[[VAL_0:.*]] : !fir.ref<!fir.box<!fir.ptr<i32>>>
a = 10
!CHECK: omp.terminator
!$omp end target
!CHECK: }
end subroutine omp_target_has_device_addr
20 changes: 17 additions & 3 deletions flang/test/Lower/OpenMP/parallel-reduction-array.f90
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ program reduce

! CHECK-LABEL: omp.declare_reduction @add_reduction_byref_box_3xi32 : !fir.ref<!fir.box<!fir.array<3xi32>>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.array<3xi32>>>):
! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.array<3xi32> {bindc_name = ".tmp"}
! CHECK: %[[VAL_2:.*]] = arith.constant 0 : i32
! CHECK: %[[VAL_3:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<3xi32>>>
! CHECK: %[[VAL_4:.*]] = arith.constant 3 : index
! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_4]] : (index) -> !fir.shape<1>
! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_1]](%[[VAL_5]]) {uniq_name = ".tmp"} : (!fir.ref<!fir.array<3xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<3xi32>>, !fir.ref<!fir.array<3xi32>>)
! CHECK: %[[VAL_7:.*]] = fir.embox %[[VAL_6]]#0(%[[VAL_5]]) : (!fir.ref<!fir.array<3xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<3xi32>>
! CHECK: %[[VAL_1:.*]] = fir.allocmem !fir.array<3xi32> {bindc_name = ".tmp", uniq_name = ""}
! CHECK: %[[TRUE:.*]] = arith.constant true
! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_1]](%[[VAL_5]]) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<3xi32>>,
!fir.shape<1>) -> (!fir.heap<!fir.array<3xi32>>, !fir.heap<!fir.array<3xi32>>)
! CHECK: %[[VAL_7:.*]] = fir.embox %[[VAL_6]]#0(%[[VAL_5]]) : (!fir.heap<!fir.array<3xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<3xi32>>
! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_7]] : i32, !fir.box<!fir.array<3xi32>>
! CHECK: %[[VAL_8:.*]] = fir.alloca !fir.box<!fir.array<3xi32>>
! CHECK: fir.store %[[VAL_7]] to %[[VAL_8]] : !fir.ref<!fir.box<!fir.array<3xi32>>>
Expand All @@ -43,6 +45,18 @@ program reduce
! CHECK: fir.store %[[VAL_13]] to %[[VAL_9]] : !fir.ref<i32>
! CHECK: }
! CHECK: omp.yield(%[[VAL_0]] : !fir.ref<!fir.box<!fir.array<3xi32>>>)
! CHECK: } cleanup {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.array<3xi32>>>):
! CHECK: %[[VAL_1:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<3xi32>>>
! CHECK: %[[VAL_2:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box<!fir.array<3xi32>>) -> !fir.ref<!fir.array<3xi32>>
! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.array<3xi32>>) -> i64
! CHECK: %[[VAL_4:.*]] = arith.constant 0 : i64
! CHECK: %[[VAL_5:.*]] = arith.cmpi ne, %[[VAL_3]], %[[VAL_4]] : i64
! CHECK: fir.if %[[VAL_5]] {
! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.array<3xi32>>) -> !fir.heap<!fir.array<3xi32>>
! CHECK: fir.freemem %[[VAL_6]] : !fir.heap<!fir.array<3xi32>>
! CHECK: }
! CHECK: omp.yield
! CHECK: }

! CHECK-LABEL: func.func @_QQmain()
Expand Down
20 changes: 17 additions & 3 deletions flang/test/Lower/OpenMP/parallel-reduction-array2.f90
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ program reduce

! CHECK-LABEL: omp.declare_reduction @add_reduction_byref_box_3xi32 : !fir.ref<!fir.box<!fir.array<3xi32>>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.array<3xi32>>>):
! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.array<3xi32> {bindc_name = ".tmp"}
! CHECK: %[[VAL_2:.*]] = arith.constant 0 : i32
! CHECK: %[[VAL_3:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<3xi32>>>
! CHECK: %[[VAL_4:.*]] = arith.constant 3 : index
! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_4]] : (index) -> !fir.shape<1>
! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_1]](%[[VAL_5]]) {uniq_name = ".tmp"} : (!fir.ref<!fir.array<3xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<3xi32>>, !fir.ref<!fir.array<3xi32>>)
! CHECK: %[[VAL_7:.*]] = fir.embox %[[VAL_6]]#0(%[[VAL_5]]) : (!fir.ref<!fir.array<3xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<3xi32>>
! CHECK: %[[VAL_1:.*]] = fir.allocmem !fir.array<3xi32>
! CHECK: %[[TRUE:.*]] = arith.constant true
! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_1]](%[[VAL_5]]) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<3xi32>>,
!fir.shape<1>) -> (!fir.heap<!fir.array<3xi32>>, !fir.heap<!fir.array<3xi32>>)
! CHECK: %[[VAL_7:.*]] = fir.embox %[[VAL_6]]#0(%[[VAL_5]]) : (!fir.heap<!fir.array<3xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<3xi32>>
! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_7]] : i32, !fir.box<!fir.array<3xi32>>
! CHECK: %[[VAL_8:.*]] = fir.alloca !fir.box<!fir.array<3xi32>>
! CHECK: fir.store %[[VAL_7]] to %[[VAL_8]] : !fir.ref<!fir.box<!fir.array<3xi32>>>
Expand All @@ -43,6 +45,18 @@ program reduce
! CHECK: fir.store %[[VAL_13]] to %[[VAL_9]] : !fir.ref<i32>
! CHECK: }
! CHECK: omp.yield(%[[VAL_0]] : !fir.ref<!fir.box<!fir.array<3xi32>>>)
! CHECK: } cleanup {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.array<3xi32>>>):
! CHECK: %[[VAL_1:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<3xi32>>>
! CHECK: %[[VAL_2:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box<!fir.array<3xi32>>) -> !fir.ref<!fir.array<3xi32>>
! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.array<3xi32>>) -> i64
! CHECK: %[[VAL_4:.*]] = arith.constant 0 : i64
! CHECK: %[[VAL_5:.*]] = arith.cmpi ne, %[[VAL_3]], %[[VAL_4]] : i64
! CHECK: fir.if %[[VAL_5]] {
! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.array<3xi32>>) -> !fir.heap<!fir.array<3xi32>>
! CHECK: fir.freemem %[[VAL_6]] : !fir.heap<!fir.array<3xi32>>
! CHECK: }
! CHECK: omp.yield
! CHECK: }

! CHECK-LABEL: func.func @_QQmain() attributes {fir.bindc_name = "reduce"} {
Expand Down
31 changes: 17 additions & 14 deletions flang/test/Lower/OpenMP/parallel-reduction3.f90
Original file line number Diff line number Diff line change
@@ -1,30 +1,21 @@
! NOTE: Assertions have been autogenerated by utils/generate-test-checks.py

! The script is designed to make adding checks to
! a test case fast, it is *not* designed to be authoritative
! about what constitutes a good test! The CHECK should be
! minimized and named to reflect the test intent.

! RUN: bbc -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s
! RUN: %flang_fc1 -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s



! CHECK-LABEL: omp.declare_reduction @add_reduction_byref_box_Uxi32 : !fir.ref<!fir.box<!fir.array<?xi32>>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.array<?xi32>>>):
! CHECK: %[[VAL_1:.*]] = arith.constant 0 : i32
! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<?xi32>>>
! CHECK: %[[VAL_3:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_4:.*]]:3 = fir.box_dims %[[VAL_2]], %[[VAL_3]] : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_4]]#1 : (index) -> !fir.shape<1>
! CHECK: %[[VAL_6:.*]] = fir.alloca !fir.array<?xi32>, %[[VAL_4]]#1 {bindc_name = ".tmp"}
! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]](%[[VAL_5]]) {uniq_name = ".tmp"} : (!fir.ref<!fir.array<?xi32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xi32>>, !fir.ref<!fir.array<?xi32>>)
! CHECK: %[[VAL_6:.*]] = fir.allocmem !fir.array<?xi32>, %[[VAL_4]]#1 {bindc_name = ".tmp", uniq_name = ""}
! CHECK: %[[TRUE:.*]] = arith.constant true
! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]](%[[VAL_5]]) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<?xi32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xi32>>, !fir.heap<!fir.array<?xi32>>)
! CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_7]]#0 : i32, !fir.box<!fir.array<?xi32>>
! CHECK: %[[VAL_8:.*]] = fir.alloca !fir.box<!fir.array<?xi32>>
! CHECK: fir.store %[[VAL_7]]#0 to %[[VAL_8]] : !fir.ref<!fir.box<!fir.array<?xi32>>>
! CHECK: omp.yield(%[[VAL_8]] : !fir.ref<!fir.box<!fir.array<?xi32>>>)

! CHECK-LABEL: } combiner {
! CHECK: } combiner {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.array<?xi32>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.array<?xi32>>>):
! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<?xi32>>>
! CHECK: %[[VAL_3:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.array<?xi32>>>
Expand All @@ -41,6 +32,18 @@
! CHECK: fir.store %[[VAL_13]] to %[[VAL_9]] : !fir.ref<i32>
! CHECK: }
! CHECK: omp.yield(%[[VAL_0]] : !fir.ref<!fir.box<!fir.array<?xi32>>>)
! CHECK: } cleanup {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.array<?xi32>>>):
! CHECK: %[[VAL_1:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<?xi32>>>
! CHECK: %[[VAL_2:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>>
! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.array<?xi32>>) -> i64
! CHECK: %[[VAL_4:.*]] = arith.constant 0 : i64
! CHECK: %[[VAL_5:.*]] = arith.cmpi ne, %[[VAL_3]], %[[VAL_4]] : i64
! CHECK: fir.if %[[VAL_5]] {
! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.array<?xi32>>) -> !fir.heap<!fir.array<?xi32>>
! CHECK: fir.freemem %[[VAL_6]] : !fir.heap<!fir.array<?xi32>>
! CHECK: }
! CHECK: omp.yield
! CHECK: }

! CHECK-LABEL: func.func @_QPs(
Expand Down Expand Up @@ -122,4 +125,4 @@ subroutine s(x)
!$omp end parallel do

if (c(1) /= 5050) stop 1
end subroutine s
end subroutine s
17 changes: 15 additions & 2 deletions flang/test/Lower/OpenMP/wsloop-reduction-array-assumed-shape.f90
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ subroutine reduce(r)
! CHECK: %[[VAL_3:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_4:.*]]:3 = fir.box_dims %[[VAL_2]], %[[VAL_3]] : (!fir.box<!fir.array<?xf64>>, index) -> (index, index, index)
! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_4]]#1 : (index) -> !fir.shape<1>
! CHECK: %[[VAL_6:.*]] = fir.alloca !fir.array<?xf64>, %[[VAL_4]]#1 {bindc_name = ".tmp"}
! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]](%[[VAL_5]]) {uniq_name = ".tmp"} : (!fir.ref<!fir.array<?xf64>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xf64>>, !fir.ref<!fir.array<?xf64>>)
! CHECK: %[[VAL_6:.*]] = fir.allocmem !fir.array<?xf64>, %[[VAL_4]]#1 {bindc_name = ".tmp", uniq_name = ""}
! CHECK: %[[TRUE:.*]] = arith.constant true
! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]](%[[VAL_5]]) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<?xf64>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xf64>>, !fir.heap<!fir.array<?xf64>>)
! CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_7]]#0 : f64, !fir.box<!fir.array<?xf64>>
! CHECK: %[[VAL_8:.*]] = fir.alloca !fir.box<!fir.array<?xf64>>
! CHECK: fir.store %[[VAL_7]]#0 to %[[VAL_8]] : !fir.ref<!fir.box<!fir.array<?xf64>>>
Expand All @@ -53,6 +54,18 @@ subroutine reduce(r)
! CHECK: fir.store %[[VAL_13]] to %[[VAL_9]] : !fir.ref<f64>
! CHECK: }
! CHECK: omp.yield(%[[VAL_0]] : !fir.ref<!fir.box<!fir.array<?xf64>>>)
! CHECK: } cleanup {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.array<?xf64>>>):
! CHECK: %[[VAL_1:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<?xf64>>>
! CHECK: %[[VAL_2:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box<!fir.array<?xf64>>) -> !fir.ref<!fir.array<?xf64>>
! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.array<?xf64>>) -> i64
! CHECK: %[[VAL_4:.*]] = arith.constant 0 : i64
! CHECK: %[[VAL_5:.*]] = arith.cmpi ne, %[[VAL_3]], %[[VAL_4]] : i64
! CHECK: fir.if %[[VAL_5]] {
! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.array<?xf64>>) -> !fir.heap<!fir.array<?xf64>>
! CHECK: fir.freemem %[[VAL_6]] : !fir.heap<!fir.array<?xf64>>
! CHECK: }
! CHECK: omp.yield
! CHECK: }

! CHECK-LABEL: func.func private @_QFPreduce(
Expand Down
19 changes: 16 additions & 3 deletions flang/test/Lower/OpenMP/wsloop-reduction-array.f90
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ program reduce

! CHECK-LABEL omp.declare_reduction @add_reduction_byref_box_2xi32 : !fir.ref<!fir.box<!fir.array<2xi32>>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.array<2xi32>>>):
! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.array<2xi32> {bindc_name = ".tmp"}
! CHECK: %[[VAL_2:.*]] = arith.constant 0 : i32
! CHECK: %[[VAL_3:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<2xi32>>>
! CHECK: %[[VAL_4:.*]] = arith.constant 2 : index
! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_4]] : (index) -> !fir.shape<1>
! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_1]](%[[VAL_5]]) {uniq_name = ".tmp"} : (!fir.ref<!fir.array<2xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<2xi32>>, !fir.ref<!fir.array<2xi32>>)
! CHECK: %[[VAL_7:.*]] = fir.embox %[[VAL_6]]#0(%[[VAL_5]]) : (!fir.ref<!fir.array<2xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<2xi32>>
! CHECK: %[[VAL_1:.*]] = fir.allocmem !fir.array<2xi32> {bindc_name = ".tmp", uniq_name = ""}
! CHECK: %[[TRUE:.*]] = arith.constant true
! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_1]](%[[VAL_5]]) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<2xi32>>, !fir.shape<1>) -> (!fir.heap<!fir.array<2xi32>>, !fir.heap<!fir.array<2xi32>>)
! CHECK: %[[VAL_7:.*]] = fir.embox %[[VAL_6]]#0(%[[VAL_5]]) : (!fir.heap<!fir.array<2xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<2xi32>>
! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_7]] : i32, !fir.box<!fir.array<2xi32>>
! CHECK: %[[VAL_8:.*]] = fir.alloca !fir.box<!fir.array<2xi32>>
! CHECK: fir.store %[[VAL_7]] to %[[VAL_8]] : !fir.ref<!fir.box<!fir.array<2xi32>>>
Expand All @@ -45,6 +46,18 @@ program reduce
! CHECK: fir.store %[[VAL_13]] to %[[VAL_9]] : !fir.ref<i32>
! CHECK: }
! CHECK: omp.yield(%[[VAL_0]] : !fir.ref<!fir.box<!fir.array<2xi32>>>)
! CHECK: } cleanup {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.array<2xi32>>>):
! CHECK: %[[VAL_1:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<2xi32>>>
! CHECK: %[[VAL_2:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box<!fir.array<2xi32>>) -> !fir.ref<!fir.array<2xi32>>
! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.array<2xi32>>) -> i64
! CHECK: %[[VAL_4:.*]] = arith.constant 0 : i64
! CHECK: %[[VAL_5:.*]] = arith.cmpi ne, %[[VAL_3]], %[[VAL_4]] : i64
! CHECK: fir.if %[[VAL_5]] {
! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.array<2xi32>>) -> !fir.heap<!fir.array<2xi32>>
! CHECK: fir.freemem %[[VAL_6]] : !fir.heap<!fir.array<2xi32>>
! CHECK: }
! CHECK: omp.yield
! CHECK: }

! CHECK-LABEL func.func @_QQmain() attributes {fir.bindc_name = "reduce"} {
Expand Down
21 changes: 17 additions & 4 deletions flang/test/Lower/OpenMP/wsloop-reduction-array2.f90
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,20 @@ program reduce

! CHECK-LABEL omp.declare_reduction @add_reduction_byref_box_2xi32 : !fir.ref<!fir.box<!fir.array<2xi32>>> init {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.array<2xi32>>>):
! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.array<2xi32> {bindc_name = ".tmp"}
! CHECK: %[[VAL_2:.*]] = arith.constant 0 : i32
! CHECK: %[[VAL_3:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<2xi32>>>
! CHECK: %[[VAL_4:.*]] = arith.constant 2 : index
! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_4]] : (index) -> !fir.shape<1>
! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_1]](%[[VAL_5]]) {uniq_name = ".tmp"} : (!fir.ref<!fir.array<2xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<2xi32>>, !fir.ref<!fir.array<2xi32>>)
! CHECK: %[[VAL_7:.*]] = fir.embox %[[VAL_6]]#0(%[[VAL_5]]) : (!fir.ref<!fir.array<2xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<2xi32>>
! CHECK: %[[VAL_1:.*]] = fir.allocmem !fir.array<2xi32> {bindc_name = ".tmp", uniq_name = ""}
! CHECK: %[[TRUE:.*]] = arith.constant true
! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_1]](%[[VAL_5]]) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<2xi32>>, !fir.shape<1>) -> (!fir.heap<!fir.array<2xi32>>, !fir.heap<!fir.array<2xi32>>)
! CHECK: %[[VAL_7:.*]] = fir.embox %[[VAL_6]]#0(%[[VAL_5]]) : (!fir.heap<!fir.array<2xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<2xi32>>
! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_7]] : i32, !fir.box<!fir.array<2xi32>>
! CHECK: %[[VAL_8:.*]] = fir.alloca !fir.box<!fir.array<2xi32>>
! CHECK: fir.store %[[VAL_7]] to %[[VAL_8]] : !fir.ref<!fir.box<!fir.array<2xi32>>>
! CHECK: omp.yield(%[[VAL_8]] : !fir.ref<!fir.box<!fir.array<2xi32>>>)

! CHECK-LABEL } combiner {
! CHECK: } combiner {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.array<2xi32>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.array<2xi32>>>):
! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<2xi32>>>
! CHECK: %[[VAL_3:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.array<2xi32>>>
Expand All @@ -45,6 +46,18 @@ program reduce
! CHECK: fir.store %[[VAL_13]] to %[[VAL_9]] : !fir.ref<i32>
! CHECK: }
! CHECK: omp.yield(%[[VAL_0]] : !fir.ref<!fir.box<!fir.array<2xi32>>>)
! CHECK: } cleanup {
! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.array<2xi32>>>):
! CHECK: %[[VAL_1:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<2xi32>>>
! CHECK: %[[VAL_2:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box<!fir.array<2xi32>>) -> !fir.ref<!fir.array<2xi32>>
! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.array<2xi32>>) -> i64
! CHECK: %[[VAL_4:.*]] = arith.constant 0 : i64
! CHECK: %[[VAL_5:.*]] = arith.cmpi ne, %[[VAL_3]], %[[VAL_4]] : i64
! CHECK: fir.if %[[VAL_5]] {
! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.array<2xi32>>) -> !fir.heap<!fir.array<2xi32>>
! CHECK: fir.freemem %[[VAL_6]] : !fir.heap<!fir.array<2xi32>>
! CHECK: }
! CHECK: omp.yield
! CHECK: }

! CHECK-LABEL: func.func @_QQmain() attributes {fir.bindc_name = "reduce"} {
Expand Down
33 changes: 33 additions & 0 deletions libc/docs/dev/code_style.rst
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,36 @@ We expect contributions to be free of warnings from the `minimum supported
compiler versions`__ (and newer).

.. __: https://libc.llvm.org/compiler_support.html#minimum-supported-versions

Header Inclusion Policy
=======================

Because llvm-libc supports
`Overlay Mode <https://libc.llvm.org/overlay_mode.html>`__ and
`Fullbuild Mode <https://libc.llvm.org/fullbuild_mode.html>`__ care must be
taken when ``#include``'ing certain headers.

The ``include/`` directory contains public facing headers that users must
consume for fullbuild mode. As such, types defined here will have ABI
implications as these definitions may differ from the underlying system for
overlay mode and are NEVER appropriate to include in ``libc/src/`` without
preprocessor guards for ``LLVM_LIBC_FULL_BUILD``.

Consider the case where an implementation in ``libc/src/`` may wish to refer to
a ``sigset_t``, what header should be included? ``<signal.h>``, ``<spawn.h>``,
``<sys/select.h>``?

None of the above. Instead, code under ``src/`` should ``#include
"hdr/types/sigset_t.h"`` which contains preprocessor guards on
``LLVM_LIBC_FULL_BUILD`` to either include the public type (fullbuild mode) or
the underlying system header (overlay mode).

Implementations in ``libc/src/`` should NOT be ``#include``'ing using ``<>`` or
``"include/*``, except for these "proxy" headers that first check for
``LLVM_LIBC_FULL_BUILD``.

These "proxy" headers are similarly used when referring to preprocessor
defines. Code under ``libc/src/`` should ``#include`` a proxy header from
``hdr/``, which contains a guard on ``LLVM_LIBC_FULL_BUILD`` to either include
our header from ``libc/include/`` (fullbuild) or the corresponding underlying
system header (overlay).
1 change: 1 addition & 0 deletions libc/docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ stages there is no ABI stability in any form.
libc_search
c23
ctype
signal

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

signal.h Functions
==================

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

* - Function
- Implemented
- Standard
* - kill
- |check|
-
* - raise
- |check|
- 7.14.2.1
* - sigaction
- |check|
-
* - sigaddset
- |check|
-
* - sigaltstack
- |check|
-
* - sigdelset
- |check|
-
* - sigemptyset
- |check|
-
* - sigfillset
- |check|
-
* - signal
- |check|
- 7.14.1.1
* - sigprocmask
- |check|
-
6 changes: 5 additions & 1 deletion libc/docs/usage_modes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ The libc can used in two different modes:

#. The **overlay** mode: In this mode, the link order semantics are exploited
to overlay implementations from LLVM's libc over the system libc. See
:ref:`overlay_mode` for more information about this mode.
:ref:`overlay_mode` for more information about this mode. In this mode, libc
uses the ABI of the system it's being overlayed onto. Headers are NOT
generated. libllvmlibc.a is the only build artifact.
#. The **fullbuild** mode: In this mode, LLVM's libc is used as the only libc
for the binary. See :ref:`fullbuild_mode` for information about this mode.
In this mode, libc uses its own ABI. Headers are generated along with a
libc.a.
2 changes: 2 additions & 0 deletions libc/hdr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,5 @@ add_proxy_header_library(
libc.include.llvm-libc-macros.fenv_macros
libc.include.fenv
)

add_subdirectory(types)
23 changes: 23 additions & 0 deletions libc/hdr/types/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
add_proxy_header_library(
sigset_t
HDRS
sigset_t.h
FULL_BUILD_DEPENDS
libc.include.llvm-libc-types.sigset_t
)

add_proxy_header_library(
struct_epoll_event
HDRS
struct_epoll_event.h
FULL_BUILD_DEPENDS
libc.include.llvm-libc-types.struct_epoll_event
)

add_proxy_header_library(
struct_timespec
HDRS
struct_timespec.h
FULL_BUILD_DEPENDS
libc.include.llvm-libc-types.struct_timespec
)
21 changes: 21 additions & 0 deletions libc/hdr/types/sigset_t.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//===-- Proxy for sigset_t ------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_HDR_TYPES_SIGSET_T_H
#define LLVM_LIBC_HDR_TYPES_SIGSET_T_H

#ifdef LIBC_FULL_BUILD

#include "include/llvm-libc-types/sigset_t.h"

#else

#include <signal.h>

#endif // LIBC_FULL_BUILD

#endif // LLVM_LIBC_HDR_TYPES_SIGSET_T_H
21 changes: 21 additions & 0 deletions libc/hdr/types/struct_epoll_event.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//===-- Proxy for struct epoll_event --------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_HDR_TYPES_STRUCT_EPOLL_EVENT_H
#define LLVM_LIBC_HDR_TYPES_STRUCT_EPOLL_EVENT_H

#ifdef LIBC_FULL_BUILD

#include "include/llvm-libc-types/struct_epoll_event.h"

#else

#include <sys/epoll.h>

#endif // LIBC_FULL_BUILD

#endif // LLVM_LIBC_HDR_TYPES_STRUCT_EPOLL_EVENT_H
21 changes: 21 additions & 0 deletions libc/hdr/types/struct_timespec.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//===-- Proxy for struct timespec ----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_HDR_TYPES_STRUCT_TIMESPEC_H
#define LLVM_LIBC_HDR_TYPES_STRUCT_TIMESPEC_H

#ifdef LIBC_FULL_BUILD

#include "include/llvm-libc-types/struct_timespec.h"

#else

#include <time.h>

#endif // LIBC_FULL_BUILD

#endif // LLVM_LIBC_HDR_TYPES_STRUCT_TIMESPEC_H
16 changes: 9 additions & 7 deletions libc/src/signal/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ add_header_library(
HDRS
signal_utils.h
DEPENDS
libc.hdr.types.sigset_t
libc.include.signal
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
)
Expand All @@ -28,7 +30,7 @@ add_entrypoint_object(
../raise.h
DEPENDS
.signal_utils
libc.include.signal
libc.hdr.types.sigset_t
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
)
Expand Down Expand Up @@ -57,7 +59,7 @@ add_entrypoint_object(
../sigaction.h
DEPENDS
.__restore
libc.include.signal
libc.hdr.types.sigset_t
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
Expand All @@ -84,7 +86,7 @@ add_entrypoint_object(
../sigprocmask.h
DEPENDS
.signal_utils
libc.include.signal
libc.hdr.types.sigset_t
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
Expand All @@ -98,7 +100,7 @@ add_entrypoint_object(
../sigemptyset.h
DEPENDS
.signal_utils
libc.include.signal
libc.hdr.types.sigset_t
libc.src.errno.errno
)

Expand All @@ -110,7 +112,7 @@ add_entrypoint_object(
../sigaddset.h
DEPENDS
.signal_utils
libc.include.signal
libc.hdr.types.sigset_t
libc.src.errno.errno
)

Expand All @@ -133,7 +135,7 @@ add_entrypoint_object(
../sigfillset.h
DEPENDS
.signal_utils
libc.include.signal
libc.hdr.types.sigset_t
libc.src.errno.errno
)

Expand All @@ -145,6 +147,6 @@ add_entrypoint_object(
../sigdelset.h
DEPENDS
.signal_utils
libc.include.signal
libc.hdr.types.sigset_t
libc.src.errno.errno
)
5 changes: 3 additions & 2 deletions libc/src/signal/linux/raise.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
//===----------------------------------------------------------------------===//

#include "src/signal/raise.h"
#include "src/signal/linux/signal_utils.h"

#include "hdr/types/sigset_t.h"
#include "src/__support/common.h"
#include "src/signal/linux/signal_utils.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(int, raise, (int sig)) {
::sigset_t sigset;
sigset_t sigset;
block_all_signals(sigset);
long pid = LIBC_NAMESPACE::syscall_impl<long>(SYS_getpid);
long tid = LIBC_NAMESPACE::syscall_impl<long>(SYS_gettid);
Expand Down
7 changes: 3 additions & 4 deletions libc/src/signal/linux/sigaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@
//===----------------------------------------------------------------------===//

#include "src/signal/sigaction.h"
#include "src/errno/libc_errno.h"
#include "src/signal/linux/signal_utils.h"

#include "hdr/types/sigset_t.h"
#include "src/__support/common.h"

#include <signal.h>
#include "src/errno/libc_errno.h"
#include "src/signal/linux/signal_utils.h"

namespace LIBC_NAMESPACE {

Expand Down
4 changes: 2 additions & 2 deletions libc/src/signal/linux/sigaddset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
//===----------------------------------------------------------------------===//

#include "src/signal/sigaddset.h"

#include "hdr/types/sigset_t.h"
#include "src/__support/common.h"
#include "src/errno/libc_errno.h"
#include "src/signal/linux/signal_utils.h"

#include <signal.h>

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(int, sigaddset, (sigset_t * set, int signum)) {
Expand Down
4 changes: 2 additions & 2 deletions libc/src/signal/linux/sigdelset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
//===----------------------------------------------------------------------===//

#include "src/signal/sigdelset.h"

#include "hdr/types/sigset_t.h"
#include "src/__support/common.h"
#include "src/errno/libc_errno.h"
#include "src/signal/linux/signal_utils.h"

#include <signal.h>

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(int, sigdelset, (sigset_t * set, int signum)) {
Expand Down
4 changes: 2 additions & 2 deletions libc/src/signal/linux/sigfillset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
//===----------------------------------------------------------------------===//

#include "src/signal/sigfillset.h"

#include "hdr/types/sigset_t.h"
#include "src/__support/common.h"
#include "src/errno/libc_errno.h"
#include "src/signal/linux/signal_utils.h"

#include <signal.h>

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(int, sigfillset, (sigset_t * set)) {
Expand Down
3 changes: 2 additions & 1 deletion libc/src/signal/linux/signal_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
#ifndef LLVM_LIBC_SRC_SIGNAL_LINUX_SIGNAL_UTILS_H
#define LLVM_LIBC_SRC_SIGNAL_LINUX_SIGNAL_UTILS_H

#include "hdr/types/sigset_t.h"
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/common.h"

#include <signal.h>
#include <signal.h> // sigaction
#include <stddef.h>
#include <sys/syscall.h> // For syscall numbers.

Expand Down
6 changes: 3 additions & 3 deletions libc/src/signal/linux/sigprocmask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
//===----------------------------------------------------------------------===//

#include "src/signal/sigprocmask.h"

#include "hdr/types/sigset_t.h"
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/common.h"
#include "src/errno/libc_errno.h"
#include "src/signal/linux/signal_utils.h"

#include "src/__support/common.h"

#include <signal.h>
#include <sys/syscall.h> // For syscall numbers.

namespace LIBC_NAMESPACE {
Expand Down
2 changes: 1 addition & 1 deletion libc/src/signal/sigaddset.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#ifndef LLVM_LIBC_SRC_SIGNAL_SIGADDSET_H
#define LLVM_LIBC_SRC_SIGNAL_SIGADDSET_H

#include <signal.h>
#include "hdr/types/sigset_t.h"

namespace LIBC_NAMESPACE {

Expand Down
2 changes: 1 addition & 1 deletion libc/src/signal/sigdelset.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#ifndef LLVM_LIBC_SRC_SIGNAL_SIGDELSET_H
#define LLVM_LIBC_SRC_SIGNAL_SIGDELSET_H

#include <signal.h>
#include "hdr/types/sigset_t.h"

namespace LIBC_NAMESPACE {

Expand Down
2 changes: 1 addition & 1 deletion libc/src/signal/sigemptyset.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#ifndef LLVM_LIBC_SRC_SIGNAL_SIGEMPTYSET_H
#define LLVM_LIBC_SRC_SIGNAL_SIGEMPTYSET_H

#include <signal.h>
#include "hdr/types/sigset_t.h"

namespace LIBC_NAMESPACE {

Expand Down
2 changes: 1 addition & 1 deletion libc/src/signal/sigfillset.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#ifndef LLVM_LIBC_SRC_SIGNAL_SIGFILLSET_H
#define LLVM_LIBC_SRC_SIGNAL_SIGFILLSET_H

#include <signal.h>
#include "hdr/types/sigset_t.h"

namespace LIBC_NAMESPACE {

Expand Down
2 changes: 1 addition & 1 deletion libc/src/signal/sigprocmask.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#ifndef LLVM_LIBC_SRC_SIGNAL_SIGPROCMASK_H
#define LLVM_LIBC_SRC_SIGNAL_SIGPROCMASK_H

#include <signal.h>
#include "hdr/types/sigset_t.h"

namespace LIBC_NAMESPACE {

Expand Down
7 changes: 2 additions & 5 deletions libc/src/sys/epoll/epoll_pwait.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,8 @@
#ifndef LLVM_LIBC_SRC_SYS_EPOLL_EPOLL_PWAIT_H
#define LLVM_LIBC_SRC_SYS_EPOLL_EPOLL_PWAIT_H

// TODO: Use this include once the include headers are also using quotes.
// #include "include/llvm-libc-types/sigset_t.h"
// #include "include/llvm-libc-types/struct_epoll_event.h"

#include <sys/epoll.h>
#include "hdr/types/sigset_t.h"
#include "hdr/types/struct_epoll_event.h"

namespace LIBC_NAMESPACE {

Expand Down
9 changes: 3 additions & 6 deletions libc/src/sys/epoll/epoll_pwait2.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@
#ifndef LLVM_LIBC_SRC_SYS_EPOLL_EPOLL_PWAIT2_H
#define LLVM_LIBC_SRC_SYS_EPOLL_EPOLL_PWAIT2_H

// TODO: Use this include once the include headers are also using quotes.
// #include "include/llvm-libc-types/sigset_t.h"
// #include "include/llvm-libc-types/struct_epoll_event.h"
// #include "include/llvm-libc-types/struct_timespec.h"

#include <sys/epoll.h>
#include "hdr/types/sigset_t.h"
#include "hdr/types/struct_epoll_event.h"
#include "hdr/types/struct_timespec.h"

namespace LIBC_NAMESPACE {

Expand Down
5 changes: 1 addition & 4 deletions libc/src/sys/epoll/epoll_wait.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@
#ifndef LLVM_LIBC_SRC_SYS_EPOLL_EPOLL_WAIT_H
#define LLVM_LIBC_SRC_SYS_EPOLL_EPOLL_WAIT_H

// TODO: Use this include once the include headers are also using quotes.
// #include "include/llvm-libc-types/struct_epoll_event.h"

#include <sys/epoll.h>
#include "hdr/types/struct_epoll_event.h"

namespace LIBC_NAMESPACE {

Expand Down
14 changes: 10 additions & 4 deletions libc/src/sys/epoll/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ add_entrypoint_object(
HDRS
../epoll_wait.h
DEPENDS
libc.include.sys_epoll
libc.hdr.types.sigset_t
libc.hdr.types.struct_epoll_event
libc.hdr.types.struct_timespec
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
Expand All @@ -18,7 +20,9 @@ add_entrypoint_object(
HDRS
../epoll_pwait.h
DEPENDS
libc.include.sys_epoll
libc.hdr.types.sigset_t
libc.hdr.types.struct_epoll_event
libc.hdr.types.struct_timespec
libc.include.signal
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
Expand All @@ -32,10 +36,12 @@ add_entrypoint_object(
HDRS
../epoll_pwait2.h
DEPENDS
libc.include.sys_epoll
libc.hdr.types.sigset_t
libc.hdr.types.struct_epoll_event
libc.hdr.types.struct_timespec
libc.include.signal
libc.include.time
libc.include.sys_syscall
libc.include.time
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
)
10 changes: 3 additions & 7 deletions libc/src/sys/epoll/linux/epoll_pwait.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,13 @@

#include "src/sys/epoll/epoll_pwait.h"

#include "hdr/types/sigset_t.h"
#include "hdr/types/struct_epoll_event.h"
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/common.h"

#include "src/errno/libc_errno.h"
#include <sys/syscall.h> // For syscall numbers.

// TODO: Use this include once the include headers are also using quotes.
// #include "include/llvm-libc-types/sigset_t.h"
// #include "include/llvm-libc-types/struct_epoll_event.h"

#include <sys/epoll.h>
#include <sys/syscall.h> // For syscall numbers.

namespace LIBC_NAMESPACE {

Expand Down
12 changes: 4 additions & 8 deletions libc/src/sys/epoll/linux/epoll_pwait2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,14 @@

#include "src/sys/epoll/epoll_pwait2.h"

#include "hdr/types/sigset_t.h"
#include "hdr/types/struct_epoll_event.h"
#include "hdr/types/struct_timespec.h"
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/common.h"

#include "src/errno/libc_errno.h"
#include <sys/syscall.h> // For syscall numbers.

// TODO: Use this include once the include headers are also using quotes.
// #include "include/llvm-libc-types/sigset_t.h"
// #include "include/llvm-libc-types/struct_epoll_event.h"
// #include "include/llvm-libc-types/struct_timespec.h"

#include <sys/epoll.h>
#include <sys/syscall.h> // For syscall numbers.

namespace LIBC_NAMESPACE {

Expand Down
9 changes: 3 additions & 6 deletions libc/src/sys/epoll/linux/epoll_wait.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,13 @@

#include "src/sys/epoll/epoll_wait.h"

#include "hdr/types/sigset_t.h"
#include "hdr/types/struct_epoll_event.h"
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/common.h"
#include "src/errno/libc_errno.h"
#include <sys/syscall.h> // For syscall numbers.

// TODO: Use this include once the include headers are also using quotes.
// #include "include/llvm-libc-types/sigset_t.h"
// #include "include/llvm-libc-types/struct_epoll_event.h"

#include <sys/epoll.h>
#include <sys/syscall.h> // For syscall numbers.

namespace LIBC_NAMESPACE {

Expand Down
8 changes: 4 additions & 4 deletions libc/src/sys/select/linux/select.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@

#include "src/sys/select/select.h"

#include "hdr/types/sigset_t.h"
#include "hdr/types/struct_timespec.h"
#include "src/__support/CPP/limits.h"
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/common.h"

#include "src/errno/libc_errno.h"
#include <signal.h>
#include <stddef.h> // For size_t
#include <sys/select.h>

#include <stddef.h> // For size_t
#include <sys/syscall.h> // For syscall numbers.

namespace LIBC_NAMESPACE {
Expand Down
13 changes: 9 additions & 4 deletions libc/utils/docgen/docgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,17 @@ def load_api(hname: str) -> Dict:
# TODO: we may need to get more sophisticated for less generic implementations.
# Does libc/src/{hname minus .h suffix}/{fname}.cpp exist?
def is_implemented(hname: str, fname: str) -> bool:
return Path(
path = Path(
Path(__file__).parent.parent.parent,
"src",
hname.rstrip(".h"),
fname + ".cpp",
).exists()
hname.rstrip(".h")
)
# Recursively search for the target source file in the subdirectories under
# libc/src/{hname}.
for _ in path.glob("**/" + fname + ".cpp"):
return True

return False


def print_functions(header: str, functions: Dict):
Expand Down
29 changes: 29 additions & 0 deletions libc/utils/docgen/signal.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"macros": [
"SIG_DFL",
"SIG_ERR",
"SIG_IGN",
"SIGABRT",
"SIGFPE",
"SIGILL",
"SIGINT",
"SIGSEGV",
"SIGTERM"
],
"functions": {
"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"
}
}
}
Loading