From f1b0a4fc540f986372f09768c325d505b75b414d Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 31 Mar 2022 18:40:40 -0700 Subject: [PATCH] An expression should only contain an unexpanded parameter pack if it lexically contains a mention of the pack. Systematically distinguish between syntactic and semantic references to packs, especially when propagating dependence from a type into an expression. We should consult the type-as-written when computing syntactic dependence and should consult the semantic type when computing semantic dependence. Fixes #54402. --- clang/include/clang/AST/ComputeDependence.h | 8 +- clang/include/clang/AST/DependenceFlags.h | 24 ++- clang/include/clang/AST/Expr.h | 6 +- clang/lib/AST/ComputeDependence.cpp | 149 +++++++++++------- clang/lib/AST/ExprCXX.cpp | 8 +- clang/lib/AST/Type.cpp | 10 +- .../cxx1z-class-template-argument-deduction.cpp | 16 +- clang/test/SemaTemplate/find-unexpanded-packs.cpp | 167 +++++++++++++++++++++ 8 files changed, 318 insertions(+), 70 deletions(-) create mode 100644 clang/test/SemaTemplate/find-unexpanded-packs.cpp diff --git a/clang/include/clang/AST/ComputeDependence.h b/clang/include/clang/AST/ComputeDependence.h index cb545af..3360fd1 100644 --- a/clang/include/clang/AST/ComputeDependence.h +++ b/clang/include/clang/AST/ComputeDependence.h @@ -30,7 +30,8 @@ class UnaryExprOrTypeTraitExpr; class ArraySubscriptExpr; class MatrixSubscriptExpr; class CompoundLiteralExpr; -class CastExpr; +class ImplicitCastExpr; +class ExplicitCastExpr; class BinaryOperator; class ConditionalOperator; class BinaryConditionalOperator; @@ -70,6 +71,7 @@ class CXXPseudoDestructorExpr; class OverloadExpr; class DependentScopeDeclRefExpr; class CXXConstructExpr; +class CXXTemporaryObjectExpr; class CXXDefaultInitExpr; class CXXDefaultArgExpr; class LambdaExpr; @@ -114,7 +116,8 @@ ExprDependence computeDependence(UnaryExprOrTypeTraitExpr *E); ExprDependence computeDependence(ArraySubscriptExpr *E); ExprDependence computeDependence(MatrixSubscriptExpr *E); ExprDependence computeDependence(CompoundLiteralExpr *E); -ExprDependence computeDependence(CastExpr *E); +ExprDependence computeDependence(ImplicitCastExpr *E); +ExprDependence computeDependence(ExplicitCastExpr *E); ExprDependence computeDependence(BinaryOperator *E); ExprDependence computeDependence(ConditionalOperator *E); ExprDependence computeDependence(BinaryConditionalOperator *E); @@ -156,6 +159,7 @@ ExprDependence computeDependence(OverloadExpr *E, bool KnownDependent, bool KnownContainsUnexpandedParameterPack); ExprDependence computeDependence(DependentScopeDeclRefExpr *E); ExprDependence computeDependence(CXXConstructExpr *E); +ExprDependence computeDependence(CXXTemporaryObjectExpr *E); ExprDependence computeDependence(CXXDefaultInitExpr *E); ExprDependence computeDependence(CXXDefaultArgExpr *E); ExprDependence computeDependence(LambdaExpr *E, diff --git a/clang/include/clang/AST/DependenceFlags.h b/clang/include/clang/AST/DependenceFlags.h index 62efdb4..3b3c1af 100644 --- a/clang/include/clang/AST/DependenceFlags.h +++ b/clang/include/clang/AST/DependenceFlags.h @@ -130,6 +130,14 @@ public: // Dependence that is propagated syntactically, regardless of semantics. Syntactic = UnexpandedPack | Instantiation | Error, + // Dependence that is propagated semantically, even in cases where the + // type doesn't syntactically appear. This currently excludes only + // UnexpandedPack. Even though Instantiation dependence is also notionally + // syntactic, we also want to propagate it semantically because anything + // that semantically depends on an instantiation-dependent entity should + // always be instantiated when that instantiation-dependent entity is. + Semantic = + Instantiation | Type | Value | Dependent | Error | VariablyModified, LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/VariablyModified) }; @@ -175,6 +183,14 @@ public: return Result; } + /// Extract the semantic portions of this type's dependence that apply even + /// to uses where the type does not appear syntactically. + Dependence semantic() { + Dependence Result = *this; + Result.V &= Semantic; + return Result; + } + TypeDependence type() const { return translate(V, UnexpandedPack, TypeDependence::UnexpandedPack) | translate(V, Instantiation, TypeDependence::Instantiation) | @@ -231,7 +247,10 @@ private: inline ExprDependence toExprDependence(TemplateArgumentDependence TA) { return Dependence(TA).expr(); } -inline ExprDependence toExprDependence(TypeDependence D) { +inline ExprDependence toExprDependenceForImpliedType(TypeDependence D) { + return Dependence(D).semantic().expr(); +} +inline ExprDependence toExprDependenceAsWritten(TypeDependence D) { return Dependence(D).expr(); } // Note: it's often necessary to strip `Dependent` from qualifiers. @@ -269,6 +288,9 @@ inline TypeDependence toTypeDependence(TemplateArgumentDependence D) { inline TypeDependence toSyntacticDependence(TypeDependence D) { return Dependence(D).syntactic().type(); } +inline TypeDependence toSemanticDependence(TypeDependence D) { + return Dependence(D).semantic().type(); +} inline NestedNameSpecifierDependence toNestedNameSpecifierDependendence(TypeDependence D) { diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 3ecfaa1..b4f76fd 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -3497,7 +3497,6 @@ protected: CastExprBits.BasePathSize = BasePathSize; assert((CastExprBits.BasePathSize == BasePathSize) && "BasePathSize overflow!"); - setDependence(computeDependence(this)); assert(CastConsistency()); CastExprBits.HasFPFeatures = HasFPFeatures; } @@ -3631,6 +3630,7 @@ class ImplicitCastExpr final ExprValueKind VK) : CastExpr(ImplicitCastExprClass, ty, VK, kind, op, BasePathLength, FPO.requiresTrailingStorage()) { + setDependence(computeDependence(this)); if (hasStoredFPFeatures()) *getTrailingFPFeatures() = FPO; } @@ -3708,7 +3708,9 @@ protected: CastKind kind, Expr *op, unsigned PathSize, bool HasFPFeatures, TypeSourceInfo *writtenTy) : CastExpr(SC, exprTy, VK, kind, op, PathSize, HasFPFeatures), - TInfo(writtenTy) {} + TInfo(writtenTy) { + setDependence(computeDependence(this)); + } /// Construct an empty explicit cast. ExplicitCastExpr(StmtClass SC, EmptyShell Shell, unsigned PathSize, diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index 5648cf2..2a2b987 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -26,7 +26,7 @@ ExprDependence clang::computeDependence(FullExpr *E) { } ExprDependence clang::computeDependence(OpaqueValueExpr *E) { - auto D = toExprDependence(E->getType()->getDependence()); + auto D = toExprDependenceForImpliedType(E->getType()->getDependence()); if (auto *S = E->getSourceExpr()) D |= S->getDependence(); assert(!(D & ExprDependence::UnexpandedPack)); @@ -39,8 +39,10 @@ ExprDependence clang::computeDependence(ParenExpr *E) { ExprDependence clang::computeDependence(UnaryOperator *E, const ASTContext &Ctx) { - ExprDependence Dep = toExprDependence(E->getType()->getDependence()) | - E->getSubExpr()->getDependence(); + 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 @@ -77,7 +79,7 @@ ExprDependence clang::computeDependence(UnaryExprOrTypeTraitExpr *E) { // Value-dependent if the argument is type-dependent. if (E->isArgumentType()) return turnTypeToValueDependence( - toExprDependence(E->getArgumentType()->getDependence())); + toExprDependenceAsWritten(E->getArgumentType()->getDependence())); auto ArgDeps = E->getArgumentExpr()->getDependence(); auto Deps = ArgDeps & ~ExprDependence::TypeValue; @@ -120,21 +122,36 @@ ExprDependence clang::computeDependence(MatrixSubscriptExpr *E) { } ExprDependence clang::computeDependence(CompoundLiteralExpr *E) { - return toExprDependence(E->getTypeSourceInfo()->getType()->getDependence()) | + return toExprDependenceAsWritten( + E->getTypeSourceInfo()->getType()->getDependence()) | + toExprDependenceForImpliedType(E->getType()->getDependence()) | turnTypeToValueDependence(E->getInitializer()->getDependence()); } -ExprDependence clang::computeDependence(CastExpr *E) { +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. - auto D = toExprDependence(E->getType()->getDependence()); - if (E->getStmtClass() == Stmt::ImplicitCastExprClass) { - // An implicit cast expression doesn't (lexically) contain an - // unexpanded pack, even if its target type does. - D &= ~ExprDependence::UnexpandedPack; - } + // + // 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(E)->getTypeAsWritten()->getDependence()) | + toExprDependenceForImpliedType(E->getType()->getDependence()); if (auto *S = E->getSubExpr()) D |= S->getDependence() & ~ExprDependence::Type; return D; @@ -158,7 +175,7 @@ ExprDependence clang::computeDependence(BinaryConditionalOperator *E) { } ExprDependence clang::computeDependence(StmtExpr *E, unsigned TemplateDepth) { - auto D = toExprDependence(E->getType()->getDependence()); + auto D = toExprDependenceForImpliedType(E->getType()->getDependence()); // Propagate dependence of the result. if (const auto *CompoundExprResult = dyn_cast_or_null(E->getSubStmt()->getStmtExprResult())) @@ -174,7 +191,8 @@ ExprDependence clang::computeDependence(StmtExpr *E, unsigned TemplateDepth) { } ExprDependence clang::computeDependence(ConvertVectorExpr *E) { - auto D = toExprDependence(E->getType()->getDependence()) | + auto D = toExprDependenceAsWritten( + E->getTypeSourceInfo()->getType()->getDependence()) | E->getSrcExpr()->getDependence(); if (!E->getType()->isDependentType()) D &= ~ExprDependence::Type; @@ -206,14 +224,14 @@ ExprDependence clang::computeDependence(ParenListExpr *P) { } ExprDependence clang::computeDependence(VAArgExpr *E) { - auto D = - toExprDependence(E->getWrittenTypeInfo()->getType()->getDependence()) | - (E->getSubExpr()->getDependence() & ~ExprDependence::Type); + auto D = toExprDependenceAsWritten( + E->getWrittenTypeInfo()->getType()->getDependence()) | + (E->getSubExpr()->getDependence() & ~ExprDependence::Type); return D & ~ExprDependence::Value; } ExprDependence clang::computeDependence(NoInitExpr *E) { - return toExprDependence(E->getType()->getDependence()) & + return toExprDependenceForImpliedType(E->getType()->getDependence()) & (ExprDependence::Instantiation | ExprDependence::Error); } @@ -226,7 +244,7 @@ ExprDependence clang::computeDependence(ArrayInitLoopExpr *E) { } ExprDependence clang::computeDependence(ImplicitValueInitExpr *E) { - return toExprDependence(E->getType()->getDependence()) & + return toExprDependenceForImpliedType(E->getType()->getDependence()) & ExprDependence::Instantiation; } @@ -235,14 +253,16 @@ ExprDependence clang::computeDependence(ExtVectorElementExpr *E) { } ExprDependence clang::computeDependence(BlockExpr *E) { - auto D = toExprDependence(E->getType()->getDependence()); + auto D = toExprDependenceForImpliedType(E->getType()->getDependence()); if (E->getBlockDecl()->isDependentContext()) D |= ExprDependence::Instantiation; - return D & ~ExprDependence::UnexpandedPack; + return D; } ExprDependence clang::computeDependence(AsTypeExpr *E) { - auto D = toExprDependence(E->getType()->getDependence()) | + // 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; @@ -255,15 +275,14 @@ ExprDependence clang::computeDependence(CXXRewrittenBinaryOperator *E) { ExprDependence clang::computeDependence(CXXStdInitializerListExpr *E) { auto D = turnTypeToValueDependence(E->getSubExpr()->getDependence()); - D |= toExprDependence(E->getType()->getDependence()) & - (ExprDependence::Type | ExprDependence::Error); + D |= toExprDependenceForImpliedType(E->getType()->getDependence()); return D; } ExprDependence clang::computeDependence(CXXTypeidExpr *E) { auto D = ExprDependence::None; if (E->isTypeOperand()) - D = toExprDependence( + D = toExprDependenceAsWritten( E->getTypeOperandSourceInfo()->getType()->getDependence()); else D = turnTypeToValueDependence(E->getExprOperand()->getDependence()); @@ -281,7 +300,7 @@ ExprDependence clang::computeDependence(MSPropertySubscriptExpr *E) { ExprDependence clang::computeDependence(CXXUuidofExpr *E) { if (E->isTypeOperand()) - return turnTypeToValueDependence(toExprDependence( + return turnTypeToValueDependence(toExprDependenceAsWritten( E->getTypeOperandSourceInfo()->getType()->getDependence())); return turnTypeToValueDependence(E->getExprOperand()->getDependence()); @@ -290,7 +309,7 @@ ExprDependence clang::computeDependence(CXXUuidofExpr *E) { 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 = toExprDependence(E->getType()->getDependence()); + auto D = toExprDependenceForImpliedType(E->getType()->getDependence()); assert(!(D & ExprDependence::UnexpandedPack)); return D; } @@ -307,8 +326,10 @@ ExprDependence clang::computeDependence(CXXBindTemporaryExpr *E) { } ExprDependence clang::computeDependence(CXXScalarValueInitExpr *E) { - return toExprDependence(E->getType()->getDependence()) & - ~ExprDependence::TypeValue; + auto D = toExprDependenceForImpliedType(E->getType()->getDependence()); + if (auto *TSI = E->getTypeSourceInfo()) + D |= toExprDependenceAsWritten(TSI->getType()->getDependence()); + return D; } ExprDependence clang::computeDependence(CXXDeleteExpr *E) { @@ -316,7 +337,7 @@ ExprDependence clang::computeDependence(CXXDeleteExpr *E) { } ExprDependence clang::computeDependence(ArrayTypeTraitExpr *E) { - auto D = toExprDependence(E->getQueriedType()->getDependence()); + auto D = toExprDependenceAsWritten(E->getQueriedType()->getDependence()); if (auto *Dim = E->getDimensionExpression()) D |= Dim->getDependence(); return turnTypeToValueDependence(D); @@ -366,7 +387,7 @@ ExprDependence clang::computeDependence(ObjCBoxedExpr *E) { } ExprDependence clang::computeDependence(ObjCEncodeExpr *E) { - return toExprDependence(E->getEncodedType()->getDependence()); + return toExprDependenceAsWritten(E->getEncodedType()->getDependence()); } ExprDependence clang::computeDependence(ObjCIvarRefExpr *E) { @@ -377,7 +398,8 @@ ExprDependence clang::computeDependence(ObjCPropertyRefExpr *E) { if (E->isObjectReceiver()) return E->getBase()->getDependence() & ~ExprDependence::Type; if (E->isSuperReceiver()) - return toExprDependence(E->getSuperReceiverType()->getDependence()) & + return toExprDependenceForImpliedType( + E->getSuperReceiverType()->getDependence()) & ~ExprDependence::TypeValue; assert(E->isClassReceiver()); return ExprDependence::None; @@ -406,19 +428,22 @@ ExprDependence clang::computeDependence(OMPArraySectionExpr *E) { } ExprDependence clang::computeDependence(OMPArrayShapingExpr *E) { - auto D = E->getBase()->getDependence() | - toExprDependence(E->getType()->getDependence()); + auto D = E->getBase()->getDependence(); for (Expr *Dim: E->getDimensions()) if (Dim) - D |= Dim->getDependence(); + D |= turnValueToTypeDependence(Dim->getDependence()); return D; } ExprDependence clang::computeDependence(OMPIteratorExpr *E) { - auto D = toExprDependence(E->getType()->getDependence()); + auto D = toExprDependenceForImpliedType(E->getType()->getDependence()); for (unsigned I = 0, End = E->numOfIterators(); I < End; ++I) { - if (auto *VD = cast_or_null(E->getIteratorDecl(I))) - D |= toExprDependence(VD->getType()->getDependence()); + if (auto *DD = cast_or_null(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(); @@ -451,7 +476,8 @@ ExprDependence clang::computeDependence(DeclRefExpr *E, const ASTContext &Ctx) { if (Decl->isParameterPack()) Deps |= ExprDependence::UnexpandedPack; - Deps |= toExprDependence(Type->getDependence()) & ExprDependence::Error; + Deps |= toExprDependenceForImpliedType(Type->getDependence()) & + ExprDependence::Error; // C++ [temp.dep.expr]p3: // An id-expression is type-dependent if it contains: @@ -547,7 +573,7 @@ ExprDependence clang::computeDependence(RecoveryExpr *E) { // - 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 = toExprDependence(E->getType()->getDependence()) | + auto D = toExprDependenceForImpliedType(E->getType()->getDependence()) | ExprDependence::ErrorDependent; // FIXME: remove the type-dependent bit from subexpressions, if the // RecoveryExpr has a non-dependent type. @@ -557,12 +583,12 @@ ExprDependence clang::computeDependence(RecoveryExpr *E) { } ExprDependence clang::computeDependence(SYCLUniqueStableNameExpr *E) { - return toExprDependence(E->getTypeSourceInfo()->getType()->getDependence()); + return toExprDependenceAsWritten( + E->getTypeSourceInfo()->getType()->getDependence()); } ExprDependence clang::computeDependence(PredefinedExpr *E) { - return toExprDependence(E->getType()->getDependence()) & - ~ExprDependence::UnexpandedPack; + return toExprDependenceForImpliedType(E->getType()->getDependence()); } ExprDependence clang::computeDependence(CallExpr *E, @@ -578,8 +604,8 @@ ExprDependence clang::computeDependence(CallExpr *E, } ExprDependence clang::computeDependence(OffsetOfExpr *E) { - auto D = turnTypeToValueDependence( - toExprDependence(E->getTypeSourceInfo()->getType()->getDependence())); + 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; @@ -615,7 +641,7 @@ ExprDependence clang::computeDependence(InitListExpr *E) { } ExprDependence clang::computeDependence(ShuffleVectorExpr *E) { - auto D = toExprDependence(E->getType()->getDependence()); + auto D = toExprDependenceForImpliedType(E->getType()->getDependence()); for (auto *C : llvm::makeArrayRef(E->getSubExprs(), E->getNumSubExprs())) D |= C->getDependence(); return D; @@ -666,7 +692,9 @@ ExprDependence clang::computeDependence(AtomicExpr *A) { } ExprDependence clang::computeDependence(CXXNewExpr *E) { - auto D = toExprDependence(E->getType()->getDependence()); + auto D = toExprDependenceAsWritten( + E->getAllocatedTypeSourceInfo()->getType()->getDependence()); + D |= toExprDependenceForImpliedType(E->getAllocatedType()->getDependence()); auto Size = E->getArraySize(); if (Size.hasValue() && *Size) D |= turnTypeToValueDependence((*Size)->getDependence()); @@ -679,11 +707,11 @@ ExprDependence clang::computeDependence(CXXNewExpr *E) { ExprDependence clang::computeDependence(CXXPseudoDestructorExpr *E) { auto D = E->getBase()->getDependence(); - if (!E->getDestroyedType().isNull()) - D |= toExprDependence(E->getDestroyedType()->getDependence()); + if (auto *TSI = E->getDestroyedTypeInfo()) + D |= toExprDependenceAsWritten(TSI->getType()->getDependence()); if (auto *ST = E->getScopeTypeInfo()) D |= turnTypeToValueDependence( - toExprDependence(ST->getType()->getDependence())); + toExprDependenceAsWritten(ST->getType()->getDependence())); if (auto *Q = E->getQualifier()) D |= toExprDependence(Q->getDependence() & ~NestedNameSpecifierDependence::Dependent); @@ -738,12 +766,20 @@ ExprDependence clang::computeDependence(DependentScopeDeclRefExpr *E) { } ExprDependence clang::computeDependence(CXXConstructExpr *E) { - auto D = toExprDependence(E->getType()->getDependence()); + 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(); } @@ -754,7 +790,7 @@ ExprDependence clang::computeDependence(CXXDefaultArgExpr *E) { ExprDependence clang::computeDependence(LambdaExpr *E, bool ContainsUnexpandedParameterPack) { - auto D = toExprDependence(E->getType()->getDependence()); + auto D = toExprDependenceForImpliedType(E->getType()->getDependence()); if (ContainsUnexpandedParameterPack) D |= ExprDependence::UnexpandedPack; return D; @@ -762,7 +798,8 @@ ExprDependence clang::computeDependence(LambdaExpr *E, ExprDependence clang::computeDependence(CXXUnresolvedConstructExpr *E) { auto D = ExprDependence::ValueInstantiation; - D |= toExprDependence(E->getType()->getDependence()); + D |= toExprDependenceAsWritten(E->getTypeAsWritten()->getDependence()); + D |= toExprDependenceForImpliedType(E->getType()->getDependence()); for (auto *A : E->arguments()) D |= A->getDependence() & (ExprDependence::UnexpandedPack | ExprDependence::Error); @@ -797,8 +834,8 @@ ExprDependence clang::computeDependence(CXXFoldExpr *E) { ExprDependence clang::computeDependence(TypeTraitExpr *E) { auto D = ExprDependence::None; for (const auto *A : E->getArgs()) - D |= - toExprDependence(A->getType()->getDependence()) & ~ExprDependence::Type; + D |= toExprDependenceAsWritten(A->getType()->getDependence()) & + ~ExprDependence::Type; return D; } @@ -845,7 +882,7 @@ ExprDependence clang::computeDependence(ObjCMessageExpr *E) { if (auto *R = E->getInstanceReceiver()) D |= R->getDependence(); else - D |= toExprDependence(E->getType()->getDependence()); + D |= toExprDependenceForImpliedType(E->getType()->getDependence()); for (auto *A : E->arguments()) D |= A->getDependence(); return D; diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index c98cfd7..55f3c35 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -989,7 +989,9 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr( Cons, /* Elidable=*/false, Args, HadMultipleCandidates, ListInitialization, StdInitListInitialization, ZeroInitialization, CXXConstructExpr::CK_Complete, ParenOrBraceRange), - TSI(TSI) {} + TSI(TSI) { + setDependence(computeDependence(this)); +} CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(EmptyShell Empty, unsigned NumArgs) @@ -1075,7 +1077,9 @@ CXXConstructExpr::CXXConstructExpr( TrailingArgs[I] = Args[I]; } - setDependence(computeDependence(this)); + // CXXTemporaryObjectExpr does this itself after setting its TypeSourceInfo. + if (SC == CXXConstructExprClass) + setDependence(computeDependence(this)); } CXXConstructExpr::CXXConstructExpr(StmtClass SC, EmptyShell Empty, diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index a7fdcdd..936550d 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -722,8 +722,7 @@ bool Type::isObjCClassOrClassKindOfType() const { ObjCTypeParamType::ObjCTypeParamType(const ObjCTypeParamDecl *D, QualType can, ArrayRef protocols) - : Type(ObjCTypeParam, can, - can->getDependence() & ~TypeDependence::UnexpandedPack), + : Type(ObjCTypeParam, can, toSemanticDependence(can->getDependence())), OTPDecl(const_cast(D)) { initialize(protocols); } @@ -3409,7 +3408,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, TypedefType::TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType underlying, QualType can) - : Type(tc, can, underlying->getDependence()), + : Type(tc, can, toSemanticDependence(underlying->getDependence())), Decl(const_cast(D)) { assert(!isa(can) && "Invalid canonical type"); } @@ -3420,7 +3419,7 @@ QualType TypedefType::desugar() const { UsingType::UsingType(const UsingShadowDecl *Found, QualType Underlying, QualType Canon) - : Type(Using, Canon, Underlying->getDependence()), + : Type(Using, Canon, toSemanticDependence(Underlying->getDependence())), Found(const_cast(Found)) { assert(Underlying == getUnderlyingType()); } @@ -3676,8 +3675,7 @@ TemplateSpecializationType::TemplateSpecializationType( : Type(TemplateSpecialization, Canon.isNull() ? QualType(this, 0) : Canon, (Canon.isNull() ? TypeDependence::DependentInstantiation - : Canon->getDependence() & ~(TypeDependence::VariablyModified | - TypeDependence::UnexpandedPack)) | + : toSemanticDependence(Canon->getDependence())) | (toTypeDependence(T.getDependence()) & TypeDependence::UnexpandedPack)), Template(T) { diff --git a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp index 5a49f28..a490d31 100644 --- a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp +++ b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp @@ -294,7 +294,7 @@ namespace tuple_tests { } namespace dependent { - template struct X { + template struct X { // expected-note 3{{here}} X(T); }; template int Var(T t) { @@ -304,12 +304,26 @@ namespace dependent { template int Cast(T t) { return X(X(t)) + 1; // expected-error {{invalid operands}} } + template int Cast2(T t) { + return (X)(X)t + 1; // expected-error {{deduction not allowed}} + } + template int Cast3(T t) { + return X{X{t}} + 1; // expected-error {{invalid operands}} + } + template int Cast4(T t) { + return (X){(X){t}} + 1; // expected-error 2{{deduction not allowed}} + } template int New(T t) { return X(new X(t)) + 1; // expected-error {{invalid operands}} }; + template int *New2(T t) { + return new X(X(t)) * 2; // expected-error {{invalid operands}} + }; template int Var(float); // expected-note {{instantiation of}} template int Cast(float); // expected-note {{instantiation of}} + template int Cast3(float); // expected-note {{instantiation of}} template int New(float); // expected-note {{instantiation of}} + template int *New2(float); // expected-note {{instantiation of}} template int operator+(X, int); template int Var(int); template int Cast(int); diff --git a/clang/test/SemaTemplate/find-unexpanded-packs.cpp b/clang/test/SemaTemplate/find-unexpanded-packs.cpp new file mode 100644 index 0000000..ae989c6 --- /dev/null +++ b/clang/test/SemaTemplate/find-unexpanded-packs.cpp @@ -0,0 +1,167 @@ +// RUN: %clang_cc1 -verify %s -std=c++17 -Wno-unused + +template void PackInsideTypedefDeclaration() { + ([] { + typedef Ts Type; + (void)Type(); + }(), ...); +} +template void PackInsideTypedefDeclaration<>(); +template void PackInsideTypedefDeclaration(); +template void PackInsideTypedefDeclaration(); + +template void PackInsideTypedefDeclarationInvalid() { + [] { // expected-error {{contains unexpanded parameter pack 'Ts'}} + typedef Ts Type; + (void)Type(); + }; + + ([] { + typedef Ts Type; + // A reference to a typedef containing an unexpanded pack does not + // itself contain an unexpanded pack. + f(Type()...); // expected-error {{does not contain any unexpanded}} + }, ...); +} + + +template void PackInsideAliasDeclaration() { + ([] { + using Type = Ts; + (void)Type(); + }(), ...); +} +template void PackInsideAliasDeclaration<>(); +template void PackInsideAliasDeclaration(); +template void PackInsideAliasDeclaration(); + +template void PackInsideAliasDeclarationInvalid() { + [] { // expected-error {{contains unexpanded parameter pack 'Ts'}} + using Type = Ts; + (void)Type(); + }; + ([] { + using Type = Ts; + // A reference to an alias containing an unexpanded pack does not + // itself contain an unexpanded pack. + f(Type()...); // expected-error {{does not contain any unexpanded}} + }, ...); +} + + +template void PackInsideUsingDeclaration() { + ([] { + struct A { + using Type = Ts; + }; + struct B : A { + using typename A::Type; + }; + (void)typename B::Type(); + }(), ...); +} +template void PackInsideUsingDeclaration<>(); +template void PackInsideUsingDeclaration(); +template void PackInsideUsingDeclaration(); + +template void PackInsideUsingDeclarationInvalid() { + ([] { + struct A { + using Type = Ts; + }; + struct B : A { + using typename A::Type...; // expected-error {{does not contain any unexpanded}} + }; + }(), ...); +} + + +template void PackInsideVarDeclaration() { + ([] { + Ts ts; + (void)ts; + }, ...); +} +template void PackInsideVarDeclaration<>(); +template void PackInsideVarDeclaration(); +template void PackInsideVarDeclaration(); + +template void PackInsideVarDeclarationInvalid() { + [] { // expected-error {{contains unexpanded parameter pack 'Ts'}} + Ts ts; + (void)ts; + }; +} + + +template void PackInsideFunctionDeclaration() { + ([] { + Ts ts(Ts); + ts({}); + }, ...); +} +template void PackInsideFunctionDeclaration<>(); +template void PackInsideFunctionDeclaration(); +template void PackInsideFunctionDeclaration(); + +template void PackInsideFunctionDeclarationInvalid() { + [] { // expected-error {{contains unexpanded parameter pack 'Ts'}} + Ts ts(Ts); + ts({}); + }; +} + + +template void PackInsideLocalClass() { + ([] { + class Local { + Ts ts; + }; + Local l; + }, ...); +} +template void PackInsideLocalClass<>(); +template void PackInsideLocalClass(); +template void PackInsideLocalClass(); + +template void PackInsideLocalClassInvalid() { + [] { // expected-error {{contains unexpanded parameter pack 'Ts'}} + class Local { + Ts ts; + }; + Local l; + }; +} + +template using Int = int; +struct AClass {}; +template using Class = AClass; +template void HiddenPack() { + (Int(), ...); + (Int{}, ...); + (Class(), ...); + (Class{}, ...); + + ([] { + Int(); + }, ...); + ([] { + Int{}; + }, ...); + ([] { + Class(); + }, ...); + ([] { + Class{}; + }, ...); +} +template void HiddenPack<>(); +template void HiddenPack(); +template void HiddenPack(); + +template void HiddenPackInvalid() { + Int(); // expected-error {{unexpanded}} + Int{}; // expected-error {{unexpanded}} + Class(); // expected-error {{unexpanded}} + Class{}; // expected-error {{unexpanded}} +} -- 2.7.4