Author: Richard Smith Date: 2020-06-18T17:52:13-07:00 New Revision: c36b03e32556a966e584386ac7dbb110bc7e4bc5
URL: https://github.com/llvm/llvm-project/commit/c36b03e32556a966e584386ac7dbb110bc7e4bc5 DIFF: https://github.com/llvm/llvm-project/commit/c36b03e32556a966e584386ac7dbb110bc7e4bc5.diff LOG: The type of a reference to a non-type template parameter pack should not be a pack expansion type. Using a pack expansion type for a pack declaration makes sense, but general expressions should never have pack expansion types. If we have a pack `T *...V`, then the type of `V` is the type `T *`, which contains an unexpanded pack, and is a pointer type. This allows us to better diagnose issues where a template is invalid due to some non-dependent portion of a dependent type of a non-type template parameter pack. Added: Modified: clang/include/clang/AST/Type.h clang/lib/AST/ASTContext.cpp clang/lib/AST/Type.cpp clang/lib/Sema/SemaExpr.cpp clang/test/AST/ast-dump-expr-json.cpp clang/test/AST/ast-dump-expr.cpp clang/test/Import/pack-expansion-expr/test.cpp clang/test/SemaTemplate/temp_arg_nontype.cpp Removed: ################################################################################ diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index d32e657843da..10b8b41efeeb 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -944,6 +944,12 @@ class QualType { /// from non-class types (in C++) or all types (in C). QualType getNonLValueExprType(const ASTContext &Context) const; + /// Remove an outer pack expansion type (if any) from this type. Used as part + /// of converting the type of a declaration to the type of an expression that + /// references that expression. It's meaningless for an expression to have a + /// pack expansion type. + QualType getNonPackExpansionType() const; + /// Return the specified type with any "sugar" removed from /// the type. This takes off typedefs, typeof's etc. If the outer level of /// the type is already concrete, it returns it unmodified. This is similar diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 01a737e307d0..2ba643f12a82 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -4724,7 +4724,7 @@ TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) { } else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { Expr *E = new (*this) DeclRefExpr( *this, NTTP, /*enclosing*/ false, - NTTP->getType().getNonLValueExprType(*this), + NTTP->getType().getNonPackExpansionType().getNonLValueExprType(*this), Expr::getValueKindForType(NTTP->getType()), NTTP->getLocation()); if (NTTP->isParameterPack()) diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 7dd85d1e16ab..ba0d86befe1b 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3049,6 +3049,13 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { llvm_unreachable("Invalid builtin type."); } +QualType QualType::getNonPackExpansionType() const { + // We never wrap type sugar around a PackExpansionType. + if (auto *PET = dyn_cast<PackExpansionType>(getTypePtr())) + return PET->getPattern(); + return *this; +} + QualType QualType::getNonLValueExprType(const ASTContext &Context) const { if (const auto *RefType = getTypePtr()->getAs<ReferenceType>()) return RefType->getPointeeType(); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 64cb47eab70a..59e7d88b7691 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3151,6 +3151,11 @@ ExprResult Sema::BuildDeclarationNameExpr( return ExprError(); ExprValueKind valueKind = VK_RValue; + // In 'T ...V;', the type of the declaration 'V' is 'T...', but the type of + // a reference to 'V' is simply (unexpanded) 'T'. The type, like the value, + // is expanded by some outer '...' in the context of the use. + type = type.getNonPackExpansionType(); + switch (D->getKind()) { // Ignore all the non-ValueDecl kinds. #define ABSTRACT_DECL(kind) diff --git a/clang/test/AST/ast-dump-expr-json.cpp b/clang/test/AST/ast-dump-expr-json.cpp index 403ce670f193..245c56cafdae 100644 --- a/clang/test/AST/ast-dump-expr-json.cpp +++ b/clang/test/AST/ast-dump-expr-json.cpp @@ -5042,7 +5042,7 @@ void TestNonADLCall3() { // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "type": { -// CHECK-NEXT: "qualType": "Ts..." +// CHECK-NEXT: "qualType": "Ts" // CHECK-NEXT: }, // CHECK-NEXT: "valueCategory": "lvalue", // CHECK-NEXT: "referencedDecl": { @@ -6622,7 +6622,7 @@ void TestNonADLCall3() { // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "type": { -// CHECK-NEXT: "qualType": "Ts..." +// CHECK-NEXT: "qualType": "Ts" // CHECK-NEXT: }, // CHECK-NEXT: "valueCategory": "lvalue", // CHECK-NEXT: "referencedDecl": { @@ -7603,7 +7603,7 @@ void TestNonADLCall3() { // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "type": { -// CHECK-NEXT: "qualType": "Ts..." +// CHECK-NEXT: "qualType": "Ts" // CHECK-NEXT: }, // CHECK-NEXT: "valueCategory": "lvalue", // CHECK-NEXT: "referencedDecl": { @@ -7656,7 +7656,7 @@ void TestNonADLCall3() { // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "type": { -// CHECK-NEXT: "qualType": "Ts..." +// CHECK-NEXT: "qualType": "Ts" // CHECK-NEXT: }, // CHECK-NEXT: "valueCategory": "lvalue", // CHECK-NEXT: "referencedDecl": { @@ -7707,7 +7707,7 @@ void TestNonADLCall3() { // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "type": { -// CHECK-NEXT: "qualType": "Ts..." +// CHECK-NEXT: "qualType": "Ts" // CHECK-NEXT: }, // CHECK-NEXT: "valueCategory": "lvalue", // CHECK-NEXT: "referencedDecl": { diff --git a/clang/test/AST/ast-dump-expr.cpp b/clang/test/AST/ast-dump-expr.cpp index f04c311c6347..d52caf329f99 100644 --- a/clang/test/AST/ast-dump-expr.cpp +++ b/clang/test/AST/ast-dump-expr.cpp @@ -327,7 +327,7 @@ void PrimaryExpressions(Ts... a) { // CHECK-NEXT: CompoundStmt // CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <col:4> col:4 implicit 'Ts...' // CHECK-NEXT: ParenListExpr 0x{{[^ ]*}} <col:4> 'NULL TYPE' - // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:4> 'Ts...' lvalue ParmVar 0x{{[^ ]*}} 'a' 'Ts...' + // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:4> 'Ts' lvalue ParmVar 0x{{[^ ]*}} 'a' 'Ts...' // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} <col:9, col:10> [=]{}; @@ -440,7 +440,7 @@ void PrimaryExpressions(Ts... a) { // CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <col:4> col:4 implicit 'Ts...' // CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <col:10> col:10 implicit 'int':'int' // CHECK-NEXT: ParenListExpr 0x{{[^ ]*}} <col:4> 'NULL TYPE' - // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:4> 'Ts...' lvalue ParmVar 0x{{[^ ]*}} 'a' 'Ts...' + // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:4> 'Ts' lvalue ParmVar 0x{{[^ ]*}} 'a' 'Ts...' // CHECK-NEXT: IntegerLiteral 0x{{[^ ]*}} <col:14> 'int' 12 // CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} <col:17, col:18> @@ -514,17 +514,17 @@ void PrimaryExpressions(Ts... a) { (a + ...); // CHECK: CXXFoldExpr 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:11> '<dependent type>' - // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:4> 'Ts...' lvalue ParmVar 0x{{[^ ]*}} 'a' 'Ts...' + // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:4> 'Ts' lvalue ParmVar 0x{{[^ ]*}} 'a' 'Ts...' // CHECK-NEXT: <<<NULL>>> (... + a); // CHECK: CXXFoldExpr 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:11> '<dependent type>' // CHECK-NEXT: <<<NULL>>> - // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:10> 'Ts...' lvalue ParmVar 0x{{[^ ]*}} 'a' 'Ts...' + // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:10> 'Ts' lvalue ParmVar 0x{{[^ ]*}} 'a' 'Ts...' (a + ... + b); // CHECK: CXXFoldExpr 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:15> '<dependent type>' - // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:4> 'Ts...' lvalue ParmVar 0x{{[^ ]*}} 'a' 'Ts...' + // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:4> 'Ts' lvalue ParmVar 0x{{[^ ]*}} 'a' 'Ts...' // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:14> 'int' lvalue Var 0x{{[^ ]*}} 'b' 'int' } diff --git a/clang/test/Import/pack-expansion-expr/test.cpp b/clang/test/Import/pack-expansion-expr/test.cpp index 3e9867b1a736..6866c41cfbcf 100644 --- a/clang/test/Import/pack-expansion-expr/test.cpp +++ b/clang/test/Import/pack-expansion-expr/test.cpp @@ -3,9 +3,10 @@ // CHECK: PackExpansionExpr // CHECK-SAME: '<dependent type>' // CHECK-NEXT: DeclRefExpr -// CHECK-SAME: 'T...' +// CHECK-SAME: 'T' // CHECK-SAME: ParmVar // CHECK-SAME: 'a' +// CHECK-SAME: 'T...' void expr() { f(); diff --git a/clang/test/SemaTemplate/temp_arg_nontype.cpp b/clang/test/SemaTemplate/temp_arg_nontype.cpp index 245b9a60269d..dd086dbb25bc 100644 --- a/clang/test/SemaTemplate/temp_arg_nontype.cpp +++ b/clang/test/SemaTemplate/temp_arg_nontype.cpp @@ -506,3 +506,11 @@ namespace complete_array_from_incomplete { extern const char *const kStrs[3] = {}; Derived<T, kStrs> d; } + +namespace type_of_pack { + template<typename ...T> struct A { // expected-warning 0-1{{extension}} + template<T *...V> void f() { + g(V.f() ...); // expected-error {{base type 'T *' is not a structure or union}} + } + }; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits