]> granicus.if.org Git - clang/commitdiff
Track whether a function type has a trailing return type as type sugar. Use this
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 10 Feb 2012 09:58:53 +0000 (09:58 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 10 Feb 2012 09:58:53 +0000 (09:58 +0000)
to pretty-print such function types better, and to fix a case where we were not
instantiating templates in lexical order. In passing, move the Variadic bit from
Type's bitfields to FunctionProtoType to get the Type bitfields down to 32 bits.
Also ensure that we always substitute the return type of a function when
substituting explicitly-specified arguments, since that can cause us to bail
out with a SFINAE error before we hit a hard error in parameter substitution.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150241 91177308-0d34-0410-b5e6-96231b3b80d8

14 files changed:
include/clang/AST/Type.h
include/clang/Sema/Sema.h
lib/AST/ASTContext.cpp
lib/AST/Type.cpp
lib/AST/TypePrinter.cpp
lib/Sema/SemaLambda.cpp
lib/Sema/SemaTemplateDeduction.cpp
lib/Sema/SemaType.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp
test/PCH/cxx-trailing-return.cpp [new file with mode: 0644]
test/SemaCXX/trailing-return-0x.cpp
test/SemaTemplate/instantiation-order.cpp [new file with mode: 0644]

index ef4dbdd241cd151894d6fdbad342702aec7af2b7..dcc9fca3285cbe30683ceddae5ffb69b9b9903fc 100644 (file)
@@ -1197,9 +1197,6 @@ protected:
     /// regparm and the calling convention.
     unsigned ExtInfo : 8;
 
-    /// Whether the function is variadic.  Only used by FunctionProtoType.
-    unsigned Variadic : 1;
-
     /// TypeQuals - Used only by FunctionProtoType, put here to pack with the
     /// other bitfields.
     /// The qualifiers are part of FunctionProtoType because...
@@ -2615,7 +2612,7 @@ class FunctionType : public Type {
   };
 
 protected:
-  FunctionType(TypeClass tc, QualType res, bool variadic,
+  FunctionType(TypeClass tc, QualType res,
                unsigned typeQuals, RefQualifierKind RefQualifier,
                QualType Canonical, bool Dependent,
                bool InstantiationDependent,
@@ -2625,11 +2622,9 @@ protected:
            ContainsUnexpandedParameterPack),
       ResultType(res) {
     FunctionTypeBits.ExtInfo = Info.Bits;
-    FunctionTypeBits.Variadic = variadic;
     FunctionTypeBits.TypeQuals = typeQuals;
     FunctionTypeBits.RefQualifier = static_cast<unsigned>(RefQualifier);
   }
-  bool isVariadic() const { return FunctionTypeBits.Variadic; }
   unsigned getTypeQuals() const { return FunctionTypeBits.TypeQuals; }
 
   RefQualifierKind getRefQualifier() const {
@@ -2665,7 +2660,7 @@ public:
 /// no information available about its arguments.
 class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
   FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info)
-    : FunctionType(FunctionNoProto, Result, false, 0, RQ_None, Canonical,
+    : FunctionType(FunctionNoProto, Result, 0, RQ_None, Canonical,
                    /*Dependent=*/false, /*InstantiationDependent=*/false,
                    Result->isVariablyModifiedType(),
                    /*ContainsUnexpandedParameterPack=*/false, Info) {}
@@ -2703,12 +2698,13 @@ public:
   /// ExtProtoInfo - Extra information about a function prototype.
   struct ExtProtoInfo {
     ExtProtoInfo() :
-      Variadic(false), ExceptionSpecType(EST_None), TypeQuals(0),
-      RefQualifier(RQ_None), NumExceptions(0), Exceptions(0), NoexceptExpr(0),
-      ConsumedArguments(0) {}
+      Variadic(false), HasTrailingReturn(false), ExceptionSpecType(EST_None),
+      TypeQuals(0), RefQualifier(RQ_None), NumExceptions(0), Exceptions(0),
+      NoexceptExpr(0), ConsumedArguments(0) {}
 
     FunctionType::ExtInfo ExtInfo;
     bool Variadic;
+    bool HasTrailingReturn;
     ExceptionSpecificationType ExceptionSpecType;
     unsigned char TypeQuals;
     RefQualifierKind RefQualifier;
@@ -2734,7 +2730,7 @@ private:
                     QualType canonical, const ExtProtoInfo &epi);
 
   /// NumArgs - The number of arguments this function has, not counting '...'.
-  unsigned NumArgs : 19;
+  unsigned NumArgs : 17;
 
   /// NumExceptions - The number of types in the exception spec, if any.
   unsigned NumExceptions : 9;
@@ -2745,6 +2741,12 @@ private:
   /// HasAnyConsumedArgs - Whether this function has any consumed arguments.
   unsigned HasAnyConsumedArgs : 1;
 
+  /// Variadic - Whether the function is variadic.
+  unsigned Variadic : 1;
+
+  /// HasTrailingReturn - Whether this function has a trailing return type.
+  unsigned HasTrailingReturn : 1;
+
   // ArgInfo - There is an variable size array after the class in memory that
   // holds the argument types.
 
@@ -2784,6 +2786,7 @@ public:
     ExtProtoInfo EPI;
     EPI.ExtInfo = getExtInfo();
     EPI.Variadic = isVariadic();
+    EPI.HasTrailingReturn = hasTrailingReturn();
     EPI.ExceptionSpecType = getExceptionSpecType();
     EPI.TypeQuals = static_cast<unsigned char>(getTypeQuals());
     EPI.RefQualifier = getRefQualifier();
@@ -2845,16 +2848,18 @@ public:
     return getNoexceptSpec(Ctx) == NR_Nothrow;
   }
 
-  using FunctionType::isVariadic;
+  bool isVariadic() const { return Variadic; }
 
   /// \brief Determines whether this function prototype contains a
   /// parameter pack at the end.
   ///
   /// A function template whose last parameter is a parameter pack can be
   /// called with an arbitrary number of arguments, much like a variadic
-  /// function. However,
+  /// function.
   bool isTemplateVariadic() const;
 
+  bool hasTrailingReturn() const { return HasTrailingReturn; }
+
   unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); }
 
 
index 14a5f70e7beb6617b698844ba12830516a642d39..b111e7bbe888a5e28c368707289b873cab71e46a 100644 (file)
@@ -775,8 +775,8 @@ public:
                               SourceLocation AttrLoc);
   QualType BuildFunctionType(QualType T,
                              QualType *ParamTypes, unsigned NumParamTypes,
-                             bool Variadic, unsigned Quals,
-                             RefQualifierKind RefQualifier,
+                             bool Variadic, bool HasTrailingReturn,
+                             unsigned Quals, RefQualifierKind RefQualifier,
                              SourceLocation Loc, DeclarationName Entity,
                              FunctionType::ExtInfo Info);
   QualType BuildMemberPointerType(QualType T, QualType Class,
index fb7d7473776fc6eb2f658865ab2baa3fef98ebe7..bb93a68d26550ea3daecd85c28534ec51cfd4680 100644 (file)
@@ -2132,7 +2132,9 @@ ASTContext::getFunctionType(QualType ResultTy,
     return QualType(FTP, 0);
 
   // Determine whether the type being created is already canonical or not.
-  bool isCanonical= EPI.ExceptionSpecType == EST_None && ResultTy.isCanonical();
+  bool isCanonical =
+    EPI.ExceptionSpecType == EST_None && ResultTy.isCanonical() &&
+    !EPI.HasTrailingReturn;
   for (unsigned i = 0; i != NumArgs && isCanonical; ++i)
     if (!ArgArray[i].isCanonicalAsParam())
       isCanonical = false;
@@ -2151,6 +2153,7 @@ ASTContext::getFunctionType(QualType ResultTy,
       CanonicalArgs.push_back(getCanonicalParamType(ArgArray[i]));
 
     FunctionProtoType::ExtProtoInfo CanonicalEPI = EPI;
+    CanonicalEPI.HasTrailingReturn = false;
     CanonicalEPI.ExceptionSpecType = EST_None;
     CanonicalEPI.NumExceptions = 0;
     CanonicalEPI.ExtInfo
index b52e61b5284980f5bad422e73b18989f24364958..6732c724c2bb797273d5dc44ff66f7a689e4c92b 100644 (file)
@@ -1557,8 +1557,8 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
 FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
                                      unsigned numArgs, QualType canonical,
                                      const ExtProtoInfo &epi)
-  : FunctionType(FunctionProto, result, epi.Variadic, epi.TypeQuals, 
-                 epi.RefQualifier, canonical,
+  : FunctionType(FunctionProto, result, epi.TypeQuals, epi.RefQualifier,
+                 canonical,
                  result->isDependentType(),
                  result->isInstantiationDependentType(),
                  result->isVariablyModifiedType(),
@@ -1566,7 +1566,8 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
                  epi.ExtInfo),
     NumArgs(numArgs), NumExceptions(epi.NumExceptions),
     ExceptionSpecType(epi.ExceptionSpecType),
-    HasAnyConsumedArgs(epi.ConsumedArguments != 0)
+    HasAnyConsumedArgs(epi.ConsumedArguments != 0),
+    Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn)
 {
   // Fill in the trailing argument array.
   QualType *argSlot = reinterpret_cast<QualType*>(this+1);
@@ -1664,8 +1665,8 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
   // This is followed by an optional "consumed argument" section of the
   // same length as the first type sequence:
   //      bool*
-  // Finally, we have the ext info:
-  //      int
+  // Finally, we have the ext info and trailing return type flag:
+  //      int bool
   // 
   // There is no ambiguity between the consumed arguments and an empty EH
   // spec because of the leading 'bool' which unambiguously indicates
@@ -1697,6 +1698,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
       ID.AddBoolean(epi.ConsumedArguments[i]);
   }
   epi.ExtInfo.Profile(ID);
+  ID.AddBoolean(epi.HasTrailingReturn);
 }
 
 void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID,
index abe68ef07b2707b6790e96cdfda4bbe71c340cde..7d30b7ff8b8d4d554cf6c4130412d7093bddbb26 100644 (file)
@@ -500,7 +500,12 @@ void TypePrinter::printFunctionProto(const FunctionProtoType *T,
     break;
   }
   T->printExceptionSpecification(S, Policy);
-  print(T->getResultType(), S);
+  if (T->hasTrailingReturn()) {
+    std::string ResultS;
+    print(T->getResultType(), ResultS);
+    S = "auto " + S + " -> " + ResultS;
+  } else
+    print(T->getResultType(), S);
 }
 
 void TypePrinter::printFunctionNoProto(const FunctionNoProtoType *T, 
index 1a7f1a12b3b7387bfe14e7544e2d474e65a517fa..ed05eff8e1236da0285cbfc32cdb7316408b79b9 100644 (file)
@@ -46,6 +46,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
     //   If a lambda-expression does not include a lambda-declarator, it is as 
     //   if the lambda-declarator were ().
     FunctionProtoType::ExtProtoInfo EPI;
+    EPI.HasTrailingReturn = true;
     EPI.TypeQuals |= DeclSpec::TQ_const;
     MethodTy = Context.getFunctionType(Context.DependentTy,
                                        /*Args=*/0, /*NumArgs=*/0, EPI);
index 9d711001b35e316f4e7da4575417fcf6cd651ebc..1d84ce31b2dc1302eec35cbf40063b4137f3f7ef 100644 (file)
@@ -2291,33 +2291,45 @@ Sema::SubstituteExplicitTemplateArguments(
     }
   }
 
+  const FunctionProtoType *Proto
+    = Function->getType()->getAs<FunctionProtoType>();
+  assert(Proto && "Function template does not have a prototype?");
+
   // Instantiate the types of each of the function parameters given the
-  // explicitly-specified template arguments.
-  if (SubstParmTypes(Function->getLocation(),
+  // explicitly-specified template arguments. If the function has a trailing
+  // return type, substitute it after the arguments to ensure we substitute
+  // in lexical order.
+  if (Proto->hasTrailingReturn() &&
+      SubstParmTypes(Function->getLocation(),
                      Function->param_begin(), Function->getNumParams(),
                      MultiLevelTemplateArgumentList(*ExplicitArgumentList),
                      ParamTypes))
     return TDK_SubstitutionFailure;
 
-  // If the caller wants a full function type back, instantiate the return
-  // type and form that function type.
-  if (FunctionType) {
-    // FIXME: exception-specifications?
-    const FunctionProtoType *Proto
-      = Function->getType()->getAs<FunctionProtoType>();
-    assert(Proto && "Function template does not have a prototype?");
-
-    QualType ResultType
-      = SubstType(Proto->getResultType(),
-                  MultiLevelTemplateArgumentList(*ExplicitArgumentList),
-                  Function->getTypeSpecStartLoc(),
-                  Function->getDeclName());
-    if (ResultType.isNull() || Trap.hasErrorOccurred())
-      return TDK_SubstitutionFailure;
+  // Instantiate the return type.
+  // FIXME: exception-specifications?
+  QualType ResultType
+    = SubstType(Proto->getResultType(),
+                MultiLevelTemplateArgumentList(*ExplicitArgumentList),
+                Function->getTypeSpecStartLoc(),
+                Function->getDeclName());
+  if (ResultType.isNull() || Trap.hasErrorOccurred())
+    return TDK_SubstitutionFailure;
 
+  // Instantiate the types of each of the function parameters given the
+  // explicitly-specified template arguments if we didn't do so earlier.
+  if (!Proto->hasTrailingReturn() &&
+      SubstParmTypes(Function->getLocation(),
+                     Function->param_begin(), Function->getNumParams(),
+                     MultiLevelTemplateArgumentList(*ExplicitArgumentList),
+                     ParamTypes))
+    return TDK_SubstitutionFailure;
+
+  if (FunctionType) {
     *FunctionType = BuildFunctionType(ResultType,
                                       ParamTypes.data(), ParamTypes.size(),
                                       Proto->isVariadic(),
+                                      Proto->hasTrailingReturn(),
                                       Proto->getTypeQuals(),
                                       Proto->getRefQualifier(),
                                       Function->getLocation(),
index 9fd611b5fec0b9edbfebccbc74f01885d062090f..51e1fb06e201632f17a0cce6abef0f15355c930a 100644 (file)
@@ -1434,6 +1434,8 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize,
 ///
 /// \param Variadic Whether this is a variadic function type.
 ///
+/// \param HasTrailingReturn Whether this function has a trailing return type.
+///
 /// \param Quals The cvr-qualifiers to be applied to the function type.
 ///
 /// \param Loc The location of the entity whose type involves this
@@ -1448,7 +1450,8 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize,
 QualType Sema::BuildFunctionType(QualType T,
                                  QualType *ParamTypes,
                                  unsigned NumParamTypes,
-                                 bool Variadic, unsigned Quals,
+                                 bool Variadic, bool HasTrailingReturn,
+                                 unsigned Quals,
                                  RefQualifierKind RefQualifier,
                                  SourceLocation Loc, DeclarationName Entity,
                                  FunctionType::ExtInfo Info) {
@@ -1487,6 +1490,7 @@ QualType Sema::BuildFunctionType(QualType T,
 
   FunctionProtoType::ExtProtoInfo EPI;
   EPI.Variadic = Variadic;
+  EPI.HasTrailingReturn = HasTrailingReturn;
   EPI.TypeQuals = Quals;
   EPI.RefQualifier = RefQualifier;
   EPI.ExtInfo = Info;
@@ -1498,7 +1502,6 @@ QualType Sema::BuildFunctionType(QualType T,
 ///
 /// \param T the type to which the member pointer refers.
 /// \param Class the class type into which the member pointer points.
-/// \param CVR Qualifiers applied to the member pointer type
 /// \param Loc the location where this type begins
 /// \param Entity the name of the entity that will have this member pointer type
 ///
@@ -2185,6 +2188,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
 
         FunctionProtoType::ExtProtoInfo EPI;
         EPI.Variadic = FTI.isVariadic;
+        EPI.HasTrailingReturn = FTI.TrailingReturnType;
         EPI.TypeQuals = FTI.TypeQuals;
         EPI.RefQualifier = !FTI.hasRefQualifier()? RQ_None
                     : FTI.RefQualifierIsLValueRef? RQ_LValue
index ca72bc7d26e8c3d93c908d9ef2fd5f5b20638fc3..4742bbfc96b022ebbd0c5cdfa777fccb13503dcd 100644 (file)
@@ -666,7 +666,8 @@ public:
   QualType RebuildFunctionProtoType(QualType T,
                                     QualType *ParamTypes,
                                     unsigned NumParamTypes,
-                                    bool Variadic, unsigned Quals,
+                                    bool Variadic, bool HasTrailingReturn,
+                                    unsigned Quals,
                                     RefQualifierKind RefQualifier,
                                     const FunctionType::ExtInfo &Info);
 
@@ -4137,6 +4138,7 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
                                                    ParamTypes.data(),
                                                    ParamTypes.size(),
                                                    T->isVariadic(),
+                                                   T->hasTrailingReturn(),
                                                    T->getTypeQuals(),
                                                    T->getRefQualifier(),
                                                    T->getExtInfo());
@@ -8209,7 +8211,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
                                                         paramTypes.data(),
                                                         paramTypes.size(),
                                                         oldBlock->isVariadic(),
-                                                        0, RQ_None,
+                                                        false, 0, RQ_None,
                                                exprFunctionType->getExtInfo());
   blockScope->FunctionType = functionType;
 
@@ -8452,11 +8454,12 @@ QualType TreeTransform<Derived>::RebuildFunctionProtoType(QualType T,
                                                           QualType *ParamTypes,
                                                         unsigned NumParamTypes,
                                                           bool Variadic,
+                                                         bool HasTrailingReturn,
                                                           unsigned Quals,
                                                   RefQualifierKind RefQualifier,
                                             const FunctionType::ExtInfo &Info) {
   return SemaRef.BuildFunctionType(T, ParamTypes, NumParamTypes, Variadic,
-                                   Quals, RefQualifier,
+                                   HasTrailingReturn, Quals, RefQualifier,
                                    getDerived().getBaseLocation(),
                                    getDerived().getBaseEntity(),
                                    Info);
index 5c9905f049dea45856c2350c4bcdd752953bd1be..312f5c718f0041473a2389f0f10a679b9b70238d 100644 (file)
@@ -3878,6 +3878,7 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
       ParamTypes.push_back(readType(*Loc.F, Record, Idx));
 
     EPI.Variadic = Record[Idx++];
+    EPI.HasTrailingReturn = Record[Idx++];
     EPI.TypeQuals = Record[Idx++];
     EPI.RefQualifier = static_cast<RefQualifierKind>(Record[Idx++]);
     ExceptionSpecificationType EST =
index 827fbed177a24cee62ee7b1ce1e1d8177d9070e9..5364aa83cb84028406cc8994cd9586da66e9760b 100644 (file)
@@ -185,6 +185,7 @@ void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
   for (unsigned I = 0, N = T->getNumArgs(); I != N; ++I)
     Writer.AddTypeRef(T->getArgType(I), Record);
   Record.push_back(T->isVariadic());
+  Record.push_back(T->hasTrailingReturn());
   Record.push_back(T->getTypeQuals());
   Record.push_back(static_cast<unsigned>(T->getRefQualifier()));
   Record.push_back(T->getExceptionSpecType());
@@ -4500,4 +4501,3 @@ void ASTWriter::AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
 
   RewriteDecl(D);
 }
-
diff --git a/test/PCH/cxx-trailing-return.cpp b/test/PCH/cxx-trailing-return.cpp
new file mode 100644 (file)
index 0000000..ff85f6d
--- /dev/null
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t-cxx11
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t-cxx11 -verify %s
+
+#ifndef HEADER_INCLUDED
+
+#define HEADER_INCLUDED
+typedef auto f() -> int; // expected-note {{here}}
+typedef int g(); // expected-note {{here}}
+
+#else
+
+typedef void f; // expected-error {{typedef redefinition with different types ('void' vs 'auto () -> int')}}
+typedef void g; // expected-error {{typedef redefinition with different types ('void' vs 'int ()')}}
+
+#endif
index e25939fa3ebf73047fcaea09dc1e873bcc3c8dc7..c219b77d9e4d520b6fd36d12f3bb7b505884ad8a 100644 (file)
@@ -21,6 +21,16 @@ auto g(); // expected-error{{return without trailing return type}}
 
 int h() -> int; // expected-error{{trailing return type must specify return type 'auto', not 'int'}}
 
+int i();
+auto i() -> int;
+int i() {}
+
+using T = auto (int) -> auto (*)(char) -> void; // expected-note {{previous}}
+using T = void; // expected-error {{type alias redefinition with different types ('void' vs 'auto (int) -> auto (*)(char) -> void')}}
+
+using U = auto (int) -> auto (*)(char) -> void;
+using U = void (*(int))(char); // ok
+
 int x;
 
 template <class T>
diff --git a/test/SemaTemplate/instantiation-order.cpp b/test/SemaTemplate/instantiation-order.cpp
new file mode 100644 (file)
index 0000000..e058a5b
--- /dev/null
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+// From core issue 1227.
+
+template <class T> struct A { using X = typename T::X; }; // expected-error {{no members}}
+template <class T> typename T::X f(typename A<T>::X);
+template <class T> void f(...) {}
+template <class T> auto g(typename A<T>::X) -> typename T::X; // expected-note {{here}} expected-note {{substituting}}
+template <class T> void g(...) {}
+
+void h()
+{
+  f<int>(0); // ok, SFINAE in return type
+  g<int>(0); // not ok, substitution inside A<int> is a hard error
+}