llvm-project/clang/lib/AST/ComputeDependence.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

900 lines
33 KiB
C++
Raw Normal View History

//===- 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())
Revert "Following up on PR48517, fix handling of template arguments that refer" Combined with 'da98651 - Revert "DR2064: decltype(E) is only a dependent', this change (5a391d3) caused verifier errors when building Chromium. See https://crbug.com/1168494#c1 for a reproducer. Additionally it reverts changes that were dependent on this one, see below. > Following up on PR48517, fix handling of template arguments that refer > to dependent declarations. > > Treat an id-expression that names a local variable in a templated > function as being instantiation-dependent. > > This addresses a language defect whereby a reference to a dependent > declaration can be formed without any construct being value-dependent. > Fixing that through value-dependence turns out to be problematic, so > instead this patch takes the approach (proposed on the core reflector) > of allowing the use of pointers or references to (but not values of) > dependent declarations inside value-dependent expressions, and instead > treating template arguments as dependent if they evaluate to a constant > involving such dependent declarations. > > This ends up affecting a bunch of OpenMP tests, due to OpenMP > imprecisely handling instantiation-dependent constructs, bailing out > early instead of processing dependent constructs to the extent possible > when handling the template. > > Previously committed as 8c1f2d15b826591cdf6bd6b468b8a7d23377b29e, and > reverted because a dependency commit was reverted. This reverts commit 5a391d38ac6c561ba908334d427f26124ed9132e. It also restores clang/test/SemaCXX/coroutines.cpp to its state before da986511fb9da1a46a0ca4dba2e49e2426036303. Revert "[c++20] P1907R1: Support for generalized non-type template arguments of scalar type." > Previously committed as 9e08e51a20d0d2b1c5724bb17e969d036fced4cd, and > reverted because a dependency commit was reverted. This incorporates the > following follow-on commits that were also reverted: > > 7e84aa1b81e72d44bcc58ffe1731bfc7abb73ce0 by Simon Pilgrim > ed13d8c66781b50ff007cb089c5905f9bb9e8af2 by me > 95c7b6cadbc9a3d4376ef44edbeb3c8bb5b8d7fc by Sam McCall > 430d5d8429473c2b10b109991d7577a3cea41140 by Dave Zarzycki This reverts commit 4b574008aef5a7235c1f894ab065fe300d26e786. Revert "[msabi] Mangle a template argument referring to array-to-pointer decay" > [msabi] Mangle a template argument referring to array-to-pointer decay > applied to an array the same as the array itself. > > This follows MS ABI, and corrects a regression from the implementation > of generalized non-type template parameters, where we "forgot" how to > mangle this case. This reverts commit 18e093faf726d15f210ab4917142beec51848258.
2021-01-20 15:25:33 +01:00
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>()) {
[AST] Fix recovery-expr crash on invalid aligned attr. Summary: crash stack: ``` lang: tools/clang/include/clang/AST/AttrImpl.inc:1490: unsigned int clang::AlignedAttr::getAlignment(clang::ASTContext &) const: Assertion `!isAlignmentDependent()' failed. PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace, preprocessed source, and associated run script. Stack dump: 0. Program arguments: ./bin/clang -cc1 -std=c++1y -ast-dump -frecovery-ast -fcxx-exceptions /tmp/t4.cpp 1. /tmp/t4.cpp:3:31: current parser token ';' #0 0x0000000002530cff llvm::sys::PrintStackTrace(llvm::raw_ostream&) llvm-project/llvm/lib/Support/Unix/Signals.inc:564:13 #1 0x000000000252ee30 llvm::sys::RunSignalHandlers() llvm-project/llvm/lib/Support/Signals.cpp:69:18 #2 0x000000000253126c SignalHandler(int) llvm-project/llvm/lib/Support/Unix/Signals.inc:396:3 #3 0x00007f86964d0520 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x13520) #4 0x00007f8695f9ff61 raise /build/glibc-oCLvUT/glibc-2.29/signal/../sysdeps/unix/sysv/linux/raise.c:51:1 #5 0x00007f8695f8b535 abort /build/glibc-oCLvUT/glibc-2.29/stdlib/abort.c:81:7 #6 0x00007f8695f8b40f _nl_load_domain /build/glibc-oCLvUT/glibc-2.29/intl/loadmsgcat.c:1177:9 #7 0x00007f8695f98b92 (/lib/x86_64-linux-gnu/libc.so.6+0x32b92) #8 0x0000000004503d9f llvm::APInt::getZExtValue() const llvm-project/llvm/include/llvm/ADT/APInt.h:1623:5 #9 0x0000000004503d9f clang::AlignedAttr::getAlignment(clang::ASTContext&) const llvm-project/build/tools/clang/include/clang/AST/AttrImpl.inc:1492:0 ``` Reviewers: sammccall Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D78085
2020-04-12 23:06:00 +02:00
if (I->isAlignmentErrorDependent())
Deps |= ExprDependence::Error;
if (I->isAlignmentDependent())
[AST] Fix recovery-expr crash on invalid aligned attr. Summary: crash stack: ``` lang: tools/clang/include/clang/AST/AttrImpl.inc:1490: unsigned int clang::AlignedAttr::getAlignment(clang::ASTContext &) const: Assertion `!isAlignmentDependent()' failed. PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace, preprocessed source, and associated run script. Stack dump: 0. Program arguments: ./bin/clang -cc1 -std=c++1y -ast-dump -frecovery-ast -fcxx-exceptions /tmp/t4.cpp 1. /tmp/t4.cpp:3:31: current parser token ';' #0 0x0000000002530cff llvm::sys::PrintStackTrace(llvm::raw_ostream&) llvm-project/llvm/lib/Support/Unix/Signals.inc:564:13 #1 0x000000000252ee30 llvm::sys::RunSignalHandlers() llvm-project/llvm/lib/Support/Signals.cpp:69:18 #2 0x000000000253126c SignalHandler(int) llvm-project/llvm/lib/Support/Unix/Signals.inc:396:3 #3 0x00007f86964d0520 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x13520) #4 0x00007f8695f9ff61 raise /build/glibc-oCLvUT/glibc-2.29/signal/../sysdeps/unix/sysv/linux/raise.c:51:1 #5 0x00007f8695f8b535 abort /build/glibc-oCLvUT/glibc-2.29/stdlib/abort.c:81:7 #6 0x00007f8695f8b40f _nl_load_domain /build/glibc-oCLvUT/glibc-2.29/intl/loadmsgcat.c:1177:9 #7 0x00007f8695f98b92 (/lib/x86_64-linux-gnu/libc.so.6+0x32b92) #8 0x0000000004503d9f llvm::APInt::getZExtValue() const llvm-project/llvm/include/llvm/ADT/APInt.h:1623:5 #9 0x0000000004503d9f clang::AlignedAttr::getAlignment(clang::ASTContext&) const llvm-project/build/tools/clang/include/clang/AST/AttrImpl.inc:1492:0 ``` Reviewers: sammccall Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D78085
2020-04-12 23:06:00 +02:00
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 state 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::Value;
}
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) {
auto D = toExprDependenceForImpliedType(E->getType()->getDependence());
if (E->getBlockDecl()->isDependentContext())
D |= ExprDependence::Instantiation;
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());
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(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(OMPArraySectionExpr *E) {
auto D = E->getBase()->getDependence();
if (auto *LB = E->getLowerBound())
D |= LB->getDependence();
if (auto *Len = E->getLength())
D |= Len->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;
if (auto *NNS = E->getQualifier())
Deps |= toExprDependence(NNS->getDependence() &
~NestedNameSpecifierDependence::Dependent);
if (auto *FirstArg = E->getTemplateArgs()) {
unsigned NumArgs = E->getNumTemplateArgs();
for (auto *Arg = FirstArg, *End = FirstArg + NumArgs; Arg < End; ++Arg)
Revert "Following up on PR48517, fix handling of template arguments that refer" Combined with 'da98651 - Revert "DR2064: decltype(E) is only a dependent', this change (5a391d3) caused verifier errors when building Chromium. See https://crbug.com/1168494#c1 for a reproducer. Additionally it reverts changes that were dependent on this one, see below. > Following up on PR48517, fix handling of template arguments that refer > to dependent declarations. > > Treat an id-expression that names a local variable in a templated > function as being instantiation-dependent. > > This addresses a language defect whereby a reference to a dependent > declaration can be formed without any construct being value-dependent. > Fixing that through value-dependence turns out to be problematic, so > instead this patch takes the approach (proposed on the core reflector) > of allowing the use of pointers or references to (but not values of) > dependent declarations inside value-dependent expressions, and instead > treating template arguments as dependent if they evaluate to a constant > involving such dependent declarations. > > This ends up affecting a bunch of OpenMP tests, due to OpenMP > imprecisely handling instantiation-dependent constructs, bailing out > early instead of processing dependent constructs to the extent possible > when handling the template. > > Previously committed as 8c1f2d15b826591cdf6bd6b468b8a7d23377b29e, and > reverted because a dependency commit was reverted. This reverts commit 5a391d38ac6c561ba908334d427f26124ed9132e. It also restores clang/test/SemaCXX/coroutines.cpp to its state before da986511fb9da1a46a0ca4dba2e49e2426036303. Revert "[c++20] P1907R1: Support for generalized non-type template arguments of scalar type." > Previously committed as 9e08e51a20d0d2b1c5724bb17e969d036fced4cd, and > reverted because a dependency commit was reverted. This incorporates the > following follow-on commits that were also reverted: > > 7e84aa1b81e72d44bcc58ffe1731bfc7abb73ce0 by Simon Pilgrim > ed13d8c66781b50ff007cb089c5905f9bb9e8af2 by me > 95c7b6cadbc9a3d4376ef44edbeb3c8bb5b8d7fc by Sam McCall > 430d5d8429473c2b10b109991d7577a3cea41140 by Dave Zarzycki This reverts commit 4b574008aef5a7235c1f894ab065fe300d26e786. Revert "[msabi] Mangle a template argument referring to array-to-pointer decay" > [msabi] Mangle a template argument referring to array-to-pointer decay > applied to an array the same as the array itself. > > This follows MS ABI, and corrects a regression from the implementation > of generalized non-type template parameters, where we "forgot" how to > mangle this case. This reverts commit 18e093faf726d15f210ab4917142beec51848258.
2021-01-20 15:25:33 +01:00
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
//
// [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())
return Deps | ExprDependence::TypeValueInstantiation;
else if (Type->isInstantiationDependentType())
Deps |= ExprDependence::Instantiation;
// - 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 (Var->mightBeUsableInConstantExpressions(Ctx)) {
if (const Expr *Init = Var->getAnyInitializer()) {
if (Init->isValueDependent())
Deps |= ExprDependence::ValueInstantiation;
if (Init->containsErrors())
Deps |= ExprDependence::Error;
}
}
// - 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;
}
[AST] Add RecoveryExpr to retain expressions on semantic errors Normally clang avoids creating expressions when it encounters semantic errors, even if the parser knows which expression to produce. This works well for the compiler. However, this is not ideal for source-level tools that have to deal with broken code, e.g. clangd is not able to provide navigation features even for names that compiler knows how to resolve. The new RecoveryExpr aims to capture the minimal set of information useful for the tools that need to deal with incorrect code: source range of the expression being dropped, subexpressions of the expression. We aim to make constructing RecoveryExprs as simple as possible to ensure writing code to avoid dropping expressions is easy. Producing RecoveryExprs can result in new code paths being taken in the frontend. In particular, clang can produce some new diagnostics now and we aim to suppress bogus ones based on Expr::containsErrors. We deliberately produce RecoveryExprs only in the parser for now to minimize the code affected by this patch. Producing RecoveryExprs in Sema potentially allows to preserve more information (e.g. type of an expression), but also results in more code being affected. E.g. SFINAE checks will have to take presence of RecoveryExprs into account. Initial implementation only works in C++ mode, as it relies on compiler postponing diagnostics on dependent expressions. C and ObjC often do not do this, so they require more work to make sure we do not produce too many bogus diagnostics on the new expressions. See documentation of RecoveryExpr for more details. original patch from Ilya This change is based on https://reviews.llvm.org/D61722 Reviewers: sammccall, rsmith Reviewed By: sammccall, rsmith Tags: #clang Differential Revision: https://reviews.llvm.org/D69330
2020-03-19 16:30:40 +01:00
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.
[AST] Add RecoveryExpr to retain expressions on semantic errors Normally clang avoids creating expressions when it encounters semantic errors, even if the parser knows which expression to produce. This works well for the compiler. However, this is not ideal for source-level tools that have to deal with broken code, e.g. clangd is not able to provide navigation features even for names that compiler knows how to resolve. The new RecoveryExpr aims to capture the minimal set of information useful for the tools that need to deal with incorrect code: source range of the expression being dropped, subexpressions of the expression. We aim to make constructing RecoveryExprs as simple as possible to ensure writing code to avoid dropping expressions is easy. Producing RecoveryExprs can result in new code paths being taken in the frontend. In particular, clang can produce some new diagnostics now and we aim to suppress bogus ones based on Expr::containsErrors. We deliberately produce RecoveryExprs only in the parser for now to minimize the code affected by this patch. Producing RecoveryExprs in Sema potentially allows to preserve more information (e.g. type of an expression), but also results in more code being affected. E.g. SFINAE checks will have to take presence of RecoveryExprs into account. Initial implementation only works in C++ mode, as it relies on compiler postponing diagnostics on dependent expressions. C and ObjC often do not do this, so they require more work to make sure we do not produce too many bogus diagnostics on the new expressions. See documentation of RecoveryExpr for more details. original patch from Ilya This change is based on https://reviews.llvm.org/D61722 Reviewers: sammccall, rsmith Reviewed By: sammccall, rsmith Tags: #clang Differential Revision: https://reviews.llvm.org/D69330
2020-03-19 16:30:40 +01:00
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,
llvm::ArrayRef<Expr *> PreArgs) {
auto D = E->getCallee()->getDependence();
for (auto *A : llvm::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;
}
ExprDependence clang::computeDependence(MemberExpr *E) {
auto *MemberDecl = E->getMemberDecl();
auto D = E->getBase()->getDependence();
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;
}
}
// FIXME: move remaining dependence computation from MemberExpr::Create()
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 : llvm::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;
D |= E->getControllingExpr()->getDependence() & ExprDependence::Error;
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 (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 : llvm::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()));
if (auto *Q = E->getQualifier())
D |= toExprDependence(Q->getDependence() &
~NestedNameSpecifierDependence::Dependent);
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(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());
if (auto *Q = E->getQualifier())
Deps |= toExprDependence(Q->getDependence() &
~NestedNameSpecifierDependence::Dependent);
for (auto *D : E->decls()) {
if (D->getDeclContext()->isDependentContext() ||
isa<UnresolvedUsingValueDecl>(D))
Deps |= ExprDependence::TypeValueInstantiation;
}
// If we have explicit template arguments, check for dependent
// template arguments and whether they contain any unexpanded pack
// expansions.
for (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());
if (auto *Q = E->getQualifier())
D |= toExprDependence(Q->getDependence());
for (auto A : E->template_arguments())
D |= toExprDependence(A.getArgument().getDependence());
return D;
}
ExprDependence clang::computeDependence(CXXConstructExpr *E) {
ExprDependence D =
toExprDependenceForImpliedType(E->getType()->getDependence());
2020-03-17 09:48:35 +01:00
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();
if (auto *Q = E->getQualifier())
D |= toExprDependence(Q->getDependence());
D |= getDependenceInExpr(E->getMemberNameInfo());
for (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;
}