SemaTemplateVariadic.cpp revision 7536dd5e6c99584481b7dab68b7e7d8df9c54054
1//===------- SemaTemplateVariadic.cpp - C++ Variadic Templates ------------===/
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//===----------------------------------------------------------------------===/
8//
9//  This file implements semantic analysis for C++0x variadic templates.
10//===----------------------------------------------------------------------===/
11
12#include "clang/Sema/Sema.h"
13#include "clang/Sema/ParsedTemplate.h"
14#include "clang/Sema/SemaInternal.h"
15#include "clang/AST/Expr.h"
16#include "clang/AST/RecursiveASTVisitor.h"
17#include "clang/AST/TypeLoc.h"
18
19using namespace clang;
20
21//----------------------------------------------------------------------------
22// Visitor that collects unexpanded parameter packs
23//----------------------------------------------------------------------------
24
25// FIXME: No way to easily map from TemplateTypeParmTypes to
26// TemplateTypeParmDecls, so we have this horrible PointerUnion.
27typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType*, NamedDecl*>,
28                  SourceLocation> UnexpandedParameterPack;
29
30namespace {
31  /// \brief A class that collects unexpanded parameter packs.
32  class CollectUnexpandedParameterPacksVisitor :
33    public RecursiveASTVisitor<CollectUnexpandedParameterPacksVisitor>
34  {
35    typedef RecursiveASTVisitor<CollectUnexpandedParameterPacksVisitor>
36      inherited;
37
38    llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded;
39
40  public:
41    explicit CollectUnexpandedParameterPacksVisitor(
42                  llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded)
43      : Unexpanded(Unexpanded) { }
44
45    //------------------------------------------------------------------------
46    // Recording occurrences of (unexpanded) parameter packs.
47    //------------------------------------------------------------------------
48
49    /// \brief Record occurrences of template type parameter packs.
50    bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
51      if (TL.getTypePtr()->isParameterPack())
52        Unexpanded.push_back(std::make_pair(TL.getTypePtr(), TL.getNameLoc()));
53      return true;
54    }
55
56    /// \brief Record occurrences of template type parameter packs
57    /// when we don't have proper source-location information for
58    /// them.
59    ///
60    /// Ideally, this routine would never be used.
61    bool VisitTemplateTypeParmType(TemplateTypeParmType *T) {
62      if (T->isParameterPack())
63        Unexpanded.push_back(std::make_pair(T, SourceLocation()));
64
65      return true;
66    }
67
68    // FIXME: Record occurrences of non-type and template template
69    // parameter packs.
70
71    // FIXME: Once we have pack expansions in the AST, block their
72    // traversal.
73
74    //------------------------------------------------------------------------
75    // Pruning the search for unexpanded parameter packs.
76    //------------------------------------------------------------------------
77
78    /// \brief Suppress traversal into statements and expressions that
79    /// do not contain unexpanded parameter packs.
80    bool TraverseStmt(Stmt *S) {
81      if (Expr *E = dyn_cast_or_null<Expr>(S))
82        if (E->containsUnexpandedParameterPack())
83          return inherited::TraverseStmt(E);
84
85      return true;
86    }
87
88    /// \brief Suppress traversal into types that do not contain
89    /// unexpanded parameter packs.
90    bool TraverseType(QualType T) {
91      if (!T.isNull() && T->containsUnexpandedParameterPack())
92        return inherited::TraverseType(T);
93
94      return true;
95    }
96
97    /// \brief Suppress traversel into types with location information
98    /// that do not contain unexpanded parameter packs.
99    bool TraverseTypeLoc(TypeLoc TL) {
100      if (!TL.getType().isNull() && TL.
101          getType()->containsUnexpandedParameterPack())
102        return inherited::TraverseTypeLoc(TL);
103
104      return true;
105    }
106
107    /// \brief Suppress traversal of non-parameter declarations, since
108    /// they cannot contain unexpanded parameter packs.
109    bool TraverseDecl(Decl *D) {
110      if (D && isa<ParmVarDecl>(D))
111        return inherited::TraverseDecl(D);
112
113      return true;
114    }
115  };
116}
117
118/// \brief Diagnose all of the unexpanded parameter packs in the given
119/// vector.
120static void
121DiagnoseUnexpandedParameterPacks(Sema &S, SourceLocation Loc,
122                                 Sema::UnexpandedParameterPackContext UPPC,
123             const llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
124  llvm::SmallVector<SourceLocation, 4> Locations;
125  llvm::SmallVector<IdentifierInfo *, 4> Names;
126  llvm::SmallPtrSet<IdentifierInfo *, 4> NamesKnown;
127
128  for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
129    IdentifierInfo *Name = 0;
130    if (const TemplateTypeParmType *TTP
131          = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>())
132      Name = TTP->getName();
133    else
134      Name = Unexpanded[I].first.get<NamedDecl *>()->getIdentifier();
135
136    if (Name && NamesKnown.insert(Name))
137      Names.push_back(Name);
138
139    if (Unexpanded[I].second.isValid())
140      Locations.push_back(Unexpanded[I].second);
141  }
142
143  DiagnosticBuilder DB
144    = Names.size() == 0? S.Diag(Loc, diag::err_unexpanded_parameter_pack_0)
145                           << (int)UPPC
146    : Names.size() == 1? S.Diag(Loc, diag::err_unexpanded_parameter_pack_1)
147                           << (int)UPPC << Names[0]
148    : Names.size() == 2? S.Diag(Loc, diag::err_unexpanded_parameter_pack_2)
149                           << (int)UPPC << Names[0] << Names[1]
150    : S.Diag(Loc, diag::err_unexpanded_parameter_pack_3_or_more)
151        << (int)UPPC << Names[0] << Names[1];
152
153  for (unsigned I = 0, N = Locations.size(); I != N; ++I)
154    DB << SourceRange(Locations[I]);
155}
156
157bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
158                                           TypeSourceInfo *T,
159                                         UnexpandedParameterPackContext UPPC) {
160  // C++0x [temp.variadic]p5:
161  //   An appearance of a name of a parameter pack that is not expanded is
162  //   ill-formed.
163  if (!T->getType()->containsUnexpandedParameterPack())
164    return false;
165
166  llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
167  CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc(
168                                                              T->getTypeLoc());
169  assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
170  DiagnoseUnexpandedParameterPacks(*this, Loc, UPPC, Unexpanded);
171  return true;
172}
173
174bool Sema::DiagnoseUnexpandedParameterPack(Expr *E,
175                                        UnexpandedParameterPackContext UPPC) {
176  // C++0x [temp.variadic]p5:
177  //   An appearance of a name of a parameter pack that is not expanded is
178  //   ill-formed.
179  if (!E->containsUnexpandedParameterPack())
180    return false;
181
182  llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
183  CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseStmt(E);
184  assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
185  DiagnoseUnexpandedParameterPacks(*this, E->getLocStart(), UPPC, Unexpanded);
186  return true;
187}
188
189bool Sema::DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS,
190                                        UnexpandedParameterPackContext UPPC) {
191  // C++0x [temp.variadic]p5:
192  //   An appearance of a name of a parameter pack that is not expanded is
193  //   ill-formed.
194  if (!SS.getScopeRep() ||
195      !SS.getScopeRep()->containsUnexpandedParameterPack())
196    return false;
197
198  llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
199  CollectUnexpandedParameterPacksVisitor(Unexpanded)
200    .TraverseNestedNameSpecifier(SS.getScopeRep());
201  assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
202  DiagnoseUnexpandedParameterPacks(*this, SS.getRange().getBegin(),
203                                   UPPC, Unexpanded);
204  return true;
205}
206
207bool Sema::DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo,
208                                         UnexpandedParameterPackContext UPPC) {
209  // C++0x [temp.variadic]p5:
210  //   An appearance of a name of a parameter pack that is not expanded is
211  //   ill-formed.
212  switch (NameInfo.getName().getNameKind()) {
213  case DeclarationName::Identifier:
214  case DeclarationName::ObjCZeroArgSelector:
215  case DeclarationName::ObjCOneArgSelector:
216  case DeclarationName::ObjCMultiArgSelector:
217  case DeclarationName::CXXOperatorName:
218  case DeclarationName::CXXLiteralOperatorName:
219  case DeclarationName::CXXUsingDirective:
220    return false;
221
222  case DeclarationName::CXXConstructorName:
223  case DeclarationName::CXXDestructorName:
224  case DeclarationName::CXXConversionFunctionName:
225    // FIXME: We shouldn't need this null check!
226    if (TypeSourceInfo *TSInfo = NameInfo.getNamedTypeInfo())
227      return DiagnoseUnexpandedParameterPack(NameInfo.getLoc(), TSInfo, UPPC);
228
229    if (!NameInfo.getName().getCXXNameType()->containsUnexpandedParameterPack())
230      return false;
231
232    break;
233  }
234
235  llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
236  CollectUnexpandedParameterPacksVisitor(Unexpanded)
237    .TraverseType(NameInfo.getName().getCXXNameType());
238  assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
239  DiagnoseUnexpandedParameterPacks(*this, NameInfo.getLoc(), UPPC, Unexpanded);
240  return true;
241}
242
243bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
244                                           TemplateName Template,
245                                       UnexpandedParameterPackContext UPPC) {
246
247  if (Template.isNull() || !Template.containsUnexpandedParameterPack())
248    return false;
249
250  llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
251  CollectUnexpandedParameterPacksVisitor(Unexpanded)
252    .TraverseTemplateName(Template);
253  assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
254  DiagnoseUnexpandedParameterPacks(*this, Loc, UPPC, Unexpanded);
255  return true;
256}
257
258ParsedTemplateArgument
259Sema::ActOnPackExpansion(const ParsedTemplateArgument &Arg,
260                         SourceLocation EllipsisLoc) {
261  if (Arg.isInvalid())
262    return Arg;
263
264  switch (Arg.getKind()) {
265  case ParsedTemplateArgument::Type: {
266    TypeResult Result = ActOnPackExpansion(Arg.getAsType(), EllipsisLoc);
267    if (Result.isInvalid())
268      return ParsedTemplateArgument();
269
270    return ParsedTemplateArgument(Arg.getKind(), Result.get().getAsOpaquePtr(),
271                                  Arg.getLocation());
272  }
273
274  case ParsedTemplateArgument::NonType:
275    Diag(EllipsisLoc, diag::err_pack_expansion_unsupported)
276      << 0;
277    return ParsedTemplateArgument();
278
279  case ParsedTemplateArgument::Template:
280    Diag(EllipsisLoc, diag::err_pack_expansion_unsupported)
281      << 1;
282    return ParsedTemplateArgument();
283  }
284  llvm_unreachable("Unhandled template argument kind?");
285  return ParsedTemplateArgument();
286}
287
288TypeResult Sema::ActOnPackExpansion(ParsedType Type,
289                                    SourceLocation EllipsisLoc) {
290  TypeSourceInfo *TSInfo;
291  GetTypeFromParser(Type, &TSInfo);
292  if (!TSInfo)
293    return true;
294
295  // C++0x [temp.variadic]p5:
296  //   The pattern of a pack expansion shall name one or more
297  //   parameter packs that are not expanded by a nested pack
298  //   expansion.
299  if (!TSInfo->getType()->containsUnexpandedParameterPack()) {
300    Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
301      << TSInfo->getTypeLoc().getSourceRange();
302    return true;
303  }
304
305  // Create the pack expansion type and source-location information.
306  QualType Result = Context.getPackExpansionType(TSInfo->getType());
307  TypeSourceInfo *TSResult = Context.CreateTypeSourceInfo(Result);
308  PackExpansionTypeLoc TL = cast<PackExpansionTypeLoc>(TSResult->getTypeLoc());
309  TL.setEllipsisLoc(EllipsisLoc);
310
311  // Copy over the source-location information from the type.
312  memcpy(TL.getNextTypeLoc().getOpaqueData(),
313         TSInfo->getTypeLoc().getOpaqueData(),
314         TSInfo->getTypeLoc().getFullDataSize());
315  return CreateParsedType(Result, TSResult);
316}
317