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
1 change: 1 addition & 0 deletions clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ void Flang::addCodegenOptions(const ArgList &Args,

Args.addAllArgs(CmdArgs, {options::OPT_flang_experimental_hlfir,
options::OPT_flang_deprecated_no_hlfir,
options::OPT_flang_experimental_integer_overflow,
options::OPT_fno_ppc_native_vec_elem_order,
options::OPT_fppc_native_vec_elem_order});
}
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
3 changes: 2 additions & 1 deletion clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ void printLine(llvm::raw_ostream &OS, const UnwrappedLine &Line,
OS << Prefix;
NewLine = false;
}
OS << I->Tok->Tok.getName() << "[" << "T=" << (unsigned)I->Tok->getType()
OS << I->Tok->Tok.getName() << "["
<< "T=" << (unsigned)I->Tok->getType()
<< ", OC=" << I->Tok->OriginalColumn << ", \"" << I->Tok->TokenText
<< "\"] ";
for (SmallVectorImpl<UnwrappedLine>::const_iterator
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
413 changes: 198 additions & 215 deletions clang/lib/Sema/SemaExpr.cpp

Large diffs are not rendered by default.

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
88 changes: 79 additions & 9 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
86 changes: 86 additions & 0 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3237,6 +3237,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 +3339,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
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
17 changes: 7 additions & 10 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -16236,10 +16236,11 @@ ExprResult TreeTransform<Derived>::RebuildCXXOperatorCallExpr(
return getSema().CreateBuiltinUnaryOp(OpLoc, Opc, First);
}
} else {
if (!First->getType()->isOverloadableType() &&
if (!First->isTypeDependent() && !Second->isTypeDependent() &&
!First->getType()->isOverloadableType() &&
!Second->getType()->isOverloadableType()) {
// Neither of the arguments is an overloadable type, so try to
// create a built-in binary operation.
// Neither of the arguments is type-dependent or has an overloadable
// type, so try to create a built-in binary operation.
BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op);
ExprResult Result
= SemaRef.CreateBuiltinBinOp(OpLoc, Opc, First, Second);
Expand All @@ -16250,12 +16251,8 @@ ExprResult TreeTransform<Derived>::RebuildCXXOperatorCallExpr(
}
}

// Add any functions found via argument-dependent lookup.
Expr *Args[2] = { First, Second };
unsigned NumArgs = 1 + (Second != nullptr);

// Create the overloaded operator invocation for unary operators.
if (NumArgs == 1 || isPostIncDec) {
if (!Second || isPostIncDec) {
UnaryOperatorKind Opc
= UnaryOperator::getOverloadedOpcode(Op, isPostIncDec);
return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, First,
Expand All @@ -16264,8 +16261,8 @@ ExprResult TreeTransform<Derived>::RebuildCXXOperatorCallExpr(

// Create the overloaded operator invocation for binary operators.
BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op);
ExprResult Result = SemaRef.CreateOverloadedBinOp(
OpLoc, Opc, Functions, Args[0], Args[1], RequiresADL);
ExprResult Result = SemaRef.CreateOverloadedBinOp(OpLoc, Opc, Functions,
First, Second, RequiresADL);
if (Result.isInvalid())
return ExprError();

Expand Down
370 changes: 204 additions & 166 deletions clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -525,11 +525,19 @@ bool TrivialFunctionAnalysis::isTrivialImpl(
if (!IsNew)
return It->second;

TrivialFunctionAnalysisVisitor V(Cache);

if (auto *CtorDecl = dyn_cast<CXXConstructorDecl>(D)) {
for (auto *CtorInit : CtorDecl->inits()) {
if (!V.Visit(CtorInit->getInit()))
return false;
}
}

const Stmt *Body = D->getBody();
if (!Body)
return false;

TrivialFunctionAnalysisVisitor V(Cache);
bool Result = V.Visit(Body);
if (Result)
Cache[D] = true;
Expand Down
66 changes: 49 additions & 17 deletions clang/test/AST/Interp/builtin-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -644,24 +644,23 @@ static_assert(__builtin_os_log_format_buffer_size("%{mask.xyz}s", "abc") != 0, "
/// Some tests are missing since we run this for multiple targets,
/// some of which do not support _BitInt.
#ifndef __AVR__
namespace convertvector {
typedef _BitInt(128) BitInt128;

typedef double vector4double __attribute__((__vector_size__(32)));
typedef float vector4float __attribute__((__vector_size__(16)));
typedef long long vector4long __attribute__((__vector_size__(32)));
typedef int vector4int __attribute__((__vector_size__(16)));
typedef short vector4short __attribute__((__vector_size__(8)));
typedef char vector4char __attribute__((__vector_size__(4)));
typedef BitInt128 vector4BitInt128 __attribute__((__vector_size__(64)));
typedef double vector8double __attribute__((__vector_size__(64)));
typedef float vector8float __attribute__((__vector_size__(32)));
typedef long long vector8long __attribute__((__vector_size__(64)));
typedef int vector8int __attribute__((__vector_size__(32)));
typedef short vector8short __attribute__((__vector_size__(16)));
typedef char vector8char __attribute__((__vector_size__(8)));
typedef BitInt128 vector8BitInt128 __attribute__((__vector_size__(128)));
typedef _BitInt(128) BitInt128;
typedef double vector4double __attribute__((__vector_size__(32)));
typedef float vector4float __attribute__((__vector_size__(16)));
typedef long long vector4long __attribute__((__vector_size__(32)));
typedef int vector4int __attribute__((__vector_size__(16)));
typedef short vector4short __attribute__((__vector_size__(8)));
typedef char vector4char __attribute__((__vector_size__(4)));
typedef BitInt128 vector4BitInt128 __attribute__((__vector_size__(64)));
typedef double vector8double __attribute__((__vector_size__(64)));
typedef float vector8float __attribute__((__vector_size__(32)));
typedef long long vector8long __attribute__((__vector_size__(64)));
typedef int vector8int __attribute__((__vector_size__(32)));
typedef short vector8short __attribute__((__vector_size__(16)));
typedef char vector8char __attribute__((__vector_size__(8)));
typedef BitInt128 vector8BitInt128 __attribute__((__vector_size__(128)));

namespace convertvector {
constexpr vector4double from_vector4double_to_vector4double_var =
__builtin_convertvector((vector4double){0, 1, 2, 3}, vector4double);
constexpr vector4float from_vector4double_to_vector4float_var =
Expand Down Expand Up @@ -873,4 +872,37 @@ namespace convertvector {
static_assert(from_vector8BitInt128_to_vector8BitInt128_var[3] == 3, ""); // ref-error {{not an integral constant expression}}
static_assert(from_vector8BitInt128_to_vector8BitInt128_var[4] == 4, ""); // ref-error {{not an integral constant expression}}
}

namespace shufflevector {
constexpr vector4char vector4charConst1 = {0, 1, 2, 3};
constexpr vector4char vector4charConst2 = {4, 5, 6, 7};
constexpr vector8char vector8intConst = {8, 9, 10, 11, 12, 13, 14, 15};
constexpr vector4char vectorShuffle1 =
__builtin_shufflevector(vector4charConst1, vector4charConst2, 0, 1, 2, 3);
constexpr vector4char vectorShuffle2 =
__builtin_shufflevector(vector4charConst1, vector4charConst2, 4, 5, 6, 7);
constexpr vector4char vectorShuffle3 =
__builtin_shufflevector(vector4charConst1, vector4charConst2, 0, 2, 4, 6);
constexpr vector8char vectorShuffle4 = __builtin_shufflevector(
vector8intConst, vector8intConst, 0, 2, 4, 6, 8, 10, 12, 14);
constexpr vector4char vectorShuffle5 =
__builtin_shufflevector(vector8intConst, vector8intConst, 0, 2, 4, 6);
constexpr vector8char vectorShuffle6 = __builtin_shufflevector(
vector4charConst1, vector4charConst2, 0, 2, 4, 6, 1, 3, 5, 7);

static_assert(vectorShuffle6[0] == 0, "");// ref-error {{not an integral constant expression}}
static_assert(vectorShuffle6[1] == 2, "");// ref-error {{not an integral constant expression}}
static_assert(vectorShuffle6[2] == 4, "");// ref-error {{not an integral constant expression}}
static_assert(vectorShuffle6[3] == 6, "");// ref-error {{not an integral constant expression}}
static_assert(vectorShuffle6[4] == 1, "");// ref-error {{not an integral constant expression}}
static_assert(vectorShuffle6[5] == 3, "");// ref-error {{not an integral constant expression}}
static_assert(vectorShuffle6[6] == 5, "");// ref-error {{not an integral constant expression}}
static_assert(vectorShuffle6[7] == 7, "");// ref-error {{not an integral constant expression}}

constexpr vector4char vectorShuffleFail1 = __builtin_shufflevector( // both-error {{must be initialized by a constant expression}}\
// ref-error {{index for __builtin_shufflevector not within the bounds of the input vectors; index of -1 found at position 0 not permitted in a constexpr context.}}
vector4charConst1,
vector4charConst2, -1, -1, -1, -1);
}

#endif
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
4 changes: 2 additions & 2 deletions clang/test/AST/ast-dump-expr-json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4261,9 +4261,9 @@ void TestNonADLCall3() {
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "type": {
// CHECK-NEXT: "qualType": "<dependent type>"
// CHECK-NEXT: "qualType": "V"
// CHECK-NEXT: },
// CHECK-NEXT: "valueCategory": "prvalue",
// CHECK-NEXT: "valueCategory": "lvalue",
// CHECK-NEXT: "isPostfix": false,
// CHECK-NEXT: "opcode": "*",
// CHECK-NEXT: "canOverflow": false,
Expand Down
9 changes: 8 additions & 1 deletion clang/test/AST/ast-dump-expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ void PrimaryExpressions(Ts... a) {
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <col:8> col:8 implicit 'V'
// CHECK-NEXT: ParenListExpr 0x{{[^ ]*}} <col:8> 'NULL TYPE'
// CHECK-NEXT: UnaryOperator 0x{{[^ ]*}} <col:8> '<dependent type>' prefix '*' cannot overflow
// CHECK-NEXT: UnaryOperator 0x{{[^ ]*}} <col:8> 'V' lvalue prefix '*' cannot overflow
// CHECK-NEXT: CXXThisExpr 0x{{[^ ]*}} <col:8> 'V *' this
}
};
Expand Down 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 *'
}

2 changes: 1 addition & 1 deletion clang/test/AST/ast-dump-lambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ template <typename... Ts> void test(Ts... a) {
// CHECK-NEXT: | | | `-CompoundStmt {{.*}} <col:15, col:16>
// CHECK-NEXT: | | `-FieldDecl {{.*}} <col:8> col:8{{( imported)?}} implicit 'V'
// CHECK-NEXT: | |-ParenListExpr {{.*}} <col:8> 'NULL TYPE'
// CHECK-NEXT: | | `-UnaryOperator {{.*}} <col:8> '<dependent type>' prefix '*' cannot overflow
// CHECK-NEXT: | | `-UnaryOperator {{.*}} <col:8> 'V' lvalue prefix '*' cannot overflow
// CHECK-NEXT: | | `-CXXThisExpr {{.*}} <col:8> 'V *' this
// CHECK-NEXT: | `-CompoundStmt {{.*}} <col:15, col:16>
// CHECK-NEXT: |-DeclStmt {{.*}} <line:22:3, col:11>
Expand Down
21 changes: 21 additions & 0 deletions clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,13 @@ template<typename E> class OptionSet {
StorageType m_storage { 0 };
};

int atoi(const char* str);

class Number {
public:
Number(int v) : v(v) { }
Number(double);
Number(const char* str) : v(atoi(str)) { }
Number operator+(const Number&);
Number& operator++() { ++v; return *this; }
Number operator++(int) { Number returnValue(v); ++v; return returnValue; }
Expand All @@ -173,9 +176,16 @@ class Number {
int v;
};

class DerivedNumber : public Number {
public:
DerivedNumber(char c) : Number(c - '0') { }
DerivedNumber(const char* str) : Number(atoi(str)) { }
};

class ComplexNumber {
public:
ComplexNumber() : realPart(0), complexPart(0) { }
ComplexNumber(int real, const char* str) : realPart(real), complexPart(str) { }
ComplexNumber(const ComplexNumber&);
ComplexNumber& operator++() { realPart.someMethod(); return *this; }
ComplexNumber operator++(int);
Expand Down Expand Up @@ -311,6 +321,7 @@ class RefCounted {
return;
}
unsigned trivial60() { return ObjectWithNonTrivialDestructor { 5 }.value(); }
unsigned trivial61() { return DerivedNumber('7').value(); }

static RefCounted& singleton() {
static RefCounted s_RefCounted;
Expand Down Expand Up @@ -391,6 +402,9 @@ class RefCounted {
ComplexNumber nonTrivial18() { return +complex; }
ComplexNumber* nonTrivial19() { return new ComplexNumber(complex); }
unsigned nonTrivial20() { return ObjectWithMutatingDestructor { 7 }.value(); }
unsigned nonTrivial21() { return Number("123").value(); }
unsigned nonTrivial22() { return ComplexNumber(123, "456").real().value(); }
unsigned nonTrivial23() { return DerivedNumber("123").value(); }

static unsigned s_v;
unsigned v { 0 };
Expand Down Expand Up @@ -479,6 +493,7 @@ class UnrelatedClass {
getFieldTrivial().trivial58(); // no-warning
getFieldTrivial().trivial59(); // no-warning
getFieldTrivial().trivial60(); // no-warning
getFieldTrivial().trivial61(); // no-warning

RefCounted::singleton().trivial18(); // no-warning
RefCounted::singleton().someFunction(); // no-warning
Expand Down Expand Up @@ -525,6 +540,12 @@ class UnrelatedClass {
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial20();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial21();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial22();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial23();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
}
};

Expand Down
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
8 changes: 7 additions & 1 deletion clang/test/C/C2x/n2900_n3011.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,14 @@ void test(void) {
compat-warning {{use of an empty initializer is incompatible with C standards before C23}}
int vla[i] = {}; // compat-warning {{use of an empty initializer is incompatible with C standards before C23}} \
pedantic-warning {{use of an empty initializer is a C23 extension}}
// C99 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.
int *compound_literal_vla = (int[i]){}; // compat-warning {{use of an empty initializer is incompatible with C standards before C23}} \
pedantic-warning {{use of an empty initializer is a C23 extension}}
pedantic-warning {{use of an empty initializer is a C23 extension}}\
compat-error {{compound literal cannot be of variable-length array type}} \
pedantic-error {{compound literal cannot be of variable-length array type}}\


struct T {
int i;
Expand Down
16 changes: 0 additions & 16 deletions clang/test/C/C2x/n2900_n3011_2.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,22 +76,6 @@ void test_zero_size_vla() {
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr {{.*}} %[[VLA]], i8 0, i64 %[[BYTES_TO_COPY]], i1 false)
}

void test_compound_literal_vla() {
int num_elts = 12;
int *compound_literal_vla = (int[num_elts]){};
// CHECK: define {{.*}} void @test_compound_literal_vla
// CHECK-NEXT: entry:
// CHECK-NEXT: %[[NUM_ELTS_PTR:.+]] = alloca i32
// CHECK-NEXT: %[[COMP_LIT_VLA:.+]] = alloca ptr
// CHECK-NEXT: %[[COMP_LIT:.+]] = alloca i32
// CHECK-NEXT: store i32 12, ptr %[[NUM_ELTS_PTR]]
// CHECK-NEXT: %[[NUM_ELTS:.+]] = load i32, ptr %[[NUM_ELTS_PTR]]
// CHECK-NEXT: %[[NUM_ELTS_EXT:.+]] = zext i32 %[[NUM_ELTS]] to i64
// CHECK-NEXT: %[[BYTES_TO_COPY:.+]] = mul nuw i64 %[[NUM_ELTS_EXT]], 4
// CHECK-NEXT: call void @llvm.memset.p0.i64(ptr {{.*}} %[[COMP_LIT]], i8 0, i64 %[[BYTES_TO_COPY]], i1 false)
// CHECK-NEXT: store ptr %[[COMP_LIT]], ptr %[[COMP_LIT_VLA]]
}

void test_nested_structs() {
struct T t1 = { 1, {} };
struct T t2 = { 1, { 2, {} } };
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
65 changes: 65 additions & 0 deletions clang/test/CXX/expr/expr.unary/expr.unary.general/p1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// RUN: %clang_cc1 -Wno-unused -fsyntax-only %s -verify

struct A {
void operator*();
void operator+();
void operator-();
void operator!();
void operator~();
void operator&();
void operator++();
void operator--();
};

struct B { };

template<typename T, typename U>
void dependent(T t, T* pt, T U::* mpt, T(&ft)(), T(&at)[4]) {
*t;
+t;
-t;
!t;
~t;
&t;
++t;
--t;

*pt;
+pt;
-pt; // expected-error {{invalid argument type 'T *' to unary expression}}
!pt;
~pt; // expected-error {{invalid argument type 'T *' to unary expression}}
&pt;
++pt;
--pt;

*mpt; // expected-error {{indirection requires pointer operand ('T U::*' invalid)}}
+mpt; // expected-error {{invalid argument type 'T U::*' to unary expression}}
-mpt; // expected-error {{invalid argument type 'T U::*' to unary expression}}
!mpt;
~mpt; // expected-error {{invalid argument type 'T U::*' to unary expression}}
&mpt;
++mpt; // expected-error {{cannot increment value of type 'T U::*'}}
--mpt; // expected-error {{cannot decrement value of type 'T U::*'}}

*ft;
+ft;
-ft; // expected-error {{invalid argument type 'T (*)()' to unary expression}}
!ft;
~ft; // expected-error {{invalid argument type 'T (*)()' to unary expression}}
&ft;
++ft; // expected-error {{cannot increment value of type 'T ()'}}
--ft; // expected-error {{cannot decrement value of type 'T ()'}}

*at;
+at;
-at; // expected-error {{invalid argument type 'T *' to unary expression}}
!at;
~at; // expected-error {{invalid argument type 'T *' to unary expression}}
&at;
++at; // expected-error {{cannot increment value of type 'T[4]'}}
--at; // expected-error {{cannot decrement value of type 'T[4]'}}
}

// Make sure we only emit diagnostics once.
template void dependent(A t, A* pt, A B::* mpt, A(&ft)(), A(&at)[4]);
158 changes: 128 additions & 30 deletions clang/test/CXX/over/over.built/ast.cpp
Original file line number Diff line number Diff line change
@@ -1,41 +1,139 @@
// RUN: %clang_cc1 -std=c++17 -ast-dump %s -ast-dump-filter Test | FileCheck %s
// RUN: %clang_cc1 -std=c++17 -Wno-unused -ast-dump %s -ast-dump-filter Test | FileCheck %s

struct A{};
namespace Test {
template<typename T, typename U>
void Unary(T t, T* pt, T U::* mpt, T(&ft)(), T(&at)[4]) {
// CHECK: UnaryOperator {{.*}} '<dependent type>' lvalue prefix '*' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T'
*t;

template <typename T, typename U>
auto Test(T* pt, U* pu) {
// CHECK: UnaryOperator {{.*}} '<dependent type>' lvalue prefix '*'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
(void)*pt;
// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '+' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T'
+t;

// CHECK: UnaryOperator {{.*}} '<dependent type>' lvalue prefix '++'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
(void)(++pt);
// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '-' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T'
-t;

// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '+'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
(void)(+pt);
// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '!' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T'
!t;

// CHECK: BinaryOperator {{.*}} '<dependent type>' '+'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
(void)(pt + 3);
// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '~' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T'
~t;

// CHECK: BinaryOperator {{.*}} '<dependent type>' '-'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
(void)(pt - pt);
// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '&' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T'
&t;

// CHECK: BinaryOperator {{.*}} '<dependent type>' '-'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
// CHECK-NEXT: DeclRefExpr {{.*}} 'U *' lvalue ParmVar {{.*}} 'pu' 'U *'
(void)(pt - pu);
// CHECK: UnaryOperator {{.*}} '<dependent type>' lvalue prefix '++' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T'
++t;

// CHECK: BinaryOperator {{.*}} '<dependent type>' '=='
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
// CHECK-NEXT: DeclRefExpr {{.*}} 'U *' lvalue ParmVar {{.*}} 'pu' 'U *'
(void)(pt == pu);
// CHECK: UnaryOperator {{.*}} '<dependent type>' lvalue prefix '--' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T'
--t;

}
// CHECK: UnaryOperator {{.*}} 'T' lvalue prefix '*' cannot overflow
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
*pt;

// CHECK: UnaryOperator {{.*}} 'T *' prefix '+' cannot overflow
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
+pt;

// CHECK: UnaryOperator {{.*}} 'bool' prefix '!' cannot overflow
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'bool' <PointerToBoolean>
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
!pt;

// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '&' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
&pt;

// CHECK: UnaryOperator {{.*}} 'T *' lvalue prefix '++' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
++pt;

// CHECK: UnaryOperator {{.*}} 'T *' lvalue prefix '--' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
--pt;

// CHECK: UnaryOperator {{.*}} 'bool' prefix '!' cannot overflow
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'bool' <MemberPointerToBoolean>
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T U::*' <LValueToRValue>
// CHECK-NEXT: DeclRefExpr {{.*}} 'T U::*' lvalue ParmVar {{.*}} 'mpt' 'T U::*'
!mpt;

// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '&' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T U::*' lvalue ParmVar {{.*}} 'mpt' 'T U::*'
&mpt;

// CHECK: UnaryOperator {{.*}} 'T ()' lvalue prefix '*' cannot overflow
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr {{.*}} 'T ()' lvalue ParmVar {{.*}} 'ft' 'T (&)()'
*ft;

// CHECK: UnaryOperator {{.*}} 'T (*)()' prefix '+' cannot overflow
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr {{.*}} 'T ()' lvalue ParmVar {{.*}} 'ft' 'T (&)()'
+ft;

// CHECK: UnaryOperator {{.*}} 'bool' prefix '!' cannot overflow
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'bool' <PointerToBoolean>
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T (*)()' <FunctionToPointerDecay>
// CHECK-NEXT: DeclRefExpr {{.*}} 'T ()' lvalue ParmVar {{.*}} 'ft' 'T (&)()'
!ft;

// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '&' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T ()' lvalue ParmVar {{.*}} 'ft' 'T (&)()'
&ft;

// CHECK: UnaryOperator {{.*}} 'T' lvalue prefix '*' cannot overflow
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' <ArrayToPointerDecay>
// CHECK-NEXT: DeclRefExpr {{.*}} 'T[4]' lvalue ParmVar {{.*}} 'at' 'T (&)[4]'
*at;

// CHECK: UnaryOperator {{.*}} 'T *' prefix '+' cannot overflow
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' <ArrayToPointerDecay>
// CHECK-NEXT: DeclRefExpr {{.*}} 'T[4]' lvalue ParmVar {{.*}} 'at' 'T (&)[4]'
+at;

// CHECK: UnaryOperator {{.*}} 'bool' prefix '!' cannot overflow
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'bool' <PointerToBoolean>
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' <ArrayToPointerDecay>
// CHECK-NEXT: DeclRefExpr {{.*}} 'T[4]' lvalue ParmVar {{.*}} 'at' 'T (&)[4]'
!at;

// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '&' cannot overflow
// CHECK-NEXT: DeclRefExpr {{.*}} 'T[4]' lvalue ParmVar {{.*}} 'at' 'T (&)[4]'
&at;
}

template<typename T, typename U>
void Binary(T* pt, U* pu) {
// CHECK: BinaryOperator {{.*}} '<dependent type>' '+'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
pt + 3;

// CHECK: BinaryOperator {{.*}} '<dependent type>' '-'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
pt - pt;

// CHECK: BinaryOperator {{.*}} '<dependent type>' '-'
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
// CHECK-NEXT: DeclRefExpr {{.*}} 'U *' lvalue ParmVar {{.*}} 'pu' 'U *'
pt - pu;

// CHECK: BinaryOperator {{.*}} '<dependent type>' '=='
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
// CHECK-NEXT: DeclRefExpr {{.*}} 'U *' lvalue ParmVar {{.*}} 'pu' 'U *'
pt == pu;
}
} // namespace Test
2 changes: 1 addition & 1 deletion clang/test/CXX/over/over.built/p10.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ void f(int i, float f, bool b, char c, int* pi, A* pa, T* pt) {

(void)-pi; // expected-error {{invalid argument type}}
(void)-pa; // expected-error {{invalid argument type}}
(void)-pt; // FIXME: we should be able to give an error here.
(void)-pt; // expected-error {{invalid argument type}}
}

2 changes: 1 addition & 1 deletion clang/test/CXX/over/over.built/p11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ void f(int i, float f, bool b, char c, int* pi, T* pt) {
(void)~b;
(void)~c;
(void)~pi; // expected-error {{invalid argument type}}
(void)~pt; // FIXME: we should be able to give an error here.
(void)~pt; // expected-error {{invalid argument type}}
}

173 changes: 173 additions & 0 deletions clang/test/CXX/over/over.oper/over.oper.general/p1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// RUN: %clang_cc1 -std=c++20 -verify -Wno-unused %s

template<typename T, typename U>
void operator->*(T, U);

template<typename T, typename U>
void operator+(T, U);

template<typename T, typename U>
void operator-(T, U);

template<typename T, typename U>
void operator*(T, U);

template<typename T, typename U>
void operator/(T, U);

template<typename T, typename U>
void operator%(T, U);

template<typename T, typename U>
void operator^(T, U);

template<typename T, typename U>
void operator&(T, U);

template<typename T, typename U>
void operator|(T, U);

template<typename T, typename U>
void operator+=(T, U);

template<typename T, typename U>
void operator-=(T, U);

template<typename T, typename U>
void operator*=(T, U);

template<typename T, typename U>
void operator/=(T, U);

template<typename T, typename U>
void operator%=(T, U);

template<typename T, typename U>
void operator^=(T, U);

template<typename T, typename U>
void operator&=(T, U);

template<typename T, typename U>
void operator|=(T, U);

template<typename T, typename U>
void operator==(T, U);

template<typename T, typename U>
void operator!=(T, U);

template<typename T, typename U>
void operator<(T, U);

template<typename T, typename U>
void operator>(T, U);

template<typename T, typename U>
void operator<=(T, U);

template<typename T, typename U>
void operator>=(T, U);

template<typename T, typename U>
void operator<=>(T, U);

template<typename T, typename U>
void operator&&(T, U);

template<typename T, typename U>
void operator||(T, U);

template<typename T, typename U>
void operator<<(T, U);

template<typename T, typename U>
void operator>>(T, U);

template<typename T, typename U>
void operator<<=(T, U);

template<typename T, typename U>
void operator>>=(T, U);

template<typename T, typename U>
void operator,(T, U);

template<typename T>
void operator*(T);

template<typename T>
void operator&(T);

template<typename T>
void operator+(T);

template<typename T>
void operator-(T);

template<typename T>
void operator!(T);

template<typename T>
void operator~(T);

template<typename T>
void operator++(T);

template<typename T>
void operator--(T);

template<typename T>
void operator++(T, int);

template<typename T>
void operator--(T, int);

template<typename T>
void f(int *x) {
[&](auto *y) {
*y;
&y;
+y;
-y; // expected-error {{invalid argument type 'auto *' to unary expression}}
!y;
~y; // expected-error {{invalid argument type 'auto *' to unary expression}}
++y;
--y;
y++;
y--;
y->*x;
y + x;
y - x;
y * x;
y / x;
y % x;
y ^ x;
y & x;
y | x;
y += x;
y -= x;
y *= x;
y /= x;
y %= x;
y ^= x;
y &= x;
y |= x;
y == x;
y != x;
y < x;
y > x;
y <= x;
y >= x;
y <=> x;
y && x;
y || x;
y << x;
y >> x;
y <<= x;
y >>= x;
y, x;
};
}

template void f<int>(int*);
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>;
}
25 changes: 10 additions & 15 deletions clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,17 +357,14 @@ namespace N0 {
a->A::f4(); // expected-error{{no member named 'f4' in 'N0::A'}}
a->B::A::f4(); // expected-error{{no member named 'f4' in 'N0::A'}}

// FIXME: An overloaded unary 'operator*' is built for these
// even though the operand is a pointer (to a dependent type).
// Type::isOverloadableType should return false for such cases.
(*this).x4;
(*this).B::x4;
(*this).A::x4;
(*this).B::A::x4;
(*this).f4();
(*this).B::f4();
(*this).A::f4();
(*this).B::A::f4();
(*this).x4; // expected-error{{no member named 'x4' in 'B<T>'}}
(*this).B::x4; // expected-error{{no member named 'x4' in 'B<T>'}}
(*this).A::x4; // expected-error{{no member named 'x4' in 'N0::A'}}
(*this).B::A::x4; // expected-error{{no member named 'x4' in 'N0::A'}}
(*this).f4(); // expected-error{{no member named 'f4' in 'B<T>'}}
(*this).B::f4(); // expected-error{{no member named 'f4' in 'B<T>'}}
(*this).A::f4(); // expected-error{{no member named 'f4' in 'N0::A'}}
(*this).B::A::f4(); // expected-error{{no member named 'f4' in 'N0::A'}}

b.x4; // expected-error{{no member named 'x4' in 'B<T>'}}
b.B::x4; // expected-error{{no member named 'x4' in 'B<T>'}}
Expand Down Expand Up @@ -399,15 +396,13 @@ namespace N1 {
f<0>();
this->f<0>();
a->f<0>();
// FIXME: This should not require 'template'!
(*this).f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
(*this).f<0>();
b.f<0>();

x.f<0>();
this->x.f<0>();
a->x.f<0>();
// FIXME: This should not require 'template'!
(*this).x.f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
(*this).x.f<0>();
b.x.f<0>();

// FIXME: None of these should require 'template'!
Expand Down
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"
4 changes: 2 additions & 2 deletions clang/test/Frontend/noderef_templates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
#define NODEREF __attribute__((noderef))

template <typename T>
int func(T NODEREF *a) { // expected-note 2 {{a declared here}}
return *a + 1; // expected-warning 2 {{dereferencing a; was declared with a 'noderef' type}}
int func(T NODEREF *a) { // expected-note 3 {{a declared here}}
return *a + 1; // expected-warning 3 {{dereferencing a; was declared with a 'noderef' type}}
}

void func() {
Expand Down
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
13 changes: 12 additions & 1 deletion clang/test/Sema/compound-literal.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ int main(int argc, char **argv) {
struct Incomplete; // expected-note{{forward declaration of 'struct Incomplete'}}
struct Incomplete* I1 = &(struct Incomplete){1, 2, 3}; // expected-error {{variable has incomplete type}}
void IncompleteFunc(unsigned x) {
struct Incomplete* I2 = (struct foo[x]){1, 2, 3}; // expected-error {{variable-sized object may not be initialized}}
struct Incomplete* I2 = (struct foo[x]){1, 2, 3}; // expected-error {{compound literal cannot be of variable-length array type}}
(void){1,2,3}; // expected-error {{variable has incomplete type}}
(void(void)) { 0 }; // expected-error{{illegal initializer type 'void (void)'}}
}
Expand All @@ -42,3 +42,14 @@ int (^block)(int) = ^(int i) {
int *array = (int[]) {i, i + 2, i + 4};
return array[i];
};

// C99 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.
// So check that VLA type compound literals are rejected (see https://github.com/llvm/llvm-project/issues/89835).
void vla(int n) {
int size = 5;
(void)(int[size]){}; // expected-warning {{use of an empty initializer is a C23 extension}}
// expected-error@-1 {{compound literal cannot be of variable-length array type}}
(void)(int[size]){1}; // expected-error {{compound literal cannot be of variable-length array type}}
(void)(int[size]){1,2,3}; // expected-error {{compound literal cannot be of variable-length array type}}
(void)(int[size]){1,2,3,4,5}; // expected-error {{compound literal cannot be of variable-length array type}}
}
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}}

}
26 changes: 17 additions & 9 deletions clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,9 +135,13 @@ 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 {
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: 2 additions & 4 deletions clang/test/SemaCXX/cxx2b-deducing-this.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ struct S {
// new and delete are implicitly static
void *operator new(this unsigned long); // expected-error{{an explicit object parameter cannot appear in a static function}}
void operator delete(this void*); // expected-error{{an explicit object parameter cannot appear in a static function}}

void g(this auto) const; // expected-error{{explicit object member function cannot have 'const' qualifier}}
void h(this auto) &; // expected-error{{explicit object member function cannot have '&' qualifier}}
void i(this auto) &&; // expected-error{{explicit object member function cannot have '&&' qualifier}}
Expand Down Expand Up @@ -198,9 +198,7 @@ void func(int i) {
void TestMutationInLambda() {
[i = 0](this auto &&){ i++; }();
[i = 0](this auto){ i++; }();
[i = 0](this const auto&){ i++; }();
// expected-error@-1 {{cannot assign to a variable captured by copy in a non-mutable lambda}}
// expected-note@-2 {{in instantiation of}}
[i = 0](this const auto&){ i++; }(); // expected-error {{cannot assign to a variable captured by copy in a non-mutable lambda}}

int x;
const auto l1 = [x](this auto&) { x = 42; }; // expected-error {{cannot assign to a variable captured by copy in a non-mutable lambda}}
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());
}
12 changes: 6 additions & 6 deletions clang/test/SemaTemplate/class-template-spec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ int test_specs(A<float, float> *a1, A<float, int> *a2) {
return a1->x + a2->y;
}

int test_incomplete_specs(A<double, double> *a1,
int test_incomplete_specs(A<double, double> *a1,
A<double> *a2)
{
(void)a1->x; // expected-error{{member access into incomplete type}}
Expand All @@ -39,7 +39,7 @@ template <> struct X<int, int> { int foo(); }; // #1
template <> struct X<float> { int bar(); }; // #2

typedef int int_type;
void testme(X<int_type> *x1, X<float, int> *x2) {
void testme(X<int_type> *x1, X<float, int> *x2) {
(void)x1->foo(); // okay: refers to #1
(void)x2->bar(); // okay: refers to #2
}
Expand All @@ -53,7 +53,7 @@ struct A<char> {
A<char>::A() { }

// Make sure we can see specializations defined before the primary template.
namespace N{
namespace N{
template<typename T> struct A0;
}

Expand Down Expand Up @@ -97,7 +97,7 @@ namespace M {
template<> struct ::A<long double>; // expected-error{{must occur at global scope}}
}

template<> struct N::B<char> {
template<> struct N::B<char> {
int testf(int x) { return f(x); }
};

Expand Down Expand Up @@ -138,9 +138,9 @@ namespace PR18009 {

template <typename T> struct C {
template <int N, int M> struct S;
template <int N> struct S<N, N ? **(T(*)[N])0 : 0> {}; // expected-error {{depends on a template parameter of the partial specialization}}
template <int N> struct S<N, N ? **(T(*)[N])0 : 0> {}; // ok
};
C<int> c; // expected-note {{in instantiation of}}
C<int> c;

template<int A> struct outer {
template<int B, int C> struct inner {};
Expand Down
58 changes: 58 additions & 0 deletions clang/test/SemaTemplate/cwg2398.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,61 @@ namespace ttp_defaults {
// old-error@-2 {{template template argument has different template parameters}}
// old-error@-3 {{explicit instantiation of 'f' does not refer to a function template}}
} // 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}}
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}}

template <class ... > struct B;
template <class > struct C;
template <class, class > struct D;
template <class, class, class> struct E;

static_assert(A<B>::V == 0); // new-error {{ambiguous partial specializations}}
static_assert(A<C>::V == 1);
static_assert(A<D>::V == 2);
static_assert(A<E>::V == 0);
} // namespace ttp_only

namespace consistency {
template<class T> struct nondeduced { using type = T; };
template<class T8, class T9 = float> struct B;

namespace t1 {
template<class T1, class T2, class T3> struct A;

template<template<class, class> class TT1,
class T1, class T2, class T3, class T4>
struct A<TT1<T1, T2>, TT1<T3, T4>, typename nondeduced<TT1<T1, T2>>::type> {};

template<template<class> class UU1,
template<class> class UU2,
class U1, class U2>
struct A<UU1<U1>, UU2<U2>, typename nondeduced<UU1<U1>>::type>;

template struct A<B<int>, B<int>, B<int>>;
} // namespace t1
namespace t2 {
template<class T1, class T2, class T3> struct A;

template<template<class, class> class TT1,
class T1, class T2, class T3, class T4>
struct A<TT1<T1, T2>, TT1<T3, T4>, typename nondeduced<TT1<T1, T4>>::type> {};
// new-note@-1 {{partial specialization matches}}

template<template<class> class UU1,
template<class> class UU2,
class U1, class U2>
struct A<UU1<U1>, UU2<U2>, typename nondeduced<UU1<U1>>::type>;
// new-note@-1 {{partial specialization matches}}

template struct A<B<int>, B<int>, B<int>>;
// new-error@-1 {{ambiguous partial specializations}}
} // namespace t1
} // 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
3 changes: 2 additions & 1 deletion clang/tools/clang-format/ClangFormat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,8 @@ static void outputReplacementXML(StringRef Text) {

static void outputReplacementsXML(const Replacements &Replaces) {
for (const auto &R : Replaces) {
outs() << "<replacement " << "offset='" << R.getOffset() << "' "
outs() << "<replacement "
<< "offset='" << R.getOffset() << "' "
<< "length='" << R.getLength() << "'>";
outputReplacementXML(R.getReplacementText());
outs() << "</replacement>\n";
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
3 changes: 3 additions & 0 deletions clang/tools/driver/cc1as_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,9 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
Str.get()->emitZeros(1);
}

// Assembly to object compilation should leverage assembly info.
Str->setUseAssemblerInfoForParsing(true);

bool Failed = false;

std::unique_ptr<MCAsmParser> Parser(
Expand Down
6 changes: 3 additions & 3 deletions clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1572,9 +1572,9 @@ TEST_P(ASTMatchersTest, IsArrow_MatchesMemberVariablesViaArrow) {
EXPECT_TRUE(
matches("template <class T> class Y { void x() { this->m; } int m; };",
memberExpr(isArrow())));
EXPECT_TRUE(
notMatches("template <class T> class Y { void x() { (*this).m; } };",
cxxDependentScopeMemberExpr(isArrow())));
EXPECT_TRUE(notMatches(
"template <class T> class Y { void x() { (*this).m; } int m; };",
memberExpr(isArrow())));
}

TEST_P(ASTMatchersTest, IsArrow_MatchesStaticMemberVariablesViaArrow) {
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
4 changes: 4 additions & 0 deletions flang/include/flang/Lower/LoweringOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,9 @@ ENUM_LOWERINGOPT(NoPPCNativeVecElemOrder, unsigned, 1, 0)
/// On by default.
ENUM_LOWERINGOPT(Underscoring, unsigned, 1, 1)

/// If true, add nsw flags to loop variable increments.
/// Off by default.
ENUM_LOWERINGOPT(NSWOnLoopVarInc, unsigned, 1, 0)

#undef LOWERINGOPT
#undef ENUM_LOWERINGOPT
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#ifndef OPTIMIZER_CODEGEN_CGOPS_H
#define OPTIMIZER_CODEGEN_CGOPS_H

#include "flang/Optimizer/Dialect/FIRAttr.h"
#include "flang/Optimizer/Dialect/FIRType.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"

Expand Down
34 changes: 34 additions & 0 deletions flang/include/flang/Optimizer/CodeGen/CGOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

include "mlir/IR/SymbolInterfaces.td"
include "flang/Optimizer/Dialect/FIRTypes.td"
include "flang/Optimizer/Dialect/FIRAttr.td"
include "mlir/IR/BuiltinAttributes.td"

def fircg_Dialect : Dialect {
let name = "fircg";
Expand Down Expand Up @@ -202,4 +204,36 @@ def fircg_XArrayCoorOp : fircg_Op<"ext_array_coor", [AttrSizedOperandSegments]>
}];
}

// Extended Declare operation.
def fircg_XDeclareOp : fircg_Op<"ext_declare", [AttrSizedOperandSegments]> {
let summary = "for internal conversion only";

let description = [{
Prior to lowering to LLVM IR dialect, a DeclareOp will
be converted to an extended DeclareOp.
}];

let arguments = (ins
AnyRefOrBox:$memref,
Variadic<AnyIntegerType>:$shape,
Variadic<AnyIntegerType>:$shift,
Variadic<AnyIntegerType>:$typeparams,
Optional<fir_DummyScopeType>:$dummy_scope,
Builtin_StringAttr:$uniq_name
);
let results = (outs AnyRefOrBox);

let assemblyFormat = [{
$memref (`(` $shape^ `)`)? (`origin` $shift^)? (`typeparams` $typeparams^)?
(`dummy_scope` $dummy_scope^)?
attr-dict `:` functional-type(operands, results)
}];

let extraClassDeclaration = [{
// Shape is optional, but if it exists, it will be at offset 1.
unsigned shapeOffset() { return 1; }
unsigned shiftOffset() { return shapeOffset() + getShape().size(); }
}];
}

#endif
4 changes: 4 additions & 0 deletions flang/include/flang/Optimizer/CodeGen/CGPasses.td
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ def CodeGenRewrite : Pass<"cg-rewrite", "mlir::ModuleOp"> {
let dependentDialects = [
"fir::FIROpsDialect", "fir::FIRCodeGenDialect"
];
let options = [
Option<"preserveDeclare", "preserve-declare", "bool", /*default=*/"false",
"Preserve DeclareOp during pre codegen re-write.">
];
let statistics = [
Statistic<"numDCE", "num-dce'd", "Number of operations eliminated">
];
Expand Down
Loading