]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp
MFC r244628:
[FreeBSD/stable/9.git] / contrib / llvm / tools / clang / lib / AST / NestedNameSpecifier.cpp
1 //===--- NestedNameSpecifier.cpp - C++ nested name specifiers -----*- C++ -*-=//
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 defines the NestedNameSpecifier class, which represents
11 //  a C++ nested-name-specifier.
12 //
13 //===----------------------------------------------------------------------===//
14 #include "clang/AST/NestedNameSpecifier.h"
15 #include "clang/AST/ASTContext.h"
16 #include "clang/AST/Decl.h"
17 #include "clang/AST/DeclCXX.h"
18 #include "clang/AST/PrettyPrinter.h"
19 #include "clang/AST/Type.h"
20 #include "clang/AST/TypeLoc.h"
21 #include "llvm/Support/AlignOf.h"
22 #include "llvm/Support/raw_ostream.h"
23 #include <cassert>
24
25 using namespace clang;
26
27 NestedNameSpecifier *
28 NestedNameSpecifier::FindOrInsert(const ASTContext &Context,
29                                   const NestedNameSpecifier &Mockup) {
30   llvm::FoldingSetNodeID ID;
31   Mockup.Profile(ID);
32
33   void *InsertPos = 0;
34   NestedNameSpecifier *NNS
35     = Context.NestedNameSpecifiers.FindNodeOrInsertPos(ID, InsertPos);
36   if (!NNS) {
37     NNS = new (Context, llvm::alignOf<NestedNameSpecifier>())
38         NestedNameSpecifier(Mockup);
39     Context.NestedNameSpecifiers.InsertNode(NNS, InsertPos);
40   }
41
42   return NNS;
43 }
44
45 NestedNameSpecifier *
46 NestedNameSpecifier::Create(const ASTContext &Context,
47                             NestedNameSpecifier *Prefix, IdentifierInfo *II) {
48   assert(II && "Identifier cannot be NULL");
49   assert((!Prefix || Prefix->isDependent()) && "Prefix must be dependent");
50
51   NestedNameSpecifier Mockup;
52   Mockup.Prefix.setPointer(Prefix);
53   Mockup.Prefix.setInt(StoredIdentifier);
54   Mockup.Specifier = II;
55   return FindOrInsert(Context, Mockup);
56 }
57
58 NestedNameSpecifier *
59 NestedNameSpecifier::Create(const ASTContext &Context,
60                             NestedNameSpecifier *Prefix, NamespaceDecl *NS) {
61   assert(NS && "Namespace cannot be NULL");
62   assert((!Prefix ||
63           (Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) &&
64          "Broken nested name specifier");
65   NestedNameSpecifier Mockup;
66   Mockup.Prefix.setPointer(Prefix);
67   Mockup.Prefix.setInt(StoredNamespaceOrAlias);
68   Mockup.Specifier = NS;
69   return FindOrInsert(Context, Mockup);
70 }
71
72 NestedNameSpecifier *
73 NestedNameSpecifier::Create(const ASTContext &Context,
74                             NestedNameSpecifier *Prefix, 
75                             NamespaceAliasDecl *Alias) {
76   assert(Alias && "Namespace alias cannot be NULL");
77   assert((!Prefix ||
78           (Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) &&
79          "Broken nested name specifier");
80   NestedNameSpecifier Mockup;
81   Mockup.Prefix.setPointer(Prefix);
82   Mockup.Prefix.setInt(StoredNamespaceOrAlias);
83   Mockup.Specifier = Alias;
84   return FindOrInsert(Context, Mockup);
85 }
86
87 NestedNameSpecifier *
88 NestedNameSpecifier::Create(const ASTContext &Context,
89                             NestedNameSpecifier *Prefix,
90                             bool Template, const Type *T) {
91   assert(T && "Type cannot be NULL");
92   NestedNameSpecifier Mockup;
93   Mockup.Prefix.setPointer(Prefix);
94   Mockup.Prefix.setInt(Template? StoredTypeSpecWithTemplate : StoredTypeSpec);
95   Mockup.Specifier = const_cast<Type*>(T);
96   return FindOrInsert(Context, Mockup);
97 }
98
99 NestedNameSpecifier *
100 NestedNameSpecifier::Create(const ASTContext &Context, IdentifierInfo *II) {
101   assert(II && "Identifier cannot be NULL");
102   NestedNameSpecifier Mockup;
103   Mockup.Prefix.setPointer(0);
104   Mockup.Prefix.setInt(StoredIdentifier);
105   Mockup.Specifier = II;
106   return FindOrInsert(Context, Mockup);
107 }
108
109 NestedNameSpecifier *
110 NestedNameSpecifier::GlobalSpecifier(const ASTContext &Context) {
111   if (!Context.GlobalNestedNameSpecifier)
112     Context.GlobalNestedNameSpecifier =
113         new (Context, llvm::alignOf<NestedNameSpecifier>())
114             NestedNameSpecifier();
115   return Context.GlobalNestedNameSpecifier;
116 }
117
118 NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const {
119   if (Specifier == 0)
120     return Global;
121
122   switch (Prefix.getInt()) {
123   case StoredIdentifier:
124     return Identifier;
125
126   case StoredNamespaceOrAlias:
127     return isa<NamespaceDecl>(static_cast<NamedDecl *>(Specifier))? Namespace
128                                                             : NamespaceAlias;
129
130   case StoredTypeSpec:
131     return TypeSpec;
132
133   case StoredTypeSpecWithTemplate:
134     return TypeSpecWithTemplate;
135   }
136
137   llvm_unreachable("Invalid NNS Kind!");
138 }
139
140 /// \brief Retrieve the namespace stored in this nested name
141 /// specifier.
142 NamespaceDecl *NestedNameSpecifier::getAsNamespace() const {
143   if (Prefix.getInt() == StoredNamespaceOrAlias)
144     return dyn_cast<NamespaceDecl>(static_cast<NamedDecl *>(Specifier));
145
146   return 0;
147 }
148
149 /// \brief Retrieve the namespace alias stored in this nested name
150 /// specifier.
151 NamespaceAliasDecl *NestedNameSpecifier::getAsNamespaceAlias() const {
152   if (Prefix.getInt() == StoredNamespaceOrAlias)
153     return dyn_cast<NamespaceAliasDecl>(static_cast<NamedDecl *>(Specifier));
154
155   return 0;
156 }
157
158
159 /// \brief Whether this nested name specifier refers to a dependent
160 /// type or not.
161 bool NestedNameSpecifier::isDependent() const {
162   switch (getKind()) {
163   case Identifier:
164     // Identifier specifiers always represent dependent types
165     return true;
166
167   case Namespace:
168   case NamespaceAlias:
169   case Global:
170     return false;
171
172   case TypeSpec:
173   case TypeSpecWithTemplate:
174     return getAsType()->isDependentType();
175   }
176
177   llvm_unreachable("Invalid NNS Kind!");
178 }
179
180 /// \brief Whether this nested name specifier refers to a dependent
181 /// type or not.
182 bool NestedNameSpecifier::isInstantiationDependent() const {
183   switch (getKind()) {
184   case Identifier:
185     // Identifier specifiers always represent dependent types
186     return true;
187     
188   case Namespace:
189   case NamespaceAlias:
190   case Global:
191     return false;
192     
193   case TypeSpec:
194   case TypeSpecWithTemplate:
195     return getAsType()->isInstantiationDependentType();
196   }
197
198   llvm_unreachable("Invalid NNS Kind!");
199 }
200
201 bool NestedNameSpecifier::containsUnexpandedParameterPack() const {
202   switch (getKind()) {
203   case Identifier:
204     return getPrefix() && getPrefix()->containsUnexpandedParameterPack();
205
206   case Namespace:
207   case NamespaceAlias:
208   case Global:
209     return false;
210
211   case TypeSpec:
212   case TypeSpecWithTemplate:
213     return getAsType()->containsUnexpandedParameterPack();
214   }
215
216   llvm_unreachable("Invalid NNS Kind!");
217 }
218
219 /// \brief Print this nested name specifier to the given output
220 /// stream.
221 void
222 NestedNameSpecifier::print(raw_ostream &OS,
223                            const PrintingPolicy &Policy) const {
224   if (getPrefix())
225     getPrefix()->print(OS, Policy);
226
227   switch (getKind()) {
228   case Identifier:
229     OS << getAsIdentifier()->getName();
230     break;
231
232   case Namespace:
233     if (getAsNamespace()->isAnonymousNamespace())
234       return;
235       
236     OS << getAsNamespace()->getName();
237     break;
238
239   case NamespaceAlias:
240     OS << getAsNamespaceAlias()->getName();
241     break;
242
243   case Global:
244     break;
245
246   case TypeSpecWithTemplate:
247     OS << "template ";
248     // Fall through to print the type.
249
250   case TypeSpec: {
251     std::string TypeStr;
252     const Type *T = getAsType();
253
254     PrintingPolicy InnerPolicy(Policy);
255     InnerPolicy.SuppressScope = true;
256
257     // Nested-name-specifiers are intended to contain minimally-qualified
258     // types. An actual ElaboratedType will not occur, since we'll store
259     // just the type that is referred to in the nested-name-specifier (e.g.,
260     // a TypedefType, TagType, etc.). However, when we are dealing with
261     // dependent template-id types (e.g., Outer<T>::template Inner<U>),
262     // the type requires its own nested-name-specifier for uniqueness, so we
263     // suppress that nested-name-specifier during printing.
264     assert(!isa<ElaboratedType>(T) &&
265            "Elaborated type in nested-name-specifier");
266     if (const TemplateSpecializationType *SpecType
267           = dyn_cast<TemplateSpecializationType>(T)) {
268       // Print the template name without its corresponding
269       // nested-name-specifier.
270       SpecType->getTemplateName().print(OS, InnerPolicy, true);
271
272       // Print the template argument list.
273       TypeStr = TemplateSpecializationType::PrintTemplateArgumentList(
274                                                           SpecType->getArgs(),
275                                                        SpecType->getNumArgs(),
276                                                                  InnerPolicy);
277     } else {
278       // Print the type normally
279       TypeStr = QualType(T, 0).getAsString(InnerPolicy);
280     }
281     OS << TypeStr;
282     break;
283   }
284   }
285
286   OS << "::";
287 }
288
289 void NestedNameSpecifier::dump(const LangOptions &LO) {
290   print(llvm::errs(), PrintingPolicy(LO));
291 }
292
293 unsigned 
294 NestedNameSpecifierLoc::getLocalDataLength(NestedNameSpecifier *Qualifier) {
295   assert(Qualifier && "Expected a non-NULL qualifier");
296
297   // Location of the trailing '::'.
298   unsigned Length = sizeof(unsigned);
299
300   switch (Qualifier->getKind()) {
301   case NestedNameSpecifier::Global:
302     // Nothing more to add.
303     break;
304
305   case NestedNameSpecifier::Identifier:
306   case NestedNameSpecifier::Namespace:
307   case NestedNameSpecifier::NamespaceAlias:
308     // The location of the identifier or namespace name.
309     Length += sizeof(unsigned);
310     break;
311
312   case NestedNameSpecifier::TypeSpecWithTemplate:
313   case NestedNameSpecifier::TypeSpec:
314     // The "void*" that points at the TypeLoc data.
315     // Note: the 'template' keyword is part of the TypeLoc.
316     Length += sizeof(void *);
317     break;
318   }
319
320   return Length;
321 }
322
323 unsigned 
324 NestedNameSpecifierLoc::getDataLength(NestedNameSpecifier *Qualifier) {
325   unsigned Length = 0;
326   for (; Qualifier; Qualifier = Qualifier->getPrefix())
327     Length += getLocalDataLength(Qualifier);
328   return Length;
329 }
330
331 namespace {
332   /// \brief Load a (possibly unaligned) source location from a given address
333   /// and offset.
334   SourceLocation LoadSourceLocation(void *Data, unsigned Offset) {
335     unsigned Raw;
336     memcpy(&Raw, static_cast<char *>(Data) + Offset, sizeof(unsigned));
337     return SourceLocation::getFromRawEncoding(Raw);
338   }
339   
340   /// \brief Load a (possibly unaligned) pointer from a given address and
341   /// offset.
342   void *LoadPointer(void *Data, unsigned Offset) {
343     void *Result;
344     memcpy(&Result, static_cast<char *>(Data) + Offset, sizeof(void*));
345     return Result;
346   }
347 }
348
349 SourceRange NestedNameSpecifierLoc::getSourceRange() const {
350   if (!Qualifier)
351     return SourceRange();
352   
353   NestedNameSpecifierLoc First = *this;
354   while (NestedNameSpecifierLoc Prefix = First.getPrefix())
355     First = Prefix;
356   
357   return SourceRange(First.getLocalSourceRange().getBegin(), 
358                      getLocalSourceRange().getEnd());
359 }
360
361 SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const {
362   if (!Qualifier)
363     return SourceRange();
364   
365   unsigned Offset = getDataLength(Qualifier->getPrefix());
366   switch (Qualifier->getKind()) {
367   case NestedNameSpecifier::Global:
368     return LoadSourceLocation(Data, Offset);
369
370   case NestedNameSpecifier::Identifier:
371   case NestedNameSpecifier::Namespace:
372   case NestedNameSpecifier::NamespaceAlias:
373     return SourceRange(LoadSourceLocation(Data, Offset),
374                        LoadSourceLocation(Data, Offset + sizeof(unsigned)));
375
376   case NestedNameSpecifier::TypeSpecWithTemplate:
377   case NestedNameSpecifier::TypeSpec: {
378     // The "void*" that points at the TypeLoc data.
379     // Note: the 'template' keyword is part of the TypeLoc.
380     void *TypeData = LoadPointer(Data, Offset);
381     TypeLoc TL(Qualifier->getAsType(), TypeData);
382     return SourceRange(TL.getBeginLoc(),
383                        LoadSourceLocation(Data, Offset + sizeof(void*)));
384   }
385   }
386
387   llvm_unreachable("Invalid NNS Kind!");
388 }
389
390 TypeLoc NestedNameSpecifierLoc::getTypeLoc() const {
391   assert((Qualifier->getKind() == NestedNameSpecifier::TypeSpec ||
392           Qualifier->getKind() == NestedNameSpecifier::TypeSpecWithTemplate) &&
393          "Nested-name-specifier location is not a type");
394
395   // The "void*" that points at the TypeLoc data.
396   unsigned Offset = getDataLength(Qualifier->getPrefix());
397   void *TypeData = LoadPointer(Data, Offset);
398   return TypeLoc(Qualifier->getAsType(), TypeData);
399 }
400
401 namespace {
402   void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize,
403               unsigned &BufferCapacity) {
404     if (BufferSize + (End - Start) > BufferCapacity) {
405       // Reallocate the buffer.
406       unsigned NewCapacity 
407       = std::max((unsigned)(BufferCapacity? BufferCapacity * 2 
408                             : sizeof(void*) * 2),
409                  (unsigned)(BufferSize + (End - Start)));
410       char *NewBuffer = static_cast<char *>(malloc(NewCapacity));
411       memcpy(NewBuffer, Buffer, BufferSize);
412       
413       if (BufferCapacity)
414         free(Buffer);
415       Buffer = NewBuffer;
416       BufferCapacity = NewCapacity;
417     }
418     
419     memcpy(Buffer + BufferSize, Start, End - Start);
420     BufferSize += End-Start;
421   }
422   
423   /// \brief Save a source location to the given buffer.
424   void SaveSourceLocation(SourceLocation Loc, char *&Buffer,
425                           unsigned &BufferSize, unsigned &BufferCapacity) {
426     unsigned Raw = Loc.getRawEncoding();
427     Append(reinterpret_cast<char *>(&Raw),
428            reinterpret_cast<char *>(&Raw) + sizeof(unsigned),
429            Buffer, BufferSize, BufferCapacity);
430   }
431   
432   /// \brief Save a pointer to the given buffer.
433   void SavePointer(void *Ptr, char *&Buffer, unsigned &BufferSize,
434                    unsigned &BufferCapacity) {
435     Append(reinterpret_cast<char *>(&Ptr),
436            reinterpret_cast<char *>(&Ptr) + sizeof(void *),
437            Buffer, BufferSize, BufferCapacity);
438   }
439 }
440
441 NestedNameSpecifierLocBuilder::
442 NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other) 
443   : Representation(Other.Representation), Buffer(0),
444     BufferSize(0), BufferCapacity(0)
445 {
446   if (!Other.Buffer)
447     return;
448   
449   if (Other.BufferCapacity == 0) {
450     // Shallow copy is okay.
451     Buffer = Other.Buffer;
452     BufferSize = Other.BufferSize;
453     return;
454   }
455   
456   // Deep copy
457   BufferSize = Other.BufferSize;
458   BufferCapacity = Other.BufferSize;
459   Buffer = static_cast<char *>(malloc(BufferCapacity));
460   memcpy(Buffer, Other.Buffer, BufferSize);
461 }
462
463 NestedNameSpecifierLocBuilder &
464 NestedNameSpecifierLocBuilder::
465 operator=(const NestedNameSpecifierLocBuilder &Other) {
466   Representation = Other.Representation;
467   
468   if (Buffer && Other.Buffer && BufferCapacity >= Other.BufferSize) {
469     // Re-use our storage.
470     BufferSize = Other.BufferSize;
471     memcpy(Buffer, Other.Buffer, BufferSize);
472     return *this;
473   }
474   
475   // Free our storage, if we have any.
476   if (BufferCapacity) {
477     free(Buffer);
478     BufferCapacity = 0;
479   }
480   
481   if (!Other.Buffer) {
482     // Empty.
483     Buffer = 0;
484     BufferSize = 0;
485     return *this;
486   }
487   
488   if (Other.BufferCapacity == 0) {
489     // Shallow copy is okay.
490     Buffer = Other.Buffer;
491     BufferSize = Other.BufferSize;
492     return *this;
493   }
494   
495   // Deep copy.
496   BufferSize = Other.BufferSize;
497   BufferCapacity = BufferSize;
498   Buffer = static_cast<char *>(malloc(BufferSize));
499   memcpy(Buffer, Other.Buffer, BufferSize);
500   return *this;
501 }
502
503 void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, 
504                                            SourceLocation TemplateKWLoc, 
505                                            TypeLoc TL, 
506                                            SourceLocation ColonColonLoc) {
507   Representation = NestedNameSpecifier::Create(Context, Representation, 
508                                                TemplateKWLoc.isValid(), 
509                                                TL.getTypePtr());
510   
511   // Push source-location info into the buffer.
512   SavePointer(TL.getOpaqueData(), Buffer, BufferSize, BufferCapacity);
513   SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
514 }
515
516 void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, 
517                                            IdentifierInfo *Identifier,
518                                            SourceLocation IdentifierLoc, 
519                                            SourceLocation ColonColonLoc) {
520   Representation = NestedNameSpecifier::Create(Context, Representation, 
521                                                Identifier);
522   
523   // Push source-location info into the buffer.
524   SaveSourceLocation(IdentifierLoc, Buffer, BufferSize, BufferCapacity);
525   SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
526 }
527
528 void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, 
529                                            NamespaceDecl *Namespace,
530                                            SourceLocation NamespaceLoc, 
531                                            SourceLocation ColonColonLoc) {
532   Representation = NestedNameSpecifier::Create(Context, Representation, 
533                                                Namespace);
534   
535   // Push source-location info into the buffer.
536   SaveSourceLocation(NamespaceLoc, Buffer, BufferSize, BufferCapacity);
537   SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
538 }
539
540 void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context,
541                                            NamespaceAliasDecl *Alias,
542                                            SourceLocation AliasLoc, 
543                                            SourceLocation ColonColonLoc) {
544   Representation = NestedNameSpecifier::Create(Context, Representation, Alias);
545   
546   // Push source-location info into the buffer.
547   SaveSourceLocation(AliasLoc, Buffer, BufferSize, BufferCapacity);
548   SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
549 }
550
551 void NestedNameSpecifierLocBuilder::MakeGlobal(ASTContext &Context, 
552                                                SourceLocation ColonColonLoc) {
553   assert(!Representation && "Already have a nested-name-specifier!?");
554   Representation = NestedNameSpecifier::GlobalSpecifier(Context);
555   
556   // Push source-location info into the buffer.
557   SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
558 }
559
560 void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context, 
561                                                 NestedNameSpecifier *Qualifier, 
562                                                 SourceRange R) {
563   Representation = Qualifier;
564   
565   // Construct bogus (but well-formed) source information for the 
566   // nested-name-specifier.
567   BufferSize = 0;
568   SmallVector<NestedNameSpecifier *, 4> Stack;
569   for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix())
570     Stack.push_back(NNS);
571   while (!Stack.empty()) {
572     NestedNameSpecifier *NNS = Stack.back();
573     Stack.pop_back();
574     switch (NNS->getKind()) {
575       case NestedNameSpecifier::Identifier:
576       case NestedNameSpecifier::Namespace:
577       case NestedNameSpecifier::NamespaceAlias:
578         SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity);
579         break;
580         
581       case NestedNameSpecifier::TypeSpec:
582       case NestedNameSpecifier::TypeSpecWithTemplate: {
583         TypeSourceInfo *TSInfo
584         = Context.getTrivialTypeSourceInfo(QualType(NNS->getAsType(), 0),
585                                            R.getBegin());
586         SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize, 
587                     BufferCapacity);
588         break;
589       }
590         
591       case NestedNameSpecifier::Global:
592         break;
593     }
594     
595     // Save the location of the '::'.
596     SaveSourceLocation(Stack.empty()? R.getEnd() : R.getBegin(), 
597                        Buffer, BufferSize, BufferCapacity);
598   }
599 }
600
601 void NestedNameSpecifierLocBuilder::Adopt(NestedNameSpecifierLoc Other) {
602   if (BufferCapacity)
603     free(Buffer);
604
605   if (!Other) {
606     Representation = 0;
607     BufferSize = 0;
608     return;
609   }
610   
611   // Rather than copying the data (which is wasteful), "adopt" the 
612   // pointer (which points into the ASTContext) but set the capacity to zero to
613   // indicate that we don't own it.
614   Representation = Other.getNestedNameSpecifier();
615   Buffer = static_cast<char *>(Other.getOpaqueData());
616   BufferSize = Other.getDataLength();
617   BufferCapacity = 0;
618 }
619
620 NestedNameSpecifierLoc 
621 NestedNameSpecifierLocBuilder::getWithLocInContext(ASTContext &Context) const {
622   if (!Representation)
623     return NestedNameSpecifierLoc();
624   
625   // If we adopted our data pointer from elsewhere in the AST context, there's
626   // no need to copy the memory.
627   if (BufferCapacity == 0)
628     return NestedNameSpecifierLoc(Representation, Buffer);
629   
630   // FIXME: After copying the source-location information, should we free
631   // our (temporary) buffer and adopt the ASTContext-allocated memory?
632   // Doing so would optimize repeated calls to getWithLocInContext().
633   void *Mem = Context.Allocate(BufferSize, llvm::alignOf<void *>());
634   memcpy(Mem, Buffer, BufferSize);
635   return NestedNameSpecifierLoc(Representation, Mem);
636 }