[cfe-commits] r116409 - in /cfe/trunk: include/clang/AST/Type.h include/clang/Sema/Sema.h lib/AST/Type.cpp

Douglas Gregor dgregor at apple.com
Wed Oct 13 09:58:14 PDT 2010


Author: dgregor
Date: Wed Oct 13 11:58:14 2010
New Revision: 116409

URL: http://llvm.org/viewvc/llvm-project?rev=116409&view=rev
Log:
Compute whether a type is variably modified as we build the type,
rather than walking the type's structure every time we request this
information. Performance optimization; no functionality change.

Modified:
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/Type.cpp

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=116409&r1=116408&r2=116409&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Wed Oct 13 11:58:14 2010
@@ -793,6 +793,9 @@
   /// subclasses can pack their bitfields into the same word.
   bool Dependent : 1;
   
+  /// \brief Whether this type is a variably-modified type (C99 6.7.5).
+  bool VariablyModified : 1;
+  
   /// \brief Whether the linkage of this type is already known.
   mutable bool LinkageKnown : 1;
   
@@ -808,20 +811,25 @@
   }
 
 protected:
-  /// \brief Compute the linkage of this type.
+  /// \brief Compute the linkage of this type along with the presence of
+  /// any local or unnamed types.
   virtual Linkage getLinkageImpl() const;
   
   enum { BitsRemainingInType = 19 };
 
   // silence VC++ warning C4355: 'this' : used in base member initializer list
   Type *this_() { return this; }
-  Type(TypeClass tc, QualType Canonical, bool dependent)
+  Type(TypeClass tc, QualType Canonical, bool Dependent, bool VariablyModified)
     : CanonicalType(Canonical.isNull() ? QualType(this_(), 0) : Canonical),
-      TC(tc), Dependent(dependent), LinkageKnown(false), 
+      TC(tc), Dependent(Dependent), VariablyModified(VariablyModified),
+      LinkageKnown(false), 
       CachedLinkage(NoLinkage), FromAST(false) {}
   virtual ~Type();
   friend class ASTContext;
 
+  void setDependent(bool D = true) { Dependent = D; }
+  void setVariablyModified(bool VM = true) { VariablyModified = VM; }
+  
 public:
   TypeClass getTypeClass() const { return static_cast<TypeClass>(TC); }
 
@@ -854,10 +862,6 @@
   /// (C++0x [basic.types]p10)
   bool isLiteralType() const;
 
-  /// isVariablyModifiedType (C99 6.7.5.2p2) - Return true for variable array
-  /// types that have a non-constant expression. This does not include "[]".
-  bool isVariablyModifiedType() const;
-
   /// Helper methods to distinguish type categories. All type predicates
   /// operate on the canonical type, ignoring typedefs and qualifiers.
 
@@ -951,6 +955,10 @@
   /// that its definition somehow depends on a template parameter
   /// (C++ [temp.dep.type]).
   bool isDependentType() const { return Dependent; }
+  
+  /// \brief Whether this type is a variably-modified type (C99 6.7.5).
+  bool isVariablyModifiedType() const { return VariablyModified; }
+  
   bool isOverloadableType() const;
 
   /// \brief Determine wither this type is a C++ elaborated-type-specifier.
@@ -1142,7 +1150,8 @@
   
 public:
   BuiltinType(Kind K)
-    : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent)),
+    : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent),
+           /*VariablyModified=*/false),
       TypeKind(K) {}
 
   Kind getKind() const { return TypeKind; }
@@ -1185,7 +1194,8 @@
 class ComplexType : public Type, public llvm::FoldingSetNode {
   QualType ElementType;
   ComplexType(QualType Element, QualType CanonicalPtr) :
-    Type(Complex, CanonicalPtr, Element->isDependentType()),
+    Type(Complex, CanonicalPtr, Element->isDependentType(),
+         Element->isVariablyModifiedType()),
     ElementType(Element) {
   }
   friend class ASTContext;  // ASTContext creates these.
@@ -1216,7 +1226,9 @@
   QualType PointeeType;
 
   PointerType(QualType Pointee, QualType CanonicalPtr) :
-    Type(Pointer, CanonicalPtr, Pointee->isDependentType()), PointeeType(Pointee) {
+    Type(Pointer, CanonicalPtr, Pointee->isDependentType(),
+         Pointee->isVariablyModifiedType()), 
+    PointeeType(Pointee) {
   }
   friend class ASTContext;  // ASTContext creates these.
 
@@ -1248,7 +1260,8 @@
 class BlockPointerType : public Type, public llvm::FoldingSetNode {
   QualType PointeeType;  // Block is some kind of pointer type
   BlockPointerType(QualType Pointee, QualType CanonicalCls) :
-    Type(BlockPointer, CanonicalCls, Pointee->isDependentType()),
+    Type(BlockPointer, CanonicalCls, Pointee->isDependentType(),
+         Pointee->isVariablyModifiedType()),
     PointeeType(Pointee) {
   }
   friend class ASTContext;  // ASTContext creates these.
@@ -1302,7 +1315,8 @@
 protected:
   ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef,
                 bool SpelledAsLValue) :
-    Type(tc, CanonicalRef, Referencee->isDependentType()),
+    Type(tc, CanonicalRef, Referencee->isDependentType(),
+         Referencee->isVariablyModifiedType()),
     PointeeType(Referencee), SpelledAsLValue(SpelledAsLValue),
     InnerRef(Referencee->isReferenceType()) {
   }
@@ -1384,7 +1398,8 @@
 
   MemberPointerType(QualType Pointee, const Type *Cls, QualType CanonicalPtr) :
     Type(MemberPointer, CanonicalPtr,
-         Cls->isDependentType() || Pointee->isDependentType()),
+         Cls->isDependentType() || Pointee->isDependentType(),
+         Pointee->isVariablyModifiedType()),
     PointeeType(Pointee), Class(Cls) {
   }
   friend class ASTContext; // ASTContext creates these.
@@ -1458,7 +1473,8 @@
   //       value-dependent,
   ArrayType(TypeClass tc, QualType et, QualType can,
             ArraySizeModifier sm, unsigned tq)
-    : Type(tc, can, et->isDependentType() || tc == DependentSizedArray),
+    : Type(tc, can, et->isDependentType() || tc == DependentSizedArray,
+           (tc == VariableArray || et->isVariablyModifiedType())),
       ElementType(et), SizeModifier(sm), IndexTypeQuals(tq) {}
 
   friend class ASTContext;  // ASTContext creates these.
@@ -1702,7 +1718,8 @@
 
   DependentSizedExtVectorType(ASTContext &Context, QualType ElementType,
                               QualType can, Expr *SizeExpr, SourceLocation loc)
-    : Type (DependentSizedExtVector, can, true),
+    : Type(DependentSizedExtVector, can, /*Dependent=*/true,
+           ElementType->isVariablyModifiedType()),
       Context(Context), SizeExpr(SizeExpr), ElementType(ElementType),
       loc(loc) {}
   friend class ASTContext;
@@ -1753,11 +1770,15 @@
 
   VectorType(QualType vecType, unsigned nElements, QualType canonType,
       AltiVecSpecific altiVecSpec) :
-    Type(Vector, canonType, vecType->isDependentType()),
+    Type(Vector, canonType, vecType->isDependentType(),
+         vecType->isVariablyModifiedType()),
     ElementType(vecType), NumElements(nElements), AltiVecSpec(altiVecSpec) {}
+  
   VectorType(TypeClass tc, QualType vecType, unsigned nElements,
              QualType canonType, AltiVecSpecific altiVecSpec)
-    : Type(tc, canonType, vecType->isDependentType()), ElementType(vecType),
+    : Type(tc, canonType, vecType->isDependentType(),
+           vecType->isVariablyModifiedType()), 
+      ElementType(vecType),
       NumElements(nElements), AltiVecSpec(altiVecSpec) {}
   friend class ASTContext;  // ASTContext creates these.
   
@@ -1958,8 +1979,8 @@
 protected:
   FunctionType(TypeClass tc, QualType res, bool SubclassInfo,
                unsigned typeQuals, QualType Canonical, bool Dependent,
-               const ExtInfo &Info)
-    : Type(tc, Canonical, Dependent),
+               bool VariablyModified, const ExtInfo &Info)
+    : Type(tc, Canonical, Dependent, VariablyModified),
       SubClassData(SubclassInfo), TypeQuals(typeQuals),
       NoReturn(Info.getNoReturn()),
       RegParm(Info.getRegParm()), CallConv(Info.getCC()), ResultType(res) {}
@@ -1997,7 +2018,8 @@
   FunctionNoProtoType(QualType Result, QualType Canonical,
                       const ExtInfo &Info)
     : FunctionType(FunctionNoProto, Result, false, 0, Canonical,
-                   /*Dependent=*/false, Info) {}
+                   /*Dependent=*/false, Result->isVariablyModifiedType(), 
+                   Info) {}
   friend class ASTContext;  // ASTContext creates these.
   
 protected:
@@ -2032,36 +2054,11 @@
 /// exception specification, but this specification is not part of the canonical
 /// type.
 class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
-  /// hasAnyDependentType - Determine whether there are any dependent
-  /// types within the arguments passed in.
-  static bool hasAnyDependentType(const QualType *ArgArray, unsigned numArgs) {
-    for (unsigned Idx = 0; Idx < numArgs; ++Idx)
-      if (ArgArray[Idx]->isDependentType())
-    return true;
-
-    return false;
-  }
-
   FunctionProtoType(QualType Result, const QualType *ArgArray, unsigned numArgs,
                     bool isVariadic, unsigned typeQuals, bool hasExs,
                     bool hasAnyExs, const QualType *ExArray,
                     unsigned numExs, QualType Canonical,
-                    const ExtInfo &Info)
-    : FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical,
-                   (Result->isDependentType() ||
-                    hasAnyDependentType(ArgArray, numArgs)),
-                   Info),
-      NumArgs(numArgs), NumExceptions(numExs), HasExceptionSpec(hasExs),
-      AnyExceptionSpec(hasAnyExs) {
-    // Fill in the trailing argument array.
-    QualType *ArgInfo = reinterpret_cast<QualType*>(this+1);
-    for (unsigned i = 0; i != numArgs; ++i)
-      ArgInfo[i] = ArgArray[i];
-    // Fill in the exception array.
-    QualType *Ex = ArgInfo + numArgs;
-    for (unsigned i = 0; i != numExs; ++i)
-      Ex[i] = ExArray[i];
-  }
+                    const ExtInfo &Info);
 
   /// NumArgs - The number of arguments this function has, not counting '...'.
   unsigned NumArgs : 20;
@@ -2149,7 +2146,7 @@
   UnresolvedUsingTypenameDecl *Decl;
 
   UnresolvedUsingType(const UnresolvedUsingTypenameDecl *D)
-    : Type(UnresolvedUsing, QualType(), true),
+    : Type(UnresolvedUsing, QualType(), true, false),
       Decl(const_cast<UnresolvedUsingTypenameDecl*>(D)) {}
   friend class ASTContext; // ASTContext creates these.
 public:
@@ -2178,7 +2175,7 @@
   TypedefDecl *Decl;
 protected:
   TypedefType(TypeClass tc, const TypedefDecl *D, QualType can)
-    : Type(tc, can, can->isDependentType()),
+    : Type(tc, can, can->isDependentType(), can->isVariablyModifiedType()),
       Decl(const_cast<TypedefDecl*>(D)) {
     assert(!isa<TypedefType>(can) && "Invalid canonical type");
   }
@@ -2251,7 +2248,8 @@
 class TypeOfType : public Type {
   QualType TOType;
   TypeOfType(QualType T, QualType can)
-    : Type(TypeOf, can, T->isDependentType()), TOType(T) {
+    : Type(TypeOf, can, T->isDependentType(), T->isVariablyModifiedType()), 
+      TOType(T) {
     assert(!isa<TypedefType>(can) && "Invalid canonical type");
   }
   friend class ASTContext;  // ASTContext creates these.
@@ -2406,11 +2404,13 @@
 
   TemplateTypeParmType(unsigned D, unsigned I, bool PP, IdentifierInfo *N,
                        QualType Canon)
-    : Type(TemplateTypeParm, Canon, /*Dependent=*/true),
+    : Type(TemplateTypeParm, Canon, /*Dependent=*/true,
+           /*VariablyModified=*/false),
       Depth(D), Index(I), ParameterPack(PP), Name(N) { }
 
   TemplateTypeParmType(unsigned D, unsigned I, bool PP)
-    : Type(TemplateTypeParm, QualType(this, 0), /*Dependent=*/true),
+    : Type(TemplateTypeParm, QualType(this, 0), /*Dependent=*/true,
+           /*VariablyModified=*/false),
       Depth(D), Index(I), ParameterPack(PP), Name(0) { }
 
   friend class ASTContext;  // ASTContext creates these
@@ -2455,7 +2455,8 @@
   const TemplateTypeParmType *Replaced;
 
   SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon)
-    : Type(SubstTemplateTypeParm, Canon, Canon->isDependentType()),
+    : Type(SubstTemplateTypeParm, Canon, Canon->isDependentType(),
+           Canon->isVariablyModifiedType()),
       Replaced(Param) { }
 
   friend class ASTContext;
@@ -2629,7 +2630,8 @@
                           // currently suitable for AST reading, too much
                           // interdependencies.
   InjectedClassNameType(CXXRecordDecl *D, QualType TST)
-    : Type(InjectedClassName, QualType(), true),
+    : Type(InjectedClassName, QualType(), /*Dependent=*/true,
+           /*VariablyModified=*/false),
       Decl(D), InjectedType(TST) {
     assert(isa<TemplateSpecializationType>(TST));
     assert(!TST.hasQualifiers());
@@ -2693,8 +2695,9 @@
 
 protected:
   TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc,
-                  QualType Canonical, bool dependent)
-    : Type(tc, Canonical, dependent), Keyword(Keyword) {}
+                  QualType Canonical, bool Dependent, bool VariablyModified)
+    : Type(tc, Canonical, Dependent, VariablyModified), 
+      Keyword(Keyword) {}
 
 public:
   virtual ~TypeWithKeyword(); // pin vtable to Type.cpp
@@ -2752,7 +2755,8 @@
   ElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
                  QualType NamedType, QualType CanonType)
     : TypeWithKeyword(Keyword, Elaborated, CanonType,
-                      NamedType->isDependentType()),
+                      NamedType->isDependentType(),
+                      NamedType->isVariablyModifiedType()),
       NNS(NNS), NamedType(NamedType) {
     assert(!(Keyword == ETK_None && NNS == 0) &&
            "ElaboratedType cannot have elaborated type keyword "
@@ -2812,7 +2816,8 @@
 
   DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, 
                     const IdentifierInfo *Name, QualType CanonType)
-    : TypeWithKeyword(Keyword, DependentName, CanonType, true),
+    : TypeWithKeyword(Keyword, DependentName, CanonType, /*Dependent=*/true,
+                      /*VariablyModified=*/false),
       NNS(NNS), Name(Name) {
     assert(NNS->isDependent() &&
            "DependentNameType requires a dependent nested-name-specifier");
@@ -2981,7 +2986,7 @@
 
   enum Nonce_ObjCInterface { Nonce_ObjCInterface };
   ObjCObjectType(enum Nonce_ObjCInterface)
-    : Type(ObjCInterface, QualType(), false),
+    : Type(ObjCInterface, QualType(), false, false),
       NumProtocols(0),
       BaseType(QualType(this_(), 0)) {}
 
@@ -3139,7 +3144,7 @@
   QualType PointeeType;
 
   ObjCObjectPointerType(QualType Canonical, QualType Pointee)
-    : Type(ObjCObjectPointer, Canonical, false),
+    : Type(ObjCObjectPointer, Canonical, false, false),
       PointeeType(Pointee) {}
   friend class ASTContext;  // ASTContext creates these.
 

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=116409&r1=116408&r2=116409&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Oct 13 11:58:14 2010
@@ -165,7 +165,8 @@
   TypeSourceInfo *DeclInfo;
 
   LocInfoType(QualType ty, TypeSourceInfo *TInfo)
-    : Type((TypeClass)LocInfo, ty, ty->isDependentType()), DeclInfo(TInfo) {
+    : Type((TypeClass)LocInfo, ty, ty->isDependentType(), 
+           ty->isVariablyModifiedType()), DeclInfo(TInfo) {
     assert(getTypeClass() == (TypeClass)LocInfo && "LocInfo didn't fit in TC?");
   }
   friend class Sema;

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=116409&r1=116408&r2=116409&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Wed Oct 13 11:58:14 2010
@@ -268,42 +268,6 @@
   return QualType();
 }
 
-/// isVariablyModifiedType (C99 6.7.5p3) - Return true for variable length
-/// array types and types that contain variable array types in their
-/// declarator
-bool Type::isVariablyModifiedType() const {
-  // FIXME: We should really keep a "variably modified" bit in Type, rather
-  // than walking the type hierarchy to recompute it.
-  
-  // A VLA is a variably modified type.
-  if (isVariableArrayType())
-    return true;
-
-  // An array can contain a variably modified type
-  if (const Type *T = getArrayElementTypeNoTypeQual())
-    return T->isVariablyModifiedType();
-
-  // A pointer can point to a variably modified type.
-  // Also, C++ references and member pointers can point to a variably modified
-  // type, where VLAs appear as an extension to C++, and should be treated
-  // correctly.
-  if (const PointerType *PT = getAs<PointerType>())
-    return PT->getPointeeType()->isVariablyModifiedType();
-  if (const ReferenceType *RT = getAs<ReferenceType>())
-    return RT->getPointeeType()->isVariablyModifiedType();
-  if (const MemberPointerType *PT = getAs<MemberPointerType>())
-    return PT->getPointeeType()->isVariablyModifiedType();
-
-  // A function can return a variably modified type
-  // This one isn't completely obvious, but it follows from the
-  // definition in C99 6.7.5p3. Because of this rule, it's
-  // illegal to declare a function returning a variably modified type.
-  if (const FunctionType *FT = getAs<FunctionType>())
-    return FT->getResultType()->isVariablyModifiedType();
-
-  return false;
-}
-
 const RecordType *Type::getAsStructureType() const {
   // If this is directly a structure type, return it.
   if (const RecordType *RT = dyn_cast<RecordType>(this)) {
@@ -346,7 +310,7 @@
 ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base,
                                ObjCProtocolDecl * const *Protocols,
                                unsigned NumProtocols)
-  : Type(ObjCObject, Canonical, false),
+  : Type(ObjCObject, Canonical, false, false),
     NumProtocols(NumProtocols),
     BaseType(Base) {
   assert(this->NumProtocols == NumProtocols &&
@@ -913,7 +877,8 @@
                          NestedNameSpecifier *NNS, const IdentifierInfo *Name,
                          unsigned NumArgs, const TemplateArgument *Args,
                          QualType Canon)
-  : TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon, true),
+  : TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon, true,
+                    false),
     NNS(NNS), Name(Name), NumArgs(NumArgs) {
   assert(NNS && NNS->isDependent() &&
          "DependentTemplateSpecializatonType requires dependent qualifier");
@@ -1026,6 +991,35 @@
   }
 }
 
+FunctionProtoType::FunctionProtoType(QualType Result, const QualType *ArgArray,
+                                     unsigned numArgs, bool isVariadic, 
+                                     unsigned typeQuals, bool hasExs,
+                                     bool hasAnyExs, const QualType *ExArray,
+                                     unsigned numExs, QualType Canonical,
+                                     const ExtInfo &Info)
+  : FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical,
+                 Result->isDependentType(),
+                 Result->isVariablyModifiedType(),
+                 Info),
+    NumArgs(numArgs), NumExceptions(numExs), HasExceptionSpec(hasExs),
+    AnyExceptionSpec(hasAnyExs) 
+{
+  // Fill in the trailing argument array.
+  QualType *ArgInfo = reinterpret_cast<QualType*>(this+1);
+  for (unsigned i = 0; i != numArgs; ++i) {
+    if (ArgArray[i]->isDependentType())
+      setDependent();
+    
+    ArgInfo[i] = ArgArray[i];
+  }
+  
+  // Fill in the exception array.
+  QualType *Ex = ArgInfo + numArgs;
+  for (unsigned i = 0; i != numExs; ++i)
+    Ex[i] = ExArray[i];
+}
+
+
 void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
                                 arg_type_iterator ArgTys,
                                 unsigned NumArgs, bool isVariadic,
@@ -1087,7 +1081,8 @@
 }
 
 TypeOfExprType::TypeOfExprType(Expr *E, QualType can)
-  : Type(TypeOfExpr, can, E->isTypeDependent()), TOExpr(E) {
+  : Type(TypeOfExpr, can, E->isTypeDependent(), 
+         E->getType()->isVariablyModifiedType()), TOExpr(E) {
 }
 
 QualType TypeOfExprType::desugar() const {
@@ -1100,7 +1095,8 @@
 }
 
 DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can)
-  : Type(Decltype, can, E->isTypeDependent()), E(E),
+  : Type(Decltype, can, E->isTypeDependent(), 
+         E->getType()->isVariablyModifiedType()), E(E),
   UnderlyingType(underlyingType) {
 }
 
@@ -1113,7 +1109,7 @@
 }
 
 TagType::TagType(TypeClass TC, const TagDecl *D, QualType can)
-  : Type(TC, can, D->isDependentType()),
+  : Type(TC, can, D->isDependentType(), /*VariablyModified=*/false),
     decl(const_cast<TagDecl*>(D)) {}
 
 static TagDecl *getInterestingTagDecl(TagDecl *decl) {
@@ -1213,16 +1209,25 @@
                            unsigned NumArgs, QualType Canon)
   : Type(TemplateSpecialization,
          Canon.isNull()? QualType(this, 0) : Canon,
-         T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)),
-    Template(T), NumArgs(NumArgs) {
+         T.isDependent(), false),
+    Template(T), NumArgs(NumArgs) 
+{
   assert((!Canon.isNull() ||
           T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)) &&
          "No canonical type for non-dependent class template specialization");
 
   TemplateArgument *TemplateArgs
     = reinterpret_cast<TemplateArgument *>(this + 1);
-  for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
+  for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+    // Update dependent and variably-modified bits.
+    if (isDependent(Args[Arg]))
+      setDependent();
+    if (Args[Arg].getKind() == TemplateArgument::Type &&
+        Args[Arg].getAsType()->isVariablyModifiedType())
+      setVariablyModified();
+    
     new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]);
+  }
 }
 
 void





More information about the cfe-commits mailing list