364 changes: 261 additions & 103 deletions clang/docs/LibASTMatchersReference.html

Large diffs are not rendered by default.

20 changes: 19 additions & 1 deletion clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,14 @@ C++ Specific Potentially Breaking Changes
- The behavior controlled by the `-frelaxed-template-template-args` flag is now
on by default, and the flag is deprecated. Until the flag is finally removed,
it's negative spelling can be used to obtain compatibility with previous
versions of clang.
versions of clang. The deprecation warning for the negative spelling can be
disabled with `-Wno-deprecated-no-relaxed-template-template-args`.

- Clang now rejects pointer to member from parenthesized expression in unevaluated context such as ``decltype(&(foo::bar))``. (#GH40906).

- Clang now performs semantic analysis for unary operators with dependent operands
that are known to be of non-class non-enumeration type prior to instantiation.

ABI Changes in This Version
---------------------------
- Fixed Microsoft name mangling of implicitly defined variables used for thread
Expand Down Expand Up @@ -114,6 +118,9 @@ Clang Frontend Potentially Breaking Changes
$ clang --target=<your target triple> -print-target-triple
<the normalized target triple>

- The ``hasTypeLoc`` AST matcher will no longer match a ``classTemplateSpecializationDecl``;
existing uses should switch to ``templateArgumentLoc`` or ``hasAnyTemplateArgumentLoc`` instead.

What's New in Clang |release|?
==============================
Some of the major new features and improvements to Clang are listed
Expand Down Expand Up @@ -487,6 +494,9 @@ Improvements to Clang's diagnostics
Improvements to Clang's time-trace
----------------------------------

- Clang now specifies that using ``auto`` in a lambda parameter is a C++14 extension when
appropriate. (`#46059: <https://github.com/llvm/llvm-project/issues/46059>`_).

Bug Fixes in This Version
-------------------------
- Clang's ``-Wundefined-func-template`` no longer warns on pure virtual
Expand Down Expand Up @@ -563,6 +573,9 @@ Bug Fixes in This Version
- Clang will no longer emit a duplicate -Wunused-value warning for an expression
`(A, B)` which evaluates to glvalue `B` that can be converted to non ODR-use. (#GH45783)

- Clang now correctly disallows VLA type compound literals, e.g. ``(int[size]){}``,
as the C standard mandates. (#GH89835)

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -710,11 +723,16 @@ Bug Fixes to C++ Support
- Correctly treat the compound statement of an ``if consteval`` as an immediate context. Fixes (#GH91509).
- When partial ordering alias templates against template template parameters,
allow pack expansions when the alias has a fixed-size parameter list. Fixes (#GH62529).
- Clang now ignores template parameters only used within the exception specification of candidate function
templates during partial ordering when deducing template arguments from a function declaration or when
taking the address of a function template.
- Fix a bug with checking constrained non-type template parameters for equivalence. Fixes (#GH77377).

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
- Clang now properly preserves ``FoundDecls`` within a ``ConceptReference``. (#GH82628)
- The presence of the ``typename`` keyword is now stored in ``TemplateTemplateParmDecl``.
- Fixed malformed AST generated for anonymous union access in templates. (#GH90842)

Miscellaneous Bug Fixes
^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
226 changes: 97 additions & 129 deletions clang/include/clang/AST/DeclTemplate.h

Large diffs are not rendered by default.

55 changes: 36 additions & 19 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -736,13 +736,27 @@ bool RecursiveASTVisitor<Derived>::TraverseDecl(Decl *D) {

// As a syntax visitor, by default we want to ignore declarations for
// implicit declarations (ones not typed explicitly by the user).
if (!getDerived().shouldVisitImplicitCode() && D->isImplicit()) {
// For an implicit template type parameter, its type constraints are not
// implicit and are not represented anywhere else. We still need to visit
// them.
if (auto *TTPD = dyn_cast<TemplateTypeParmDecl>(D))
return TraverseTemplateTypeParamDeclConstraints(TTPD);
return true;
if (!getDerived().shouldVisitImplicitCode()) {
if (D->isImplicit()) {
// For an implicit template type parameter, its type constraints are not
// implicit and are not represented anywhere else. We still need to visit
// them.
if (auto *TTPD = dyn_cast<TemplateTypeParmDecl>(D))
return TraverseTemplateTypeParamDeclConstraints(TTPD);
return true;
}

// Deduction guides for alias templates are always synthesized, so they
// should not be traversed unless shouldVisitImplicitCode() returns true.
//
// It's important to note that checking the implicit bit is not efficient
// for the alias case. For deduction guides synthesized from explicit
// user-defined deduction guides, we must maintain the explicit bit to
// ensure correct overload resolution.
if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
if (llvm::isa_and_present<TypeAliasTemplateDecl>(
FTD->getDeclName().getCXXDeductionGuideTemplate()))
return true;
}

switch (D->getKind()) {
Expand Down Expand Up @@ -2030,6 +2044,15 @@ DEF_TRAVERSE_DECL(RecordDecl, { TRY_TO(TraverseRecordHelper(D)); })

DEF_TRAVERSE_DECL(CXXRecordDecl, { TRY_TO(TraverseCXXRecordHelper(D)); })

template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
const TemplateArgumentLoc *TAL, unsigned Count) {
for (unsigned I = 0; I < Count; ++I) {
TRY_TO(TraverseTemplateArgumentLoc(TAL[I]));
}
return true;
}

#define DEF_TRAVERSE_TMPL_SPEC_DECL(TMPLDECLKIND, DECLKIND) \
DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateSpecializationDecl, { \
/* For implicit instantiations ("set<int> x;"), we don't want to \
Expand All @@ -2039,9 +2062,12 @@ DEF_TRAVERSE_DECL(CXXRecordDecl, { TRY_TO(TraverseCXXRecordHelper(D)); })
TemplateSpecializationType). For explicit instantiations \
("template set<int>;"), we do need a callback, since this \
is the only callback that's made for this instantiation. \
We use getTypeAsWritten() to distinguish. */ \
if (TypeSourceInfo *TSI = D->getTypeAsWritten()) \
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); \
We use getTemplateArgsAsWritten() to distinguish. */ \
if (const auto *ArgsWritten = D->getTemplateArgsAsWritten()) { \
/* The args that remains unspecialized. */ \
TRY_TO(TraverseTemplateArgumentLocsHelper( \
ArgsWritten->getTemplateArgs(), ArgsWritten->NumTemplateArgs)); \
} \
\
if (getDerived().shouldVisitTemplateInstantiations() || \
D->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { \
Expand All @@ -2061,15 +2087,6 @@ DEF_TRAVERSE_DECL(CXXRecordDecl, { TRY_TO(TraverseCXXRecordHelper(D)); })
DEF_TRAVERSE_TMPL_SPEC_DECL(Class, CXXRecord)
DEF_TRAVERSE_TMPL_SPEC_DECL(Var, Var)

template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
const TemplateArgumentLoc *TAL, unsigned Count) {
for (unsigned I = 0; I < Count; ++I) {
TRY_TO(TraverseTemplateArgumentLoc(TAL[I]));
}
return true;
}

#define DEF_TRAVERSE_TMPL_PART_SPEC_DECL(TMPLDECLKIND, DECLKIND) \
DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplatePartialSpecializationDecl, { \
/* The partial specialization. */ \
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -8044,7 +8044,10 @@ inline bool Type::isUndeducedType() const {
/// Determines whether this is a type for which one can define
/// an overloaded operator.
inline bool Type::isOverloadableType() const {
return isDependentType() || isRecordType() || isEnumeralType();
if (!CanonicalType->isDependentType())
return isRecordType() || isEnumeralType();
return !isArrayType() && !isFunctionType() && !isAnyPointerType() &&
!isMemberPointerType();
}

/// Determines whether this type is written as a typedef-name.
Expand Down
6 changes: 3 additions & 3 deletions clang/include/clang/AST/VTTBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class VTTBuilder {
using AddressPointsMapTy = llvm::DenseMap<BaseSubobject, uint64_t>;

/// The sub-VTT indices for the bases of the most derived class.
llvm::DenseMap<BaseSubobject, uint64_t> SubVTTIndicies;
llvm::DenseMap<BaseSubobject, uint64_t> SubVTTIndices;

/// The secondary virtual pointer indices of all subobjects of
/// the most derived class.
Expand Down Expand Up @@ -148,8 +148,8 @@ class VTTBuilder {
}

/// Returns a reference to the sub-VTT indices.
const llvm::DenseMap<BaseSubobject, uint64_t> &getSubVTTIndicies() const {
return SubVTTIndicies;
const llvm::DenseMap<BaseSubobject, uint64_t> &getSubVTTIndices() const {
return SubVTTIndices;
}

/// Returns a reference to the secondary virtual pointer indices.
Expand Down
74 changes: 41 additions & 33 deletions clang/include/clang/ASTMatchers/ASTMatchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -764,9 +764,9 @@ AST_POLYMORPHIC_MATCHER(isImplicit,
return Node.isImplicit();
}

/// Matches classTemplateSpecializations, templateSpecializationType and
/// functionDecl that have at least one TemplateArgument matching the given
/// InnerMatcher.
/// Matches templateSpecializationTypes, class template specializations,
/// variable template specializations, and function template specializations
/// that have at least one TemplateArgument matching the given InnerMatcher.
///
/// Given
/// \code
Expand All @@ -788,8 +788,8 @@ AST_POLYMORPHIC_MATCHER(isImplicit,
AST_POLYMORPHIC_MATCHER_P(
hasAnyTemplateArgument,
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
TemplateSpecializationType,
FunctionDecl),
VarTemplateSpecializationDecl, FunctionDecl,
TemplateSpecializationType),
internal::Matcher<TemplateArgument>, InnerMatcher) {
ArrayRef<TemplateArgument> List =
internal::getTemplateSpecializationArgs(Node);
Expand Down Expand Up @@ -1047,8 +1047,9 @@ AST_MATCHER(Expr, isTypeDependent) { return Node.isTypeDependent(); }
/// expr(isValueDependent()) matches return Size
AST_MATCHER(Expr, isValueDependent) { return Node.isValueDependent(); }

/// Matches classTemplateSpecializations, templateSpecializationType and
/// functionDecl where the n'th TemplateArgument matches the given InnerMatcher.
/// Matches templateSpecializationType, class template specializations,
/// variable template specializations, and function template specializations
/// where the n'th TemplateArgument matches the given InnerMatcher.
///
/// Given
/// \code
Expand All @@ -1068,8 +1069,8 @@ AST_MATCHER(Expr, isValueDependent) { return Node.isValueDependent(); }
AST_POLYMORPHIC_MATCHER_P2(
hasTemplateArgument,
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
TemplateSpecializationType,
FunctionDecl),
VarTemplateSpecializationDecl, FunctionDecl,
TemplateSpecializationType),
unsigned, N, internal::Matcher<TemplateArgument>, InnerMatcher) {
ArrayRef<TemplateArgument> List =
internal::getTemplateSpecializationArgs(Node);
Expand Down Expand Up @@ -4066,7 +4067,7 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
/// Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
/// Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>,
/// Matcher<CXXUnresolvedConstructExpr>,
/// Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>,
/// Matcher<CompoundLiteralExpr>,
/// Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>,
/// Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>,
/// Matcher<TypedefNameDecl>
Expand All @@ -4075,9 +4076,8 @@ AST_POLYMORPHIC_MATCHER_P(
AST_POLYMORPHIC_SUPPORTED_TYPES(
BlockDecl, CXXBaseSpecifier, CXXCtorInitializer, CXXFunctionalCastExpr,
CXXNewExpr, CXXTemporaryObjectExpr, CXXUnresolvedConstructExpr,
ClassTemplateSpecializationDecl, CompoundLiteralExpr, DeclaratorDecl,
ExplicitCastExpr, ObjCPropertyDecl, TemplateArgumentLoc,
TypedefNameDecl),
CompoundLiteralExpr, DeclaratorDecl, ExplicitCastExpr, ObjCPropertyDecl,
TemplateArgumentLoc, TypedefNameDecl),
internal::Matcher<TypeLoc>, Inner) {
TypeSourceInfo *source = internal::GetTypeSourceInfo(Node);
if (source == nullptr) {
Expand Down Expand Up @@ -5304,9 +5304,10 @@ AST_POLYMORPHIC_MATCHER_P(parameterCountIs,
return Node.getNumParams() == N;
}

/// Matches classTemplateSpecialization, templateSpecializationType and
/// functionDecl nodes where the template argument matches the inner matcher.
/// This matcher may produce multiple matches.
/// Matches templateSpecializationType, class template specialization,
/// variable template specialization, and function template specialization
/// nodes where the template argument matches the inner matcher. This matcher
/// may produce multiple matches.
///
/// Given
/// \code
Expand All @@ -5330,7 +5331,8 @@ AST_POLYMORPHIC_MATCHER_P(parameterCountIs,
AST_POLYMORPHIC_MATCHER_P(
forEachTemplateArgument,
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
TemplateSpecializationType, FunctionDecl),
VarTemplateSpecializationDecl, FunctionDecl,
TemplateSpecializationType),
internal::Matcher<TemplateArgument>, InnerMatcher) {
ArrayRef<TemplateArgument> TemplateArgs =
clang::ast_matchers::internal::getTemplateSpecializationArgs(Node);
Expand Down Expand Up @@ -6905,8 +6907,10 @@ extern const internal::VariadicDynCastAllOfMatcher<
TypeLoc, TemplateSpecializationTypeLoc>
templateSpecializationTypeLoc;

/// Matches template specialization `TypeLoc`s that have at least one
/// `TemplateArgumentLoc` matching the given `InnerMatcher`.
/// Matches template specialization `TypeLoc`s, class template specializations,
/// variable template specializations, and function template specializations
/// that have at least one `TemplateArgumentLoc` matching the given
/// `InnerMatcher`.
///
/// Given
/// \code
Expand All @@ -6916,20 +6920,21 @@ extern const internal::VariadicDynCastAllOfMatcher<
/// varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
/// hasTypeLoc(loc(asString("int")))))))
/// matches `A<int> a`.
AST_MATCHER_P(TemplateSpecializationTypeLoc, hasAnyTemplateArgumentLoc,
internal::Matcher<TemplateArgumentLoc>, InnerMatcher) {
for (unsigned Index = 0, N = Node.getNumArgs(); Index < N; ++Index) {
clang::ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder);
if (InnerMatcher.matches(Node.getArgLoc(Index), Finder, &Result)) {
*Builder = std::move(Result);
return true;
}
}
AST_POLYMORPHIC_MATCHER_P(
hasAnyTemplateArgumentLoc,
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
VarTemplateSpecializationDecl, FunctionDecl,
DeclRefExpr, TemplateSpecializationTypeLoc),
internal::Matcher<TemplateArgumentLoc>, InnerMatcher) {
auto Args = internal::getTemplateArgsWritten(Node);
return matchesFirstInRange(InnerMatcher, Args.begin(), Args.end(), Finder,
Builder) != Args.end();
return false;
}

/// Matches template specialization `TypeLoc`s where the n'th
/// `TemplateArgumentLoc` matches the given `InnerMatcher`.
/// Matches template specialization `TypeLoc`s, class template specializations,
/// variable template specializations, and function template specializations
/// where the n'th `TemplateArgumentLoc` matches the given `InnerMatcher`.
///
/// Given
/// \code
Expand All @@ -6942,10 +6947,13 @@ AST_MATCHER_P(TemplateSpecializationTypeLoc, hasAnyTemplateArgumentLoc,
/// matches `A<double, int> b`, but not `A<int, double> c`.
AST_POLYMORPHIC_MATCHER_P2(
hasTemplateArgumentLoc,
AST_POLYMORPHIC_SUPPORTED_TYPES(DeclRefExpr, TemplateSpecializationTypeLoc),
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
VarTemplateSpecializationDecl, FunctionDecl,
DeclRefExpr, TemplateSpecializationTypeLoc),
unsigned, Index, internal::Matcher<TemplateArgumentLoc>, InnerMatcher) {
return internal::MatchTemplateArgLocAt(Node, Index, InnerMatcher, Finder,
Builder);
auto Args = internal::getTemplateArgsWritten(Node);
return Index < Args.size() &&
InnerMatcher.matches(Args[Index], Finder, Builder);
}

/// Matches C or C++ elaborated `TypeLoc`s.
Expand Down
50 changes: 45 additions & 5 deletions clang/include/clang/ASTMatchers/ASTMatchersInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,6 @@ inline TypeSourceInfo *GetTypeSourceInfo(const BlockDecl &Node) {
inline TypeSourceInfo *GetTypeSourceInfo(const CXXNewExpr &Node) {
return Node.getAllocatedTypeSourceInfo();
}
inline TypeSourceInfo *
GetTypeSourceInfo(const ClassTemplateSpecializationDecl &Node) {
return Node.getTypeAsWritten();
}

/// Unifies obtaining the FunctionProtoType pointer from both
/// FunctionProtoType and FunctionDecl nodes..
Expand Down Expand Up @@ -1939,6 +1935,11 @@ getTemplateSpecializationArgs(const ClassTemplateSpecializationDecl &D) {
return D.getTemplateArgs().asArray();
}

inline ArrayRef<TemplateArgument>
getTemplateSpecializationArgs(const VarTemplateSpecializationDecl &D) {
return D.getTemplateArgs().asArray();
}

inline ArrayRef<TemplateArgument>
getTemplateSpecializationArgs(const TemplateSpecializationType &T) {
return T.template_arguments();
Expand All @@ -1948,7 +1949,46 @@ inline ArrayRef<TemplateArgument>
getTemplateSpecializationArgs(const FunctionDecl &FD) {
if (const auto* TemplateArgs = FD.getTemplateSpecializationArgs())
return TemplateArgs->asArray();
return ArrayRef<TemplateArgument>();
return std::nullopt;
}

inline ArrayRef<TemplateArgumentLoc>
getTemplateArgsWritten(const ClassTemplateSpecializationDecl &D) {
if (const ASTTemplateArgumentListInfo *Args = D.getTemplateArgsAsWritten())
return Args->arguments();
return std::nullopt;
}

inline ArrayRef<TemplateArgumentLoc>
getTemplateArgsWritten(const VarTemplateSpecializationDecl &D) {
if (const ASTTemplateArgumentListInfo *Args = D.getTemplateArgsAsWritten())
return Args->arguments();
return std::nullopt;
}

inline ArrayRef<TemplateArgumentLoc>
getTemplateArgsWritten(const FunctionDecl &FD) {
if (const auto *Args = FD.getTemplateSpecializationArgsAsWritten())
return Args->arguments();
return std::nullopt;
}

inline ArrayRef<TemplateArgumentLoc>
getTemplateArgsWritten(const DeclRefExpr &DRE) {
if (const auto *Args = DRE.getTemplateArgs())
return {Args, DRE.getNumTemplateArgs()};
return std::nullopt;
}

inline SmallVector<TemplateArgumentLoc>
getTemplateArgsWritten(const TemplateSpecializationTypeLoc &T) {
SmallVector<TemplateArgumentLoc> Args;
if (!T.isNull()) {
Args.reserve(T.getNumArgs());
for (unsigned I = 0; I < T.getNumArgs(); ++I)
Args.emplace_back(T.getArgLoc(I));
}
return Args;
}

struct NotEqualsBoundNodePredicate {
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ class UnsafeBufferUsageHandler {
virtual void handleUnsafeOperation(const Stmt *Operation,
bool IsRelatedToDecl, ASTContext &Ctx) = 0;

/// Invoked when an unsafe operation with a std container is found.
virtual void handleUnsafeOperationInContainer(const Stmt *Operation,
bool IsRelatedToDecl,
ASTContext &Ctx) = 0;

/// Invoked when a fix is suggested against a variable. This function groups
/// all variables that must be fixed together (i.e their types must be changed
/// to the same target type to prevent type mismatches) into a single fixit.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ WARNING_GADGET(Decrement)
WARNING_GADGET(ArraySubscript)
WARNING_GADGET(PointerArithmetic)
WARNING_GADGET(UnsafeBufferUsageAttr)
WARNING_GADGET(UnsafeBufferUsageCtorAttr)
WARNING_GADGET(DataInvocation)
WARNING_CONTAINER_GADGET(SpanTwoParamConstructor) // Uses of `std::span(arg0, arg1)`
FIXABLE_GADGET(ULCArraySubscript) // `DRE[any]` in an Unspecified Lvalue Context
Expand Down
118 changes: 73 additions & 45 deletions clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "clang/AST/DeclBase.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
#include "clang/Analysis/FlowSensitive/ASTOps.h"
#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
#include "clang/Analysis/FlowSensitive/Formula.h"
Expand All @@ -30,9 +31,11 @@
#include "llvm/ADT/MapVector.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include <cassert>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>

namespace clang {
namespace dataflow {
Expand Down Expand Up @@ -155,32 +158,40 @@ class Environment {

/// Creates an environment that uses `DACtx` to store objects that encompass
/// the state of a program.
explicit Environment(DataflowAnalysisContext &DACtx);
explicit Environment(DataflowAnalysisContext &DACtx)
: DACtx(&DACtx),
FlowConditionToken(DACtx.arena().makeFlowConditionToken()) {}

/// Creates an environment that uses `DACtx` to store objects that encompass
/// the state of a program, with `S` as the statement to analyze.
Environment(DataflowAnalysisContext &DACtx, Stmt &S) : Environment(DACtx) {
InitialTargetStmt = &S;
}

/// Creates an environment that uses `DACtx` to store objects that encompass
/// the state of a program, with `FD` as the function to analyze.
///
/// Requirements:
///
/// The function must have a body, i.e.
/// `FunctionDecl::doesThisDecalarationHaveABody()` must be true.
Environment(DataflowAnalysisContext &DACtx, const FunctionDecl &FD)
: Environment(DACtx, *FD.getBody()) {
assert(FD.doesThisDeclarationHaveABody());
InitialTargetFunc = &FD;
}

// Copy-constructor is private, Environments should not be copied. See fork().
Environment &operator=(const Environment &Other) = delete;

Environment(Environment &&Other) = default;
Environment &operator=(Environment &&Other) = default;

/// Creates an environment that uses `DACtx` to store objects that encompass
/// the state of a program.
///
/// If `DeclCtx` is a function, initializes the environment with symbolic
/// representations of the function parameters.
///
/// If `DeclCtx` is a non-static member function, initializes the environment
/// with a symbolic representation of the `this` pointee.
Environment(DataflowAnalysisContext &DACtx, const DeclContext &DeclCtx);

/// Assigns storage locations and values to all parameters, captures, global
/// variables, fields and functions referenced in the function currently being
/// analyzed.
///
/// Requirements:
/// variables, fields and functions referenced in the `Stmt` or `FunctionDecl`
/// passed to the constructor.
///
/// The function must have a body, i.e.
/// `FunctionDecl::doesThisDecalarationHaveABody()` must be true.
/// If no `Stmt` or `FunctionDecl` was supplied, this function does nothing.
void initialize();

/// Returns a new environment that is a copy of this one.
Expand All @@ -193,7 +204,7 @@ class Environment {
/// forked flow condition references the original).
Environment fork() const;

/// Creates and returns an environment to use for an inline analysis of the
/// Creates and returns an environment to use for an inline analysis of the
/// callee. Uses the storage location from each argument in the `Call` as the
/// storage location for the corresponding parameter in the callee.
///
Expand Down Expand Up @@ -365,46 +376,51 @@ class Environment {
RecordStorageLocation &
getResultObjectLocation(const Expr &RecordPRValue) const;

/// Returns the return value of the current function. This can be null if:
/// Returns the return value of the function currently being analyzed.
/// This can be null if:
/// - The function has a void return type
/// - No return value could be determined for the function, for example
/// because it calls a function without a body.
///
/// Requirements:
/// The current function must have a non-reference return type.
/// The current analysis target must be a function and must have a
/// non-reference return type.
Value *getReturnValue() const {
assert(getCurrentFunc() != nullptr &&
!getCurrentFunc()->getReturnType()->isReferenceType());
return ReturnVal;
}

/// Returns the storage location for the reference returned by the current
/// function. This can be null if function doesn't return a single consistent
/// reference.
/// Returns the storage location for the reference returned by the function
/// currently being analyzed. This can be null if the function doesn't return
/// a single consistent reference.
///
/// Requirements:
/// The current function must have a reference return type.
/// The current analysis target must be a function and must have a reference
/// return type.
StorageLocation *getReturnStorageLocation() const {
assert(getCurrentFunc() != nullptr &&
getCurrentFunc()->getReturnType()->isReferenceType());
return ReturnLoc;
}

/// Sets the return value of the current function.
/// Sets the return value of the function currently being analyzed.
///
/// Requirements:
/// The current function must have a non-reference return type.
/// The current analysis target must be a function and must have a
/// non-reference return type.
void setReturnValue(Value *Val) {
assert(getCurrentFunc() != nullptr &&
!getCurrentFunc()->getReturnType()->isReferenceType());
ReturnVal = Val;
}

/// Sets the storage location for the reference returned by the current
/// function.
/// Sets the storage location for the reference returned by the function
/// currently being analyzed.
///
/// Requirements:
/// The current function must have a reference return type.
/// The current analysis target must be a function and must have a reference
/// return type.
void setReturnStorageLocation(StorageLocation *Loc) {
assert(getCurrentFunc() != nullptr &&
getCurrentFunc()->getReturnType()->isReferenceType());
Expand Down Expand Up @@ -641,23 +657,21 @@ class Environment {
/// (or the flow condition is overly constraining) or if the solver times out.
bool allows(const Formula &) const;

/// Returns the `DeclContext` of the block being analysed, if any. Otherwise,
/// returns null.
const DeclContext *getDeclCtx() const { return CallStack.back(); }

/// Returns the function currently being analyzed, or null if the code being
/// analyzed isn't part of a function.
const FunctionDecl *getCurrentFunc() const {
return dyn_cast<FunctionDecl>(getDeclCtx());
return CallStack.empty() ? InitialTargetFunc : CallStack.back();
}

/// Returns the size of the call stack.
/// Returns the size of the call stack, not counting the initial analysis
/// target.
size_t callStackSize() const { return CallStack.size(); }

/// Returns whether this `Environment` can be extended to analyze the given
/// `Callee` (i.e. if `pushCall` can be used), with recursion disallowed and a
/// given `MaxDepth`.
bool canDescend(unsigned MaxDepth, const DeclContext *Callee) const;
/// `Callee` (i.e. if `pushCall` can be used).
/// Recursion is not allowed. `MaxDepth` is the maximum size of the call stack
/// (i.e. the maximum value that `callStackSize()` may assume after the call).
bool canDescend(unsigned MaxDepth, const FunctionDecl *Callee) const;

/// Returns the `DataflowAnalysisContext` used by the environment.
DataflowAnalysisContext &getDataflowAnalysisContext() const { return *DACtx; }
Expand Down Expand Up @@ -719,15 +733,20 @@ class Environment {
ArrayRef<const Expr *> Args);

/// Assigns storage locations and values to all global variables, fields
/// and functions referenced in `FuncDecl`. `FuncDecl` must have a body.
void initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl);
/// and functions in `Referenced`.
void initFieldsGlobalsAndFuncs(const ReferencedDecls &Referenced);

static PrValueToResultObject
buildResultObjectMap(DataflowAnalysisContext *DACtx,
const FunctionDecl *FuncDecl,
RecordStorageLocation *ThisPointeeLoc,
RecordStorageLocation *LocForRecordReturnVal);

static PrValueToResultObject
buildResultObjectMap(DataflowAnalysisContext *DACtx, Stmt *S,
RecordStorageLocation *ThisPointeeLoc,
RecordStorageLocation *LocForRecordReturnVal);

// `DACtx` is not null and not owned by this object.
DataflowAnalysisContext *DACtx;

Expand All @@ -736,11 +755,20 @@ class Environment {
// shared between environments in the same call.
// https://github.com/llvm/llvm-project/issues/59005

// `DeclContext` of the block being analysed if provided.
std::vector<const DeclContext *> CallStack;
// The stack of functions called from the initial analysis target.
std::vector<const FunctionDecl *> CallStack;

// Initial function to analyze, if a function was passed to the constructor.
// Null otherwise.
const FunctionDecl *InitialTargetFunc = nullptr;
// Top-level statement of the initial analysis target.
// If a function was passed to the constructor, this is its body.
// If a statement was passed to the constructor, this is that statement.
// Null if no analysis target was passed to the constructor.
Stmt *InitialTargetStmt = nullptr;

// Maps from prvalues of record type to their result objects. Shared between
// all environments for the same function.
// all environments for the same analysis target.
// FIXME: It's somewhat unsatisfactory that we have to use a `shared_ptr`
// here, though the cost is acceptable: The overhead of a `shared_ptr` is
// incurred when it is copied, and this happens only relatively rarely (when
Expand All @@ -749,7 +777,7 @@ class Environment {
std::shared_ptr<PrValueToResultObject> ResultObjectMap;

// The following three member variables handle various different types of
// return values.
// return values when the current analysis target is a function.
// - If the return type is not a reference and not a record: Value returned
// by the function.
Value *ReturnVal = nullptr;
Expand All @@ -762,7 +790,7 @@ class Environment {
RecordStorageLocation *LocForRecordReturnVal = nullptr;

// The storage location of the `this` pointee. Should only be null if the
// function being analyzed is only a function and not a method.
// analysis target is not a method.
RecordStorageLocation *ThisPointeeLoc = nullptr;

// Maps from declarations and glvalue expression to storage locations that are
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticDriverKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,9 @@ def warn_drv_clang_unsupported : Warning<
"the clang compiler does not support '%0'">;
def warn_drv_deprecated_arg : Warning<
"argument '%0' is deprecated%select{|, use '%2' instead}1">, InGroup<Deprecated>;
def warn_drv_deprecated_arg_no_relaxed_template_template_args : Warning<
"argument '-fno-relaxed-template-template-args' is deprecated">,
InGroup<DeprecatedNoRelaxedTemplateTemplateArgs>;
def warn_drv_deprecated_custom : Warning<
"argument '%0' is deprecated, %1">, InGroup<Deprecated>;
def warn_drv_assuming_mfloat_abi_is : Warning<
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ def EnumConversion : DiagGroup<"enum-conversion",
[EnumEnumConversion,
EnumFloatConversion,
EnumCompareConditional]>;
def DeprecatedNoRelaxedTemplateTemplateArgs : DiagGroup<"deprecated-no-relaxed-template-template-args">;
def ObjCSignedCharBoolImplicitIntConversion :
DiagGroup<"objc-signed-char-bool-implicit-int-conversion">;
def Shorten64To32 : DiagGroup<"shorten-64-to-32">;
Expand Down Expand Up @@ -228,6 +229,7 @@ def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
DeprecatedLiteralOperator,
DeprecatedPragma,
DeprecatedRegister,
DeprecatedNoRelaxedTemplateTemplateArgs,
DeprecatedThisCapture,
DeprecatedType,
DeprecatedVolatile,
Expand Down
14 changes: 13 additions & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -2433,7 +2433,9 @@ def err_auto_not_allowed : Error<
"|in template parameter|in friend declaration|in function prototype that is "
"not a function declaration|in requires expression parameter"
"|in array declaration"
"|in declaration of conversion function template}1">;
"|in declaration of conversion function template"
"|in lambda parameter before C++14}1">;

def err_dependent_deduced_tst : Error<
"typename specifier refers to "
"%select{class template|function template|variable template|alias template|"
Expand Down Expand Up @@ -3003,6 +3005,8 @@ def note_single_arg_concept_specialization_constraint_evaluated_to_false : Note<
"%select{and|because}0 %1 does not satisfy %2">;
def note_atomic_constraint_evaluated_to_false_elaborated : Note<
"%select{and|because}0 '%1' (%2 %3 %4) evaluated to false">;
def note_is_deducible_constraint_evaluated_to_false : Note<
"cannot deduce template arguments for %0 from %1">;
def err_constrained_virtual_method : Error<
"virtual function cannot have a requires clause">;
def err_trailing_requires_clause_on_deduction_guide : Error<
Expand Down Expand Up @@ -3371,6 +3375,8 @@ def err_field_with_address_space : Error<
"field may not be qualified with an address space">;
def err_compound_literal_with_address_space : Error<
"compound literal in function scope may not be qualified with an address space">;
def err_compound_literal_with_vla_type : Error<
"compound literal cannot be of variable-length array type">;
def err_address_space_mismatch_templ_inst : Error<
"conflicting address space qualifiers are provided between types %0 and %1">;
def err_attr_objc_ownership_redundant : Error<
Expand Down Expand Up @@ -10035,6 +10041,12 @@ def warn_new_dangling_initializer_list : Warning<
"the allocated initializer list}0 "
"will be destroyed at the end of the full-expression">,
InGroup<DanglingInitializerList>;
def warn_unsupported_lifetime_extension : Warning<
"lifetime extension of "
"%select{temporary|backing array of initializer list}0 created "
"by aggregate initialization using a default member initializer "
"is not yet supported; lifetime of %select{temporary|backing array}0 "
"will end at the end of the full-expression">, InGroup<Dangling>;

// For non-floating point, expressions of the form x == x or x != x
// should result in a warning, since these always evaluate to a constant.
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,9 @@ TYPE_TRAIT_1(__can_pass_in_regs, CanPassInRegs, KEYCXX)
TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX)
TYPE_TRAIT_2(__reference_constructs_from_temporary, ReferenceConstructsFromTemporary, KEYCXX)
TYPE_TRAIT_2(__reference_converts_from_temporary, ReferenceConvertsFromTemporary, KEYCXX)
// IsDeducible is only used internally by clang for CTAD implementation and
// is not exposed to users.
TYPE_TRAIT_2(/*EmptySpellingName*/, IsDeducible, KEYCXX)

// Embarcadero Expression Traits
EXPRESSION_TRAIT(__is_lvalue_expr, IsLValueExpr, KEYCXX)
Expand Down
10 changes: 5 additions & 5 deletions clang/include/clang/Basic/arm_sve.td
Original file line number Diff line number Diff line change
Expand Up @@ -2095,7 +2095,7 @@ def SVFCLAMP_BF : SInst<"svclamp[_{d}]", "dddd", "b", MergeNone, "aarch64_sve_
multiclass MinMaxIntr<string i, string zm, string mul, string t> {
def SVS # NAME : SInst<"sv" # i # "[" # zm # "_{d}_" # mul # "]", t, "csil", MergeNone, "aarch64_sve_s" # i # zm # "_" # mul, [IsStreaming], []>;
def SVU # NAME : SInst<"sv" # i # "[" # zm # "_{d}_" # mul # "]", t, "UcUsUiUl", MergeNone, "aarch64_sve_u" # i # zm # "_" # mul, [IsStreaming], []>;
def SVF # NAME : SInst<"sv" # i # "[" # zm # "_{d}_" # mul # "]", t, "hfd", MergeNone, "aarch64_sve_f" # i # zm # "_" # mul, [IsStreaming], []>;
def SVF # NAME : SInst<"sv" # i # "[" # zm # "_{d}_" # mul # "]", t, "bhfd", MergeNone, "aarch64_sve_f" # i # zm # "_" # mul, [IsStreaming], []>;
}

let TargetGuard = "sme2" in {
Expand All @@ -2113,11 +2113,11 @@ let TargetGuard = "sme2" in {
}

multiclass SInstMinMaxByVector<string name> {
def NAME # _SINGLE_X2 : SInst<"sv" # name # "nm[_single_{d}_x2]", "22d", "hfd", MergeNone, "aarch64_sve_f" # name # "nm_single_x2", [IsStreaming], []>;
def NAME # _SINGLE_X4 : SInst<"sv" # name # "nm[_single_{d}_x4]", "44d", "hfd", MergeNone, "aarch64_sve_f" # name # "nm_single_x4", [IsStreaming], []>;
def NAME # _SINGLE_X2 : SInst<"sv" # name # "nm[_single_{d}_x2]", "22d", "bhfd", MergeNone, "aarch64_sve_f" # name # "nm_single_x2", [IsStreaming], []>;
def NAME # _SINGLE_X4 : SInst<"sv" # name # "nm[_single_{d}_x4]", "44d", "bhfd", MergeNone, "aarch64_sve_f" # name # "nm_single_x4", [IsStreaming], []>;

def NAME # _X2 : SInst<"sv" # name # "nm[_{d}_x2]", "222", "hfd", MergeNone, "aarch64_sve_f" # name # "nm_x2", [IsStreaming], []>;
def NAME # _X4 : SInst<"sv" # name # "nm[_{d}_x4]", "444", "hfd", MergeNone, "aarch64_sve_f" # name # "nm_x4", [IsStreaming], []>;
def NAME # _X2 : SInst<"sv" # name # "nm[_{d}_x2]", "222", "bhfd", MergeNone, "aarch64_sve_f" # name # "nm_x2", [IsStreaming], []>;
def NAME # _X4 : SInst<"sv" # name # "nm[_{d}_x4]", "444", "bhfd", MergeNone, "aarch64_sve_f" # name # "nm_x4", [IsStreaming], []>;
}

let TargetGuard = "sme2" in {
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Driver/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,9 @@ class Driver {
/// option.
void setDriverMode(StringRef DriverModeValue);

/// Set the resource directory, depending on which driver is being used.
void setResourceDirectory();

/// Parse the \p Args list for LTO options and record the type of LTO
/// compilation based on which -f(no-)?lto(=.*)? option occurs last.
void setLTOMode(const llvm::opt::ArgList &Args);
Expand Down
17 changes: 13 additions & 4 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1858,13 +1858,13 @@ defm apinotes : BoolOption<"f", "apinotes",
LangOpts<"APINotes">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption], "Enable">,
NegFlag<SetFalse, [], [ClangOption], "Disable">,
BothFlags<[], [ClangOption, CC1Option], "external API notes support">>,
BothFlags<[], [ClangOption, CC1Option], " external API notes support">>,
Group<f_clang_Group>;
defm apinotes_modules : BoolOption<"f", "apinotes-modules",
LangOpts<"APINotesModules">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption], "Enable">,
NegFlag<SetFalse, [], [ClangOption], "Disable">,
BothFlags<[], [ClangOption, CC1Option], "module-based external API notes support">>,
BothFlags<[], [ClangOption, CC1Option], " module-based external API notes support">>,
Group<f_clang_Group>;
def fapinotes_swift_version : Joined<["-"], "fapinotes-swift-version=">,
Group<f_clang_Group>, Visibility<[ClangOption, CC1Option]>,
Expand Down Expand Up @@ -5491,7 +5491,10 @@ def print_prog_name_EQ : Joined<["-", "--"], "print-prog-name=">,
Visibility<[ClangOption, CLOption]>;
def print_resource_dir : Flag<["-", "--"], "print-resource-dir">,
HelpText<"Print the resource directory pathname">,
Visibility<[ClangOption, CLOption]>;
HelpTextForVariants<[FlangOption],
"Print the resource directory pathname that contains lib and "
"include directories with the runtime libraries and MODULE files.">,
Visibility<[ClangOption, CLOption, FlangOption]>;
def print_search_dirs : Flag<["-", "--"], "print-search-dirs">,
HelpText<"Print the paths used for finding libraries and programs">,
Visibility<[ClangOption, CLOption]>;
Expand Down Expand Up @@ -6547,6 +6550,10 @@ def flang_deprecated_no_hlfir : Flag<["-"], "flang-deprecated-no-hlfir">,
Flags<[HelpHidden]>, Visibility<[FlangOption, FC1Option]>,
HelpText<"Do not use HLFIR lowering (deprecated)">;

def flang_experimental_integer_overflow : Flag<["-"], "flang-experimental-integer-overflow">,
Flags<[HelpHidden]>, Visibility<[FlangOption, FC1Option]>,
HelpText<"Add nsw flag to internal operations such as do-variable increment (experimental)">;

//===----------------------------------------------------------------------===//
// FLangOption + CoreOption + NoXarchOption
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -6644,7 +6651,9 @@ def fdebug_unparse : Flag<["-"], "fdebug-unparse">, Group<Action_Group>,
DocBrief<[{Run the parser and the semantic checks. Then unparse the
parse-tree and output the generated Fortran source file.}]>;
def fdebug_unparse_with_symbols : Flag<["-"], "fdebug-unparse-with-symbols">, Group<Action_Group>,
HelpText<"Unparse and stop.">;
HelpText<"Unparse with symbols and stop.">;
def fdebug_unparse_with_modules : Flag<["-"], "fdebug-unparse-with-modules">, Group<Action_Group>,
HelpText<"Unparse with dependent modules and stop.">;
def fdebug_dump_symbols : Flag<["-"], "fdebug-dump-symbols">, Group<Action_Group>,
HelpText<"Dump symbols after the semantic analysis">;
def fdebug_dump_parse_tree : Flag<["-"], "fdebug-dump-parse-tree">, Group<Action_Group>,
Expand Down
14 changes: 12 additions & 2 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -9133,7 +9133,7 @@ class Sema final : public SemaBase {
CheckTemplateArgumentKind CTAK);
bool CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
TemplateParameterList *Params,
TemplateArgumentLoc &Arg);
TemplateArgumentLoc &Arg, bool IsDeduced);

void NoteTemplateLocation(const NamedDecl &Decl,
std::optional<SourceRange> ParamRange = {});
Expand Down Expand Up @@ -9492,6 +9492,15 @@ class Sema final : public SemaBase {
ArrayRef<TemplateArgument> TemplateArgs,
sema::TemplateDeductionInfo &Info);

/// Deduce the template arguments of the given template from \p FromType.
/// Used to implement the IsDeducible constraint for alias CTAD per C++
/// [over.match.class.deduct]p4.
///
/// It only supports class or type alias templates.
TemplateDeductionResult
DeduceTemplateArgumentsFromType(TemplateDecl *TD, QualType FromType,
sema::TemplateDeductionInfo &Info);

TemplateDeductionResult DeduceTemplateArguments(
TemplateParameterList *TemplateParams, ArrayRef<TemplateArgument> Ps,
ArrayRef<TemplateArgument> As, sema::TemplateDeductionInfo &Info,
Expand Down Expand Up @@ -9603,7 +9612,8 @@ class Sema final : public SemaBase {
sema::TemplateDeductionInfo &Info);

bool isTemplateTemplateParameterAtLeastAsSpecializedAs(
TemplateParameterList *PParam, TemplateDecl *AArg, SourceLocation Loc);
TemplateParameterList *PParam, TemplateDecl *AArg, SourceLocation Loc,
bool IsDeduced);

void MarkUsedTemplateParameters(const Expr *E, bool OnlyDeduced,
unsigned Depth, llvm::SmallBitVector &Used);
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ namespace serialization {
/// Version 4 of AST files also requires that the version control branch and
/// revision match exactly, since there is no backward compatibility of
/// AST files at this time.
const unsigned VERSION_MAJOR = 30;
const unsigned VERSION_MAJOR = 31;

/// AST file minor version number supported by this version of
/// Clang.
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5910,7 +5910,8 @@ QualType ASTContext::getUnconstrainedType(QualType T) const {
if (auto *AT = CanonT->getAs<AutoType>()) {
if (!AT->isConstrained())
return T;
return getQualifiedType(getAutoType(QualType(), AT->getKeyword(), false,
return getQualifiedType(getAutoType(QualType(), AT->getKeyword(),
AT->isDependentType(),
AT->containsUnexpandedParameterPack()),
T.getQualifiers());
}
Expand Down
68 changes: 32 additions & 36 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -443,8 +443,9 @@ namespace clang {
Expected<FunctionTemplateAndArgsTy>
ImportFunctionTemplateWithTemplateArgsFromSpecialization(
FunctionDecl *FromFD);
Error ImportTemplateParameterLists(const DeclaratorDecl *FromD,
DeclaratorDecl *ToD);

template <typename DeclTy>
Error ImportTemplateParameterLists(const DeclTy *FromD, DeclTy *ToD);

Error ImportTemplateInformation(FunctionDecl *FromFD, FunctionDecl *ToFD);

Expand Down Expand Up @@ -3322,8 +3323,9 @@ ExpectedDecl ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) {
return ToEnumerator;
}

Error ASTNodeImporter::ImportTemplateParameterLists(const DeclaratorDecl *FromD,
DeclaratorDecl *ToD) {
template <typename DeclTy>
Error ASTNodeImporter::ImportTemplateParameterLists(const DeclTy *FromD,
DeclTy *ToD) {
unsigned int Num = FromD->getNumTemplateParameterLists();
if (Num == 0)
return Error::success();
Expand Down Expand Up @@ -6210,15 +6212,16 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
if (!IdLocOrErr)
return IdLocOrErr.takeError();

// Import TemplateArgumentListInfo.
TemplateArgumentListInfo ToTAInfo;
if (const auto *ASTTemplateArgs = D->getTemplateArgsAsWritten()) {
if (Error Err = ImportTemplateArgumentListInfo(*ASTTemplateArgs, ToTAInfo))
return std::move(Err);
}

// Create the specialization.
ClassTemplateSpecializationDecl *D2 = nullptr;
if (PartialSpec) {
// Import TemplateArgumentListInfo.
TemplateArgumentListInfo ToTAInfo;
const auto &ASTTemplateArgs = *PartialSpec->getTemplateArgsAsWritten();
if (Error Err = ImportTemplateArgumentListInfo(ASTTemplateArgs, ToTAInfo))
return std::move(Err);

QualType CanonInjType;
if (Error Err = importInto(
CanonInjType, PartialSpec->getInjectedSpecializationType()))
Expand All @@ -6228,7 +6231,7 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>(
D2, D, Importer.getToContext(), D->getTagKind(), DC, *BeginLocOrErr,
*IdLocOrErr, ToTPList, ClassTemplate,
llvm::ArrayRef(TemplateArgs.data(), TemplateArgs.size()), ToTAInfo,
llvm::ArrayRef(TemplateArgs.data(), TemplateArgs.size()),
CanonInjType,
cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl)))
return D2;
Expand Down Expand Up @@ -6276,28 +6279,27 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
else
return BraceRangeOrErr.takeError();

if (Error Err = ImportTemplateParameterLists(D, D2))
return std::move(Err);

// Import the qualifier, if any.
if (auto LocOrErr = import(D->getQualifierLoc()))
D2->setQualifierInfo(*LocOrErr);
else
return LocOrErr.takeError();

if (auto *TSI = D->getTypeAsWritten()) {
if (auto TInfoOrErr = import(TSI))
D2->setTypeAsWritten(*TInfoOrErr);
else
return TInfoOrErr.takeError();
if (D->getTemplateArgsAsWritten())
D2->setTemplateArgsAsWritten(ToTAInfo);

if (auto LocOrErr = import(D->getTemplateKeywordLoc()))
D2->setTemplateKeywordLoc(*LocOrErr);
else
return LocOrErr.takeError();
if (auto LocOrErr = import(D->getTemplateKeywordLoc()))
D2->setTemplateKeywordLoc(*LocOrErr);
else
return LocOrErr.takeError();

if (auto LocOrErr = import(D->getExternLoc()))
D2->setExternLoc(*LocOrErr);
else
return LocOrErr.takeError();
}
if (auto LocOrErr = import(D->getExternKeywordLoc()))
D2->setExternKeywordLoc(*LocOrErr);
else
return LocOrErr.takeError();

if (D->getPointOfInstantiation().isValid()) {
if (auto POIOrErr = import(D->getPointOfInstantiation()))
Expand Down Expand Up @@ -6517,22 +6519,14 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl *D2 = nullptr;

TemplateArgumentListInfo ToTAInfo;
if (const ASTTemplateArgumentListInfo *Args = D->getTemplateArgsInfo()) {
if (const auto *Args = D->getTemplateArgsAsWritten()) {
if (Error Err = ImportTemplateArgumentListInfo(*Args, ToTAInfo))
return std::move(Err);
}

using PartVarSpecDecl = VarTemplatePartialSpecializationDecl;
// Create a new specialization.
if (auto *FromPartial = dyn_cast<PartVarSpecDecl>(D)) {
// Import TemplateArgumentListInfo
TemplateArgumentListInfo ArgInfos;
const auto *FromTAArgsAsWritten = FromPartial->getTemplateArgsAsWritten();
// NOTE: FromTAArgsAsWritten and template parameter list are non-null.
if (Error Err =
ImportTemplateArgumentListInfo(*FromTAArgsAsWritten, ArgInfos))
return std::move(Err);

auto ToTPListOrErr = import(FromPartial->getTemplateParameters());
if (!ToTPListOrErr)
return ToTPListOrErr.takeError();
Expand All @@ -6541,7 +6535,7 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
if (GetImportedOrCreateDecl(ToPartial, D, Importer.getToContext(), DC,
*BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr,
VarTemplate, QualType(), nullptr,
D->getStorageClass(), TemplateArgs, ArgInfos))
D->getStorageClass(), TemplateArgs))
return ToPartial;

if (Expected<PartVarSpecDecl *> ToInstOrErr =
Expand Down Expand Up @@ -6584,7 +6578,9 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
}

D2->setSpecializationKind(D->getSpecializationKind());
D2->setTemplateArgsInfo(ToTAInfo);

if (D->getTemplateArgsAsWritten())
D2->setTemplateArgsAsWritten(ToTAInfo);

if (auto LocOrErr = import(D->getQualifierLoc()))
D2->setQualifierInfo(*LocOrErr);
Expand Down
13 changes: 10 additions & 3 deletions clang/lib/AST/ComputeDependence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,12 +375,19 @@ ExprDependence clang::computeDependence(PackExpansionExpr *E) {
}

ExprDependence clang::computeDependence(PackIndexingExpr *E) {

ExprDependence PatternDep = E->getPackIdExpression()->getDependence() &
~ExprDependence::UnexpandedPack;

ExprDependence D = E->getIndexExpr()->getDependence();
if (D & ExprDependence::TypeValueInstantiation)
D |= E->getIndexExpr()->getDependence() | PatternDep |
ExprDependence::Instantiation;

ArrayRef<Expr *> Exprs = E->getExpressions();
if (Exprs.empty())
D |= (E->getPackIdExpression()->getDependence() |
ExprDependence::TypeValueInstantiation) &
~ExprDependence::UnexpandedPack;
D |= PatternDep | ExprDependence::Instantiation;

else if (!E->getIndexExpr()->isInstantiationDependent()) {
std::optional<unsigned> Index = E->getSelectedIndex();
assert(Index && *Index < Exprs.size() && "pack index out of bound");
Expand Down
18 changes: 9 additions & 9 deletions clang/lib/AST/DeclPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1083,15 +1083,15 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
NNS->print(Out, Policy);
Out << *D;

if (auto S = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
ArrayRef<TemplateArgument> Args = S->getTemplateArgs().asArray();
if (!Policy.PrintCanonicalTypes)
if (const auto* TSI = S->getTypeAsWritten())
if (const auto *TST =
dyn_cast<TemplateSpecializationType>(TSI->getType()))
Args = TST->template_arguments();
printTemplateArguments(
Args, S->getSpecializedTemplate()->getTemplateParameters());
if (auto *S = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
const TemplateParameterList *TParams =
S->getSpecializedTemplate()->getTemplateParameters();
const ASTTemplateArgumentListInfo *TArgAsWritten =
S->getTemplateArgsAsWritten();
if (TArgAsWritten && !Policy.PrintCanonicalTypes)
printTemplateArguments(TArgAsWritten->arguments(), TParams);
else
printTemplateArguments(S->getTemplateArgs().asArray(), TParams);
}
}

Expand Down
266 changes: 167 additions & 99 deletions clang/lib/AST/DeclTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -985,41 +985,67 @@ ClassTemplateSpecializationDecl::getSpecializedTemplate() const {

SourceRange
ClassTemplateSpecializationDecl::getSourceRange() const {
if (ExplicitInfo) {
SourceLocation Begin = getTemplateKeywordLoc();
if (Begin.isValid()) {
// Here we have an explicit (partial) specialization or instantiation.
assert(getSpecializationKind() == TSK_ExplicitSpecialization ||
getSpecializationKind() == TSK_ExplicitInstantiationDeclaration ||
getSpecializationKind() == TSK_ExplicitInstantiationDefinition);
if (getExternLoc().isValid())
Begin = getExternLoc();
SourceLocation End = getBraceRange().getEnd();
if (End.isInvalid())
End = getTypeAsWritten()->getTypeLoc().getEndLoc();
return SourceRange(Begin, End);
}
// An implicit instantiation of a class template partial specialization
// uses ExplicitInfo to record the TypeAsWritten, but the source
// locations should be retrieved from the instantiation pattern.
using CTPSDecl = ClassTemplatePartialSpecializationDecl;
auto *ctpsd = const_cast<CTPSDecl *>(cast<CTPSDecl>(this));
CTPSDecl *inst_from = ctpsd->getInstantiatedFromMember();
assert(inst_from != nullptr);
return inst_from->getSourceRange();
}
else {
// No explicit info available.
switch (getSpecializationKind()) {
case TSK_Undeclared:
case TSK_ImplicitInstantiation: {
llvm::PointerUnion<ClassTemplateDecl *,
ClassTemplatePartialSpecializationDecl *>
inst_from = getInstantiatedFrom();
if (inst_from.isNull())
return getSpecializedTemplate()->getSourceRange();
if (const auto *ctd = inst_from.dyn_cast<ClassTemplateDecl *>())
return ctd->getSourceRange();
return inst_from.get<ClassTemplatePartialSpecializationDecl *>()
->getSourceRange();
Pattern = getSpecializedTemplateOrPartial();
assert(!Pattern.isNull() &&
"Class template specialization without pattern?");
if (const auto *CTPSD =
Pattern.dyn_cast<ClassTemplatePartialSpecializationDecl *>())
return CTPSD->getSourceRange();
return Pattern.get<ClassTemplateDecl *>()->getSourceRange();
}
case TSK_ExplicitSpecialization: {
SourceRange Range = CXXRecordDecl::getSourceRange();
if (const ASTTemplateArgumentListInfo *Args = getTemplateArgsAsWritten();
!isThisDeclarationADefinition() && Args)
Range.setEnd(Args->getRAngleLoc());
return Range;
}
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition: {
SourceRange Range = CXXRecordDecl::getSourceRange();
if (SourceLocation ExternKW = getExternKeywordLoc(); ExternKW.isValid())
Range.setBegin(ExternKW);
else if (SourceLocation TemplateKW = getTemplateKeywordLoc();
TemplateKW.isValid())
Range.setBegin(TemplateKW);
if (const ASTTemplateArgumentListInfo *Args = getTemplateArgsAsWritten())
Range.setEnd(Args->getRAngleLoc());
return Range;
}
}
llvm_unreachable("unhandled template specialization kind");
}

void ClassTemplateSpecializationDecl::setExternKeywordLoc(SourceLocation Loc) {
auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>();
if (!Info) {
// Don't allocate if the location is invalid.
if (Loc.isInvalid())
return;
Info = new (getASTContext()) ExplicitInstantiationInfo;
Info->TemplateArgsAsWritten = getTemplateArgsAsWritten();
ExplicitInfo = Info;
}
Info->ExternKeywordLoc = Loc;
}

void ClassTemplateSpecializationDecl::setTemplateKeywordLoc(
SourceLocation Loc) {
auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>();
if (!Info) {
// Don't allocate if the location is invalid.
if (Loc.isInvalid())
return;
Info = new (getASTContext()) ExplicitInstantiationInfo;
Info->TemplateArgsAsWritten = getTemplateArgsAsWritten();
ExplicitInfo = Info;
}
Info->TemplateKeywordLoc = Loc;
}

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1087,43 +1113,29 @@ void ImplicitConceptSpecializationDecl::setTemplateArguments(
//===----------------------------------------------------------------------===//
void ClassTemplatePartialSpecializationDecl::anchor() {}

ClassTemplatePartialSpecializationDecl::
ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK,
DeclContext *DC,
SourceLocation StartLoc,
SourceLocation IdLoc,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
ArrayRef<TemplateArgument> Args,
const ASTTemplateArgumentListInfo *ArgInfos,
ClassTemplatePartialSpecializationDecl *PrevDecl)
: ClassTemplateSpecializationDecl(Context,
ClassTemplatePartialSpecialization,
TK, DC, StartLoc, IdLoc,
SpecializedTemplate, Args, PrevDecl),
TemplateParams(Params), ArgsAsWritten(ArgInfos),
InstantiatedFromMember(nullptr, false) {
ClassTemplatePartialSpecializationDecl::ClassTemplatePartialSpecializationDecl(
ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
ClassTemplatePartialSpecializationDecl *PrevDecl)
: ClassTemplateSpecializationDecl(
Context, ClassTemplatePartialSpecialization, TK, DC, StartLoc, IdLoc,
SpecializedTemplate, Args, PrevDecl),
TemplateParams(Params), InstantiatedFromMember(nullptr, false) {
if (AdoptTemplateParameterList(Params, this))
setInvalidDecl();
}

ClassTemplatePartialSpecializationDecl *
ClassTemplatePartialSpecializationDecl::
Create(ASTContext &Context, TagKind TK,DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
ArrayRef<TemplateArgument> Args,
const TemplateArgumentListInfo &ArgInfos,
QualType CanonInjectedType,
ClassTemplatePartialSpecializationDecl *PrevDecl) {
const ASTTemplateArgumentListInfo *ASTArgInfos =
ASTTemplateArgumentListInfo::Create(Context, ArgInfos);

auto *Result = new (Context, DC)
ClassTemplatePartialSpecializationDecl(Context, TK, DC, StartLoc, IdLoc,
Params, SpecializedTemplate, Args,
ASTArgInfos, PrevDecl);
ClassTemplatePartialSpecializationDecl::Create(
ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
QualType CanonInjectedType,
ClassTemplatePartialSpecializationDecl *PrevDecl) {
auto *Result = new (Context, DC) ClassTemplatePartialSpecializationDecl(
Context, TK, DC, StartLoc, IdLoc, Params, SpecializedTemplate, Args,
PrevDecl);
Result->setSpecializationKind(TSK_ExplicitSpecialization);
Result->setMayHaveOutOfDateDef(false);

Expand All @@ -1139,6 +1151,18 @@ ClassTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C,
return Result;
}

SourceRange ClassTemplatePartialSpecializationDecl::getSourceRange() const {
if (const ClassTemplatePartialSpecializationDecl *MT =
getInstantiatedFromMember();
MT && !isMemberSpecialization())
return MT->getSourceRange();
SourceRange Range = ClassTemplateSpecializationDecl::getSourceRange();
if (const TemplateParameterList *TPL = getTemplateParameters();
TPL && !getNumTemplateParameterLists())
Range.setBegin(TPL->getTemplateLoc());
return Range;
}

//===----------------------------------------------------------------------===//
// FriendTemplateDecl Implementation
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1371,27 +1395,74 @@ VarTemplateDecl *VarTemplateSpecializationDecl::getSpecializedTemplate() const {
return SpecializedTemplate.get<VarTemplateDecl *>();
}

void VarTemplateSpecializationDecl::setTemplateArgsInfo(
const TemplateArgumentListInfo &ArgsInfo) {
TemplateArgsInfo =
ASTTemplateArgumentListInfo::Create(getASTContext(), ArgsInfo);
}

void VarTemplateSpecializationDecl::setTemplateArgsInfo(
const ASTTemplateArgumentListInfo *ArgsInfo) {
TemplateArgsInfo =
ASTTemplateArgumentListInfo::Create(getASTContext(), ArgsInfo);
}

SourceRange VarTemplateSpecializationDecl::getSourceRange() const {
if (isExplicitSpecialization() && !hasInit()) {
if (const ASTTemplateArgumentListInfo *Info = getTemplateArgsInfo())
return SourceRange(getOuterLocStart(), Info->getRAngleLoc());
switch (getSpecializationKind()) {
case TSK_Undeclared:
case TSK_ImplicitInstantiation: {
llvm::PointerUnion<VarTemplateDecl *,
VarTemplatePartialSpecializationDecl *>
Pattern = getSpecializedTemplateOrPartial();
assert(!Pattern.isNull() &&
"Variable template specialization without pattern?");
if (const auto *VTPSD =
Pattern.dyn_cast<VarTemplatePartialSpecializationDecl *>())
return VTPSD->getSourceRange();
VarTemplateDecl *VTD = Pattern.get<VarTemplateDecl *>();
if (hasInit()) {
if (VarTemplateDecl *Definition = VTD->getDefinition())
return Definition->getSourceRange();
}
return VTD->getCanonicalDecl()->getSourceRange();
}
case TSK_ExplicitSpecialization: {
SourceRange Range = VarDecl::getSourceRange();
if (const ASTTemplateArgumentListInfo *Args = getTemplateArgsAsWritten();
!hasInit() && Args)
Range.setEnd(Args->getRAngleLoc());
return Range;
}
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition: {
SourceRange Range = VarDecl::getSourceRange();
if (SourceLocation ExternKW = getExternKeywordLoc(); ExternKW.isValid())
Range.setBegin(ExternKW);
else if (SourceLocation TemplateKW = getTemplateKeywordLoc();
TemplateKW.isValid())
Range.setBegin(TemplateKW);
if (const ASTTemplateArgumentListInfo *Args = getTemplateArgsAsWritten())
Range.setEnd(Args->getRAngleLoc());
return Range;
}
return VarDecl::getSourceRange();
}
llvm_unreachable("unhandled template specialization kind");
}

void VarTemplateSpecializationDecl::setExternKeywordLoc(SourceLocation Loc) {
auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>();
if (!Info) {
// Don't allocate if the location is invalid.
if (Loc.isInvalid())
return;
Info = new (getASTContext()) ExplicitInstantiationInfo;
Info->TemplateArgsAsWritten = getTemplateArgsAsWritten();
ExplicitInfo = Info;
}
Info->ExternKeywordLoc = Loc;
}

void VarTemplateSpecializationDecl::setTemplateKeywordLoc(SourceLocation Loc) {
auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>();
if (!Info) {
// Don't allocate if the location is invalid.
if (Loc.isInvalid())
return;
Info = new (getASTContext()) ExplicitInstantiationInfo;
Info->TemplateArgsAsWritten = getTemplateArgsAsWritten();
ExplicitInfo = Info;
}
Info->TemplateKeywordLoc = Loc;
}


//===----------------------------------------------------------------------===//
// VarTemplatePartialSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
Expand All @@ -1402,13 +1473,11 @@ VarTemplatePartialSpecializationDecl::VarTemplatePartialSpecializationDecl(
ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
StorageClass S, ArrayRef<TemplateArgument> Args,
const ASTTemplateArgumentListInfo *ArgInfos)
StorageClass S, ArrayRef<TemplateArgument> Args)
: VarTemplateSpecializationDecl(VarTemplatePartialSpecialization, Context,
DC, StartLoc, IdLoc, SpecializedTemplate, T,
TInfo, S, Args),
TemplateParams(Params), ArgsAsWritten(ArgInfos),
InstantiatedFromMember(nullptr, false) {
TemplateParams(Params), InstantiatedFromMember(nullptr, false) {
if (AdoptTemplateParameterList(Params, DC))
setInvalidDecl();
}
Expand All @@ -1418,15 +1487,10 @@ VarTemplatePartialSpecializationDecl::Create(
ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
StorageClass S, ArrayRef<TemplateArgument> Args,
const TemplateArgumentListInfo &ArgInfos) {
const ASTTemplateArgumentListInfo *ASTArgInfos
= ASTTemplateArgumentListInfo::Create(Context, ArgInfos);

auto *Result =
new (Context, DC) VarTemplatePartialSpecializationDecl(
Context, DC, StartLoc, IdLoc, Params, SpecializedTemplate, T, TInfo,
S, Args, ASTArgInfos);
StorageClass S, ArrayRef<TemplateArgument> Args) {
auto *Result = new (Context, DC) VarTemplatePartialSpecializationDecl(
Context, DC, StartLoc, IdLoc, Params, SpecializedTemplate, T, TInfo, S,
Args);
Result->setSpecializationKind(TSK_ExplicitSpecialization);
return Result;
}
Expand All @@ -1438,11 +1502,15 @@ VarTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C,
}

SourceRange VarTemplatePartialSpecializationDecl::getSourceRange() const {
if (isExplicitSpecialization() && !hasInit()) {
if (const ASTTemplateArgumentListInfo *Info = getTemplateArgsAsWritten())
return SourceRange(getOuterLocStart(), Info->getRAngleLoc());
}
return VarDecl::getSourceRange();
if (const VarTemplatePartialSpecializationDecl *MT =
getInstantiatedFromMember();
MT && !isMemberSpecialization())
return MT->getSourceRange();
SourceRange Range = VarTemplateSpecializationDecl::getSourceRange();
if (const TemplateParameterList *TPL = getTemplateParameters();
TPL && !getNumTemplateParameterLists())
Range.setBegin(TPL->getTemplateLoc());
return Range;
}

static TemplateParameterList *
Expand Down
98 changes: 98 additions & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2488,6 +2488,94 @@ bool ByteCodeExprGen<Emitter>::VisitRecoveryExpr(const RecoveryExpr *E) {
return this->emitError(E);
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitAddrLabelExpr(const AddrLabelExpr *E) {
assert(E->getType()->isVoidPointerType());

unsigned Offset = allocateLocalPrimitive(
E->getLabel(), PT_Ptr, /*IsConst=*/true, /*IsExtended=*/false);

return this->emitGetLocal(PT_Ptr, Offset, E);
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitConvertVectorExpr(
const ConvertVectorExpr *E) {
assert(Initializing);
const auto *VT = E->getType()->castAs<VectorType>();
QualType ElemType = VT->getElementType();
PrimType ElemT = classifyPrim(ElemType);
const Expr *Src = E->getSrcExpr();
PrimType SrcElemT =
classifyPrim(Src->getType()->castAs<VectorType>()->getElementType());

unsigned SrcOffset = this->allocateLocalPrimitive(Src, PT_Ptr, true, false);
if (!this->visit(Src))
return false;
if (!this->emitSetLocal(PT_Ptr, SrcOffset, E))
return false;

for (unsigned I = 0; I != VT->getNumElements(); ++I) {
if (!this->emitGetLocal(PT_Ptr, SrcOffset, E))
return false;
if (!this->emitArrayElemPop(SrcElemT, I, E))
return false;
if (SrcElemT != ElemT) {
if (!this->emitPrimCast(SrcElemT, ElemT, ElemType, E))
return false;
}
if (!this->emitInitElem(ElemT, I, E))
return false;
}

return true;
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitShuffleVectorExpr(
const ShuffleVectorExpr *E) {
assert(Initializing);
assert(E->getNumSubExprs() > 2);

const Expr *Vecs[] = {E->getExpr(0), E->getExpr(1)};
assert(Vecs[0]->getType() == Vecs[1]->getType());

const VectorType *VT = Vecs[0]->getType()->castAs<VectorType>();
PrimType ElemT = classifyPrim(VT->getElementType());
unsigned NumInputElems = VT->getNumElements();
unsigned NumOutputElems = E->getNumSubExprs() - 2;
assert(NumOutputElems > 0);

// Save both input vectors to a local variable.
unsigned VectorOffsets[2];
for (unsigned I = 0; I != 2; ++I) {
VectorOffsets[I] = this->allocateLocalPrimitive(
Vecs[I], PT_Ptr, /*IsConst=*/true, /*IsExtended=*/false);
if (!this->visit(Vecs[I]))
return false;
if (!this->emitSetLocal(PT_Ptr, VectorOffsets[I], E))
return false;
}
for (unsigned I = 0; I != NumOutputElems; ++I) {
APSInt ShuffleIndex = E->getShuffleMaskIdx(Ctx.getASTContext(), I);
if (ShuffleIndex == -1)
return this->emitInvalid(E); // FIXME: Better diagnostic.

assert(ShuffleIndex < (NumInputElems * 2));
if (!this->emitGetLocal(PT_Ptr,
VectorOffsets[ShuffleIndex >= NumInputElems], E))
return false;
unsigned InputVectorIndex = ShuffleIndex.getZExtValue() % NumInputElems;
if (!this->emitArrayElemPop(ElemT, InputVectorIndex, E))
return false;

if (!this->emitInitElem(ElemT, I, E))
return false;
}

return true;
}

template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/true,
/*NewInitializing=*/false);
Expand Down Expand Up @@ -3675,12 +3763,22 @@ bool ByteCodeExprGen<Emitter>::emitPrimCast(PrimType FromT, PrimType ToT,
return this->emitCastFP(ToSem, getRoundingMode(E), E);
}

if (ToT == PT_IntAP)
return this->emitCastFloatingIntegralAP(Ctx.getBitWidth(ToQT), E);
if (ToT == PT_IntAPS)
return this->emitCastFloatingIntegralAPS(Ctx.getBitWidth(ToQT), E);

// Float to integral.
if (isIntegralType(ToT) || ToT == PT_Bool)
return this->emitCastFloatingIntegral(ToT, E);
}

if (isIntegralType(FromT) || FromT == PT_Bool) {
if (ToT == PT_IntAP)
return this->emitCastAP(FromT, Ctx.getBitWidth(ToQT), E);
if (ToT == PT_IntAPS)
return this->emitCastAPS(FromT, Ctx.getBitWidth(ToQT), E);

// Integral to integral.
if (isIntegralType(ToT) || ToT == PT_Bool)
return FromT != ToT ? this->emitCast(FromT, ToT, E) : true;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
bool VisitPseudoObjectExpr(const PseudoObjectExpr *E);
bool VisitPackIndexingExpr(const PackIndexingExpr *E);
bool VisitRecoveryExpr(const RecoveryExpr *E);
bool VisitAddrLabelExpr(const AddrLabelExpr *E);
bool VisitConvertVectorExpr(const ConvertVectorExpr *E);
bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E);

protected:
bool visitExpr(const Expr *E) override;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/IntegralAP.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ template <bool Signed> class IntegralAP final {

IntegralAP(APInt V) : V(V) {}
/// Arbitrary value for uninitialized variables.
IntegralAP() : IntegralAP(-1, 1024) {}
IntegralAP() : IntegralAP(-1, 3) {}

IntegralAP operator-() const { return IntegralAP(-V); }
IntegralAP operator-(const IntegralAP &Other) const {
Expand Down
14 changes: 7 additions & 7 deletions clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,9 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {

QualType T = VD->getType();
if (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11)
return T->isSignedIntegerOrEnumerationType() || T->isUnsignedIntegerOrEnumerationType();
return (T->isSignedIntegerOrEnumerationType() ||
T->isUnsignedIntegerOrEnumerationType()) &&
T.isConstQualified();

if (T.isConstQualified())
return true;
Expand All @@ -316,12 +318,10 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
return false;
};

if (const auto *D = Desc->asValueDecl()) {
if (const auto *VD = dyn_cast<VarDecl>(D);
VD && VD->hasGlobalStorage() && !IsConstType(VD)) {
diagnoseNonConstVariable(S, OpPC, VD);
return S.inConstantContext();
}
if (const auto *D = Desc->asVarDecl();
D && D->hasGlobalStorage() && !IsConstType(D)) {
diagnoseNonConstVariable(S, OpPC, D);
return S.inConstantContext();
}

return true;
Expand Down
9 changes: 5 additions & 4 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1569,9 +1569,7 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
APSInt NewIndex =
(Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
<< NewIndex
<< /*array*/ static_cast<int>(!Ptr.inArray())
<< static_cast<unsigned>(MaxIndex);
<< NewIndex << /*array*/ static_cast<int>(!Ptr.inArray()) << MaxIndex;
Invalid = true;
};

Expand All @@ -1598,7 +1596,7 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
}
}

if (Invalid && !Ptr.isDummy() && S.getLangOpts().CPlusPlus)
if (Invalid && S.getLangOpts().CPlusPlus)
return false;

// Offset is valid - compute it on unsigned.
Expand Down Expand Up @@ -2110,6 +2108,9 @@ inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
return true;
}

if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
return false;

if (!Ptr.isUnknownSizeArray() || Ptr.isDummy()) {
S.Stk.push<Pointer>(Ptr.atIndex(0));
return true;
Expand Down
8 changes: 6 additions & 2 deletions clang/lib/AST/Interp/InterpBlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,15 @@ class Block final {
/// Creates a new block.
Block(const std::optional<unsigned> &DeclID, const Descriptor *Desc,
bool IsStatic = false, bool IsExtern = false)
: DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), Desc(Desc) {}
: DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), Desc(Desc) {
assert(Desc);
}

Block(const Descriptor *Desc, bool IsStatic = false, bool IsExtern = false)
: DeclID((unsigned)-1), IsStatic(IsStatic), IsExtern(IsExtern),
Desc(Desc) {}
Desc(Desc) {
assert(Desc);
}

/// Returns the block's descriptor.
const Descriptor *getDescriptor() const { return Desc; }
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/AST/Interp/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,17 +181,17 @@ void Pointer::print(llvm::raw_ostream &OS) const {
if (isBlockPointer()) {
OS << "Block) {";

if (PointeeStorage.BS.Base == RootPtrMark)
OS << "rootptr, ";
if (isRoot())
OS << "rootptr(" << PointeeStorage.BS.Base << "), ";
else
OS << PointeeStorage.BS.Base << ", ";

if (Offset == PastEndMark)
if (isElementPastEnd())
OS << "pastend, ";
else
OS << Offset << ", ";

if (isBlockPointer() && PointeeStorage.BS.Pointee)
if (PointeeStorage.BS.Pointee)
OS << PointeeStorage.BS.Pointee->getSize();
else
OS << "nullptr";
Expand Down
7 changes: 0 additions & 7 deletions clang/lib/AST/Interp/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -384,11 +384,6 @@ class Pointer {
bool isUnknownSizeArray() const {
if (!isBlockPointer())
return false;
// If this points inside a dummy block, return true.
// FIXME: This might change in the future. If it does, we need
// to set the proper Ctor/Dtor functions for dummy Descriptors.
if (!isRoot() && isDummy())
return true;
return getFieldDesc()->isUnknownSizeArray();
}
/// Checks if the pointer points to an array.
Expand Down Expand Up @@ -560,8 +555,6 @@ class Pointer {

if (!asBlockPointer().Pointee)
return false;
if (isDummy())
return false;

return isElementPastEnd() || getSize() == getOffset();
}
Expand Down
11 changes: 7 additions & 4 deletions clang/lib/AST/Interp/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,15 @@ std::optional<unsigned> Program::getOrCreateDummy(const ValueDecl *VD) {
if (auto It = DummyVariables.find(VD); It != DummyVariables.end())
return It->second;

QualType QT = VD->getType();
if (const auto *RT = QT->getAs<ReferenceType>())
QT = RT->getPointeeType();

Descriptor *Desc;
if (std::optional<PrimType> T = Ctx.classify(VD->getType()))
if (std::optional<PrimType> T = Ctx.classify(QT))
Desc = createDescriptor(VD, *T, std::nullopt, true, false);
else
Desc = createDescriptor(VD, VD->getType().getTypePtr(), std::nullopt, true,
false);
Desc = createDescriptor(VD, QT.getTypePtr(), std::nullopt, true, false);
if (!Desc)
Desc = allocateDescriptor(VD);

Expand Down Expand Up @@ -372,7 +375,7 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
// Arrays of composites. In this case, the array is a list of pointers,
// followed by the actual elements.
const Descriptor *ElemDesc = createDescriptor(
D, ElemTy.getTypePtr(), MDSize, IsConst, IsTemporary);
D, ElemTy.getTypePtr(), std::nullopt, IsConst, IsTemporary);
if (!ElemDesc)
return nullptr;
unsigned ElemSize =
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/OpenACCClause.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ void OpenACCClausePrinter::VisitDeviceTypeClause(
if (Arch.first == nullptr)
OS << "*";
else
OS << Arch.first;
OS << Arch.first->getName();
});
OS << ")";
}
25 changes: 11 additions & 14 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1472,21 +1472,18 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) {

// If this is a class template specialization, print the template
// arguments.
if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
ArrayRef<TemplateArgument> Args;
TypeSourceInfo *TAW = Spec->getTypeAsWritten();
if (!Policy.PrintCanonicalTypes && TAW) {
const TemplateSpecializationType *TST =
cast<TemplateSpecializationType>(TAW->getType());
Args = TST->template_arguments();
} else {
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
Args = TemplateArgs.asArray();
}
if (auto *S = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
const TemplateParameterList *TParams =
S->getSpecializedTemplate()->getTemplateParameters();
const ASTTemplateArgumentListInfo *TArgAsWritten =
S->getTemplateArgsAsWritten();
IncludeStrongLifetimeRAII Strong(Policy);
printTemplateArgumentList(
OS, Args, Policy,
Spec->getSpecializedTemplate()->getTemplateParameters());
if (TArgAsWritten && !Policy.PrintCanonicalTypes)
printTemplateArgumentList(OS, TArgAsWritten->arguments(), Policy,
TParams);
else
printTemplateArgumentList(OS, S->getTemplateArgs().asArray(), Policy,
TParams);
}

spaceBeforePlaceHolder(OS);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/VTTBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) {

if (!IsPrimaryVTT) {
// Remember the sub-VTT index.
SubVTTIndicies[Base] = VTTComponents.size();
SubVTTIndices[Base] = VTTComponents.size();
}

uint64_t VTableIndex = VTTVTables.size();
Expand Down
107 changes: 57 additions & 50 deletions clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,22 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/Type.h"
#include "clang/Analysis/FlowSensitive/ASTOps.h"
#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
#include "clang/Analysis/FlowSensitive/Value.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
#include <cassert>
#include <memory>
#include <utility>

#define DEBUG_TYPE "dataflow"
Expand Down Expand Up @@ -290,15 +295,14 @@ widenKeyToValueMap(const llvm::MapVector<Key, Value *> &CurMap,
namespace {

// Visitor that builds a map from record prvalues to result objects.
// This traverses the body of the function to be analyzed; for each result
// object that it encounters, it propagates the storage location of the result
// object to all record prvalues that can initialize it.
// For each result object that it encounters, it propagates the storage location
// of the result object to all record prvalues that can initialize it.
class ResultObjectVisitor : public RecursiveASTVisitor<ResultObjectVisitor> {
public:
// `ResultObjectMap` will be filled with a map from record prvalues to result
// object. If the function being analyzed returns a record by value,
// `LocForRecordReturnVal` is the location to which this record should be
// written; otherwise, it is null.
// object. If this visitor will traverse a function that returns a record by
// value, `LocForRecordReturnVal` is the location to which this record should
// be written; otherwise, it is null.
explicit ResultObjectVisitor(
llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap,
RecordStorageLocation *LocForRecordReturnVal,
Expand Down Expand Up @@ -514,39 +518,31 @@ class ResultObjectVisitor : public RecursiveASTVisitor<ResultObjectVisitor> {

} // namespace

Environment::Environment(DataflowAnalysisContext &DACtx)
: DACtx(&DACtx),
FlowConditionToken(DACtx.arena().makeFlowConditionToken()) {}

Environment::Environment(DataflowAnalysisContext &DACtx,
const DeclContext &DeclCtx)
: Environment(DACtx) {
CallStack.push_back(&DeclCtx);
}

void Environment::initialize() {
const DeclContext *DeclCtx = getDeclCtx();
if (DeclCtx == nullptr)
if (InitialTargetStmt == nullptr)
return;

const auto *FuncDecl = dyn_cast<FunctionDecl>(DeclCtx);
if (FuncDecl == nullptr)
if (InitialTargetFunc == nullptr) {
initFieldsGlobalsAndFuncs(getReferencedDecls(*InitialTargetStmt));
ResultObjectMap =
std::make_shared<PrValueToResultObject>(buildResultObjectMap(
DACtx, InitialTargetStmt, getThisPointeeStorageLocation(),
/*LocForRecordReturnValue=*/nullptr));
return;
}

assert(FuncDecl->doesThisDeclarationHaveABody());

initFieldsGlobalsAndFuncs(FuncDecl);
initFieldsGlobalsAndFuncs(getReferencedDecls(*InitialTargetFunc));

for (const auto *ParamDecl : FuncDecl->parameters()) {
for (const auto *ParamDecl : InitialTargetFunc->parameters()) {
assert(ParamDecl != nullptr);
setStorageLocation(*ParamDecl, createObject(*ParamDecl, nullptr));
}

if (FuncDecl->getReturnType()->isRecordType())
if (InitialTargetFunc->getReturnType()->isRecordType())
LocForRecordReturnVal = &cast<RecordStorageLocation>(
createStorageLocation(FuncDecl->getReturnType()));
createStorageLocation(InitialTargetFunc->getReturnType()));

if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(DeclCtx)) {
if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(InitialTargetFunc)) {
auto *Parent = MethodDecl->getParent();
assert(Parent != nullptr);

Expand All @@ -558,7 +554,7 @@ void Environment::initialize() {
setStorageLocation(*VarDecl, createObject(*VarDecl, nullptr));
} else if (Capture.capturesThis()) {
const auto *SurroundingMethodDecl =
cast<CXXMethodDecl>(DeclCtx->getNonClosureAncestor());
cast<CXXMethodDecl>(InitialTargetFunc->getNonClosureAncestor());
QualType ThisPointeeType =
SurroundingMethodDecl->getFunctionObjectParameterType();
setThisPointeeStorageLocation(
Expand All @@ -580,18 +576,16 @@ void Environment::initialize() {

// We do this below the handling of `CXXMethodDecl` above so that we can
// be sure that the storage location for `this` has been set.
ResultObjectMap = std::make_shared<PrValueToResultObject>(
buildResultObjectMap(DACtx, FuncDecl, getThisPointeeStorageLocation(),
LocForRecordReturnVal));
ResultObjectMap =
std::make_shared<PrValueToResultObject>(buildResultObjectMap(
DACtx, InitialTargetFunc, getThisPointeeStorageLocation(),
LocForRecordReturnVal));
}

// FIXME: Add support for resetting globals after function calls to enable
// the implementation of sound analyses.
void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) {
assert(FuncDecl->doesThisDeclarationHaveABody());

ReferencedDecls Referenced = getReferencedDecls(*FuncDecl);
// FIXME: Add support for resetting globals after function calls to enable the
// implementation of sound analyses.

void Environment::initFieldsGlobalsAndFuncs(const ReferencedDecls &Referenced) {
// These have to be added before the lines that follow to ensure that
// `create*` work correctly for structs.
DACtx->addModeledFields(Referenced.Fields);
Expand All @@ -602,9 +596,9 @@ void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) {

// We don't run transfer functions on the initializers of global variables,
// so they won't be associated with a value or storage location. We
// therefore intentionally don't pass an initializer to `createObject()`;
// in particular, this ensures that `createObject()` will initialize the
// fields of record-type variables with values.
// therefore intentionally don't pass an initializer to `createObject()`; in
// particular, this ensures that `createObject()` will initialize the fields
// of record-type variables with values.
setStorageLocation(*D, createObject(*D, nullptr));
}

Expand All @@ -623,8 +617,8 @@ Environment Environment::fork() const {
}

bool Environment::canDescend(unsigned MaxDepth,
const DeclContext *Callee) const {
return CallStack.size() <= MaxDepth && !llvm::is_contained(CallStack, Callee);
const FunctionDecl *Callee) const {
return CallStack.size() < MaxDepth && !llvm::is_contained(CallStack, Callee);
}

Environment Environment::pushCall(const CallExpr *Call) const {
Expand Down Expand Up @@ -671,7 +665,7 @@ void Environment::pushCallInternal(const FunctionDecl *FuncDecl,

CallStack.push_back(FuncDecl);

initFieldsGlobalsAndFuncs(FuncDecl);
initFieldsGlobalsAndFuncs(getReferencedDecls(*FuncDecl));

const auto *ParamIt = FuncDecl->param_begin();

Expand Down Expand Up @@ -755,6 +749,8 @@ LatticeEffect Environment::widen(const Environment &PrevEnv,
assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc);
assert(CallStack == PrevEnv.CallStack);
assert(ResultObjectMap == PrevEnv.ResultObjectMap);
assert(InitialTargetFunc == PrevEnv.InitialTargetFunc);
assert(InitialTargetStmt == PrevEnv.InitialTargetStmt);

auto Effect = LatticeEffect::Unchanged;

Expand Down Expand Up @@ -790,21 +786,22 @@ Environment Environment::join(const Environment &EnvA, const Environment &EnvB,
assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc);
assert(EnvA.CallStack == EnvB.CallStack);
assert(EnvA.ResultObjectMap == EnvB.ResultObjectMap);
assert(EnvA.InitialTargetFunc == EnvB.InitialTargetFunc);
assert(EnvA.InitialTargetStmt == EnvB.InitialTargetStmt);

Environment JoinedEnv(*EnvA.DACtx);

JoinedEnv.CallStack = EnvA.CallStack;
JoinedEnv.ResultObjectMap = EnvA.ResultObjectMap;
JoinedEnv.LocForRecordReturnVal = EnvA.LocForRecordReturnVal;
JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc;
JoinedEnv.InitialTargetFunc = EnvA.InitialTargetFunc;
JoinedEnv.InitialTargetStmt = EnvA.InitialTargetStmt;

if (EnvA.CallStack.empty()) {
const FunctionDecl *Func = EnvA.getCurrentFunc();
if (!Func) {
JoinedEnv.ReturnVal = nullptr;
} else {
// FIXME: Make `CallStack` a vector of `FunctionDecl` so we don't need this
// cast.
auto *Func = dyn_cast<FunctionDecl>(EnvA.CallStack.back());
assert(Func != nullptr);
JoinedEnv.ReturnVal =
joinValues(Func->getReturnType(), EnvA.ReturnVal, EnvA, EnvB.ReturnVal,
EnvB, JoinedEnv, Model);
Expand Down Expand Up @@ -1229,16 +1226,26 @@ Environment::PrValueToResultObject Environment::buildResultObjectMap(
RecordStorageLocation *LocForRecordReturnVal) {
assert(FuncDecl->doesThisDeclarationHaveABody());

PrValueToResultObject Map;
PrValueToResultObject Map = buildResultObjectMap(
DACtx, FuncDecl->getBody(), ThisPointeeLoc, LocForRecordReturnVal);

ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(FuncDecl))
Visitor.TraverseConstructorInits(Ctor, ThisPointeeLoc);
Visitor.TraverseStmt(FuncDecl->getBody());

return Map;
}

Environment::PrValueToResultObject Environment::buildResultObjectMap(
DataflowAnalysisContext *DACtx, Stmt *S,
RecordStorageLocation *ThisPointeeLoc,
RecordStorageLocation *LocForRecordReturnVal) {
PrValueToResultObject Map;
ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
Visitor.TraverseStmt(S);
return Map;
}

RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE,
const Environment &Env) {
Expr *ImplicitObject = MCE.getImplicitObjectArgument();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ runTypeErasedDataflowAnalysis(
PrettyStackTraceAnalysis CrashInfo(ACFG, "runTypeErasedDataflowAnalysis");

std::optional<Environment> MaybeStartingEnv;
if (InitEnv.callStackSize() == 1) {
if (InitEnv.callStackSize() == 0) {
MaybeStartingEnv = InitEnv.fork();
MaybeStartingEnv->initialize();
}
Expand Down
Loading