mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-27 06:06:06 +00:00
Implement the C++0x "trailing return type" feature, e.g.,
auto f(int) -> int from Daniel Wallin! (With a few minor bug fixes from me). llvm-svn: 115322
This commit is contained in:
parent
f14331f5c3
commit
7fb25418ed
@ -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>
|
||||
<!-- ======================================================================= -->
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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">;
|
||||
|
@ -1061,6 +1061,10 @@ private:
|
||||
llvm::SmallVectorImpl<SourceRange> &Ranges,
|
||||
bool &hasAnyExceptionSpec);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++0x 8: Function declaration trailing-return-type
|
||||
TypeResult ParseTrailingReturnType();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ 2.13.5: C++ Boolean Literals
|
||||
ExprResult ParseCXXBoolLiteral();
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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++])));
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
61
clang/test/SemaCXX/trailing-return-0x.cpp
Normal file
61
clang/test/SemaCXX/trailing-return-0x.cpp
Normal file
@ -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);
|
Loading…
x
Reference in New Issue
Block a user