diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/docs/LanguageExtensions.html | 6 | ||||
-rw-r--r-- | clang/include/clang/AST/TypeLoc.h | 9 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 4 | ||||
-rw-r--r-- | clang/include/clang/Parse/Parser.h | 4 | ||||
-rw-r--r-- | clang/include/clang/Sema/DeclSpec.h | 8 | ||||
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Lex/PPMacroExpansion.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 27 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 19 | ||||
-rw-r--r-- | clang/lib/Sema/DeclSpec.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 26 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 35 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 1 | ||||
-rw-r--r-- | clang/test/SemaCXX/trailing-return-0x.cpp | 61 |
15 files changed, 189 insertions, 18 deletions
diff --git a/clang/docs/LanguageExtensions.html b/clang/docs/LanguageExtensions.html index 75a4608993e..48d5aa64a1d 100644 --- a/clang/docs/LanguageExtensions.html +++ b/clang/docs/LanguageExtensions.html @@ -41,6 +41,7 @@ td { <li><a href="#cxx_auto_type">C++0x type inference</a></li> <li><a href="#cxx_variadic_templates">C++0x variadic templates</a></li> <li><a href="#cxx_inline_namespaces">C++0x inline namespaces</a></li> + <li><a href="#cxx_trailing_return">C++0x trailing return type</a></li> </ul> <li><a href="#blocks">Blocks</a></li> <li><a href="#overloading-in-c">Function Overloading in C</a></li> @@ -353,6 +354,11 @@ enabled. clang does not yet fully implement this feature.</p> <p>Use <tt>__has_feature(cxx_inline_namespaces)</tt> to determine if support for inline namespaces is enabled.</p> +<h3 id="cxx_trailing_return">C++0x trailing return type</h3> + +<p>Use <tt>__has_feature(cxx_trailing_return)</tt> to determine if support for +the alternate function declaration syntax with trailing return type is enabled.</p> + <!-- ======================================================================= --> <h2 id="blocks">Blocks</h2> <!-- ======================================================================= --> diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h index 23235801749..35bba03d773 100644 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -812,6 +812,7 @@ public: struct FunctionLocInfo { SourceLocation LParenLoc, RParenLoc; + bool TrailingReturn; }; /// \brief Wrapper for source info for functions. @@ -839,6 +840,13 @@ public: getLocalData()->RParenLoc = Loc; } + bool getTrailingReturn() const { + return getLocalData()->TrailingReturn; + } + void setTrailingReturn(bool Trailing) { + getLocalData()->TrailingReturn = Trailing; + } + unsigned getNumArgs() const { if (isa<FunctionNoProtoType>(getTypePtr())) return 0; @@ -858,6 +866,7 @@ public: void initializeLocal(SourceLocation Loc) { setLParenLoc(Loc); setRParenLoc(Loc); + setTrailingReturn(false); for (unsigned i = 0, e = getNumArgs(); i != e; ++i) setArg(i, NULL); } diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 9a2576208fe..e6bcd86609d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -811,6 +811,10 @@ def err_auto_not_allowed : Error< "|class member|exception declaration|template parameter|block literal}0">; def err_auto_var_requires_init : Error< "declaration of variable %0 with type %1 requires an initializer">; +def err_auto_missing_trailing_return : Error< + "'auto' return without trailing return type">; +def err_trailing_return_without_auto : Error< + "trailing return type without 'auto' return">; // C++0x attributes def err_repeat_attribute : Error<"'%0' attribute cannot be repeated">; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index f8db30af5bb..1cdeef727e0 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1062,6 +1062,10 @@ private: bool &hasAnyExceptionSpec); //===--------------------------------------------------------------------===// + // C++0x 8: Function declaration trailing-return-type + TypeResult ParseTrailingReturnType(); + + //===--------------------------------------------------------------------===// // C++ 2.13.5: C++ Boolean Literals ExprResult ParseCXXBoolLiteral(); diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 0893ae7e495..0957e77557e 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -925,6 +925,11 @@ struct DeclaratorChunk { /// specification and their locations. TypeAndRange *Exceptions; + /// TrailingReturnType - If this isn't null, it's the trailing return type + /// specified. This is actually a ParsedType, but stored as void* to + /// allow union storage. + void *TrailingReturnType; + /// freeArgs - reset the argument list to having zero arguments. This is /// used in various places for error recovery. void freeArgs() { @@ -1077,7 +1082,8 @@ struct DeclaratorChunk { SourceRange *ExceptionRanges, unsigned NumExceptions, SourceLocation LPLoc, SourceLocation RPLoc, - Declarator &TheDeclarator); + Declarator &TheDeclarator, + ParsedType TrailingReturnType = ParsedType()); /// getBlockPointer - Return a DeclaratorChunk for a block. /// diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index ce76fcd9ba4..5c9530beb24 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1733,6 +1733,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, bool hasAnyExceptionSpec, unsigned NumExs, const QualType *ExArray, const FunctionType::ExtInfo &Info) { + const CallingConv CallConv= Info.getCC(); // Unique functions, to guarantee there is only one function of a particular // structure. diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 46b671da199..ac69595227f 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -518,6 +518,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("cxx_exceptions", LangOpts.Exceptions) .Case("cxx_rtti", LangOpts.RTTI) .Case("cxx_static_assert", LangOpts.CPlusPlus0x) + .Case("cxx_trailing_return", LangOpts.CPlusPlus0x) .Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI) .Case("objc_weak_class", LangOpts.ObjCNonFragileABI) .Case("ownership_holds", true) diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 0a48d4d5507..89b41828b06 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3024,6 +3024,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // lparen is already consumed! assert(D.isPastIdentifier() && "Should not call before identifier!"); + ParsedType TrailingReturnType; + // This parameter list may be empty. if (Tok.is(tok::r_paren)) { if (RequiresArg) { @@ -3055,6 +3057,11 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, assert(Exceptions.size() == ExceptionRanges.size() && "Produced different number of exception types and ranges."); } + + // Parse trailing-return-type. + if (getLang().CPlusPlus0x && Tok.is(tok::arrow)) { + TrailingReturnType = ParseTrailingReturnType().get(); + } } // Remember that we parsed a function type, and remember the attributes. @@ -3069,7 +3076,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, Exceptions.data(), ExceptionRanges.data(), Exceptions.size(), - LParenLoc, RParenLoc, D), + LParenLoc, RParenLoc, D, + TrailingReturnType), EndLoc); return; } @@ -3260,9 +3268,6 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, ConsumeToken(); } - // Leave prototype scope. - PrototypeScope.Exit(); - // If we have the closing ')', eat it. SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); SourceLocation EndLoc = RParenLoc; @@ -3289,8 +3294,19 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, assert(Exceptions.size() == ExceptionRanges.size() && "Produced different number of exception types and ranges."); } + + // Parse trailing-return-type. + if (getLang().CPlusPlus0x && Tok.is(tok::arrow)) { + TrailingReturnType = ParseTrailingReturnType().get(); + } } + // FIXME: We should leave the prototype scope before parsing the exception + // specification, and then reenter it when parsing the trailing return type. + + // Leave prototype scope. + PrototypeScope.Exit(); + // Remember that we parsed a function type, and remember the attributes. D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/true, IsVariadic, EllipsisLoc, @@ -3301,7 +3317,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, Exceptions.data(), ExceptionRanges.data(), Exceptions.size(), - LParenLoc, RParenLoc, D), + LParenLoc, RParenLoc, D, + TrailingReturnType), EndLoc); } diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 092268c8215..59d4f9fad39 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1871,6 +1871,25 @@ bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc, return false; } +/// ParseTrailingReturnType - Parse a trailing return type on a new-style +/// function declaration. +TypeResult Parser::ParseTrailingReturnType() { + assert(Tok.is(tok::arrow) && "expected arrow"); + + ConsumeToken(); + + // FIXME: Need to suppress declarations when parsing this typename. + // Otherwise in this function definition: + // + // auto f() -> struct X {} + // + // struct X is parsed as class definition because of the trailing + // brace. + + SourceRange Range; + return ParseTypeName(&Range); +} + /// \brief We have just started parsing the definition of a new class, /// so push that class onto our stack of classes that is currently /// being parsed. diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index b46e8af9db8..979b76ae984 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -59,7 +59,8 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, unsigned NumExceptions, SourceLocation LPLoc, SourceLocation RPLoc, - Declarator &TheDeclarator) { + Declarator &TheDeclarator, + ParsedType TrailingReturnType) { DeclaratorChunk I; I.Kind = Function; I.Loc = LPLoc; @@ -76,6 +77,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, I.Fun.hasAnyExceptionSpec = hasAnyExceptionSpec; I.Fun.NumExceptions = NumExceptions; I.Fun.Exceptions = 0; + I.Fun.TrailingReturnType = TrailingReturnType.getAsOpaquePtr(); // new[] an argument array if needed. if (NumArgs) { diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 254eb7984dc..542c31abfc4 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -994,7 +994,30 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, &ReturnTypeInfo); break; } - + + // Check for auto functions and trailing return type and adjust the + // return type accordingly. + if (getLangOptions().CPlusPlus0x && D.isFunctionDeclarator()) { + const DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + if (T == Context.UndeducedAutoTy) { + if (FTI.TrailingReturnType) { + T = GetTypeFromParser(ParsedType::getFromOpaquePtr(FTI.TrailingReturnType), + &ReturnTypeInfo); + } + else { + Diag(D.getDeclSpec().getTypeSpecTypeLoc(), + diag::err_auto_missing_trailing_return); + T = Context.IntTy; + D.setInvalidType(true); + } + } + else if (FTI.TrailingReturnType) { + Diag(D.getDeclSpec().getTypeSpecTypeLoc(), + diag::err_trailing_return_without_auto); + D.setInvalidType(true); + } + } + if (T.isNull()) return Context.getNullTypeSourceInfo(); @@ -1635,6 +1658,7 @@ namespace { assert(Chunk.Kind == DeclaratorChunk::Function); TL.setLParenLoc(Chunk.Loc); TL.setRParenLoc(Chunk.EndLoc); + TL.setTrailingReturn(!!Chunk.Fun.TrailingReturnType); const DeclaratorChunk::FunctionTypeInfo &FTI = Chunk.Fun; for (unsigned i = 0, e = TL.getNumArgs(), tpi = 0; i != e; ++i) { diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 71492254c6e..135ca46958d 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2928,20 +2928,33 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, // the parameters, because users tend to expect this (even if they shouldn't // rely on it!). // - // FIXME: When we implement late-specified return types, we'll need to - // instantiate the return tpe *after* the parameter types in that case, - // since the return type can then refer to the parameters themselves (via - // decltype, sizeof, etc.). + // When the function has a trailing return type, we instantiate the + // parameters before the return type, since the return type can then refer + // to the parameters themselves (via decltype, sizeof, etc.). + // llvm::SmallVector<QualType, 4> ParamTypes; llvm::SmallVector<ParmVarDecl*, 4> ParamDecls; FunctionProtoType *T = TL.getTypePtr(); - QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); - if (ResultType.isNull()) - return QualType(); - if (getDerived().TransformFunctionTypeParams(TL, ParamTypes, ParamDecls)) - return QualType(); - + QualType ResultType; + + if (TL.getTrailingReturn()) { + if (getDerived().TransformFunctionTypeParams(TL, ParamTypes, ParamDecls)) + return QualType(); + + ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); + if (ResultType.isNull()) + return QualType(); + } + else { + ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); + if (ResultType.isNull()) + return QualType(); + + if (getDerived().TransformFunctionTypeParams(TL, ParamTypes, ParamDecls)) + return QualType(); + } + QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ResultType != T->getResultType() || @@ -2959,6 +2972,7 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc NewTL = TLB.push<FunctionProtoTypeLoc>(Result); NewTL.setLParenLoc(TL.getLParenLoc()); NewTL.setRParenLoc(TL.getRParenLoc()); + NewTL.setTrailingReturn(TL.getTrailingReturn()); for (unsigned i = 0, e = NewTL.getNumArgs(); i != e; ++i) NewTL.setArg(i, ParamDecls[i]); @@ -2983,6 +2997,7 @@ QualType TreeTransform<Derived>::TransformFunctionNoProtoType( FunctionNoProtoTypeLoc NewTL = TLB.push<FunctionNoProtoTypeLoc>(Result); NewTL.setLParenLoc(TL.getLParenLoc()); NewTL.setRParenLoc(TL.getRParenLoc()); + NewTL.setTrailingReturn(false); return Result; } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 7b4264d51c9..ac7385976c0 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -2942,6 +2942,7 @@ void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) { TL.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); TL.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setTrailingReturn(Record[Idx++]); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { TL.setArg(i, cast_or_null<ParmVarDecl>(Reader.GetDecl(Record[Idx++]))); } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index f5f96ecd24e..ef8c52f4be1 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -412,6 +412,7 @@ void TypeLocWriter::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) { Writer.AddSourceLocation(TL.getLParenLoc(), Record); Writer.AddSourceLocation(TL.getRParenLoc(), Record); + Record.push_back(TL.getTrailingReturn()); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) Writer.AddDeclRef(TL.getArg(i), Record); } diff --git a/clang/test/SemaCXX/trailing-return-0x.cpp b/clang/test/SemaCXX/trailing-return-0x.cpp new file mode 100644 index 00000000000..0912750ee08 --- /dev/null +++ b/clang/test/SemaCXX/trailing-return-0x.cpp @@ -0,0 +1,61 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s + +template <class T> +struct only +{ + only(T) {} + + template <class U> + only(U) + { + static_assert(sizeof(U) == 0, "expected type failure"); + } +}; + +auto f() -> int +{ + return 0; +} + +auto g(); // expected-error{{return without trailing return type}} + +int h() -> int; // expected-error{{trailing return type without 'auto'}} + +int x; + +template <class T> +auto i(T x) -> decltype(x) +{ + return x; +} + +only<double> p1 = i(1.0); + +template <class T> +struct X +{ + auto f(T x) -> T { return x; } + + template <class U> + auto g(T x, U y) -> decltype(x + y) + { + return x + y; + } + + template<typename U> + struct nested { + template <class V> + auto h(T x, U y, V z) -> decltype(x + y + z) + { + return x + y + z; + } + }; + + template<typename U> + nested<U> get_nested(); +}; + +X<int> xx; +only<int> p2 = xx.f(0L); +only<double> p3 = xx.g(0L, 1.0); +only<double> p4 = xx.get_nested<double>().h(0L, 1.0, 3.14f); |