diff options
-rw-r--r-- | include/clang/AST/Type.h | 31 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 4 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 5 | ||||
-rw-r--r-- | lib/AST/Type.cpp | 12 | ||||
-rw-r--r-- | lib/AST/TypePrinter.cpp | 7 | ||||
-rw-r--r-- | lib/Sema/SemaLambda.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 46 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 9 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 1 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 2 | ||||
-rw-r--r-- | test/PCH/cxx-trailing-return.cpp | 15 | ||||
-rw-r--r-- | test/SemaCXX/trailing-return-0x.cpp | 10 | ||||
-rw-r--r-- | test/SemaTemplate/instantiation-order.cpp | 15 |
14 files changed, 121 insertions, 45 deletions
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index ef4dbdd241..dcc9fca328 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -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(); } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 14a5f70e7b..b111e7bbe8 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index fb7d747377..bb93a68d26 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -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 diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index b52e61b528..6732c724c2 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -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, diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index abe68ef07b..7d30b7ff8b 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -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, diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 1a7f1a12b3..ed05eff8e1 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -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); diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 9d711001b3..1d84ce31b2 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -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(), diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 9fd611b5fe..51e1fb06e2 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -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 diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index ca72bc7d26..4742bbfc96 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -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); diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 5c9905f049..312f5c718f 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -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 = diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 827fbed177..5364aa83cb 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -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 index 0000000000..ff85f6d1c5 --- /dev/null +++ b/test/PCH/cxx-trailing-return.cpp @@ -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 diff --git a/test/SemaCXX/trailing-return-0x.cpp b/test/SemaCXX/trailing-return-0x.cpp index e25939fa3e..c219b77d9e 100644 --- a/test/SemaCXX/trailing-return-0x.cpp +++ b/test/SemaCXX/trailing-return-0x.cpp @@ -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 index 0000000000..e058a5bc18 --- /dev/null +++ b/test/SemaTemplate/instantiation-order.cpp @@ -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 +} |