166 changes: 113 additions & 53 deletions clang/lib/Analysis/UnsafeBufferUsage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,9 @@ class Gadget {
#endif

virtual bool isWarningGadget() const = 0;
virtual const Stmt *getBaseStmt() const = 0;
// TODO remove this method from WarningGadget interface. It's only used for
// debug prints in FixableGadget.
virtual SourceLocation getSourceLoc() const = 0;

/// Returns the list of pointer-type variables on which this gadget performs
/// its operation. Typically, there's only one variable. This isn't a list
Expand All @@ -513,6 +515,10 @@ class WarningGadget : public Gadget {

static bool classof(const Gadget *G) { return G->isWarningGadget(); }
bool isWarningGadget() const final { return true; }

virtual void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
bool IsRelatedToDecl,
ASTContext &Ctx) const = 0;
};

/// Fixable gadgets correspond to code patterns that aren't always unsafe but
Expand Down Expand Up @@ -572,7 +578,12 @@ class IncrementGadget : public WarningGadget {
.bind(OpTag));
}

const UnaryOperator *getBaseStmt() const override { return Op; }
void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
bool IsRelatedToDecl,
ASTContext &Ctx) const override {
Handler.handleUnsafeOperation(Op, IsRelatedToDecl, Ctx);
}
SourceLocation getSourceLoc() const override { return Op->getBeginLoc(); }

DeclUseList getClaimedVarUseSites() const override {
SmallVector<const DeclRefExpr *, 2> Uses;
Expand Down Expand Up @@ -607,7 +618,12 @@ class DecrementGadget : public WarningGadget {
.bind(OpTag));
}

const UnaryOperator *getBaseStmt() const override { return Op; }
void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
bool IsRelatedToDecl,
ASTContext &Ctx) const override {
Handler.handleUnsafeOperation(Op, IsRelatedToDecl, Ctx);
}
SourceLocation getSourceLoc() const override { return Op->getBeginLoc(); }

DeclUseList getClaimedVarUseSites() const override {
if (const auto *DRE =
Expand Down Expand Up @@ -648,7 +664,12 @@ class ArraySubscriptGadget : public WarningGadget {
// clang-format on
}

const ArraySubscriptExpr *getBaseStmt() const override { return ASE; }
void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
bool IsRelatedToDecl,
ASTContext &Ctx) const override {
Handler.handleUnsafeOperation(ASE, IsRelatedToDecl, Ctx);
}
SourceLocation getSourceLoc() const override { return ASE->getBeginLoc(); }

DeclUseList getClaimedVarUseSites() const override {
if (const auto *DRE =
Expand Down Expand Up @@ -696,7 +717,12 @@ class PointerArithmeticGadget : public WarningGadget {
.bind(PointerArithmeticTag));
}

const Stmt *getBaseStmt() const override { return PA; }
void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
bool IsRelatedToDecl,
ASTContext &Ctx) const override {
Handler.handleUnsafeOperation(PA, IsRelatedToDecl, Ctx);
}
SourceLocation getSourceLoc() const override { return PA->getBeginLoc(); }

DeclUseList getClaimedVarUseSites() const override {
if (const auto *DRE = dyn_cast<DeclRefExpr>(Ptr->IgnoreParenImpCasts())) {
Expand Down Expand Up @@ -734,7 +760,12 @@ class SpanTwoParamConstructorGadget : public WarningGadget {
.bind(SpanTwoParamConstructorTag));
}

const Stmt *getBaseStmt() const override { return Ctor; }
void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
bool IsRelatedToDecl,
ASTContext &Ctx) const override {
Handler.handleUnsafeOperationInContainer(Ctor, IsRelatedToDecl, Ctx);
}
SourceLocation getSourceLoc() const override { return Ctor->getBeginLoc(); }

DeclUseList getClaimedVarUseSites() const override {
// If the constructor call is of the form `std::span{var, n}`, `var` is
Expand Down Expand Up @@ -780,11 +811,8 @@ class PointerInitGadget : public FixableGadget {

virtual std::optional<FixItList>
getFixits(const FixitStrategy &S) const override;

virtual const Stmt *getBaseStmt() const override {
// FIXME: This needs to be the entire DeclStmt, assuming that this method
// makes sense at all on a FixableGadget.
return PtrInitRHS;
SourceLocation getSourceLoc() const override {
return PtrInitRHS->getBeginLoc();
}

virtual DeclUseList getClaimedVarUseSites() const override {
Expand Down Expand Up @@ -833,12 +861,7 @@ class PtrToPtrAssignmentGadget : public FixableGadget {

virtual std::optional<FixItList>
getFixits(const FixitStrategy &S) const override;

virtual const Stmt *getBaseStmt() const override {
// FIXME: This should be the binary operator, assuming that this method
// makes sense at all on a FixableGadget.
return PtrLHS;
}
SourceLocation getSourceLoc() const override { return PtrLHS->getBeginLoc(); }

virtual DeclUseList getClaimedVarUseSites() const override {
return DeclUseList{PtrLHS, PtrRHS};
Expand Down Expand Up @@ -888,12 +911,7 @@ class CArrayToPtrAssignmentGadget : public FixableGadget {

virtual std::optional<FixItList>
getFixits(const FixitStrategy &S) const override;

virtual const Stmt *getBaseStmt() const override {
// FIXME: This should be the binary operator, assuming that this method
// makes sense at all on a FixableGadget.
return PtrLHS;
}
SourceLocation getSourceLoc() const override { return PtrLHS->getBeginLoc(); }

virtual DeclUseList getClaimedVarUseSites() const override {
return DeclUseList{PtrLHS, PtrRHS};
Expand Down Expand Up @@ -921,10 +939,53 @@ class UnsafeBufferUsageAttrGadget : public WarningGadget {
}

static Matcher matcher() {
return stmt(callExpr(callee(functionDecl(hasAttr(attr::UnsafeBufferUsage))))
.bind(OpTag));
auto HasUnsafeFnDecl =
callee(functionDecl(hasAttr(attr::UnsafeBufferUsage)));
return stmt(callExpr(HasUnsafeFnDecl).bind(OpTag));
}

void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
bool IsRelatedToDecl,
ASTContext &Ctx) const override {
Handler.handleUnsafeOperation(Op, IsRelatedToDecl, Ctx);
}
const Stmt *getBaseStmt() const override { return Op; }
SourceLocation getSourceLoc() const override { return Op->getBeginLoc(); }

DeclUseList getClaimedVarUseSites() const override { return {}; }
};

/// A call of a constructor that performs unchecked buffer operations
/// over one of its pointer parameters, or constructs a class object that will
/// perform buffer operations that depend on the correctness of the parameters.
class UnsafeBufferUsageCtorAttrGadget : public WarningGadget {
constexpr static const char *const OpTag = "cxx_construct_expr";
const CXXConstructExpr *Op;

public:
UnsafeBufferUsageCtorAttrGadget(const MatchFinder::MatchResult &Result)
: WarningGadget(Kind::UnsafeBufferUsageCtorAttr),
Op(Result.Nodes.getNodeAs<CXXConstructExpr>(OpTag)) {}

static bool classof(const Gadget *G) {
return G->getKind() == Kind::UnsafeBufferUsageCtorAttr;
}

static Matcher matcher() {
auto HasUnsafeCtorDecl =
hasDeclaration(cxxConstructorDecl(hasAttr(attr::UnsafeBufferUsage)));
// std::span(ptr, size) ctor is handled by SpanTwoParamConstructorGadget.
auto HasTwoParamSpanCtorDecl = SpanTwoParamConstructorGadget::matcher();
return stmt(
cxxConstructExpr(HasUnsafeCtorDecl, unless(HasTwoParamSpanCtorDecl))
.bind(OpTag));
}

void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
bool IsRelatedToDecl,
ASTContext &Ctx) const override {
Handler.handleUnsafeOperation(Op, IsRelatedToDecl, Ctx);
}
SourceLocation getSourceLoc() const override { return Op->getBeginLoc(); }

DeclUseList getClaimedVarUseSites() const override { return {}; }
};
Expand Down Expand Up @@ -953,7 +1014,13 @@ class DataInvocationGadget : public WarningGadget {
explicitCastExpr(anyOf(has(callExpr), has(parenExpr(has(callExpr)))))
.bind(OpTag));
}
const Stmt *getBaseStmt() const override { return Op; }

void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
bool IsRelatedToDecl,
ASTContext &Ctx) const override {
Handler.handleUnsafeOperation(Op, IsRelatedToDecl, Ctx);
}
SourceLocation getSourceLoc() const override { return Op->getBeginLoc(); }

DeclUseList getClaimedVarUseSites() const override { return {}; }
};
Expand Down Expand Up @@ -990,8 +1057,7 @@ class ULCArraySubscriptGadget : public FixableGadget {

virtual std::optional<FixItList>
getFixits(const FixitStrategy &S) const override;

virtual const Stmt *getBaseStmt() const override { return Node; }
SourceLocation getSourceLoc() const override { return Node->getBeginLoc(); }

virtual DeclUseList getClaimedVarUseSites() const override {
if (const auto *DRE =
Expand Down Expand Up @@ -1031,8 +1097,7 @@ class UPCStandalonePointerGadget : public FixableGadget {

virtual std::optional<FixItList>
getFixits(const FixitStrategy &S) const override;

virtual const Stmt *getBaseStmt() const override { return Node; }
SourceLocation getSourceLoc() const override { return Node->getBeginLoc(); }

virtual DeclUseList getClaimedVarUseSites() const override { return {Node}; }
};
Expand Down Expand Up @@ -1070,10 +1135,9 @@ class PointerDereferenceGadget : public FixableGadget {
return {BaseDeclRefExpr};
}

virtual const Stmt *getBaseStmt() const final { return Op; }

virtual std::optional<FixItList>
getFixits(const FixitStrategy &S) const override;
SourceLocation getSourceLoc() const override { return Op->getBeginLoc(); }
};

// Represents expressions of the form `&DRE[any]` in the Unspecified Pointer
Expand Down Expand Up @@ -1108,8 +1172,7 @@ class UPCAddressofArraySubscriptGadget : public FixableGadget {

virtual std::optional<FixItList>
getFixits(const FixitStrategy &) const override;

virtual const Stmt *getBaseStmt() const override { return Node; }
SourceLocation getSourceLoc() const override { return Node->getBeginLoc(); }

virtual DeclUseList getClaimedVarUseSites() const override {
const auto *ArraySubst = cast<ArraySubscriptExpr>(Node->getSubExpr());
Expand Down Expand Up @@ -1218,8 +1281,7 @@ class UPCPreIncrementGadget : public FixableGadget {

virtual std::optional<FixItList>
getFixits(const FixitStrategy &S) const override;

virtual const Stmt *getBaseStmt() const override { return Node; }
SourceLocation getSourceLoc() const override { return Node->getBeginLoc(); }

virtual DeclUseList getClaimedVarUseSites() const override {
return {dyn_cast<DeclRefExpr>(Node->getSubExpr())};
Expand Down Expand Up @@ -1264,8 +1326,7 @@ class UUCAddAssignGadget : public FixableGadget {

virtual std::optional<FixItList>
getFixits(const FixitStrategy &S) const override;

virtual const Stmt *getBaseStmt() const override { return Node; }
SourceLocation getSourceLoc() const override { return Node->getBeginLoc(); }

virtual DeclUseList getClaimedVarUseSites() const override {
return {dyn_cast<DeclRefExpr>(Node->getLHS())};
Expand Down Expand Up @@ -1315,9 +1376,9 @@ class DerefSimplePtrArithFixableGadget : public FixableGadget {

virtual std::optional<FixItList>
getFixits(const FixitStrategy &s) const final;

// TODO remove this method from FixableGadget interface
virtual const Stmt *getBaseStmt() const final { return nullptr; }
SourceLocation getSourceLoc() const override {
return DerefOp->getBeginLoc();
}

virtual DeclUseList getClaimedVarUseSites() const final {
return {BaseDeclRefExpr};
Expand Down Expand Up @@ -2070,7 +2131,7 @@ UUCAddAssignGadget::getFixits(const FixitStrategy &S) const {
if (S.lookup(VD) == FixitStrategy::Kind::Span) {
FixItList Fixes;

const Stmt *AddAssignNode = getBaseStmt();
const Stmt *AddAssignNode = Node;
StringRef varName = VD->getName();
const ASTContext &Ctx = VD->getASTContext();

Expand Down Expand Up @@ -2112,20 +2173,19 @@ UPCPreIncrementGadget::getFixits(const FixitStrategy &S) const {
if (S.lookup(VD) == FixitStrategy::Kind::Span) {
FixItList Fixes;
std::stringstream SS;
const Stmt *PreIncNode = getBaseStmt();
StringRef varName = VD->getName();
const ASTContext &Ctx = VD->getASTContext();

// To transform UPC(++p) to UPC((p = p.subspan(1)).data()):
SS << "(" << varName.data() << " = " << varName.data()
<< ".subspan(1)).data()";
std::optional<SourceLocation> PreIncLocation =
getEndCharLoc(PreIncNode, Ctx.getSourceManager(), Ctx.getLangOpts());
getEndCharLoc(Node, Ctx.getSourceManager(), Ctx.getLangOpts());
if (!PreIncLocation)
return std::nullopt;

Fixes.push_back(FixItHint::CreateReplacement(
SourceRange(PreIncNode->getBeginLoc(), *PreIncLocation), SS.str()));
SourceRange(Node->getBeginLoc(), *PreIncLocation), SS.str()));
return Fixes;
}
}
Expand Down Expand Up @@ -2856,7 +2916,7 @@ getFixIts(FixableGadgetSets &FixablesForAllVars, const FixitStrategy &S,
}
#ifndef NDEBUG
Handler.addDebugNoteForVar(
VD, F->getBaseStmt()->getBeginLoc(),
VD, F->getSourceLoc(),
("gadget '" + F->getDebugName() + "' refused to produce a fix")
.str());
#endif
Expand Down Expand Up @@ -3008,8 +3068,8 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
// every problematic operation and consider it done. No need to deal
// with fixable gadgets, no need to group operations by variable.
for (const auto &G : WarningGadgets) {
Handler.handleUnsafeOperation(G->getBaseStmt(), /*IsRelatedToDecl=*/false,
D->getASTContext());
G->handleUnsafeOperation(Handler, /*IsRelatedToDecl=*/false,
D->getASTContext());
}

// This return guarantees that most of the machine doesn't run when
Expand Down Expand Up @@ -3251,8 +3311,8 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
Tracker, Handler, VarGrpMgr);

for (const auto &G : UnsafeOps.noVar) {
Handler.handleUnsafeOperation(G->getBaseStmt(), /*IsRelatedToDecl=*/false,
D->getASTContext());
G->handleUnsafeOperation(Handler, /*IsRelatedToDecl=*/false,
D->getASTContext());
}

for (const auto &[VD, WarningGadgets] : UnsafeOps.byVar) {
Expand All @@ -3263,8 +3323,8 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
: FixItList{},
D, NaiveStrategy);
for (const auto &G : WarningGadgets) {
Handler.handleUnsafeOperation(G->getBaseStmt(), /*IsRelatedToDecl=*/true,
D->getASTContext());
G->handleUnsafeOperation(Handler, /*IsRelatedToDecl=*/true,
D->getASTContext());
}
}
}
10 changes: 10 additions & 0 deletions clang/lib/Basic/TypeTraits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "clang/Basic/TypeTraits.h"
#include "llvm/Support/ErrorHandling.h"
#include <cassert>
#include <cstring>
using namespace clang;

static constexpr const char *TypeTraitNames[] = {
Expand Down Expand Up @@ -81,6 +82,15 @@ const char *clang::getTraitName(UnaryExprOrTypeTrait T) {

const char *clang::getTraitSpelling(TypeTrait T) {
assert(T <= TT_Last && "invalid enum value!");
if (T == BTT_IsDeducible) {
// The __is_deducible is an internal-only type trait. To hide it from
// external users, we define it with an empty spelling name, preventing the
// clang parser from recognizing its token kind.
// However, other components such as the AST dump still require the real
// type trait name. Therefore, we return the real name when needed.
assert(std::strlen(TypeTraitSpellings[T]) == 0);
return "__is_deducible";
}
return TypeTraitSpellings[T];
}

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ enum TypeEvaluationKind {
SANITIZER_CHECK(SubOverflow, sub_overflow, 0) \
SANITIZER_CHECK(TypeMismatch, type_mismatch, 1) \
SANITIZER_CHECK(AlignmentAssumption, alignment_assumption, 0) \
SANITIZER_CHECK(VLABoundNotPositive, vla_bound_not_positive, 0)
SANITIZER_CHECK(VLABoundNotPositive, vla_bound_not_positive, 0) \
SANITIZER_CHECK(BoundsSafety, bounds_safety, 0)

enum SanitizerHandler {
#define SANITIZER_CHECK(Enum, Name, Version) Enum,
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/Driver/ToolChains/MSVC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath));
}

if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L))
for (const auto &LibPath : Args.getAllArgValues(options::OPT_L))
CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath));

if (C.getDriver().IsFlangMode()) {
addFortranRuntimeLibraryPath(TC, Args, CmdArgs);
addFortranRuntimeLibs(TC, Args, CmdArgs);
Expand All @@ -154,10 +158,6 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (TC.getVFS().exists(CRTPath))
CmdArgs.push_back(Args.MakeArgString("-libpath:" + CRTPath));

if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L))
for (const auto &LibPath : Args.getAllArgValues(options::OPT_L))
CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath));

CmdArgs.push_back("-nologo");

if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7))
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1883,6 +1883,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (Tok.is(tok::identifier)) {
Name = Tok.getIdentifierInfo();
NameLoc = ConsumeToken();
DS.SetRangeEnd(NameLoc);

if (Tok.is(tok::less) && getLangOpts().CPlusPlus) {
// The name was supposed to refer to a template, but didn't.
Expand Down
25 changes: 21 additions & 4 deletions clang/lib/Sema/AnalysisBasedWarnings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2256,11 +2256,8 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
Range = UO->getSubExpr()->getSourceRange();
MsgParam = 1;
}
} else if (const auto *CtorExpr = dyn_cast<CXXConstructExpr>(Operation)) {
S.Diag(CtorExpr->getLocation(),
diag::warn_unsafe_buffer_usage_in_container);
} else {
if (isa<CallExpr>(Operation)) {
if (isa<CallExpr>(Operation) || isa<CXXConstructExpr>(Operation)) {
// note_unsafe_buffer_operation doesn't have this mode yet.
assert(!IsRelatedToDecl && "Not implemented yet!");
MsgParam = 3;
Expand Down Expand Up @@ -2295,6 +2292,26 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
}
}

void handleUnsafeOperationInContainer(const Stmt *Operation,
bool IsRelatedToDecl,
ASTContext &Ctx) override {
SourceLocation Loc;
SourceRange Range;
unsigned MsgParam = 0;

// This function only handles SpanTwoParamConstructorGadget so far, which
// always gives a CXXConstructExpr.
const auto *CtorExpr = cast<CXXConstructExpr>(Operation);
Loc = CtorExpr->getLocation();

S.Diag(Loc, diag::warn_unsafe_buffer_usage_in_container);
if (IsRelatedToDecl) {
assert(!SuggestSuggestions &&
"Variables blamed for unsafe buffer usage without suggestions!");
S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range;
}
}

void handleUnsafeVariableGroup(const VarDecl *Variable,
const VariableGroupsManager &VarGrpMgr,
FixItList &&Fixes, const Decl *D,
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Sema/SemaConcept.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1162,6 +1162,13 @@ static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
break;
}
return;
} else if (auto *TTE = dyn_cast<TypeTraitExpr>(SubstExpr);
TTE && TTE->getTrait() == clang::TypeTrait::BTT_IsDeducible) {
assert(TTE->getNumArgs() == 2);
S.Diag(SubstExpr->getSourceRange().getBegin(),
diag::note_is_deducible_constraint_evaluated_to_false)
<< TTE->getArg(0)->getType() << TTE->getArg(1)->getType();
return;
}

S.Diag(SubstExpr->getSourceRange().getBegin(),
Expand Down
39 changes: 12 additions & 27 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5618,9 +5618,10 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
Res = Immediate.TransformInitializer(Param->getInit(),
/*NotCopy=*/false);
});
if (Res.isUsable())
Res = ConvertParamDefaultArgument(Param, Res.get(),
Res.get()->getBeginLoc());
if (Res.isInvalid())
return ExprError();
Res = ConvertParamDefaultArgument(Param, Res.get(),
Res.get()->getBeginLoc());
if (Res.isInvalid())
return ExprError();
Init = Res.get();
Expand Down Expand Up @@ -5656,7 +5657,7 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
Expr *Init = nullptr;

bool NestedDefaultChecking = isCheckingDefaultArgumentOrInitializer();
bool InLifetimeExtendingContext = isInLifetimeExtendingContext();

EnterExpressionEvaluationContext EvalContext(
*this, ExpressionEvaluationContext::PotentiallyEvaluated, Field);

Expand Down Expand Up @@ -5691,35 +5692,19 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
ImmediateCallVisitor V(getASTContext());
if (!NestedDefaultChecking)
V.TraverseDecl(Field);

// CWG1815
// Support lifetime extension of temporary created by aggregate
// initialization using a default member initializer. We should always rebuild
// the initializer if it contains any temporaries (if the initializer
// expression is an ExprWithCleanups). Then make sure the normal lifetime
// extension code recurses into the default initializer and does lifetime
// extension when warranted.
bool ContainsAnyTemporaries =
isa_and_present<ExprWithCleanups>(Field->getInClassInitializer());
if (V.HasImmediateCalls || InLifetimeExtendingContext ||
ContainsAnyTemporaries) {
if (V.HasImmediateCalls) {
ExprEvalContexts.back().DelayedDefaultInitializationContext = {Loc, Field,
CurContext};
ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer =
NestedDefaultChecking;
// Pass down lifetime extending flag, and collect temporaries in
// CreateMaterializeTemporaryExpr when we rewrite the call argument.
keepInLifetimeExtendingContext();

EnsureImmediateInvocationInDefaultArgs Immediate(*this);
ExprResult Res;

// Rebuild CXXDefaultInitExpr might cause diagnostics.
SFINAETrap Trap(*this);
runWithSufficientStackSpace(Loc, [&] {
Res = Immediate.TransformInitializer(Field->getInClassInitializer(),
/*CXXDirectInit=*/false);
});
if (Res.isUsable())
if (!Res.isInvalid())
Res = ConvertMemberDefaultInitExpression(Field, Res.get(), Loc);
if (Res.isInvalid()) {
Field->setInvalidDecl();
Expand Down Expand Up @@ -7133,10 +7118,10 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
//
// But: C99-C23 6.5.2.5 Compound literals constraint 1: The type name
// shall specify an object type or an array of unknown size, but not a
// variable length array type. This seems odd, as it allows int a[size] =
// {}; but forbids int a[size] = (int[size]){}; As this is what the
// standard says, this is what's implemented here for C (except for the
// extension that permits constant foldable size arrays)
// variable length array type. This seems odd, as it allows 'int a[size] =
// {}', but forbids 'int *a = (int[size]){}'. As this is what the standard
// says, this is what's implemented here for C (except for the extension
// that permits constant foldable size arrays)

auto diagID = LangOpts.CPlusPlus
? diag::err_variable_object_no_init
Expand Down
10 changes: 9 additions & 1 deletion clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6143,7 +6143,15 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI

return Self.IsPointerInterconvertibleBaseOf(Lhs, Rhs);
}
default: llvm_unreachable("not a BTT");
case BTT_IsDeducible: {
const auto *TSTToBeDeduced = cast<DeducedTemplateSpecializationType>(LhsT);
sema::TemplateDeductionInfo Info(KeyLoc);
return Self.DeduceTemplateArgumentsFromType(
TSTToBeDeduced->getTemplateName().getAsTemplateDecl(), RhsT,
Info) == TemplateDeductionResult::Success;
}
default:
llvm_unreachable("not a BTT");
}
llvm_unreachable("Unknown type trait or not implemented");
}
Expand Down
19 changes: 18 additions & 1 deletion clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8066,6 +8066,11 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
enum PathLifetimeKind {
/// Lifetime-extend along this path.
Extend,
/// We should lifetime-extend, but we don't because (due to technical
/// limitations) we can't. This happens for default member initializers,
/// which we don't clone for every use, so we don't have a unique
/// MaterializeTemporaryExpr to update.
ShouldExtend,
/// Do not lifetime extend along this path.
NoExtend
};
Expand All @@ -8077,7 +8082,7 @@ shouldLifetimeExtendThroughPath(const IndirectLocalPath &Path) {
PathLifetimeKind Kind = PathLifetimeKind::Extend;
for (auto Elem : Path) {
if (Elem.Kind == IndirectLocalPathEntry::DefaultInit)
Kind = PathLifetimeKind::Extend;
Kind = PathLifetimeKind::ShouldExtend;
else if (Elem.Kind != IndirectLocalPathEntry::LambdaCaptureInit)
return PathLifetimeKind::NoExtend;
}
Expand Down Expand Up @@ -8197,6 +8202,18 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
ExtendingEntity->allocateManglingNumber());
// Also visit the temporaries lifetime-extended by this initializer.
return true;

case PathLifetimeKind::ShouldExtend:
// We're supposed to lifetime-extend the temporary along this path (per
// the resolution of DR1815), but we don't support that yet.
//
// FIXME: Properly handle this situation. Perhaps the easiest approach
// would be to clone the initializer expression on each use that would
// lifetime extend its temporaries.
Diag(DiagLoc, diag::warn_unsupported_lifetime_extension)
<< RK << DiagRange;
break;

case PathLifetimeKind::NoExtend:
// If the path goes through the initialization of a variable or field,
// it can't possibly reach a temporary created in this full-expression.
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3757,7 +3757,8 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
void VisitDeclRefExpr(DeclRefExpr *E) {
if (TryCaptureCXXThisMembers || E->isTypeDependent() ||
E->isValueDependent() || E->containsUnexpandedParameterPack() ||
E->isInstantiationDependent())
E->isInstantiationDependent() ||
E->isNonOdrUse() == clang::NOUR_Unevaluated)
return;
if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) {
// Check the datasharing rules for the expressions in the clauses.
Expand Down
98 changes: 85 additions & 13 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2782,17 +2782,24 @@ NamedDecl *transformTemplateParameter(Sema &SemaRef, DeclContext *DC,
llvm_unreachable("Unhandled template parameter types");
}

// Transform the require-clause of F if any.
// Build the associated constraints for the alias deduction guides.
// C++ [over.match.class.deduct]p3.3:
// The associated constraints ([temp.constr.decl]) are the conjunction of the
// associated constraints of g and a constraint that is satisfied if and only
// if the arguments of A are deducible (see below) from the return type.
//
// The return result is expected to be the require-clause for the synthesized
// alias deduction guide.
Expr *transformRequireClause(Sema &SemaRef, FunctionTemplateDecl *F,
TypeAliasTemplateDecl *AliasTemplate,
ArrayRef<DeducedTemplateArgument> DeduceResults) {
Expr *
buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
TypeAliasTemplateDecl *AliasTemplate,
ArrayRef<DeducedTemplateArgument> DeduceResults,
Expr *IsDeducible) {
Expr *RC = F->getTemplateParameters()->getRequiresClause();
if (!RC)
return nullptr;
return IsDeducible;

auto &Context = SemaRef.Context;
ASTContext &Context = SemaRef.Context;
LocalInstantiationScope Scope(SemaRef);

// In the clang AST, constraint nodes are deliberately not instantiated unless
Expand Down Expand Up @@ -2903,7 +2910,68 @@ Expr *transformRequireClause(Sema &SemaRef, FunctionTemplateDecl *F,
ExprResult E = SemaRef.SubstExpr(RC, ArgsForBuildingRC);
if (E.isInvalid())
return nullptr;
return E.getAs<Expr>();

auto Conjunction =
SemaRef.BuildBinOp(SemaRef.getCurScope(), SourceLocation{},
BinaryOperatorKind::BO_LAnd, E.get(), IsDeducible);
if (Conjunction.isInvalid())
return nullptr;
return Conjunction.getAs<Expr>();
}
// Build the is_deducible constraint for the alias deduction guides.
// [over.match.class.deduct]p3.3:
// ... and a constraint that is satisfied if and only if the arguments
// of A are deducible (see below) from the return type.
Expr *buildIsDeducibleConstraint(Sema &SemaRef,
TypeAliasTemplateDecl *AliasTemplate,
QualType ReturnType,
SmallVector<NamedDecl *> TemplateParams) {
ASTContext &Context = SemaRef.Context;
// Constraint AST nodes must use uninstantiated depth.
if (auto *PrimaryTemplate =
AliasTemplate->getInstantiatedFromMemberTemplate()) {
LocalInstantiationScope Scope(SemaRef);

// Adjust the depth for TemplateParams.
unsigned AdjustDepth = PrimaryTemplate->getTemplateDepth();
SmallVector<TemplateArgument> TransformedTemplateArgs;
for (auto *TP : TemplateParams) {
// Rebuild any internal references to earlier parameters and reindex
// as we go.
MultiLevelTemplateArgumentList Args;
Args.setKind(TemplateSubstitutionKind::Rewrite);
Args.addOuterTemplateArguments(TransformedTemplateArgs);
NamedDecl *NewParam = transformTemplateParameter(
SemaRef, AliasTemplate->getDeclContext(), TP, Args,
/*NewIndex=*/TransformedTemplateArgs.size(),
getTemplateParameterDepth(TP) + AdjustDepth);

auto NewTemplateArgument = Context.getCanonicalTemplateArgument(
Context.getInjectedTemplateArg(NewParam));
TransformedTemplateArgs.push_back(NewTemplateArgument);
}
// Transformed the ReturnType to restore the uninstantiated depth.
MultiLevelTemplateArgumentList Args;
Args.setKind(TemplateSubstitutionKind::Rewrite);
Args.addOuterTemplateArguments(TransformedTemplateArgs);
ReturnType = SemaRef.SubstType(
ReturnType, Args, AliasTemplate->getLocation(),
Context.DeclarationNames.getCXXDeductionGuideName(AliasTemplate));
};

SmallVector<TypeSourceInfo *> IsDeducibleTypeTraitArgs = {
Context.getTrivialTypeSourceInfo(
Context.getDeducedTemplateSpecializationType(
TemplateName(AliasTemplate), /*DeducedType=*/QualType(),
/*IsDependent=*/true)), // template specialization type whose
// arguments will be deduced.
Context.getTrivialTypeSourceInfo(
ReturnType), // type from which template arguments are deduced.
};
return TypeTraitExpr::Create(
Context, Context.getLogicalOperationType(), AliasTemplate->getLocation(),
TypeTrait::BTT_IsDeducible, IsDeducibleTypeTraitArgs,
AliasTemplate->getLocation(), /*Value*/ false);
}

std::pair<TemplateDecl *, llvm::ArrayRef<TemplateArgument>>
Expand Down Expand Up @@ -3112,8 +3180,10 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
Sema::CodeSynthesisContext::BuildingDeductionGuides)) {
auto *GG = cast<CXXDeductionGuideDecl>(FPrime);

Expr *RequiresClause =
transformRequireClause(SemaRef, F, AliasTemplate, DeduceResults);
Expr *IsDeducible = buildIsDeducibleConstraint(
SemaRef, AliasTemplate, FPrime->getReturnType(), FPrimeTemplateParams);
Expr *RequiresClause = buildAssociatedConstraints(
SemaRef, F, AliasTemplate, DeduceResults, IsDeducible);

// FIXME: implement the is_deducible constraint per C++
// [over.match.class.deduct]p3.3:
Expand Down Expand Up @@ -6484,7 +6554,8 @@ bool Sema::CheckTemplateArgument(

case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
if (CheckTemplateTemplateArgument(TempParm, Params, Arg))
if (CheckTemplateTemplateArgument(TempParm, Params, Arg,
/*IsDeduced=*/CTAK != CTAK_Specified))
return true;

SugaredConverted.push_back(Arg.getArgument());
Expand Down Expand Up @@ -8402,7 +8473,8 @@ static void DiagnoseTemplateParameterListArityMismatch(
/// It returns true if an error occurred, and false otherwise.
bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
TemplateParameterList *Params,
TemplateArgumentLoc &Arg) {
TemplateArgumentLoc &Arg,
bool IsDeduced) {
TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern();
TemplateDecl *Template = Name.getAsTemplateDecl();
if (!Template) {
Expand Down Expand Up @@ -8454,8 +8526,8 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
!Template->hasAssociatedConstraints())
return false;

if (isTemplateTemplateParameterAtLeastAsSpecializedAs(Params, Template,
Arg.getLocation())) {
if (isTemplateTemplateParameterAtLeastAsSpecializedAs(
Params, Template, Arg.getLocation(), IsDeduced)) {
// P2113
// C++20[temp.func.order]p2
// [...] If both deductions succeed, the partial ordering selects the
Expand Down
153 changes: 139 additions & 14 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,15 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF,
bool PartialOrdering = false, bool DeducedFromArrayBound = false);

enum class PackFold { ParameterToArgument, ArgumentToParameter };
static TemplateDeductionResult
DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
ArrayRef<TemplateArgument> Ps,
ArrayRef<TemplateArgument> As,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool NumberOfArgumentsMustMatch);
bool NumberOfArgumentsMustMatch,
PackFold PackFold = PackFold::ParameterToArgument);

static void MarkUsedTemplateParameters(ASTContext &Ctx,
const TemplateArgument &TemplateArg,
Expand Down Expand Up @@ -2550,7 +2552,9 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
ArrayRef<TemplateArgument> As,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool NumberOfArgumentsMustMatch) {
bool NumberOfArgumentsMustMatch, PackFold PackFold) {
if (PackFold == PackFold::ArgumentToParameter)
std::swap(Ps, As);
// C++0x [temp.deduct.type]p9:
// If the template argument list of P contains a pack expansion that is not
// the last template argument, the entire template argument list is a
Expand Down Expand Up @@ -2581,8 +2585,11 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
return TemplateDeductionResult::MiscellaneousDeductionFailure;

// Perform deduction for this Pi/Ai pair.
if (auto Result = DeduceTemplateArguments(S, TemplateParams, P,
As[ArgIdx], Info, Deduced);
TemplateArgument Pi = P, Ai = As[ArgIdx];
if (PackFold == PackFold::ArgumentToParameter)
std::swap(Pi, Ai);
if (auto Result =
DeduceTemplateArguments(S, TemplateParams, Pi, Ai, Info, Deduced);
Result != TemplateDeductionResult::Success)
return Result;

Expand All @@ -2609,9 +2616,12 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
for (; hasTemplateArgumentForDeduction(As, ArgIdx) &&
PackScope.hasNextElement();
++ArgIdx) {
TemplateArgument Pi = Pattern, Ai = As[ArgIdx];
if (PackFold == PackFold::ArgumentToParameter)
std::swap(Pi, Ai);
// Deduce template arguments from the pattern.
if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pattern,
As[ArgIdx], Info, Deduced);
if (auto Result =
DeduceTemplateArguments(S, TemplateParams, Pi, Ai, Info, Deduced);
Result != TemplateDeductionResult::Success)
return Result;

Expand Down Expand Up @@ -3237,6 +3247,40 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction(

return TemplateDeductionResult::Success;
}
/// Complete template argument deduction for DeduceTemplateArgumentsFromType.
/// FIXME: this is mostly duplicated with the above two versions. Deduplicate
/// the three implementations.
static TemplateDeductionResult FinishTemplateArgumentDeduction(
Sema &S, TemplateDecl *TD,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
TemplateDeductionInfo &Info) {
// Unevaluated SFINAE context.
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::Unevaluated);
Sema::SFINAETrap Trap(S);

Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(TD));

// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
if (auto Result = ConvertDeducedTemplateArguments(
S, TD, /*IsPartialOrdering=*/false, Deduced, Info, SugaredBuilder,
CanonicalBuilder);
Result != TemplateDeductionResult::Success)
return Result;

if (Trap.hasErrorOccurred())
return TemplateDeductionResult::SubstitutionFailure;

if (auto Result = CheckDeducedArgumentConstraints(S, TD, SugaredBuilder,
CanonicalBuilder, Info);
Result != TemplateDeductionResult::Success)
return Result;

return TemplateDeductionResult::Success;
}

/// Perform template argument deduction to determine whether the given template
/// arguments match the given class or variable template partial specialization
Expand Down Expand Up @@ -3305,6 +3349,58 @@ Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial,
return ::DeduceTemplateArguments(*this, Partial, TemplateArgs, Info);
}

TemplateDeductionResult
Sema::DeduceTemplateArgumentsFromType(TemplateDecl *TD, QualType FromType,
sema::TemplateDeductionInfo &Info) {
if (TD->isInvalidDecl())
return TemplateDeductionResult::Invalid;

QualType PType;
if (const auto *CTD = dyn_cast<ClassTemplateDecl>(TD)) {
// Use the InjectedClassNameType.
PType = Context.getTypeDeclType(CTD->getTemplatedDecl());
} else if (const auto *AliasTemplate = dyn_cast<TypeAliasTemplateDecl>(TD)) {
PType = AliasTemplate->getTemplatedDecl()
->getUnderlyingType()
.getCanonicalType();
} else {
assert(false && "Expected a class or alias template");
}

// Unevaluated SFINAE context.
EnterExpressionEvaluationContext Unevaluated(
*this, Sema::ExpressionEvaluationContext::Unevaluated);
SFINAETrap Trap(*this);

// This deduction has no relation to any outer instantiation we might be
// performing.
LocalInstantiationScope InstantiationScope(*this);

SmallVector<DeducedTemplateArgument> Deduced(
TD->getTemplateParameters()->size());
SmallVector<TemplateArgument> PArgs = {TemplateArgument(PType)};
SmallVector<TemplateArgument> AArgs = {TemplateArgument(FromType)};
if (auto DeducedResult = DeduceTemplateArguments(
TD->getTemplateParameters(), PArgs, AArgs, Info, Deduced, false);
DeducedResult != TemplateDeductionResult::Success) {
return DeducedResult;
}

SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
InstantiatingTemplate Inst(*this, Info.getLocation(), TD, DeducedArgs, Info);
if (Inst.isInvalid())
return TemplateDeductionResult::InstantiationDepth;

if (Trap.hasErrorOccurred())
return TemplateDeductionResult::SubstitutionFailure;

TemplateDeductionResult Result;
runWithSufficientStackSpace(Info.getLocation(), [&] {
Result = ::FinishTemplateArgumentDeduction(*this, TD, Deduced, Info);
});
return Result;
}

/// Determine whether the given type T is a simple-template-id type.
static bool isSimpleTemplateIdType(QualType T) {
if (const TemplateSpecializationType *Spec
Expand Down Expand Up @@ -6213,7 +6309,8 @@ bool Sema::isMoreSpecializedThanPrimary(
}

bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
TemplateParameterList *P, TemplateDecl *AArg, SourceLocation Loc) {
TemplateParameterList *P, TemplateDecl *AArg, SourceLocation Loc,
bool IsDeduced) {
// C++1z [temp.arg.template]p4: (DR 150)
// A template template-parameter P is at least as specialized as a
// template template-argument A if, given the following rewrite to two
Expand All @@ -6223,11 +6320,10 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
// equivalent partial ordering by performing deduction directly on
// the template parameter lists of the template template parameters.
//
// Given an invented class template X with the template parameter list of
// A (including default arguments):
TemplateName X = Context.getCanonicalTemplateName(TemplateName(AArg));
TemplateParameterList *A = AArg->getTemplateParameters();

// Given an invented class template X with the template parameter list of
// A (including default arguments):
// - Each function template has a single function parameter whose type is
// a specialization of X with template arguments corresponding to the
// template parameters from the respective function template
Expand Down Expand Up @@ -6270,14 +6366,43 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
return false;
}

QualType AType = Context.getCanonicalTemplateSpecializationType(X, AArgs);
QualType PType = Context.getCanonicalTemplateSpecializationType(X, PArgs);
// Determine whether P1 is at least as specialized as P2.
TemplateDeductionInfo Info(Loc, A->getDepth());
SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(A->size());

// ... the function template corresponding to P is at least as specialized
// as the function template corresponding to A according to the partial
// ordering rules for function templates.
TemplateDeductionInfo Info(Loc, A->getDepth());
return isAtLeastAsSpecializedAs(*this, PType, AType, AArg, Info);

// Provisional resolution for CWG2398: Regarding temp.arg.template]p4, when
// applying the partial ordering rules for function templates on
// the rewritten template template parameters:
// - In a deduced context, the matching of packs versus fixed-size needs to
// be inverted between Ps and As. On non-deduced context, matching needs to
// happen both ways, according to [temp.arg.template]p3, but this is
// currently implemented as a special case elsewhere.
if (::DeduceTemplateArguments(*this, A, AArgs, PArgs, Info, Deduced,
/*NumberOfArgumentsMustMatch=*/false,
IsDeduced ? PackFold::ArgumentToParameter
: PackFold::ParameterToArgument) !=
TemplateDeductionResult::Success)
return false;

SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
Sema::InstantiatingTemplate Inst(*this, Info.getLocation(), AArg, DeducedArgs,
Info);
if (Inst.isInvalid())
return false;

bool AtLeastAsSpecialized;
runWithSufficientStackSpace(Info.getLocation(), [&] {
AtLeastAsSpecialized =
::FinishTemplateArgumentDeduction(
*this, AArg, /*IsPartialOrdering=*/true, PArgs, Deduced, Info) ==
TemplateDeductionResult::Success;
});
return AtLeastAsSpecialized;
}

namespace {
Expand Down
10 changes: 7 additions & 3 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3257,9 +3257,13 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
Info = &SemaRef.InventedParameterInfos.back();
} else {
// In C++14, generic lambdas allow 'auto' in their parameters.
if (!SemaRef.getLangOpts().CPlusPlus14 || !Auto ||
Auto->getKeyword() != AutoTypeKeyword::Auto) {
Error = 16;
if (!SemaRef.getLangOpts().CPlusPlus14 && Auto &&
Auto->getKeyword() == AutoTypeKeyword::Auto) {
Error = 25; // auto not allowed in lambda parameter (before C++14)
break;
} else if (!Auto || Auto->getKeyword() != AutoTypeKeyword::Auto) {
Error = 16; // __auto_type or decltype(auto) not allowed in lambda
// parameter
break;
}
Info = SemaRef.getCurLambda();
Expand Down
370 changes: 204 additions & 166 deletions clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp

Large diffs are not rendered by default.

20 changes: 15 additions & 5 deletions clang/test/AST/ast-dump-ctad-alias.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,24 @@ Out2<double>::AInner t(1.0);
// Verify that the require-clause of alias deduction guide is transformed correctly:
// - Occurrence T should be replaced with `int`;
// - Occurrence V should be replaced with the Y with depth 1
// - Depth of occurrence Y in the __is_deducible constraint should be 1
//
// CHECK: | `-FunctionTemplateDecl {{.*}} <deduction guide for AInner>
// CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} typename depth 0 index 0 Y
// CHECK-NEXT: | |-UnresolvedLookupExpr {{.*}} '<dependent type>' lvalue (no ADL) = 'Concept'
// CHECK-NEXT: | | |-TemplateArgument type 'int'
// CHECK-NEXT: | | | `-BuiltinType {{.*}} 'int'
// CHECK-NEXT: | | `-TemplateArgument type 'type-parameter-1-0'
// CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent depth 1 index 0
// CHECK-NEXT: | |-BinaryOperator {{.*}} '<dependent type>' '&&'
// CHECK-NEXT: | | |-UnresolvedLookupExpr {{.*}} '<dependent type>' lvalue (no ADL) = 'Concept'
// CHECK-NEXT: | | | |-TemplateArgument type 'int'
// CHECK-NEXT: | | | | `-BuiltinType {{.*}} 'int'
// CHECK-NEXT: | | | `-TemplateArgument type 'type-parameter-1-0'
// CHECK-NEXT: | | | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent depth 1 index 0
// CHECK-NEXT: | | `-TypeTraitExpr {{.*}} 'bool' __is_deducible
// CHECK-NEXT: | | |-DeducedTemplateSpecializationType {{.*}} 'AInner' dependent
// CHECK-NEXT: | | `-ElaboratedType {{.*}} 'Inner<type-parameter-1-0>' sugar dependent
// CHECK-NEXT: | | `-TemplateSpecializationType {{.*}} 'Inner<type-parameter-1-0>' dependent Inner
// CHECK-NEXT: | | `-TemplateArgument type 'type-parameter-1-0'
// CHECK-NEXT: | | `-SubstTemplateTypeParmType {{.*}} 'type-parameter-1-0'
// CHECK-NEXT: | | |-FunctionTemplate {{.*}} '<deduction guide for Inner>'
// CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent depth 1 index 0
// CHECK-NEXT: | |-CXXDeductionGuideDecl {{.*}} <deduction guide for AInner> 'auto (type-parameter-0-0) -> Inner<type-parameter-0-0>'
// CHECK-NEXT: | | `-ParmVarDecl {{.*}} 'type-parameter-0-0'
// CHECK-NEXT: | `-CXXDeductionGuideDecl {{.*}} used <deduction guide for AInner> 'auto (double) -> Inner<double>' implicit_instantiation
Expand Down
6 changes: 3 additions & 3 deletions clang/test/AST/ast-dump-default-init-json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -789,10 +789,10 @@ void test() {
// CHECK-NEXT: "valueCategory": "lvalue",
// CHECK-NEXT: "extendingDecl": {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "VarDecl",
// CHECK-NEXT: "name": "b",
// CHECK-NEXT: "kind": "FieldDecl",
// CHECK-NEXT: "name": "a",
// CHECK-NEXT: "type": {
// CHECK-NEXT: "qualType": "B"
// CHECK-NEXT: "qualType": "const A &"
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "storageDuration": "automatic",
Expand Down
2 changes: 1 addition & 1 deletion clang/test/AST/ast-dump-default-init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ void test() {
}
// CHECK: -CXXDefaultInitExpr 0x{{[^ ]*}} <{{.*}}> 'const A' lvalue has rewritten init
// CHECK-NEXT: `-ExprWithCleanups 0x{{[^ ]*}} <{{.*}}> 'const A' lvalue
// CHECK-NEXT: `-MaterializeTemporaryExpr 0x{{[^ ]*}} <{{.*}}> 'const A' lvalue extended by Var 0x{{[^ ]*}} 'b' 'B'
// CHECK-NEXT: `-MaterializeTemporaryExpr 0x{{[^ ]*}} <{{.*}}> 'const A' lvalue extended by Field 0x{{[^ ]*}} 'a' 'const A &'
// CHECK-NEXT: `-ImplicitCastExpr 0x{{[^ ]*}} <{{.*}}> 'const A' <NoOp>
// CHECK-NEXT: `-CXXFunctionalCastExpr 0x{{[^ ]*}} <{{.*}}> 'A' functional cast to A <NoOp>
// CHECK-NEXT: `-InitListExpr 0x{{[^ ]*}} <{{.*}}> 'A'
Expand Down
7 changes: 7 additions & 0 deletions clang/test/AST/ast-dump-expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -583,3 +583,10 @@ void NonADLCall3() {
f(x);
}
} // namespace test_adl_call_three

namespace GH35300 {
struct Sock {};
void leakNewFn() { new struct Sock; }
// CHECK: CXXNewExpr {{.*}} <col:20, col:31> 'struct Sock *'
}

9 changes: 4 additions & 5 deletions clang/test/Analysis/lifetime-extended-regions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,10 @@ void aggregateWithReferences() {
clang_analyzer_dump(viaReference); // expected-warning-re {{&lifetime_extended_object{RefAggregate, viaReference, S{{[0-9]+}}} }}
clang_analyzer_dump(viaReference.rx); // expected-warning-re {{&lifetime_extended_object{int, viaReference, S{{[0-9]+}}} }}
clang_analyzer_dump(viaReference.ry); // expected-warning-re {{&lifetime_extended_object{Composite, viaReference, S{{[0-9]+}}} }}

// FIXME: clang currently support extending lifetime of object bound to reference members of aggregates,
// that are created from default member initializer. But CFG and ExprEngine need to be updated to address this change.
// The following expect warning: {{&lifetime_extended_object{Composite, defaultInitExtended, S{{[0-9]+}}} }}
RefAggregate defaultInitExtended{i};

// clang does not currently implement extending lifetime of object bound to reference members of aggregates,
// that are created from default member initializer (see `warn_unsupported_lifetime_extension` from `-Wdangling`)
RefAggregate defaultInitExtended{i}; // clang-bug does not extend `Composite`
clang_analyzer_dump(defaultInitExtended.ry); // expected-warning {{Unknown }}
}

Expand Down
2 changes: 2 additions & 0 deletions clang/test/CXX/drs/cwg16xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,8 @@ namespace cwg1696 { // cwg1696: 7
const A &a = A(); // #cwg1696-D1-a
};
D1 d1 = {}; // #cwg1696-d1
// since-cxx14-warning@-1 {{lifetime extension of temporary created by aggregate initialization using a default member initializer is not yet supported; lifetime of temporary will end at the end of the full-expression}}
// since-cxx14-note@#cwg1696-D1-a {{initializing field 'a' with default member initializer}}

struct D2 {
const A &a = A(); // #cwg1696-D2-a
Expand Down
25 changes: 8 additions & 17 deletions clang/test/CXX/drs/cwg18xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ namespace cwg1804 { // cwg1804: 2.7
template <typename, typename>
struct A {
void f1();

template <typename V>
void f2(V);

Expand All @@ -73,7 +73,7 @@ struct A {
template <typename U>
struct A<int, U> {
void f1();

template <typename V>
void f2(V);

Expand All @@ -97,7 +97,7 @@ class D {
template <typename U>
struct A<double, U> {
void f1();

template <typename V>
void f2(V);

Expand Down Expand Up @@ -206,28 +206,19 @@ namespace cwg1814 { // cwg1814: yes
#endif
}

namespace cwg1815 { // cwg1815: 19
namespace cwg1815 { // cwg1815: no
#if __cplusplus >= 201402L
struct A { int &&r = 0; };
// FIXME: needs codegen test
struct A { int &&r = 0; }; // #cwg1815-A
A a = {};
// since-cxx14-warning@-1 {{lifetime extension of temporary created by aggregate initialization using a default member initializer is not yet supported; lifetime of temporary will end at the end of the full-expression}} FIXME
// since-cxx14-note@#cwg1815-A {{initializing field 'r' with default member initializer}}

struct B { int &&r = 0; }; // #cwg1815-B
// since-cxx14-error@-1 {{reference member 'r' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
// since-cxx14-note@#cwg1815-B {{initializing field 'r' with default member initializer}}
// since-cxx14-note@#cwg1815-b {{in implicit default constructor for 'cwg1815::B' first required here}}
B b; // #cwg1815-b

#if __cplusplus >= 201703L
struct C { const int &r = 0; };
constexpr C c = {}; // OK, since cwg1815
static_assert(c.r == 0);

constexpr int f() {
A a = {}; // OK, since cwg1815
return a.r;
}
static_assert(f() == 0);
#endif
#endif
}

Expand Down
34 changes: 0 additions & 34 deletions clang/test/CXX/special/class.temporary/p6.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,40 +269,6 @@ void init_capture_init_list() {
// CHECK: }
}

void check_dr1815() { // dr1815: yes
#if __cplusplus >= 201402L

struct A {
int &&r = 0;
~A() {}
};

struct B {
A &&a = A{};
~B() {}
};
B a = {};

// CHECK: call {{.*}}block_scope_begin_function
extern void block_scope_begin_function();
extern void block_scope_end_function();
block_scope_begin_function();
{
// CHECK: call void @_ZZ12check_dr1815vEN1BD1Ev
// CHECK: call void @_ZZ12check_dr1815vEN1AD1Ev
B b = {};
}
// CHECK: call {{.*}}block_scope_end_function
block_scope_end_function();

// CHECK: call {{.*}}some_other_function
extern void some_other_function();
some_other_function();
// CHECK: call void @_ZZ12check_dr1815vEN1BD1Ev
// CHECK: call void @_ZZ12check_dr1815vEN1AD1Ev
#endif
}

namespace P2718R0 {
namespace basic {
template <typename E> using T2 = std::list<E>;
Expand Down
13 changes: 13 additions & 0 deletions clang/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
// expected-no-diagnostics

namespace GH77377 {
template<typename T>
concept C = sizeof(T) == sizeof(int);

template<auto N>
struct A;

template<C auto N>
struct A<N>;
}
150 changes: 145 additions & 5 deletions clang/test/CodeGen/aarch64-sme2-intrinsics/acle_sme2_max.c

Large diffs are not rendered by default.

150 changes: 145 additions & 5 deletions clang/test/CodeGen/aarch64-sme2-intrinsics/acle_sme2_maxnm.c

Large diffs are not rendered by default.

150 changes: 145 additions & 5 deletions clang/test/CodeGen/aarch64-sme2-intrinsics/acle_sme2_min.c

Large diffs are not rendered by default.

150 changes: 145 additions & 5 deletions clang/test/CodeGen/aarch64-sme2-intrinsics/acle_sme2_minnm.c

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions clang/test/Driver/flang/msvc-link.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
! RUN: %clang --driver-mode=flang -target x86_64-pc-windows-msvc -### %s -Ltest 2>&1 | FileCheck %s
!
! Test that user provided paths come before the Flang runtimes
! CHECK: "-libpath:test"
! CHECK: "-libpath:{{.*(\\|/)}}lib"
41 changes: 41 additions & 0 deletions clang/test/OpenMP/task_ast_print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// RUN: %clang_cc1 -verify -Wno-vla -fopenmp-simd -ast-print %s | FileCheck %s
// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp-simd -std=c++11 -include-pch %t -verify -Wno-vla %s -ast-print | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -ast-dump %s | FileCheck %s --check-prefix=DUMP
// expected-no-diagnostics

#ifndef HEADER
Expand Down Expand Up @@ -208,4 +209,44 @@ int main(int argc, char **argv) {
extern template int S<int>::TS;
extern template long S<long>::TS;

// DUMP-LABEL: FunctionDecl {{.*}} implicit_firstprivate
void
implicit_firstprivate() {

#pragma omp parallel num_threads(1)
{
int i = 0;
// DUMP: OMPTaskDirective
// DUMP-NEXT: OMPFirstprivateClause
// DUMP-NOT: DeclRefExpr {{.+}} 'i' {{.+}} non_odr_use_unevaluated
// DUMP: DeclRefExpr {{.+}} 'i' 'int' refers_to_enclosing_variable_or_capture
// DUMP: CapturedStmt
// DUMP: BinaryOperator {{.+}} 'int' lvalue '='
// DUMP-NEXT: DeclRefExpr {{.+}} 'j' 'int'
// DUMP: DeclRefExpr {{.+}} 'i' {{.+}} non_odr_use_unevaluated
#pragma omp task
{
int j = sizeof(i);
j = i;
}
}
}

// DUMP-LABEL: FunctionDecl {{.*}} no_implicit_firstprivate
void
no_implicit_firstprivate() {

#pragma omp parallel num_threads(1)
{
int i = 0;
// DUMP: OMPTaskDirective
// DUMP-NEXT: CapturedStmt
// DUMP: DeclRefExpr {{.+}} 'i' {{.+}} non_odr_use_unevaluated refers_to_enclosing_variable_or_capture
#pragma omp task
{
int j = sizeof(i);
}
}
}

#endif
4 changes: 2 additions & 2 deletions clang/test/SemaCXX/auto-cxx0x.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ thread_local auto x; // expected-error {{requires an initializer}}
void g() {
[](auto){}(0);
#if __cplusplus == 201103L
// expected-error@-2 {{'auto' not allowed in lambda parameter}}
// expected-error@-2 {{'auto' not allowed in lambda parameter before C++14}}
#endif
}

void rdar47689465() {
int x = 0;
[](auto __attribute__((noderef)) *){}(&x);
#if __cplusplus == 201103L
// expected-error@-2 {{'auto' not allowed in lambda parameter}}
// expected-error@-2 {{'auto' not allowed in lambda parameter before C++14}}
#endif
}
4 changes: 2 additions & 2 deletions clang/test/SemaCXX/constexpr-default-arg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ void test_default_arg2() {
}

// Check that multiple CXXDefaultInitExprs don't cause an assertion failure.
struct A { int &&r = 0; };
struct A { int &&r = 0; }; // expected-note 2{{default member initializer}}
struct B { A x, y; };
B b = {}; // expected-no-diagnostics
B b = {}; // expected-warning 2{{lifetime extension of temporary created by aggregate initialization using a default member initializer is not yet supported}}

}
36 changes: 22 additions & 14 deletions clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -Wno-c++11-narrowing -Wno-literal-conversion -std=c++20 -verify %s
// RUN: %clang_cc1 -fsyntax-only -triple x86_64-unknown-linux -Wno-c++11-narrowing -Wno-literal-conversion -std=c++20 -verify %s

namespace test1 {
template <typename T>
Expand Down Expand Up @@ -74,7 +74,7 @@ struct Foo {
template <typename T>
using AF = Foo<T, 1>;

AF b{0};
AF b{0};
} // namespace test6

namespace test7 {
Expand All @@ -86,8 +86,8 @@ struct Foo {
template <typename U>
using AF1 = Foo<U>;
template <typename K>
using AF2 = AF1<K>;
AF2 b = 1;
using AF2 = AF1<K>;
AF2 b = 1;
} // namespace test7

namespace test8 {
Expand All @@ -109,10 +109,12 @@ struct Foo {
};

template <typename X, int Y>
using Bar = Foo<X, sizeof(X)>;
using Bar = Foo<X, sizeof(X)>; // expected-note {{candidate template ignored: couldn't infer template argument 'X'}} \
// expected-note {{candidate template ignored: constraints not satisfied [with X = int]}} \
// expected-note {{cannot deduce template arguments for 'Bar' from 'Foo<int, 4UL>'}}

// FIXME: we should reject this case? GCC rejects it, MSVC accepts it.
Bar s = {{1}};

Bar s = {{1}}; // expected-error {{no viable constructor or deduction guide }}
} // namespace test9

namespace test10 {
Expand All @@ -133,17 +135,21 @@ A a(2); // Foo<int*>
namespace test11 {
struct A {};
template<class T> struct Foo { T c; };
template<class X, class Y=A> using AFoo = Foo<Y>;
template<class X, class Y=A>
using AFoo = Foo<Y>; // expected-note {{candidate template ignored: could not match 'Foo<type-parameter-0-0>' against 'int'}} \
// expected-note {{candidate template ignored: constraints not satisfied [with Y = int]}} \
// expected-note {{cannot deduce template arguments for 'AFoo' from 'Foo<int>'}} \
// expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}}

AFoo s = {1};
AFoo s = {1}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'AFoo'}}
} // namespace test11

namespace test12 {
// no crash on null access attribute
template<typename X>
struct Foo {
template<typename K>
struct Bar {
struct Bar {
Bar(K);
};

Expand Down Expand Up @@ -190,13 +196,15 @@ template <class T> struct Foo { Foo(T); };

template<class V> using AFoo = Foo<V *>;
template<typename> concept False = false;
template<False W> using BFoo = AFoo<W>;
template<False W>
using BFoo = AFoo<W>; // expected-note {{candidate template ignored: constraints not satisfied [with V = int]}} \
// expected-note {{cannot deduce template arguments for 'BFoo' from 'Foo<int *>'}} \
// expected-note {{candidate template ignored: could not match 'Foo<type-parameter-0-0 *>' against 'int *'}}
int i = 0;
AFoo a1(&i); // OK, deduce Foo<int *>

// FIXME: we should reject this case as the W is not deduced from the deduced
// type Foo<int *>.
BFoo b2(&i);
// the W is not deduced from the deduced type Foo<int *>.
BFoo b2(&i); // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'BFoo'}}
} // namespace test15

namespace test16 {
Expand Down
6 changes: 4 additions & 2 deletions clang/test/SemaCXX/eval-crashes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ namespace pr33140_0b {
}

namespace pr33140_2 {
struct A { int &&r = 0; };
// FIXME: The declaration of 'b' below should lifetime-extend two int
// temporaries.
struct A { int &&r = 0; }; // expected-note 2{{initializing field 'r' with default member initializer}}
struct B { A x, y; };
B b = {};
B b = {}; // expected-warning 2{{lifetime extension of temporary created by aggregate initialization using a default member initializer is not yet supported}}
}

namespace pr33140_3 {
Expand Down
38 changes: 38 additions & 0 deletions clang/test/SemaCXX/warn-unsafe-buffer-usage-function-attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,41 @@ void testInheritance() {
BC->func(); // expected-warning{{function introduces unsafe buffer manipulation}}
BC->func1();
}

class UnsafeMembers {
public:
UnsafeMembers() {}

[[clang::unsafe_buffer_usage]]
UnsafeMembers(int) {}

[[clang::unsafe_buffer_usage]]
explicit operator int() { return 0; }

[[clang::unsafe_buffer_usage]]
void Method() {}

[[clang::unsafe_buffer_usage]]
void operator()() {}

[[clang::unsafe_buffer_usage]]
int operator+(UnsafeMembers) { return 0; }
};

template <class... Vs>
int testFoldExpression(Vs&&... v) {
return (... + v); // expected-warning{{function introduces unsafe buffer manipulation}}
}

// https://github.com/llvm/llvm-project/issues/80482
void testClassMembers() {
UnsafeMembers(3); // expected-warning{{function introduces unsafe buffer manipulation}}

(void)static_cast<int>(UnsafeMembers()); // expected-warning{{function introduces unsafe buffer manipulation}}

UnsafeMembers().Method(); // expected-warning{{function introduces unsafe buffer manipulation}}

UnsafeMembers()(); // expected-warning{{function introduces unsafe buffer manipulation}}

testFoldExpression(UnsafeMembers(), UnsafeMembers());
}
15 changes: 3 additions & 12 deletions clang/test/SemaTemplate/cwg2398.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,25 +62,19 @@ namespace templ {
namespace type_pack1 {
template<class T2> struct A;
template<template<class ...T3s> class TT1, class T4> struct A<TT1<T4>> ;
// new-note@-1 {{partial specialization matches}}
template<template<class T5 > class TT2, class T6> struct A<TT2<T6>> {};
// new-note@-1 {{partial specialization matches}}

template<class T1> struct B;
template struct A<B<char>>;
// new-error@-1 {{ambiguous partial specialization}}
} // namespace type_pack1

namespace type_pack2 {
template<class T2> struct A;
template<template<class ...T3s> class TT1, class ...T4> struct A<TT1<T4...>> ;
// new-note@-1 {{partial specialization matches}}
template<template<class T5 > class TT2, class ...T6> struct A<TT2<T6...>> {};
// new-note@-1 {{partial specialization matches}}

template<class T1> struct B;
template struct A<B<char>>;
// new-error@-1 {{ambiguous partial specialization}}
} // namespace type_pack2

namespace type_pack3 {
Expand Down Expand Up @@ -140,13 +134,10 @@ namespace ttp_defaults {

namespace ttp_only {
template <template <class... > class TT1> struct A { static constexpr int V = 0; };
// new-note@-1 2{{template is declared here}}
template <template <class > class TT2> struct A<TT2> { static constexpr int V = 1; };
// new-error@-1 {{not more specialized than the primary template}}
// new-note@-2 {{partial specialization matches}}
// new-note@-1 {{partial specialization matches}}
template <template <class, class> class TT3> struct A<TT3> { static constexpr int V = 2; };
// new-error@-1 {{not more specialized than the primary template}}
// new-note@-2 {{partial specialization matches}}
// new-note@-1 {{partial specialization matches}}

template <class ... > struct B;
template <class > struct C;
Expand Down Expand Up @@ -193,5 +184,5 @@ namespace consistency {

template struct A<B<int>, B<int>, B<int>>;
// new-error@-1 {{ambiguous partial specializations}}
} // namespace t1
} // namespace t2
} // namespace consistency
16 changes: 10 additions & 6 deletions clang/test/SemaTemplate/deduction-guide.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,12 +282,16 @@ using AFoo = Foo<G<U>>;
// CHECK-LABEL: Dumping <deduction guide for AFoo>
// CHECK: FunctionTemplateDecl {{.*}} implicit <deduction guide for AFoo>
// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} typename depth 0 index 0 U
// CHECK-NEXT: |-ParenExpr {{.*}} 'bool'
// CHECK-NEXT: | `-BinaryOperator {{.*}} 'bool' '=='
// CHECK-NEXT: | |-UnaryExprOrTypeTraitExpr {{.*}} 'G<type-parameter-0-0>'
// CHECK-NEXT: | `-ImplicitCastExpr {{.*}}
// CHECK-NEXT: | `-IntegerLiteral {{.*}}
// CHECK-NEXT: |-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for AFoo> 'auto (G<type-parameter-0-0>) -> Foo<G<type-parameter-0-0>>'
// CHECK-NEXT: |-BinaryOperator {{.*}} '&&'
// CHECK-NEXT: | |-ParenExpr {{.*}} 'bool'
// CHECK-NEXT: | | `-BinaryOperator {{.*}} 'bool' '=='
// CHECK-NEXT: | | |-UnaryExprOrTypeTraitExpr {{.*}} 'G<type-parameter-0-0>'
// CHECK-NEXT: | | `-ImplicitCastExpr {{.*}}
// CHECK-NEXT: | | `-IntegerLiteral {{.*}}
// CHECK-NEXT: | `-TypeTraitExpr {{.*}} 'bool' __is_deducible
// CHECK-NEXT: | |-DeducedTemplateSpecializationType {{.*}} 'AFoo' dependent
// CHECK-NEXT: | `-TemplateSpecializationType {{.*}} 'Foo<G<type-parameter-0-0>>' dependent Foo
// CHECK: |-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for AFoo> 'auto (G<type-parameter-0-0>) -> Foo<G<type-parameter-0-0>>'
// CHECK-NEXT: | `-ParmVarDecl {{.*}} 'G<type-parameter-0-0>'
// CHECK-NEXT: `-CXXDeductionGuideDecl {{.*}} implicit used <deduction guide for AFoo> 'auto (G<int>) -> Foo<G<int>>' implicit_instantiation
// CHECK-NEXT: |-TemplateArgument type 'int'
Expand Down
2 changes: 2 additions & 0 deletions clang/tools/clang-fuzzer/dictionary/dictionary.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

static void emit(const char *Name, const char *Spelling) {
static char Hex[] = "0123456789abcdef";
// Skip EmptySpellingName for IsDeducible.
if (!Name[0]) return;

printf("%s=\"", Name);
unsigned char C;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//===- unittest/Tooling/RecursiveASTVisitorTests/DeductionGuide.cpp -------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#include "TestVisitor.h"
#include <string>

using namespace clang;

namespace {

class DeductionGuideVisitor
: public ExpectedLocationVisitor<DeductionGuideVisitor> {
public:
DeductionGuideVisitor(bool ShouldVisitImplicitCode)
: ShouldVisitImplicitCode(ShouldVisitImplicitCode) {}
bool VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
std::string Storage;
llvm::raw_string_ostream Stream(Storage);
D->print(Stream);
Match(Stream.str(), D->getLocation());
return true;
}

bool shouldVisitTemplateInstantiations() const { return false; }

bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; }
bool ShouldVisitImplicitCode;
};

TEST(RecursiveASTVisitor, DeductionGuideNonImplicitMode) {
DeductionGuideVisitor Visitor(/*ShouldVisitImplicitCode*/ false);
// Verify that the synthezied deduction guide for alias is not visited in
// RAV's implicit mode.
Visitor.ExpectMatch("Foo(T) -> Foo<int>", 11, 1);
Visitor.DisallowMatch("Bar(type-parameter-0-0) -> Foo<int>", 14, 1);
EXPECT_TRUE(Visitor.runOver(
R"cpp(
template <typename T>
concept False = true;

template <typename T>
struct Foo {
Foo(T);
};

template<typename T> requires False<T>
Foo(T) -> Foo<int>;

template <typename U>
using Bar = Foo<U>;
Bar s(1);
)cpp",
DeductionGuideVisitor::Lang_CXX2a));
}

TEST(RecursiveASTVisitor, DeductionGuideImplicitMode) {
DeductionGuideVisitor Visitor(/*ShouldVisitImplicitCode*/ true);
Visitor.ExpectMatch("Foo(T) -> Foo<int>", 11, 1);
Visitor.ExpectMatch("Bar(type-parameter-0-0) -> Foo<int>", 14, 1);
EXPECT_TRUE(Visitor.runOver(
R"cpp(
template <typename T>
concept False = true;

template <typename T>
struct Foo {
Foo(T);
};

template<typename T> requires False<T>
Foo(T) -> Foo<int>;

template <typename U>
using Bar = Foo<U>;
Bar s(1);
)cpp",
DeductionGuideVisitor::Lang_CXX2a));
}

} // end anonymous namespace
2 changes: 1 addition & 1 deletion clang/www/cxx_dr_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -10698,7 +10698,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/1815.html">1815</a></td>
<td>CD4</td>
<td>Lifetime extension in aggregate initialization</td>
<td class="unreleased" align="center">Clang 19</td>
<td class="none" align="center">No</td>
</tr>
<tr id="1816">
<td><a href="https://cplusplus.github.io/CWG/issues/1816.html">1816</a></td>
Expand Down
6 changes: 3 additions & 3 deletions clang/www/cxx_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ <h2 id="cxx26">C++2c implementation status</h2>
<tr>
<td>Clarifying rules for brace elision in aggregate initialization</td>
<td><a href="https://wg21.link/P3106R1">P3106R1</a> (<a href="#dr">DR</a>)</td>
<td class="none" align="center">No</td>
<td class="full" align="center">Clang 17</td>
</tr>
<tr>
<td>Attributes for Structured Bindings</td>
Expand Down Expand Up @@ -870,8 +870,8 @@ <h2 id="cxx20">C++20 implementation status</h2>
<td class="partial" align="center">
<details>
<summary>Clang 19 (Partial)</summary>
The associated constraints (over.match.class.deduct#3.3) for the
synthesized deduction guides are not yet implemented.
This feature has been initially completed, but the feature macro
__cpp_deduction_guides has not been updated.
</details>
</td>
</tr>
Expand Down
95 changes: 90 additions & 5 deletions flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ struct AliasAnalysis {
/// Represents memory allocated outside of a function
/// and passed to the function via host association tuple.
HostAssoc,
/// Represents direct memory access whose source cannot be further
/// determined
Direct,
/// Represents memory allocated by unknown means and
/// with the memory address defined by a memory reading
/// operation (e.g. fir::LoadOp).
Expand All @@ -50,12 +47,85 @@ struct AliasAnalysis {
/// Attributes of the memory source object.
ENUM_CLASS(Attribute, Target, Pointer, IntentIn);

// See
// https://discourse.llvm.org/t/rfc-distinguish-between-data-and-non-data-in-fir-alias-analysis/78759/1
//
// It is possible, while following the source of a memory reference through
// the use-def chain, to arrive at the same origin, even though the starting
// points were known to not alias.
//
// clang-format off
// Example:
// ------------------- test.f90 --------------------
// module top
// real, pointer :: a(:)
// end module
//
// subroutine test()
// use top
// a(1) = 1
// end subroutine
// -------------------------------------------------
//
// flang-new -fc1 -emit-fir test.f90 -o test.fir
//
// ------------------- test.fir --------------------
// fir.global @_QMtopEa : !fir.box<!fir.ptr<!fir.array<?xf32>>>
//
// func.func @_QPtest() {
// %c1 = arith.constant 1 : index
// %cst = arith.constant 1.000000e+00 : f32
// %0 = fir.address_of(@_QMtopEa) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
// %1 = fir.declare %0 {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMtopEa"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
// %2 = fir.load %1 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
// ...
// %5 = fir.array_coor %2 %c1 : (!fir.box<!fir.ptr<!fir.array<?xf32>>>, !fir.shift<1>, index) -> !fir.ref<f32>
// fir.store %cst to %5 : !fir.ref<f32>
// return
// }
// -------------------------------------------------
//
// With high level operations, such as fir.array_coor, it is possible to
// reach into the data wrapped by the box (the descriptor). Therefore when
// asking about the memory source of %5, we are really asking about the
// source of the data of box %2.
//
// When asking about the source of %0 which is the address of the box, we
// reach the same source as in the first case: the global @_QMtopEa. Yet one
// source refers to the data while the other refers to the address of the box
// itself.
//
// To distinguish between the two, the isData flag has been added, whereby
// data is defined as any memory reference that is not a box reference.
// Additionally, because it is relied on in HLFIR lowering, we allow querying
// on a box SSA value, which is interpreted as querying on its data.
//
// So in the above example, !fir.ref<f32> and !fir.box<!fir.ptr<!fir.array<?xf32>>> is data,
// while !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>> is not data.

// This also applies to function arguments. In the example below, %arg0
// is data, %arg1 is not data but a load of %arg1 is.
//
// func.func @_QFPtest2(%arg0: !fir.ref<f32>, %arg1: !fir.ref<!fir.box<!fir.ptr<f32>>> ) {
// %0 = fir.load %arg1 : !fir.ref<!fir.box<!fir.ptr<f32>>>
// ... }
//
// clang-format on

struct Source {
using SourceUnion = llvm::PointerUnion<mlir::SymbolRefAttr, mlir::Value>;
using Attributes = Fortran::common::EnumSet<Attribute, Attribute_enumSize>;

/// Source definition of a value.
SourceUnion u;
struct SourceOrigin {
/// Source definition of a value.
SourceUnion u;

/// Whether the source was reached following data or box reference
bool isData{false};
};

SourceOrigin origin;

/// Kind of the memory source.
SourceKind kind;
/// Value type of the source definition.
Expand All @@ -77,6 +147,12 @@ struct AliasAnalysis {
/// attribute.
bool isRecordWithPointerComponent() const;

bool isDummyArgument() const;
bool isData() const;
bool isBoxData() const;

mlir::Type getType() const;

/// Return true, if `ty` is a reference type to a boxed
/// POINTER object or a raw fir::PointerType.
static bool isPointerReference(mlir::Type ty);
Expand All @@ -95,6 +171,15 @@ struct AliasAnalysis {
Source getSource(mlir::Value);
};

inline bool operator==(const AliasAnalysis::Source::SourceOrigin &lhs,
const AliasAnalysis::Source::SourceOrigin &rhs) {
return lhs.u == rhs.u && lhs.isData == rhs.isData;
}
inline bool operator!=(const AliasAnalysis::Source::SourceOrigin &lhs,
const AliasAnalysis::Source::SourceOrigin &rhs) {
return !(lhs == rhs);
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
const AliasAnalysis::Source &op) {
op.print(os);
Expand Down
213 changes: 95 additions & 118 deletions flang/lib/Lower/OpenMP/ClauseProcessor.cpp

Large diffs are not rendered by default.

113 changes: 53 additions & 60 deletions flang/lib/Lower/OpenMP/ClauseProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,44 +47,43 @@ namespace omp {
/// construct.
class ClauseProcessor {
public:
ClauseProcessor(Fortran::lower::AbstractConverter &converter,
Fortran::semantics::SemanticsContext &semaCtx,
ClauseProcessor(lower::AbstractConverter &converter,
semantics::SemanticsContext &semaCtx,
const List<Clause> &clauses)
: converter(converter), semaCtx(semaCtx), clauses(clauses) {}

// 'Unique' clauses: They can appear at most once in the clause list.
bool processCollapse(
mlir::Location currentLocation, Fortran::lower::pft::Evaluation &eval,
mlir::omp::CollapseClauseOps &result,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> &iv) const;
bool
processCollapse(mlir::Location currentLocation, lower::pft::Evaluation &eval,
mlir::omp::CollapseClauseOps &result,
llvm::SmallVectorImpl<const semantics::Symbol *> &iv) const;
bool processDefault() const;
bool processDevice(Fortran::lower::StatementContext &stmtCtx,
bool processDevice(lower::StatementContext &stmtCtx,
mlir::omp::DeviceClauseOps &result) const;
bool processDeviceType(mlir::omp::DeviceTypeClauseOps &result) const;
bool processFinal(Fortran::lower::StatementContext &stmtCtx,
bool processFinal(lower::StatementContext &stmtCtx,
mlir::omp::FinalClauseOps &result) const;
bool
processHasDeviceAddr(mlir::omp::HasDeviceAddrClauseOps &result,
llvm::SmallVectorImpl<mlir::Type> &isDeviceTypes,
llvm::SmallVectorImpl<mlir::Location> &isDeviceLocs,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
&isDeviceSymbols) const;
bool processHasDeviceAddr(
mlir::omp::HasDeviceAddrClauseOps &result,
llvm::SmallVectorImpl<mlir::Type> &isDeviceTypes,
llvm::SmallVectorImpl<mlir::Location> &isDeviceLocs,
llvm::SmallVectorImpl<const semantics::Symbol *> &isDeviceSymbols) const;
bool processHint(mlir::omp::HintClauseOps &result) const;
bool processMergeable(mlir::omp::MergeableClauseOps &result) const;
bool processNowait(mlir::omp::NowaitClauseOps &result) const;
bool processNumTeams(Fortran::lower::StatementContext &stmtCtx,
bool processNumTeams(lower::StatementContext &stmtCtx,
mlir::omp::NumTeamsClauseOps &result) const;
bool processNumThreads(Fortran::lower::StatementContext &stmtCtx,
bool processNumThreads(lower::StatementContext &stmtCtx,
mlir::omp::NumThreadsClauseOps &result) const;
bool processOrdered(mlir::omp::OrderedClauseOps &result) const;
bool processPriority(Fortran::lower::StatementContext &stmtCtx,
bool processPriority(lower::StatementContext &stmtCtx,
mlir::omp::PriorityClauseOps &result) const;
bool processProcBind(mlir::omp::ProcBindClauseOps &result) const;
bool processSafelen(mlir::omp::SafelenClauseOps &result) const;
bool processSchedule(Fortran::lower::StatementContext &stmtCtx,
bool processSchedule(lower::StatementContext &stmtCtx,
mlir::omp::ScheduleClauseOps &result) const;
bool processSimdlen(mlir::omp::SimdlenClauseOps &result) const;
bool processThreadLimit(Fortran::lower::StatementContext &stmtCtx,
bool processThreadLimit(lower::StatementContext &stmtCtx,
mlir::omp::ThreadLimitClauseOps &result) const;
bool processUntied(mlir::omp::UntiedClauseOps &result) const;

Expand All @@ -98,12 +97,11 @@ class ClauseProcessor {
processEnter(llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const;
bool processIf(omp::clause::If::DirectiveNameModifier directiveName,
mlir::omp::IfClauseOps &result) const;
bool
processIsDevicePtr(mlir::omp::IsDevicePtrClauseOps &result,
llvm::SmallVectorImpl<mlir::Type> &isDeviceTypes,
llvm::SmallVectorImpl<mlir::Location> &isDeviceLocs,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
&isDeviceSymbols) const;
bool processIsDevicePtr(
mlir::omp::IsDevicePtrClauseOps &result,
llvm::SmallVectorImpl<mlir::Type> &isDeviceTypes,
llvm::SmallVectorImpl<mlir::Location> &isDeviceLocs,
llvm::SmallVectorImpl<const semantics::Symbol *> &isDeviceSymbols) const;
bool
processLink(llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const;

Expand All @@ -113,35 +111,32 @@ class ClauseProcessor {
// They may be used later on to create the block_arguments for some of the
// target directives that require it.
bool processMap(
mlir::Location currentLocation, Fortran::lower::StatementContext &stmtCtx,
mlir::Location currentLocation, lower::StatementContext &stmtCtx,
mlir::omp::MapClauseOps &result,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *mapSyms =
nullptr,
llvm::SmallVectorImpl<const semantics::Symbol *> *mapSyms = nullptr,
llvm::SmallVectorImpl<mlir::Location> *mapSymLocs = nullptr,
llvm::SmallVectorImpl<mlir::Type> *mapSymTypes = nullptr) const;
bool processReduction(
mlir::Location currentLocation, mlir::omp::ReductionClauseOps &result,
llvm::SmallVectorImpl<mlir::Type> *reductionTypes = nullptr,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *> *reductionSyms =
llvm::SmallVectorImpl<const semantics::Symbol *> *reductionSyms =
nullptr) const;
bool processSectionsReduction(mlir::Location currentLocation,
mlir::omp::ReductionClauseOps &result) const;
bool processTo(llvm::SmallVectorImpl<DeclareTargetCapturePair> &result) const;
bool
processUseDeviceAddr(mlir::omp::UseDeviceClauseOps &result,
llvm::SmallVectorImpl<mlir::Type> &useDeviceTypes,
llvm::SmallVectorImpl<mlir::Location> &useDeviceLocs,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
&useDeviceSyms) const;
bool
processUseDevicePtr(mlir::omp::UseDeviceClauseOps &result,
llvm::SmallVectorImpl<mlir::Type> &useDeviceTypes,
llvm::SmallVectorImpl<mlir::Location> &useDeviceLocs,
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
&useDeviceSyms) const;
bool processUseDeviceAddr(
mlir::omp::UseDeviceClauseOps &result,
llvm::SmallVectorImpl<mlir::Type> &useDeviceTypes,
llvm::SmallVectorImpl<mlir::Location> &useDeviceLocs,
llvm::SmallVectorImpl<const semantics::Symbol *> &useDeviceSyms) const;
bool processUseDevicePtr(
mlir::omp::UseDeviceClauseOps &result,
llvm::SmallVectorImpl<mlir::Type> &useDeviceTypes,
llvm::SmallVectorImpl<mlir::Location> &useDeviceLocs,
llvm::SmallVectorImpl<const semantics::Symbol *> &useDeviceSyms) const;

template <typename T>
bool processMotionClauses(Fortran::lower::StatementContext &stmtCtx,
bool processMotionClauses(lower::StatementContext &stmtCtx,
mlir::omp::MapClauseOps &result);

// Call this method for these clauses that should be supported but are not
Expand All @@ -162,36 +157,34 @@ class ClauseProcessor {
/// `nullptr` if not present. If more than one instance is expected, use
/// `findRepeatableClause` instead.
template <typename T>
const T *
findUniqueClause(const Fortran::parser::CharBlock **source = nullptr) const;
const T *findUniqueClause(const parser::CharBlock **source = nullptr) const;

/// Call `callbackFn` for each occurrence of the given clause. Return `true`
/// if at least one instance was found.
template <typename T>
bool findRepeatableClause(
std::function<void(const T &, const Fortran::parser::CharBlock &source)>
std::function<void(const T &, const parser::CharBlock &source)>
callbackFn) const;

/// Set the `result` to a new `mlir::UnitAttr` if the clause is present.
template <typename T>
bool markClauseOccurrence(mlir::UnitAttr &result) const;

Fortran::lower::AbstractConverter &converter;
Fortran::semantics::SemanticsContext &semaCtx;
lower::AbstractConverter &converter;
semantics::SemanticsContext &semaCtx;
List<Clause> clauses;
};

template <typename T>
bool ClauseProcessor::processMotionClauses(
Fortran::lower::StatementContext &stmtCtx,
mlir::omp::MapClauseOps &result) {
std::map<const Fortran::semantics::Symbol *,
bool ClauseProcessor::processMotionClauses(lower::StatementContext &stmtCtx,
mlir::omp::MapClauseOps &result) {
std::map<const semantics::Symbol *,
llvm::SmallVector<OmpMapMemberIndicesData>>
parentMemberIndices;
llvm::SmallVector<const Fortran::semantics::Symbol *> mapSymbols;
llvm::SmallVector<const semantics::Symbol *> mapSymbols;

bool clauseFound = findRepeatableClause<T>(
[&](const T &clause, const Fortran::parser::CharBlock &source) {
[&](const T &clause, const parser::CharBlock &source) {
mlir::Location clauseLocation = converter.genLocation(source);
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();

Expand All @@ -209,9 +202,9 @@ bool ClauseProcessor::processMotionClauses(
llvm::SmallVector<mlir::Value> bounds;
std::stringstream asFortran;

Fortran::lower::AddrAndBoundsInfo info =
Fortran::lower::gatherDataOperandAddrAndBounds<
mlir::omp::MapBoundsOp, mlir::omp::MapBoundsType>(
lower::AddrAndBoundsInfo info =
lower::gatherDataOperandAddrAndBounds<mlir::omp::MapBoundsOp,
mlir::omp::MapBoundsType>(
converter, firOpBuilder, semaCtx, stmtCtx, *object.id(),
object.ref(), clauseLocation, asFortran, bounds,
treatIndexAsSection);
Expand Down Expand Up @@ -277,8 +270,8 @@ ClauseProcessor::findClause(ClauseIterator begin, ClauseIterator end) {
}

template <typename T>
const T *ClauseProcessor::findUniqueClause(
const Fortran::parser::CharBlock **source) const {
const T *
ClauseProcessor::findUniqueClause(const parser::CharBlock **source) const {
ClauseIterator it = findClause<T>(clauses.begin(), clauses.end());
if (it != clauses.end()) {
if (source)
Expand All @@ -290,8 +283,8 @@ const T *ClauseProcessor::findUniqueClause(

template <typename T>
bool ClauseProcessor::findRepeatableClause(
std::function<void(const T &, const Fortran::parser::CharBlock &source)>
callbackFn) const {
std::function<void(const T &, const parser::CharBlock &source)> callbackFn)
const {
bool found = false;
ClauseIterator nextIt, endIt = clauses.end();
for (ClauseIterator it = clauses.begin(); it != endIt; it = nextIt) {
Expand Down
7 changes: 3 additions & 4 deletions flang/lib/Lower/OpenMP/Clauses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,8 @@ Object makeObject(const parser::OmpObject &object,
return makeObject(std::get<parser::Designator>(object.u), semaCtx);
}

std::optional<Object>
getBaseObject(const Object &object,
Fortran::semantics::SemanticsContext &semaCtx) {
std::optional<Object> getBaseObject(const Object &object,
semantics::SemanticsContext &semaCtx) {
// If it's just the symbol, then there is no base.
if (!object.id())
return std::nullopt;
Expand Down Expand Up @@ -1211,7 +1210,7 @@ UsesAllocators make(const parser::OmpClause::UsesAllocators &inp,
// Write: empty
} // namespace clause

Clause makeClause(const Fortran::parser::OmpClause &cls,
Clause makeClause(const parser::OmpClause &cls,
semantics::SemanticsContext &semaCtx) {
return std::visit(
[&](auto &&s) {
Expand Down
7 changes: 3 additions & 4 deletions flang/lib/Lower/OpenMP/Clauses.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,8 @@ std::optional<ResultTy> maybeApply(FuncTy &&func,
return std::move(func(*arg));
}

std::optional<Object>
getBaseObject(const Object &object,
Fortran::semantics::SemanticsContext &semaCtx);
std::optional<Object> getBaseObject(const Object &object,
semantics::SemanticsContext &semaCtx);

namespace clause {
using DefinedOperator = tomp::type::DefinedOperatorT<IdTy, ExprTy>;
Expand Down Expand Up @@ -262,7 +261,7 @@ Clause makeClause(llvm::omp::Clause id, Specific &&specific,
return Clause(typename Clause::BaseT{id, specific}, source);
}

Clause makeClause(const Fortran::parser::OmpClause &cls,
Clause makeClause(const parser::OmpClause &cls,
semantics::SemanticsContext &semaCtx);

List<Clause> makeClauses(const parser::OmpClauseList &clauses,
Expand Down
Loading