[clang] c36b03e - The type of a reference to a non-type template parameter pack should
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 18 17:52:21 PDT 2020
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}}
+ }
+ };
+}
More information about the cfe-commits
mailing list