TemplateBase.cpp revision 212904
1//===--- TemplateBase.cpp - Common template AST class implementation ------===//
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//
10// This file implements common classes used throughout C++ template
11// representations.
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/ADT/FoldingSet.h"
16#include "clang/AST/TemplateBase.h"
17#include "clang/AST/DeclBase.h"
18#include "clang/AST/DeclTemplate.h"
19#include "clang/AST/Expr.h"
20#include "clang/AST/TypeLoc.h"
21#include "clang/Basic/Diagnostic.h"
22
23using namespace clang;
24
25//===----------------------------------------------------------------------===//
26// TemplateArgument Implementation
27//===----------------------------------------------------------------------===//
28
29/// \brief Construct a template argument pack.
30void TemplateArgument::setArgumentPack(TemplateArgument *args, unsigned NumArgs,
31                                       bool CopyArgs) {
32  assert(isNull() && "Must call setArgumentPack on a null argument");
33
34  Kind = Pack;
35  Args.NumArgs = NumArgs;
36  Args.CopyArgs = CopyArgs;
37  if (!Args.CopyArgs) {
38    Args.Args = args;
39    return;
40  }
41
42  // FIXME: Allocate in ASTContext
43  Args.Args = new TemplateArgument[NumArgs];
44  for (unsigned I = 0; I != Args.NumArgs; ++I)
45    Args.Args[I] = args[I];
46}
47
48void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
49                               ASTContext &Context) const {
50  ID.AddInteger(Kind);
51  switch (Kind) {
52  case Null:
53    break;
54
55  case Type:
56    getAsType().Profile(ID);
57    break;
58
59  case Declaration:
60    ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : 0);
61    break;
62
63  case Template:
64    if (TemplateTemplateParmDecl *TTP
65          = dyn_cast_or_null<TemplateTemplateParmDecl>(
66                                       getAsTemplate().getAsTemplateDecl())) {
67      ID.AddBoolean(true);
68      ID.AddInteger(TTP->getDepth());
69      ID.AddInteger(TTP->getPosition());
70    } else {
71      ID.AddBoolean(false);
72      ID.AddPointer(Context.getCanonicalTemplateName(getAsTemplate())
73                      .getAsVoidPointer());
74    }
75    break;
76
77  case Integral:
78    getAsIntegral()->Profile(ID);
79    getIntegralType().Profile(ID);
80    break;
81
82  case Expression:
83    getAsExpr()->Profile(ID, Context, true);
84    break;
85
86  case Pack:
87    ID.AddInteger(Args.NumArgs);
88    for (unsigned I = 0; I != Args.NumArgs; ++I)
89      Args.Args[I].Profile(ID, Context);
90  }
91}
92
93bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
94  if (getKind() != Other.getKind()) return false;
95
96  switch (getKind()) {
97  case Null:
98  case Type:
99  case Declaration:
100  case Template:
101  case Expression:
102    return TypeOrValue == Other.TypeOrValue;
103
104  case Integral:
105    return getIntegralType() == Other.getIntegralType() &&
106           *getAsIntegral() == *Other.getAsIntegral();
107
108  case Pack:
109    if (Args.NumArgs != Other.Args.NumArgs) return false;
110    for (unsigned I = 0, E = Args.NumArgs; I != E; ++I)
111      if (!Args.Args[I].structurallyEquals(Other.Args.Args[I]))
112        return false;
113    return true;
114  }
115
116  // Suppress warnings.
117  return false;
118}
119
120//===----------------------------------------------------------------------===//
121// TemplateArgumentLoc Implementation
122//===----------------------------------------------------------------------===//
123
124SourceRange TemplateArgumentLoc::getSourceRange() const {
125  switch (Argument.getKind()) {
126  case TemplateArgument::Expression:
127    return getSourceExpression()->getSourceRange();
128
129  case TemplateArgument::Declaration:
130    return getSourceDeclExpression()->getSourceRange();
131
132  case TemplateArgument::Type:
133    if (TypeSourceInfo *TSI = getTypeSourceInfo())
134      return TSI->getTypeLoc().getSourceRange();
135    else
136      return SourceRange();
137
138  case TemplateArgument::Template:
139    if (getTemplateQualifierRange().isValid())
140      return SourceRange(getTemplateQualifierRange().getBegin(),
141                         getTemplateNameLoc());
142    return SourceRange(getTemplateNameLoc());
143
144  case TemplateArgument::Integral:
145  case TemplateArgument::Pack:
146  case TemplateArgument::Null:
147    return SourceRange();
148  }
149
150  // Silence bonus gcc warning.
151  return SourceRange();
152}
153
154const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
155                                           const TemplateArgument &Arg) {
156  switch (Arg.getKind()) {
157  case TemplateArgument::Null:
158    // This is bad, but not as bad as crashing because of argument
159    // count mismatches.
160    return DB << "(null template argument)";
161
162  case TemplateArgument::Type:
163    return DB << Arg.getAsType();
164
165  case TemplateArgument::Declaration:
166    return DB << Arg.getAsDecl();
167
168  case TemplateArgument::Integral:
169    return DB << Arg.getAsIntegral()->toString(10);
170
171  case TemplateArgument::Template:
172    return DB << Arg.getAsTemplate();
173
174  case TemplateArgument::Expression: {
175    // This shouldn't actually ever happen, so it's okay that we're
176    // regurgitating an expression here.
177    // FIXME: We're guessing at LangOptions!
178    llvm::SmallString<32> Str;
179    llvm::raw_svector_ostream OS(Str);
180    LangOptions LangOpts;
181    LangOpts.CPlusPlus = true;
182    PrintingPolicy Policy(LangOpts);
183    Arg.getAsExpr()->printPretty(OS, 0, Policy);
184    return DB << OS.str();
185  }
186
187  case TemplateArgument::Pack:
188    // FIXME: Format arguments in a list!
189    return DB << "<parameter pack>";
190  }
191
192  return DB;
193}
194