When building types from declarators, instead of building two types (one for
the DeclaratorInfo, one for semantic analysis), just build a single type whose
canonical type will reflect the semantic analysis (assuming the type is
well-formed, of course).

To make that work, make a few changes to the type system:
* allow the nominal pointee type of a reference type to be a (possibly sugared)
  reference type.  Also, preserve the original spelling of the reference type.
  Both of these can be ignored on canonical reference types.
* Remove ObjCProtocolListType and preserve the associated source information on
  the various ObjC TypeLocs.  Preserve the spelling of protocol lists except in
  the canonical form.
* Preserve some level of source type structure on parameter types, but
  canonicalize on the canonical function type.  This is still a WIP.

Drops code size, makes strides towards accurate source location representation,
slight (~1.7%) progression on Cocoa.h because of complexity drop.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84907 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 074a6fc..6dd081b 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -448,7 +448,7 @@
   //
   QualType adjustParameterType(QualType T);
   QualType ConvertDeclSpecToType(const DeclSpec &DS, SourceLocation DeclLoc,
-                                 bool &IsInvalid, QualType &SourceTy);
+                                 bool &IsInvalid);
   void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL);
   QualType BuildPointerType(QualType T, unsigned Quals,
                             SourceLocation Loc, DeclarationName Entity);
@@ -3755,22 +3755,6 @@
                       QualType FieldTy, const Expr *BitWidth,
                       bool *ZeroWidth = 0);
 
-  /// adjustFunctionParamType - Converts the type of a function parameter to a
-  // type that can be passed as an argument type to
-  /// ASTContext::getFunctionType.
-  ///
-  /// C++ [dcl.fct]p3: "...Any cv-qualifier modifying a parameter type is
-  /// deleted. Such cv-qualifiers affect only the definition of the parameter 
-  /// within the body of the function; they do not affect the function type. 
-  QualType adjustFunctionParamType(QualType T) const {
-    if (!Context.getLangOptions().CPlusPlus)
-      return T;
-    return 
-      T->isDependentType() ? T.getUnqualifiedType()
-                            : T.getDesugaredType().getUnqualifiedType();
-    
-  }
-
   /// \name Code completion
   //@{
   void setCodeCompleteConsumer(CodeCompleteConsumer *CCC);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index e083c07..6d1f4ea 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -4281,8 +4281,7 @@
   // friend templates because ActOnTag never produces a ClassTemplateDecl
   // for a TUK_Friend.
   bool invalid = false;
-  QualType SourceTy;
-  QualType T = ConvertDeclSpecToType(DS, Loc, invalid, SourceTy);
+  QualType T = ConvertDeclSpecToType(DS, Loc, invalid);
   if (invalid) return DeclPtrTy();
 
   // This is definitely an error in C++98.  It's probably meant to
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 219ac3e..49f7119 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -52,16 +52,14 @@
 /// object.
 /// \param DS  the declaration specifiers
 /// \param DeclLoc The location of the declarator identifier or invalid if none.
-/// \param SourceTy QualType representing the type as written in source form.
 /// \returns The type described by the declaration specifiers.  This function
 /// never returns null.
 QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
                                      SourceLocation DeclLoc,
-                                     bool &isInvalid, QualType &SourceTy) {
+                                     bool &isInvalid) {
   // FIXME: Should move the logic from DeclSpec::Finish to here for validity
   // checking.
   QualType Result;
-  SourceTy = Result;
 
   switch (DS.getTypeSpecType()) {
   case DeclSpec::TST_void:
@@ -106,9 +104,6 @@
   case DeclSpec::TST_unspecified:
     // "<proto1,proto2>" is an objc qualified ID with a missing id.
     if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
-      SourceTy = Context.getObjCProtocolListType(QualType(),
-                                                 (ObjCProtocolDecl**)PQ,
-                                                 DS.getNumProtocolQualifiers());
       Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy,
                                                 (ObjCProtocolDecl**)PQ,
                                                 DS.getNumProtocolQualifiers());
@@ -226,9 +221,6 @@
     Result = GetTypeFromParser(DS.getTypeRep());
 
     if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
-      SourceTy = Context.getObjCProtocolListType(Result,
-                                                 (ObjCProtocolDecl**)PQ,
-                                                 DS.getNumProtocolQualifiers());
       if (const ObjCInterfaceType *
             Interface = Result->getAs<ObjCInterfaceType>()) {
         // It would be nice if protocol qualifiers were only stored with the
@@ -385,8 +377,6 @@
     Result = Context.getQualifiedType(Result, Quals);
   }
 
-  if (SourceTy.isNull())
-    SourceTy = Result;
   return Result;
 }
 
@@ -450,36 +440,32 @@
 ///
 /// \returns A suitable reference type, if there are no
 /// errors. Otherwise, returns a NULL type.
-QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned CVR,
-                                  SourceLocation Loc, DeclarationName Entity) {
+QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
+                                  unsigned CVR, SourceLocation Loc,
+                                  DeclarationName Entity) {
   Qualifiers Quals = Qualifiers::fromCVRMask(CVR);
-  if (LValueRef) {
-    if (const RValueReferenceType *R = T->getAs<RValueReferenceType>()) {
-      // C++0x [dcl.typedef]p9: If a typedef TD names a type that is a
-      //   reference to a type T, and attempt to create the type "lvalue
-      //   reference to cv TD" creates the type "lvalue reference to T".
-      // We use the qualifiers (restrict or none) of the original reference,
-      // not the new ones. This is consistent with GCC.
-      QualType LVRT = Context.getLValueReferenceType(R->getPointeeType());
-      return Context.getQualifiedType(LVRT, T.getQualifiers());
-    }
-  }
-  if (T->isReferenceType()) {
-    // C++ [dcl.ref]p4: There shall be no references to references.
-    //
-    // According to C++ DR 106, references to references are only
-    // diagnosed when they are written directly (e.g., "int & &"),
-    // but not when they happen via a typedef:
-    //
-    //   typedef int& intref;
-    //   typedef intref& intref2;
-    //
-    // Parser::ParseDeclaratorInternal diagnoses the case where
-    // references are written directly; here, we handle the
-    // collapsing of references-to-references as described in C++
-    // DR 106 and amended by C++ DR 540.
-    return T;
-  }
+
+  bool LValueRef = SpelledAsLValue || T->getAs<LValueReferenceType>();
+
+  // C++0x [dcl.typedef]p9: If a typedef TD names a type that is a
+  //   reference to a type T, and attempt to create the type "lvalue
+  //   reference to cv TD" creates the type "lvalue reference to T".
+  // We use the qualifiers (restrict or none) of the original reference,
+  // not the new ones. This is consistent with GCC.
+
+  // C++ [dcl.ref]p4: There shall be no references to references.
+  //
+  // According to C++ DR 106, references to references are only
+  // diagnosed when they are written directly (e.g., "int & &"),
+  // but not when they happen via a typedef:
+  //
+  //   typedef int& intref;
+  //   typedef intref& intref2;
+  //
+  // Parser::ParseDeclaratorInternal diagnoses the case where
+  // references are written directly; here, we handle the
+  // collapsing of references-to-references as described in C++
+  // DR 106 and amended by C++ DR 540.
 
   // C++ [dcl.ref]p1:
   //   A declarator that specifies the type "reference to cv void"
@@ -511,7 +497,8 @@
 
   // Handle restrict on references.
   if (LValueRef)
-    return Context.getQualifiedType(Context.getLValueReferenceType(T), Quals);
+    return Context.getQualifiedType(
+               Context.getLValueReferenceType(T, SpelledAsLValue), Quals);
   return Context.getQualifiedType(Context.getRValueReferenceType(T), Quals);
 }
 
@@ -717,7 +704,7 @@
       Invalid = true;
     }
 
-    ParamTypes[Idx] = adjustFunctionParamType(ParamType);
+    ParamTypes[Idx] = ParamType;
   }
 
   if (Invalid)
@@ -856,9 +843,6 @@
   // Determine the type of the declarator. Not all forms of declarator
   // have a type.
   QualType T;
-  // The QualType referring to the type as written in source code. We can't use
-  // T because it can change due to semantic analysis.
-  QualType SourceTy;
 
   switch (D.getKind()) {
   case Declarator::DK_Abstract:
@@ -872,7 +856,7 @@
       T = Context.DependentTy;
     } else {
       bool isInvalid = false;
-      T = ConvertDeclSpecToType(DS, D.getIdentifierLoc(), isInvalid, SourceTy);
+      T = ConvertDeclSpecToType(DS, D.getIdentifierLoc(), isInvalid);
       if (isInvalid)
         D.setInvalidType(true);
       else if (OwnedDecl && DS.isTypeSpecOwned())
@@ -891,9 +875,6 @@
     break;
   }
   
-  if (SourceTy.isNull())
-    SourceTy = T;
-
   if (T == Context.UndeducedAutoTy) {
     int Error = -1;
 
@@ -942,8 +923,6 @@
   if (D.getIdentifier())
     Name = D.getIdentifier();
 
-  bool ShouldBuildInfo = DInfo != 0;
-
   // Walk the DeclTypeInfo, building the recursive type as we go.
   // DeclTypeInfos are ordered from the identifier out, which is
   // opposite of what we want :).
@@ -952,17 +931,6 @@
     switch (DeclType.Kind) {
     default: assert(0 && "Unknown decltype!");
     case DeclaratorChunk::BlockPointer:
-      if (ShouldBuildInfo) {
-        if (SourceTy->isFunctionType())
-          SourceTy
-            = Context.getQualifiedType(Context.getBlockPointerType(SourceTy),
-                             Qualifiers::fromCVRMask(DeclType.Cls.TypeQuals));
-        else
-          // If not function type Context::getBlockPointerType asserts,
-          // so just give up.
-          ShouldBuildInfo = false;
-      }
-
       // If blocks are disabled, emit an error.
       if (!LangOpts.Blocks)
         Diag(DeclType.Loc, diag::err_blocks_disable);
@@ -971,10 +939,6 @@
                                 Name);
       break;
     case DeclaratorChunk::Pointer:
-      //FIXME: Use ObjCObjectPointer for info when appropriate.
-      if (ShouldBuildInfo)
-        SourceTy = Context.getQualifiedType(Context.getPointerType(SourceTy),
-                             Qualifiers::fromCVRMask(DeclType.Ptr.TypeQuals));
       // Verify that we're not building a pointer to pointer to function with
       // exception specification.
       if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
@@ -995,14 +959,6 @@
       Qualifiers Quals;
       if (DeclType.Ref.HasRestrict) Quals.addRestrict();
 
-      if (ShouldBuildInfo) {
-        if (DeclType.Ref.LValueRef)
-          SourceTy = Context.getLValueReferenceType(SourceTy);
-        else
-          SourceTy = Context.getRValueReferenceType(SourceTy);
-        SourceTy = Context.getQualifiedType(SourceTy, Quals);
-      }
-
       // Verify that we're not building a reference to pointer to function with
       // exception specification.
       if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
@@ -1015,11 +971,6 @@
       break;
     }
     case DeclaratorChunk::Array: {
-      if (ShouldBuildInfo)
-        // We just need to get an array type, the exact type doesn't matter.
-        SourceTy = Context.getIncompleteArrayType(SourceTy, ArrayType::Normal,
-                                                  DeclType.Arr.TypeQuals);
-
       // Verify that we're not building an array of pointers to function with
       // exception specification.
       if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
@@ -1051,24 +1002,6 @@
       break;
     }
     case DeclaratorChunk::Function: {
-      if (ShouldBuildInfo) {
-        const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
-        llvm::SmallVector<QualType, 16> ArgTys;
-
-        for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
-          ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>();
-          if (Param) {
-            QualType ArgTy = adjustFunctionParamType(Param->getType());
-
-            ArgTys.push_back(ArgTy);
-          }
-        }
-        SourceTy = Context.getFunctionType(SourceTy, ArgTys.data(),
-                                           ArgTys.size(),
-                                           FTI.isVariadic,
-                                           FTI.TypeQuals);
-      }
-
       // If the function declarator has a prototype (i.e. it is not () and
       // does not have a K&R-style identifier list), then the arguments are part
       // of the type, otherwise the argument list is ().
@@ -1137,6 +1070,7 @@
       } else if (FTI.ArgInfo[0].Param == 0) {
         // C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function definition.
         Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration);
+        D.setInvalidType(true);
       } else {
         // Otherwise, we have a function with an argument list that is
         // potentially variadic.
@@ -1185,7 +1119,7 @@
             }
           }
 
-          ArgTys.push_back(adjustFunctionParamType(ArgTy));
+          ArgTys.push_back(ArgTy);
         }
 
         llvm::SmallVector<QualType, 4> Exceptions;
@@ -1234,13 +1168,6 @@
         D.setInvalidType(true);
       }
 
-      if (ShouldBuildInfo) {
-        QualType cls = !ClsType.isNull() ? ClsType : Context.IntTy;
-        SourceTy = Context.getQualifiedType(
-                      Context.getMemberPointerType(SourceTy, cls.getTypePtr()),
-                      Qualifiers::fromCVRMask(DeclType.Mem.TypeQuals));
-      }
-
       if (!ClsType.isNull())
         T = BuildMemberPointerType(T, ClsType, DeclType.Mem.TypeQuals,
                                    DeclType.Loc, D.getIdentifier());
@@ -1293,8 +1220,12 @@
   if (const AttributeList *Attrs = D.getAttributes())
     ProcessTypeAttributeList(T, Attrs);
 
-  if (ShouldBuildInfo)
-    *DInfo = GetDeclaratorInfoForDeclarator(D, SourceTy, Skip);
+  if (DInfo) {
+    if (D.isInvalidType())
+      *DInfo = 0;
+    else
+      *DInfo = GetDeclaratorInfoForDeclarator(D, T, Skip);
+  }
 
   return T;
 }
@@ -1314,17 +1245,49 @@
     }
     void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
       TL.setNameLoc(DS.getTypeSpecTypeLoc());
-    }
-    void VisitObjCProtocolListTypeLoc(ObjCProtocolListTypeLoc TL) {
-      assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers());
-      TL.setLAngleLoc(DS.getProtocolLAngleLoc());
-      TL.setRAngleLoc(DS.getSourceRange().getEnd());
-      for (unsigned i = 0; i != DS.getNumProtocolQualifiers(); ++i)
-        TL.setProtocolLoc(i, DS.getProtocolLocs()[i]);
 
-      TypeLoc BaseLoc = TL.getBaseTypeLoc();
-      if (BaseLoc)
+      if (DS.getProtocolQualifiers()) {
+        assert(TL.getNumProtocols() > 0);
+        assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers());
+        TL.setLAngleLoc(DS.getProtocolLAngleLoc());
+        TL.setRAngleLoc(DS.getSourceRange().getEnd());
+        for (unsigned i = 0, e = DS.getNumProtocolQualifiers(); i != e; ++i)
+          TL.setProtocolLoc(i, DS.getProtocolLocs()[i]);
+      } else {
+        assert(TL.getNumProtocols() == 0);
+        TL.setLAngleLoc(SourceLocation());
+        TL.setRAngleLoc(SourceLocation());
+      }
+    }
+    void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
+      assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers());
+
+      TL.setStarLoc(SourceLocation());
+
+      if (DS.getProtocolQualifiers()) {
+        assert(TL.getNumProtocols() > 0);
+        assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers());
+        TL.setHasProtocolsAsWritten(true);
+        TL.setLAngleLoc(DS.getProtocolLAngleLoc());
+        TL.setRAngleLoc(DS.getSourceRange().getEnd());
+        for (unsigned i = 0, e = DS.getNumProtocolQualifiers(); i != e; ++i)
+          TL.setProtocolLoc(i, DS.getProtocolLocs()[i]);
+
+      } else {
+        assert(TL.getNumProtocols() == 0);
+        TL.setHasProtocolsAsWritten(false);
+        TL.setLAngleLoc(SourceLocation());
+        TL.setRAngleLoc(SourceLocation());
+      }
+
+      // This might not have been written with an inner type.
+      if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) {
+        TL.setHasBaseTypeAsWritten(false);
+        TL.getBaseTypeLoc().initialize(SourceLocation());
+      } else {
+        TL.setHasBaseTypeAsWritten(true);
         Visit(TL.getBaseTypeLoc());
+      }
     }
     void VisitTypeLoc(TypeLoc TL) {
       // FIXME: add other typespec types and change this to an assert.
@@ -1353,6 +1316,10 @@
     void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
       assert(Chunk.Kind == DeclaratorChunk::Pointer);
       TL.setStarLoc(Chunk.Loc);
+      TL.setHasBaseTypeAsWritten(true);
+      TL.setHasProtocolsAsWritten(false);
+      TL.setLAngleLoc(SourceLocation());
+      TL.setRAngleLoc(SourceLocation());
     }
     void VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
       assert(Chunk.Kind == DeclaratorChunk::MemberPointer);
@@ -1361,7 +1328,8 @@
     }
     void VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) {
       assert(Chunk.Kind == DeclaratorChunk::Reference);
-      assert(Chunk.Ref.LValueRef);
+      // 'Amp' is misleading: this might have been originally
+      /// spelled with AmpAmp.
       TL.setAmpLoc(Chunk.Loc);
     }
     void VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) {
@@ -1381,12 +1349,9 @@
       TL.setRParenLoc(Chunk.EndLoc);
 
       const DeclaratorChunk::FunctionTypeInfo &FTI = Chunk.Fun;
-      for (unsigned i = 0, e = FTI.NumArgs, tpi = 0; i != e; ++i) {
+      for (unsigned i = 0, e = TL.getNumArgs(), tpi = 0; i != e; ++i) {
         ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>();
-        if (Param) {
-          assert(tpi < TL.getNumArgs());
-          TL.setArg(tpi++, Param);
-        }
+        TL.setArg(tpi++, Param);
       }
       // FIXME: exception specs
     }
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 5f06ce5..38273dc 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -514,14 +514,6 @@
                                   SourceRange(getDerived().getBaseLocation()));
   }
 
-  /// \brief Rebuild an objective C protocol list type.
-  QualType RebuildObjCProtocolListType(QualType BaseType,
-                                       ObjCProtocolDecl **Protocols,
-                                       unsigned NumProtocols) {
-    return SemaRef.Context.getObjCProtocolListType(BaseType, Protocols,
-                                                   NumProtocols);
-  }
-
   /// \brief Build a new nested-name-specifier given the prefix and an
   /// identifier that names the next step in the nested-name-specifier.
   ///
@@ -2808,50 +2800,16 @@
 QualType
 TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB,
                                                    ObjCInterfaceTypeLoc TL) {
-  return TransformTypeSpecType(TLB, TL);
+  assert(false && "TransformObjCInterfaceType unimplemented");
+  return QualType();
 }
 
 template<typename Derived>
 QualType
 TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB,
                                                ObjCObjectPointerTypeLoc TL) {
-  TransformPointerLikeType(ObjCObjectPointerType);
-}
-
-template<typename Derived>
-QualType TreeTransform<Derived>::TransformObjCProtocolListType(
-                                                TypeLocBuilder &TLB,
-                                                ObjCProtocolListTypeLoc TL) {
-  ObjCProtocolListType *T = TL.getTypePtr();
-  QualType BaseType = T->getBaseType();
-  if (!BaseType.isNull()) {
-    BaseType = getDerived().TransformType(TLB, TL.getBaseTypeLoc());
-    if (BaseType.isNull())
-      return QualType();
-  } 
-
-  QualType Result = TL.getType();
-  if (getDerived().AlwaysRebuild() ||
-      BaseType != T->getBaseType()) {
-    // TODO: transform these?
-    llvm::SmallVector<ObjCProtocolDecl*,4> Protocols(T->getNumProtocols());
-    std::copy(T->qual_begin(), T->qual_end(), Protocols.begin());
-    Result = getDerived().RebuildObjCProtocolListType(BaseType,
-                                                      &Protocols[0],
-                                                      T->getNumProtocols());
-    if (Result.isNull())
-      return QualType();
-  }
-
-  ObjCProtocolListTypeLoc NewTL = TLB.push<ObjCProtocolListTypeLoc>(Result);
-  NewTL.setLAngleLoc(TL.getLAngleLoc());
-  NewTL.setRAngleLoc(TL.getRAngleLoc());
-
-  assert(NewTL.getNumProtocols() == TL.getNumProtocols());
-  for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
-    NewTL.setProtocolLoc(i, TL.getProtocolLoc(i));
-
-  return Result;
+  assert(false && "TransformObjCObjectPointerType unimplemented");
+  return QualType();
 }
 
 //===----------------------------------------------------------------------===//