
This is a major change on how we represent nested name qualifications in the AST. * The nested name specifier itself and how it's stored is changed. The prefixes for types are handled within the type hierarchy, which makes canonicalization for them super cheap, no memory allocation required. Also translating a type into nested name specifier form becomes a no-op. An identifier is stored as a DependentNameType. The nested name specifier gains a lightweight handle class, to be used instead of passing around pointers, which is similar to what is implemented for TemplateName. There is still one free bit available, and this handle can be used within a PointerUnion and PointerIntPair, which should keep bit-packing aficionados happy. * The ElaboratedType node is removed, all type nodes in which it could previously apply to can now store the elaborated keyword and name qualifier, tail allocating when present. * TagTypes can now point to the exact declaration found when producing these, as opposed to the previous situation of there only existing one TagType per entity. This increases the amount of type sugar retained, and can have several applications, for example in tracking module ownership, and other tools which care about source file origins, such as IWYU. These TagTypes are lazily allocated, in order to limit the increase in AST size. This patch offers a great performance benefit. It greatly improves compilation time for [stdexec](https://github.com/NVIDIA/stdexec). For one datapoint, for `test_on2.cpp` in that project, which is the slowest compiling test, this patch improves `-c` compilation time by about 7.2%, with the `-fsyntax-only` improvement being at ~12%. This has great results on compile-time-tracker as well:  This patch also further enables other optimziations in the future, and will reduce the performance impact of template specialization resugaring when that lands. It has some other miscelaneous drive-by fixes. About the review: Yes the patch is huge, sorry about that. Part of the reason is that I started by the nested name specifier part, before the ElaboratedType part, but that had a huge performance downside, as ElaboratedType is a big performance hog. I didn't have the steam to go back and change the patch after the fact. There is also a lot of internal API changes, and it made sense to remove ElaboratedType in one go, versus removing it from one type at a time, as that would present much more churn to the users. Also, the nested name specifier having a different API avoids missing changes related to how prefixes work now, which could make existing code compile but not work. How to review: The important changes are all in `clang/include/clang/AST` and `clang/lib/AST`, with also important changes in `clang/lib/Sema/TreeTransform.h`. The rest and bulk of the changes are mostly consequences of the changes in API. PS: TagType::getDecl is renamed to `getOriginalDecl` in this patch, just for easier to rebasing. I plan to rename it back after this lands. Fixes #136624 Fixes https://github.com/llvm/llvm-project/issues/43179 Fixes https://github.com/llvm/llvm-project/issues/68670 Fixes https://github.com/llvm/llvm-project/issues/92757
962 lines
35 KiB
C++
962 lines
35 KiB
C++
//===- ComputeDependence.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 "clang/AST/ComputeDependence.h"
|
|
#include "clang/AST/Attr.h"
|
|
#include "clang/AST/DeclCXX.h"
|
|
#include "clang/AST/DeclarationName.h"
|
|
#include "clang/AST/DependenceFlags.h"
|
|
#include "clang/AST/Expr.h"
|
|
#include "clang/AST/ExprCXX.h"
|
|
#include "clang/AST/ExprConcepts.h"
|
|
#include "clang/AST/ExprObjC.h"
|
|
#include "clang/AST/ExprOpenMP.h"
|
|
#include "clang/Basic/ExceptionSpecificationType.h"
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
|
|
using namespace clang;
|
|
|
|
ExprDependence clang::computeDependence(FullExpr *E) {
|
|
return E->getSubExpr()->getDependence();
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(OpaqueValueExpr *E) {
|
|
auto D = toExprDependenceForImpliedType(E->getType()->getDependence());
|
|
if (auto *S = E->getSourceExpr())
|
|
D |= S->getDependence();
|
|
assert(!(D & ExprDependence::UnexpandedPack));
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ParenExpr *E) {
|
|
return E->getSubExpr()->getDependence();
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(UnaryOperator *E,
|
|
const ASTContext &Ctx) {
|
|
ExprDependence Dep =
|
|
// FIXME: Do we need to look at the type?
|
|
toExprDependenceForImpliedType(E->getType()->getDependence()) |
|
|
E->getSubExpr()->getDependence();
|
|
|
|
// C++ [temp.dep.constexpr]p5:
|
|
// An expression of the form & qualified-id where the qualified-id names a
|
|
// dependent member of the current instantiation is value-dependent. An
|
|
// expression of the form & cast-expression is also value-dependent if
|
|
// evaluating cast-expression as a core constant expression succeeds and
|
|
// the result of the evaluation refers to a templated entity that is an
|
|
// object with static or thread storage duration or a member function.
|
|
//
|
|
// What this amounts to is: constant-evaluate the operand and check whether it
|
|
// refers to a templated entity other than a variable with local storage.
|
|
if (Ctx.getLangOpts().CPlusPlus && E->getOpcode() == UO_AddrOf &&
|
|
!(Dep & ExprDependence::Value)) {
|
|
Expr::EvalResult Result;
|
|
SmallVector<PartialDiagnosticAt, 8> Diag;
|
|
Result.Diag = &Diag;
|
|
// FIXME: This doesn't enforce the C++98 constant expression rules.
|
|
if (E->getSubExpr()->EvaluateAsConstantExpr(Result, Ctx) && Diag.empty() &&
|
|
Result.Val.isLValue()) {
|
|
auto *VD = Result.Val.getLValueBase().dyn_cast<const ValueDecl *>();
|
|
if (VD && VD->isTemplated()) {
|
|
auto *VarD = dyn_cast<VarDecl>(VD);
|
|
if (!VarD || !VarD->hasLocalStorage())
|
|
Dep |= ExprDependence::Value;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Dep;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(UnaryExprOrTypeTraitExpr *E) {
|
|
// Never type-dependent (C++ [temp.dep.expr]p3).
|
|
// Value-dependent if the argument is type-dependent.
|
|
if (E->isArgumentType())
|
|
return turnTypeToValueDependence(
|
|
toExprDependenceAsWritten(E->getArgumentType()->getDependence()));
|
|
|
|
auto ArgDeps = E->getArgumentExpr()->getDependence();
|
|
auto Deps = ArgDeps & ~ExprDependence::TypeValue;
|
|
// Value-dependent if the argument is type-dependent.
|
|
if (ArgDeps & ExprDependence::Type)
|
|
Deps |= ExprDependence::Value;
|
|
// Check to see if we are in the situation where alignof(decl) should be
|
|
// dependent because decl's alignment is dependent.
|
|
auto ExprKind = E->getKind();
|
|
if (ExprKind != UETT_AlignOf && ExprKind != UETT_PreferredAlignOf)
|
|
return Deps;
|
|
if ((Deps & ExprDependence::Value) && (Deps & ExprDependence::Instantiation))
|
|
return Deps;
|
|
|
|
auto *NoParens = E->getArgumentExpr()->IgnoreParens();
|
|
const ValueDecl *D = nullptr;
|
|
if (const auto *DRE = dyn_cast<DeclRefExpr>(NoParens))
|
|
D = DRE->getDecl();
|
|
else if (const auto *ME = dyn_cast<MemberExpr>(NoParens))
|
|
D = ME->getMemberDecl();
|
|
if (!D)
|
|
return Deps;
|
|
for (const auto *I : D->specific_attrs<AlignedAttr>()) {
|
|
if (I->isAlignmentErrorDependent())
|
|
Deps |= ExprDependence::Error;
|
|
if (I->isAlignmentDependent())
|
|
Deps |= ExprDependence::ValueInstantiation;
|
|
}
|
|
return Deps;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ArraySubscriptExpr *E) {
|
|
return E->getLHS()->getDependence() | E->getRHS()->getDependence();
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(MatrixSubscriptExpr *E) {
|
|
return E->getBase()->getDependence() | E->getRowIdx()->getDependence() |
|
|
(E->getColumnIdx() ? E->getColumnIdx()->getDependence()
|
|
: ExprDependence::None);
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CompoundLiteralExpr *E) {
|
|
return toExprDependenceAsWritten(
|
|
E->getTypeSourceInfo()->getType()->getDependence()) |
|
|
toExprDependenceForImpliedType(E->getType()->getDependence()) |
|
|
turnTypeToValueDependence(E->getInitializer()->getDependence());
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ImplicitCastExpr *E) {
|
|
// We model implicit conversions as combining the dependence of their
|
|
// subexpression, apart from its type, with the semantic portion of the
|
|
// target type.
|
|
ExprDependence D =
|
|
toExprDependenceForImpliedType(E->getType()->getDependence());
|
|
if (auto *S = E->getSubExpr())
|
|
D |= S->getDependence() & ~ExprDependence::Type;
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ExplicitCastExpr *E) {
|
|
// Cast expressions are type-dependent if the type is
|
|
// dependent (C++ [temp.dep.expr]p3).
|
|
// Cast expressions are value-dependent if the type is
|
|
// dependent or if the subexpression is value-dependent.
|
|
//
|
|
// Note that we also need to consider the dependence of the actual type here,
|
|
// because when the type as written is a deduced type, that type is not
|
|
// dependent, but it may be deduced as a dependent type.
|
|
ExprDependence D =
|
|
toExprDependenceAsWritten(
|
|
cast<ExplicitCastExpr>(E)->getTypeAsWritten()->getDependence()) |
|
|
toExprDependenceForImpliedType(E->getType()->getDependence());
|
|
if (auto *S = E->getSubExpr())
|
|
D |= S->getDependence() & ~ExprDependence::Type;
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(BinaryOperator *E) {
|
|
return E->getLHS()->getDependence() | E->getRHS()->getDependence();
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ConditionalOperator *E) {
|
|
// The type of the conditional operator depends on the type of the conditional
|
|
// to support the GCC vector conditional extension. Additionally,
|
|
// [temp.dep.expr] does specify that this should be dependent on ALL sub
|
|
// expressions.
|
|
return E->getCond()->getDependence() | E->getLHS()->getDependence() |
|
|
E->getRHS()->getDependence();
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(BinaryConditionalOperator *E) {
|
|
return E->getCommon()->getDependence() | E->getFalseExpr()->getDependence();
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(StmtExpr *E, unsigned TemplateDepth) {
|
|
auto D = toExprDependenceForImpliedType(E->getType()->getDependence());
|
|
// Propagate dependence of the result.
|
|
if (const auto *CompoundExprResult =
|
|
dyn_cast_or_null<ValueStmt>(E->getSubStmt()->getStmtExprResult()))
|
|
if (const Expr *ResultExpr = CompoundExprResult->getExprStmt())
|
|
D |= ResultExpr->getDependence();
|
|
// Note: we treat a statement-expression in a dependent context as always
|
|
// being value- and instantiation-dependent. This matches the behavior of
|
|
// lambda-expressions and GCC.
|
|
if (TemplateDepth)
|
|
D |= ExprDependence::ValueInstantiation;
|
|
// A param pack cannot be expanded over stmtexpr boundaries.
|
|
return D & ~ExprDependence::UnexpandedPack;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ConvertVectorExpr *E) {
|
|
auto D = toExprDependenceAsWritten(
|
|
E->getTypeSourceInfo()->getType()->getDependence()) |
|
|
E->getSrcExpr()->getDependence();
|
|
if (!E->getType()->isDependentType())
|
|
D &= ~ExprDependence::Type;
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ChooseExpr *E) {
|
|
if (E->isConditionDependent())
|
|
return ExprDependence::TypeValueInstantiation |
|
|
E->getCond()->getDependence() | E->getLHS()->getDependence() |
|
|
E->getRHS()->getDependence();
|
|
|
|
auto Cond = E->getCond()->getDependence();
|
|
auto Active = E->getLHS()->getDependence();
|
|
auto Inactive = E->getRHS()->getDependence();
|
|
if (!E->isConditionTrue())
|
|
std::swap(Active, Inactive);
|
|
// Take type- and value- dependency from the active branch. Propagate all
|
|
// other flags from all branches.
|
|
return (Active & ExprDependence::TypeValue) |
|
|
((Cond | Active | Inactive) & ~ExprDependence::TypeValue);
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ParenListExpr *P) {
|
|
auto D = ExprDependence::None;
|
|
for (auto *E : P->exprs())
|
|
D |= E->getDependence();
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(VAArgExpr *E) {
|
|
auto D = toExprDependenceAsWritten(
|
|
E->getWrittenTypeInfo()->getType()->getDependence()) |
|
|
(E->getSubExpr()->getDependence() & ~ExprDependence::Type);
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(NoInitExpr *E) {
|
|
return toExprDependenceForImpliedType(E->getType()->getDependence()) &
|
|
(ExprDependence::Instantiation | ExprDependence::Error);
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ArrayInitLoopExpr *E) {
|
|
auto D = E->getCommonExpr()->getDependence() |
|
|
E->getSubExpr()->getDependence() | ExprDependence::Instantiation;
|
|
if (!E->getType()->isInstantiationDependentType())
|
|
D &= ~ExprDependence::Instantiation;
|
|
return turnTypeToValueDependence(D);
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ImplicitValueInitExpr *E) {
|
|
return toExprDependenceForImpliedType(E->getType()->getDependence()) &
|
|
ExprDependence::Instantiation;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ExtVectorElementExpr *E) {
|
|
return E->getBase()->getDependence();
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(BlockExpr *E,
|
|
bool ContainsUnexpandedParameterPack) {
|
|
auto D = toExprDependenceForImpliedType(E->getType()->getDependence());
|
|
if (E->getBlockDecl()->isDependentContext())
|
|
D |= ExprDependence::Instantiation;
|
|
if (ContainsUnexpandedParameterPack)
|
|
D |= ExprDependence::UnexpandedPack;
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(AsTypeExpr *E) {
|
|
// FIXME: AsTypeExpr doesn't store the type as written. Assume the expression
|
|
// type has identical sugar for now, so is a type-as-written.
|
|
auto D = toExprDependenceAsWritten(E->getType()->getDependence()) |
|
|
E->getSrcExpr()->getDependence();
|
|
if (!E->getType()->isDependentType())
|
|
D &= ~ExprDependence::Type;
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CXXRewrittenBinaryOperator *E) {
|
|
return E->getSemanticForm()->getDependence();
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CXXStdInitializerListExpr *E) {
|
|
auto D = turnTypeToValueDependence(E->getSubExpr()->getDependence());
|
|
D |= toExprDependenceForImpliedType(E->getType()->getDependence());
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CXXTypeidExpr *E) {
|
|
auto D = ExprDependence::None;
|
|
if (E->isTypeOperand())
|
|
D = toExprDependenceAsWritten(
|
|
E->getTypeOperandSourceInfo()->getType()->getDependence());
|
|
else
|
|
D = turnTypeToValueDependence(E->getExprOperand()->getDependence());
|
|
// typeid is never type-dependent (C++ [temp.dep.expr]p4)
|
|
return D & ~ExprDependence::Type;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(MSPropertyRefExpr *E) {
|
|
return E->getBaseExpr()->getDependence() & ~ExprDependence::Type;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(MSPropertySubscriptExpr *E) {
|
|
return E->getIdx()->getDependence();
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CXXUuidofExpr *E) {
|
|
if (E->isTypeOperand())
|
|
return turnTypeToValueDependence(toExprDependenceAsWritten(
|
|
E->getTypeOperandSourceInfo()->getType()->getDependence()));
|
|
|
|
return turnTypeToValueDependence(E->getExprOperand()->getDependence());
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CXXThisExpr *E) {
|
|
// 'this' is type-dependent if the class type of the enclosing
|
|
// member function is dependent (C++ [temp.dep.expr]p2)
|
|
auto D = toExprDependenceForImpliedType(E->getType()->getDependence());
|
|
|
|
// If a lambda with an explicit object parameter captures '*this', then
|
|
// 'this' now refers to the captured copy of lambda, and if the lambda
|
|
// is type-dependent, so is the object and thus 'this'.
|
|
//
|
|
// Note: The standard does not mention this case explicitly, but we need
|
|
// to do this so we can mark NSDM accesses as dependent.
|
|
if (E->isCapturedByCopyInLambdaWithExplicitObjectParameter())
|
|
D |= ExprDependence::Type;
|
|
|
|
assert(!(D & ExprDependence::UnexpandedPack));
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CXXThrowExpr *E) {
|
|
auto *Op = E->getSubExpr();
|
|
if (!Op)
|
|
return ExprDependence::None;
|
|
return Op->getDependence() & ~ExprDependence::TypeValue;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CXXBindTemporaryExpr *E) {
|
|
return E->getSubExpr()->getDependence();
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CXXScalarValueInitExpr *E) {
|
|
auto D = toExprDependenceForImpliedType(E->getType()->getDependence());
|
|
if (auto *TSI = E->getTypeSourceInfo())
|
|
D |= toExprDependenceAsWritten(TSI->getType()->getDependence());
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CXXDeleteExpr *E) {
|
|
return turnTypeToValueDependence(E->getArgument()->getDependence());
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ArrayTypeTraitExpr *E) {
|
|
auto D = toExprDependenceAsWritten(E->getQueriedType()->getDependence());
|
|
if (auto *Dim = E->getDimensionExpression())
|
|
D |= Dim->getDependence();
|
|
return turnTypeToValueDependence(D);
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ExpressionTraitExpr *E) {
|
|
// Never type-dependent.
|
|
auto D = E->getQueriedExpression()->getDependence() & ~ExprDependence::Type;
|
|
// Value-dependent if the argument is type-dependent.
|
|
if (E->getQueriedExpression()->isTypeDependent())
|
|
D |= ExprDependence::Value;
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CXXNoexceptExpr *E, CanThrowResult CT) {
|
|
auto D = E->getOperand()->getDependence() & ~ExprDependence::TypeValue;
|
|
if (CT == CT_Dependent)
|
|
D |= ExprDependence::ValueInstantiation;
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(PackExpansionExpr *E) {
|
|
return (E->getPattern()->getDependence() & ~ExprDependence::UnexpandedPack) |
|
|
ExprDependence::TypeValueInstantiation;
|
|
}
|
|
|
|
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() || !E->isFullySubstituted())
|
|
D |= PatternDep | ExprDependence::Instantiation;
|
|
else if (!E->getIndexExpr()->isInstantiationDependent()) {
|
|
UnsignedOrNone Index = E->getSelectedIndex();
|
|
assert(Index && *Index < Exprs.size() && "pack index out of bound");
|
|
D |= Exprs[*Index]->getDependence();
|
|
}
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(SubstNonTypeTemplateParmExpr *E) {
|
|
return E->getReplacement()->getDependence();
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CoroutineSuspendExpr *E) {
|
|
if (auto *Resume = E->getResumeExpr())
|
|
return (Resume->getDependence() &
|
|
(ExprDependence::TypeValue | ExprDependence::Error)) |
|
|
(E->getCommonExpr()->getDependence() & ~ExprDependence::TypeValue);
|
|
return E->getCommonExpr()->getDependence() |
|
|
ExprDependence::TypeValueInstantiation;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(DependentCoawaitExpr *E) {
|
|
return E->getOperand()->getDependence() |
|
|
ExprDependence::TypeValueInstantiation;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ObjCBoxedExpr *E) {
|
|
return E->getSubExpr()->getDependence();
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ObjCEncodeExpr *E) {
|
|
return toExprDependenceAsWritten(E->getEncodedType()->getDependence());
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ObjCIvarRefExpr *E) {
|
|
return turnTypeToValueDependence(E->getBase()->getDependence());
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ObjCPropertyRefExpr *E) {
|
|
if (E->isObjectReceiver())
|
|
return E->getBase()->getDependence() & ~ExprDependence::Type;
|
|
if (E->isSuperReceiver())
|
|
return toExprDependenceForImpliedType(
|
|
E->getSuperReceiverType()->getDependence()) &
|
|
~ExprDependence::TypeValue;
|
|
assert(E->isClassReceiver());
|
|
return ExprDependence::None;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ObjCSubscriptRefExpr *E) {
|
|
return E->getBaseExpr()->getDependence() | E->getKeyExpr()->getDependence();
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ObjCIsaExpr *E) {
|
|
return E->getBase()->getDependence() & ~ExprDependence::Type &
|
|
~ExprDependence::UnexpandedPack;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ObjCIndirectCopyRestoreExpr *E) {
|
|
return E->getSubExpr()->getDependence();
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ArraySectionExpr *E) {
|
|
auto D = E->getBase()->getDependence();
|
|
if (auto *LB = E->getLowerBound())
|
|
D |= LB->getDependence();
|
|
if (auto *Len = E->getLength())
|
|
D |= Len->getDependence();
|
|
|
|
if (E->isOMPArraySection()) {
|
|
if (auto *Stride = E->getStride())
|
|
D |= Stride->getDependence();
|
|
}
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(OMPArrayShapingExpr *E) {
|
|
auto D = E->getBase()->getDependence();
|
|
for (Expr *Dim: E->getDimensions())
|
|
if (Dim)
|
|
D |= turnValueToTypeDependence(Dim->getDependence());
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(OMPIteratorExpr *E) {
|
|
auto D = toExprDependenceForImpliedType(E->getType()->getDependence());
|
|
for (unsigned I = 0, End = E->numOfIterators(); I < End; ++I) {
|
|
if (auto *DD = cast_or_null<DeclaratorDecl>(E->getIteratorDecl(I))) {
|
|
// If the type is omitted, it's 'int', and is not dependent in any way.
|
|
if (auto *TSI = DD->getTypeSourceInfo()) {
|
|
D |= toExprDependenceAsWritten(TSI->getType()->getDependence());
|
|
}
|
|
}
|
|
OMPIteratorExpr::IteratorRange IR = E->getIteratorRange(I);
|
|
if (Expr *BE = IR.Begin)
|
|
D |= BE->getDependence();
|
|
if (Expr *EE = IR.End)
|
|
D |= EE->getDependence();
|
|
if (Expr *SE = IR.Step)
|
|
D |= SE->getDependence();
|
|
}
|
|
return D;
|
|
}
|
|
|
|
/// Compute the type-, value-, and instantiation-dependence of a
|
|
/// declaration reference
|
|
/// based on the declaration being referenced.
|
|
ExprDependence clang::computeDependence(DeclRefExpr *E, const ASTContext &Ctx) {
|
|
auto Deps = ExprDependence::None;
|
|
|
|
Deps |= toExprDependence(E->getQualifier().getDependence() &
|
|
~NestedNameSpecifierDependence::Dependent);
|
|
|
|
if (auto *FirstArg = E->getTemplateArgs()) {
|
|
unsigned NumArgs = E->getNumTemplateArgs();
|
|
for (auto *Arg = FirstArg, *End = FirstArg + NumArgs; Arg < End; ++Arg)
|
|
Deps |= toExprDependence(Arg->getArgument().getDependence());
|
|
}
|
|
|
|
auto *Decl = E->getDecl();
|
|
auto Type = E->getType();
|
|
|
|
if (Decl->isParameterPack())
|
|
Deps |= ExprDependence::UnexpandedPack;
|
|
Deps |= toExprDependenceForImpliedType(Type->getDependence()) &
|
|
ExprDependence::Error;
|
|
|
|
// C++ [temp.dep.expr]p3:
|
|
// An id-expression is type-dependent if it contains:
|
|
|
|
// - an identifier associated by name lookup with one or more declarations
|
|
// declared with a dependent type
|
|
// - an identifier associated by name lookup with an entity captured by
|
|
// copy ([expr.prim.lambda.capture])
|
|
// in a lambda-expression that has an explicit object parameter whose
|
|
// type is dependent ([dcl.fct]),
|
|
//
|
|
// [The "or more" case is not modeled as a DeclRefExpr. There are a bunch
|
|
// more bullets here that we handle by treating the declaration as having a
|
|
// dependent type if they involve a placeholder type that can't be deduced.]
|
|
if (Type->isDependentType())
|
|
Deps |= ExprDependence::TypeValueInstantiation;
|
|
else if (Type->isInstantiationDependentType())
|
|
Deps |= ExprDependence::Instantiation;
|
|
|
|
// - an identifier associated by name lookup with an entity captured by
|
|
// copy ([expr.prim.lambda.capture])
|
|
if (E->isCapturedByCopyInLambdaWithExplicitObjectParameter())
|
|
Deps |= ExprDependence::Type;
|
|
|
|
// - a conversion-function-id that specifies a dependent type
|
|
if (Decl->getDeclName().getNameKind() ==
|
|
DeclarationName::CXXConversionFunctionName) {
|
|
QualType T = Decl->getDeclName().getCXXNameType();
|
|
if (T->isDependentType())
|
|
return Deps | ExprDependence::TypeValueInstantiation;
|
|
|
|
if (T->isInstantiationDependentType())
|
|
Deps |= ExprDependence::Instantiation;
|
|
}
|
|
|
|
// - a template-id that is dependent,
|
|
// - a nested-name-specifier or a qualified-id that names a member of an
|
|
// unknown specialization
|
|
// [These are not modeled as DeclRefExprs.]
|
|
|
|
// or if it names a dependent member of the current instantiation that is a
|
|
// static data member of type "array of unknown bound of T" for some T
|
|
// [handled below].
|
|
|
|
// C++ [temp.dep.constexpr]p2:
|
|
// An id-expression is value-dependent if:
|
|
|
|
// - it is type-dependent [handled above]
|
|
|
|
// - it is the name of a non-type template parameter,
|
|
if (isa<NonTypeTemplateParmDecl>(Decl))
|
|
return Deps | ExprDependence::ValueInstantiation;
|
|
|
|
// - it names a potentially-constant variable that is initialized with an
|
|
// expression that is value-dependent
|
|
if (const auto *Var = dyn_cast<VarDecl>(Decl)) {
|
|
if (const Expr *Init = Var->getAnyInitializer()) {
|
|
if (Init->containsErrors())
|
|
Deps |= ExprDependence::Error;
|
|
|
|
if (Var->mightBeUsableInConstantExpressions(Ctx) &&
|
|
Init->isValueDependent())
|
|
Deps |= ExprDependence::ValueInstantiation;
|
|
}
|
|
|
|
// - it names a static data member that is a dependent member of the
|
|
// current instantiation and is not initialized in a member-declarator,
|
|
if (Var->isStaticDataMember() &&
|
|
Var->getDeclContext()->isDependentContext() &&
|
|
!Var->getFirstDecl()->hasInit()) {
|
|
const VarDecl *First = Var->getFirstDecl();
|
|
TypeSourceInfo *TInfo = First->getTypeSourceInfo();
|
|
if (TInfo->getType()->isIncompleteArrayType()) {
|
|
Deps |= ExprDependence::TypeValueInstantiation;
|
|
} else if (!First->hasInit()) {
|
|
Deps |= ExprDependence::ValueInstantiation;
|
|
}
|
|
}
|
|
|
|
return Deps;
|
|
}
|
|
|
|
// - it names a static member function that is a dependent member of the
|
|
// current instantiation
|
|
//
|
|
// FIXME: It's unclear that the restriction to static members here has any
|
|
// effect: any use of a non-static member function name requires either
|
|
// forming a pointer-to-member or providing an object parameter, either of
|
|
// which makes the overall expression value-dependent.
|
|
if (auto *MD = dyn_cast<CXXMethodDecl>(Decl)) {
|
|
if (MD->isStatic() && Decl->getDeclContext()->isDependentContext())
|
|
Deps |= ExprDependence::ValueInstantiation;
|
|
}
|
|
|
|
return Deps;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(RecoveryExpr *E) {
|
|
// RecoveryExpr is
|
|
// - always value-dependent, and therefore instantiation dependent
|
|
// - contains errors (ExprDependence::Error), by definition
|
|
// - type-dependent if we don't know the type (fallback to an opaque
|
|
// dependent type), or the type is known and dependent, or it has
|
|
// type-dependent subexpressions.
|
|
auto D = toExprDependenceAsWritten(E->getType()->getDependence()) |
|
|
ExprDependence::ErrorDependent;
|
|
// FIXME: remove the type-dependent bit from subexpressions, if the
|
|
// RecoveryExpr has a non-dependent type.
|
|
for (auto *S : E->subExpressions())
|
|
D |= S->getDependence();
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(SYCLUniqueStableNameExpr *E) {
|
|
return toExprDependenceAsWritten(
|
|
E->getTypeSourceInfo()->getType()->getDependence());
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(PredefinedExpr *E) {
|
|
return toExprDependenceForImpliedType(E->getType()->getDependence());
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CallExpr *E, ArrayRef<Expr *> PreArgs) {
|
|
auto D = E->getCallee()->getDependence();
|
|
if (E->getType()->isDependentType())
|
|
D |= ExprDependence::Type;
|
|
for (auto *A : ArrayRef(E->getArgs(), E->getNumArgs())) {
|
|
if (A)
|
|
D |= A->getDependence();
|
|
}
|
|
for (auto *A : PreArgs)
|
|
D |= A->getDependence();
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(OffsetOfExpr *E) {
|
|
auto D = turnTypeToValueDependence(toExprDependenceAsWritten(
|
|
E->getTypeSourceInfo()->getType()->getDependence()));
|
|
for (unsigned I = 0, N = E->getNumExpressions(); I < N; ++I)
|
|
D |= turnTypeToValueDependence(E->getIndexExpr(I)->getDependence());
|
|
return D;
|
|
}
|
|
|
|
static inline ExprDependence getDependenceInExpr(DeclarationNameInfo Name) {
|
|
auto D = ExprDependence::None;
|
|
if (Name.isInstantiationDependent())
|
|
D |= ExprDependence::Instantiation;
|
|
if (Name.containsUnexpandedParameterPack())
|
|
D |= ExprDependence::UnexpandedPack;
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(MemberExpr *E) {
|
|
auto D = E->getBase()->getDependence();
|
|
D |= getDependenceInExpr(E->getMemberNameInfo());
|
|
|
|
D |= toExprDependence(E->getQualifier().getDependence() &
|
|
~NestedNameSpecifierDependence::Dependent);
|
|
|
|
for (const auto &A : E->template_arguments())
|
|
D |= toExprDependence(A.getArgument().getDependence());
|
|
|
|
auto *MemberDecl = E->getMemberDecl();
|
|
if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) {
|
|
DeclContext *DC = MemberDecl->getDeclContext();
|
|
// dyn_cast_or_null is used to handle objC variables which do not
|
|
// have a declaration context.
|
|
CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(DC);
|
|
if (RD && RD->isDependentContext() && RD->isCurrentInstantiation(DC)) {
|
|
if (!E->getType()->isDependentType())
|
|
D &= ~ExprDependence::Type;
|
|
}
|
|
|
|
// Bitfield with value-dependent width is type-dependent.
|
|
if (FD && FD->isBitField() && FD->getBitWidth()->isValueDependent()) {
|
|
D |= ExprDependence::Type;
|
|
}
|
|
}
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(InitListExpr *E) {
|
|
auto D = ExprDependence::None;
|
|
for (auto *A : E->inits())
|
|
D |= A->getDependence();
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ShuffleVectorExpr *E) {
|
|
auto D = toExprDependenceForImpliedType(E->getType()->getDependence());
|
|
for (auto *C : ArrayRef(E->getSubExprs(), E->getNumSubExprs()))
|
|
D |= C->getDependence();
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(GenericSelectionExpr *E,
|
|
bool ContainsUnexpandedPack) {
|
|
auto D = ContainsUnexpandedPack ? ExprDependence::UnexpandedPack
|
|
: ExprDependence::None;
|
|
for (auto *AE : E->getAssocExprs())
|
|
D |= AE->getDependence() & ExprDependence::Error;
|
|
|
|
if (E->isExprPredicate())
|
|
D |= E->getControllingExpr()->getDependence() & ExprDependence::Error;
|
|
else
|
|
D |= toExprDependenceAsWritten(
|
|
E->getControllingType()->getType()->getDependence());
|
|
|
|
if (E->isResultDependent())
|
|
return D | ExprDependence::TypeValueInstantiation;
|
|
return D | (E->getResultExpr()->getDependence() &
|
|
~ExprDependence::UnexpandedPack);
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(DesignatedInitExpr *E) {
|
|
auto Deps = E->getInit()->getDependence();
|
|
for (const auto &D : E->designators()) {
|
|
auto DesignatorDeps = ExprDependence::None;
|
|
if (D.isArrayDesignator())
|
|
DesignatorDeps |= E->getArrayIndex(D)->getDependence();
|
|
else if (D.isArrayRangeDesignator())
|
|
DesignatorDeps |= E->getArrayRangeStart(D)->getDependence() |
|
|
E->getArrayRangeEnd(D)->getDependence();
|
|
Deps |= DesignatorDeps;
|
|
if (DesignatorDeps & ExprDependence::TypeValue)
|
|
Deps |= ExprDependence::TypeValueInstantiation;
|
|
}
|
|
return Deps;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(PseudoObjectExpr *O) {
|
|
auto D = O->getSyntacticForm()->getDependence();
|
|
for (auto *E : O->semantics())
|
|
D |= E->getDependence();
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(AtomicExpr *A) {
|
|
auto D = ExprDependence::None;
|
|
for (auto *E : ArrayRef(A->getSubExprs(), A->getNumSubExprs()))
|
|
D |= E->getDependence();
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CXXNewExpr *E) {
|
|
auto D = toExprDependenceAsWritten(
|
|
E->getAllocatedTypeSourceInfo()->getType()->getDependence());
|
|
D |= toExprDependenceForImpliedType(E->getAllocatedType()->getDependence());
|
|
auto Size = E->getArraySize();
|
|
if (Size && *Size)
|
|
D |= turnTypeToValueDependence((*Size)->getDependence());
|
|
if (auto *I = E->getInitializer())
|
|
D |= turnTypeToValueDependence(I->getDependence());
|
|
for (auto *A : E->placement_arguments())
|
|
D |= turnTypeToValueDependence(A->getDependence());
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CXXPseudoDestructorExpr *E) {
|
|
auto D = E->getBase()->getDependence();
|
|
if (auto *TSI = E->getDestroyedTypeInfo())
|
|
D |= toExprDependenceAsWritten(TSI->getType()->getDependence());
|
|
if (auto *ST = E->getScopeTypeInfo())
|
|
D |= turnTypeToValueDependence(
|
|
toExprDependenceAsWritten(ST->getType()->getDependence()));
|
|
D |= toExprDependence(E->getQualifier().getDependence() &
|
|
~NestedNameSpecifierDependence::Dependent);
|
|
return D;
|
|
}
|
|
|
|
ExprDependence
|
|
clang::computeDependence(OverloadExpr *E, bool KnownDependent,
|
|
bool KnownInstantiationDependent,
|
|
bool KnownContainsUnexpandedParameterPack) {
|
|
auto Deps = ExprDependence::None;
|
|
if (KnownDependent)
|
|
Deps |= ExprDependence::TypeValue;
|
|
if (KnownInstantiationDependent)
|
|
Deps |= ExprDependence::Instantiation;
|
|
if (KnownContainsUnexpandedParameterPack)
|
|
Deps |= ExprDependence::UnexpandedPack;
|
|
Deps |= getDependenceInExpr(E->getNameInfo());
|
|
Deps |= toExprDependence(E->getQualifier().getDependence() &
|
|
~NestedNameSpecifierDependence::Dependent);
|
|
for (auto *D : E->decls()) {
|
|
if (D->getDeclContext()->isDependentContext() ||
|
|
isa<UnresolvedUsingValueDecl>(D) || isa<TemplateTemplateParmDecl>(D))
|
|
Deps |= ExprDependence::TypeValueInstantiation;
|
|
}
|
|
// If we have explicit template arguments, check for dependent
|
|
// template arguments and whether they contain any unexpanded pack
|
|
// expansions.
|
|
for (const auto &A : E->template_arguments())
|
|
Deps |= toExprDependence(A.getArgument().getDependence());
|
|
return Deps;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(DependentScopeDeclRefExpr *E) {
|
|
auto D = ExprDependence::TypeValue;
|
|
D |= getDependenceInExpr(E->getNameInfo());
|
|
D |= toExprDependence(E->getQualifier().getDependence());
|
|
for (const auto &A : E->template_arguments())
|
|
D |= toExprDependence(A.getArgument().getDependence());
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CXXConstructExpr *E) {
|
|
ExprDependence D =
|
|
toExprDependenceForImpliedType(E->getType()->getDependence());
|
|
for (auto *A : E->arguments())
|
|
D |= A->getDependence() & ~ExprDependence::Type;
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CXXTemporaryObjectExpr *E) {
|
|
CXXConstructExpr *BaseE = E;
|
|
return toExprDependenceAsWritten(
|
|
E->getTypeSourceInfo()->getType()->getDependence()) |
|
|
computeDependence(BaseE);
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CXXDefaultInitExpr *E) {
|
|
return E->getExpr()->getDependence();
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CXXDefaultArgExpr *E) {
|
|
return E->getExpr()->getDependence();
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(LambdaExpr *E,
|
|
bool ContainsUnexpandedParameterPack) {
|
|
auto D = toExprDependenceForImpliedType(E->getType()->getDependence());
|
|
if (ContainsUnexpandedParameterPack)
|
|
D |= ExprDependence::UnexpandedPack;
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CXXUnresolvedConstructExpr *E) {
|
|
auto D = ExprDependence::ValueInstantiation;
|
|
D |= toExprDependenceAsWritten(E->getTypeAsWritten()->getDependence());
|
|
D |= toExprDependenceForImpliedType(E->getType()->getDependence());
|
|
for (auto *A : E->arguments())
|
|
D |= A->getDependence() &
|
|
(ExprDependence::UnexpandedPack | ExprDependence::Error);
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CXXDependentScopeMemberExpr *E) {
|
|
auto D = ExprDependence::TypeValueInstantiation;
|
|
if (!E->isImplicitAccess())
|
|
D |= E->getBase()->getDependence();
|
|
D |= toExprDependence(E->getQualifier().getDependence());
|
|
D |= getDependenceInExpr(E->getMemberNameInfo());
|
|
for (const auto &A : E->template_arguments())
|
|
D |= toExprDependence(A.getArgument().getDependence());
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(MaterializeTemporaryExpr *E) {
|
|
return E->getSubExpr()->getDependence();
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CXXFoldExpr *E) {
|
|
auto D = ExprDependence::TypeValueInstantiation;
|
|
for (const auto *C : {E->getLHS(), E->getRHS()}) {
|
|
if (C)
|
|
D |= C->getDependence() & ~ExprDependence::UnexpandedPack;
|
|
}
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(CXXParenListInitExpr *E) {
|
|
auto D = ExprDependence::None;
|
|
for (const auto *A : E->getInitExprs())
|
|
D |= A->getDependence();
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(TypeTraitExpr *E) {
|
|
auto D = ExprDependence::None;
|
|
for (const auto *A : E->getArgs())
|
|
D |= toExprDependenceAsWritten(A->getType()->getDependence()) &
|
|
~ExprDependence::Type;
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ConceptSpecializationExpr *E,
|
|
bool ValueDependent) {
|
|
auto TA = TemplateArgumentDependence::None;
|
|
const auto InterestingDeps = TemplateArgumentDependence::Instantiation |
|
|
TemplateArgumentDependence::UnexpandedPack;
|
|
for (const TemplateArgumentLoc &ArgLoc :
|
|
E->getTemplateArgsAsWritten()->arguments()) {
|
|
TA |= ArgLoc.getArgument().getDependence() & InterestingDeps;
|
|
if (TA == InterestingDeps)
|
|
break;
|
|
}
|
|
|
|
ExprDependence D =
|
|
ValueDependent ? ExprDependence::Value : ExprDependence::None;
|
|
auto Res = D | toExprDependence(TA);
|
|
if(!ValueDependent && E->getSatisfaction().ContainsErrors)
|
|
Res |= ExprDependence::Error;
|
|
return Res;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ObjCArrayLiteral *E) {
|
|
auto D = ExprDependence::None;
|
|
Expr **Elements = E->getElements();
|
|
for (unsigned I = 0, N = E->getNumElements(); I != N; ++I)
|
|
D |= turnTypeToValueDependence(Elements[I]->getDependence());
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ObjCDictionaryLiteral *E) {
|
|
auto Deps = ExprDependence::None;
|
|
for (unsigned I = 0, N = E->getNumElements(); I < N; ++I) {
|
|
auto KV = E->getKeyValueElement(I);
|
|
auto KVDeps = turnTypeToValueDependence(KV.Key->getDependence() |
|
|
KV.Value->getDependence());
|
|
if (KV.EllipsisLoc.isValid())
|
|
KVDeps &= ~ExprDependence::UnexpandedPack;
|
|
Deps |= KVDeps;
|
|
}
|
|
return Deps;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(ObjCMessageExpr *E) {
|
|
auto D = ExprDependence::None;
|
|
if (auto *R = E->getInstanceReceiver())
|
|
D |= R->getDependence();
|
|
else
|
|
D |= toExprDependenceForImpliedType(E->getType()->getDependence());
|
|
for (auto *A : E->arguments())
|
|
D |= A->getDependence();
|
|
return D;
|
|
}
|
|
|
|
ExprDependence clang::computeDependence(OpenACCAsteriskSizeExpr *E) {
|
|
// This represents a simple asterisk as typed, so cannot be dependent in any
|
|
// way.
|
|
return ExprDependence::None;
|
|
}
|