Fix a few auto-related issues:

* 'auto' was being rejected on abstract-declarators with trailing return
types and on typedefs with trailing return types. 'auto' is always
allowed in these cases. This was found while testing the fix for PR 9278.

 * A very poor diagnostic was being issued for auto (f() -> int): "return
type must be 'auto', not 'auto'". This is closely related to PR 9060.

 * Trailing return type handling was happening slightly too late,
resulting in the checks for functions returning arrays and functions
returning functions being missed.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126166 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Richard Smith 2011-02-22 00:36:53 +00:00
Родитель 24d44eddfc
Коммит e7397c6a1b
7 изменённых файлов: 118 добавлений и 38 удалений

Просмотреть файл

@ -918,6 +918,8 @@ def err_auto_missing_trailing_return : Error<
"'auto' return without trailing return type">;
def err_trailing_return_without_auto : Error<
"function with trailing return type must specify return type 'auto', not %0">;
def err_trailing_return_in_parens : Error<
"trailing return type may not be nested within parentheses">;
def err_auto_var_deduction_failure : Error<
"variable %0 with type %1 has incompatible initializer of type %2">;
def err_auto_new_deduction_failure : Error<

Просмотреть файл

@ -1450,6 +1450,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (D.getAttributes())
distributeTypeAttrsFromDeclarator(state, T);
// C++0x [dcl.spec.auto]p5: reject 'auto' if it is not in an allowed context.
if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
!D.isFunctionDeclarator()) {
int Error = -1;
@ -1495,6 +1496,25 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
Error = 8;
// C++0x [dcl.spec.auto]p2: 'auto' is always fine if the declarator
// contains a trailing return type. That is only legal at the outermost
// level. Check all declarator chunks (outermost first) anyway, to give
// better diagnostics.
if (Error != -1) {
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
unsigned chunkIndex = e - i - 1;
state.setCurrentChunkIndex(chunkIndex);
DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex);
if (DeclType.Kind == DeclaratorChunk::Function) {
const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
if (FTI.TrailingReturnType) {
Error = -1;
break;
}
}
}
}
if (Error != -1) {
Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_auto_not_allowed)
<< Error;
@ -1502,7 +1522,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
D.setInvalidType(true);
}
}
if (T.isNull())
return Context.getNullTypeSourceInfo();
@ -1603,6 +1623,37 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// of the type, otherwise the argument list is ().
const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
// Check for auto functions and trailing return type and adjust the
// return type accordingly.
if (!D.isInvalidType()) {
// trailing-return-type is only required if we're declaring a function,
// and not, for instance, a pointer to a function.
if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
!FTI.TrailingReturnType && chunkIndex == 0) {
Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_auto_missing_trailing_return);
T = Context.IntTy;
D.setInvalidType(true);
} else if (FTI.TrailingReturnType) {
// T must be exactly 'auto' at this point. See CWG issue 681.
if (isa<ParenType>(T)) {
Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_trailing_return_in_parens)
<< T << D.getDeclSpec().getSourceRange();
D.setInvalidType(true);
} else if (T.hasQualifiers() || !isa<AutoType>(T)) {
Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_trailing_return_without_auto)
<< T << D.getDeclSpec().getSourceRange();
D.setInvalidType(true);
}
T = GetTypeFromParser(
ParsedType::getFromOpaquePtr(FTI.TrailingReturnType),
&ReturnTypeInfo);
}
}
// C99 6.7.5.3p1: The return type may not be a function or array type.
// For conversion functions, we'll diagnose this particular error later.
if ((T->isArrayType() || T->isFunctionType()) &&
@ -1618,32 +1669,6 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
D.setInvalidType(true);
}
// Check for auto functions and trailing return type and adjust the
// return type accordingly.
if (!D.isInvalidType()) {
// trailing-return-type is only required if we're declaring a function,
// and not, for instance, a pointer to a function.
if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
!FTI.TrailingReturnType && chunkIndex == 0) {
Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_auto_missing_trailing_return);
T = Context.IntTy;
D.setInvalidType(true);
} else if (FTI.TrailingReturnType) {
if (T.hasQualifiers() || !isa<AutoType>(T)) {
// T must be exactly 'auto' at this point. See CWG issue 681.
Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_trailing_return_without_auto)
<< T << D.getDeclSpec().getSourceRange();
D.setInvalidType(true);
}
T = GetTypeFromParser(
ParsedType::getFromOpaquePtr(FTI.TrailingReturnType),
&ReturnTypeInfo);
}
}
// cv-qualifiers on return types are pointless except when the type is a
// class type in C++.
if (T.getCVRQualifiers() && D.getDeclSpec().getTypeQualifiers() &&
@ -2050,7 +2075,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
break;
}
}
if (T.isNull())
return Context.getNullTypeSourceInfo();
else if (D.isInvalidType())

Просмотреть файл

@ -0,0 +1,49 @@
// RUN: %clang_cc1 -fexceptions -fsyntax-only -verify %s -std=c++0x
struct S {
virtual ~S();
void g() throw (auto(*)()->int);
// Note, this is not permitted: conversion-declarator cannot have a trailing return type.
// FIXME: don't issue the second diagnostic for this.
operator auto(*)()->int(); // expected-error{{'auto' not allowed here}} expected-error {{C++ requires a type specifier}}
};
typedef auto Fun(int a) -> decltype(a + a);
typedef auto (*PFun)(int a) -> decltype(a + a);
void g(auto (*f)() -> int) {
try { }
catch (auto (&f)() -> int) { }
catch (auto (*const f[10])() -> int) { }
}
namespace std {
class type_info;
}
template<typename T> struct U {};
void j() {
(void)typeid(auto(*)()->void);
(void)sizeof(auto(*)()->void);
(void)__alignof(auto(*)()->void);
U<auto(*)()->void> v;
int n;
(void)static_cast<auto(*)()->void>(&j);
auto p = reinterpret_cast<auto(*)()->int>(&j);
(void)const_cast<auto(**)()->int>(&p);
(void)(auto(*)()->void)(&j);
}
template <auto (*f)() -> void = &j> class C { };
struct F : auto(*)()->int {}; // expected-error{{expected class name}}
template<typename T = auto(*)()->int> struct G { };
int g();
auto (*h)() -> auto = &g; // expected-error{{'auto' not allowed here}}
auto (*i)() = &g; // ok; auto deduced as int.
auto (*k)() -> int = i; // ok; no deduction.

Просмотреть файл

@ -16,6 +16,7 @@ struct S {
// PR 9278: auto is not allowed in typedefs, except with a trailing return type.
typedef auto *AutoPtr; // expected-error{{'auto' not allowed in typedef}}
typedef auto (*PFun)(int a); // expected-error{{'auto' not allowed in typedef}}
typedef auto Fun(int a) -> decltype(a + a);
void g(auto a) { // expected-error{{'auto' not allowed in function prototype}}
@ -64,13 +65,5 @@ template<typename T = auto> struct G { }; // expected-error{{'auto' not allowed
using A = auto; // expected-error{{expected ';'}} expected-error{{requires a qualified name}}
// Whether this is illegal depends on the interpretation of [decl.spec.auto]p2 and p3,
// and in particular the "Otherwise, ..." at the start of p3.
namespace TrailingReturnType {
// FIXME: don't issue the second diagnostic for this error.
auto f() -> auto; // expected-error{{'auto' not allowed here}} unexpected-error{{without trailing return type}}
int g();
auto (*h)() -> auto = &g; // expected-error{{'auto' not allowed here}}
auto (*i)() = &g; // ok; auto deduced as int.
auto (*j)() -> int = i; // ok; no deduction.
}
// FIXME: don't issue the second diagnostic for this error.
auto k() -> auto; // expected-error{{'auto' not allowed here}} unexpected-error{{without trailing return type}}

Просмотреть файл

@ -3,3 +3,5 @@
auto a() -> int; // ok
const auto b() -> int; // expected-error {{function with trailing return type must specify return type 'auto', not 'auto const'}}
auto *c() -> int; // expected-error {{function with trailing return type must specify return type 'auto', not 'auto *'}}
auto (d() -> int); // expected-error {{trailing return type may not be nested within parentheses}}
auto e() -> auto (*)() -> auto (*)() -> void; // ok: same as void (*(*e())())();

Просмотреть файл

@ -0,0 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
auto f() -> int[32]; // expected-error{{function cannot return array}}
auto g() -> int(int); // expected-error{{function cannot return function}}
auto h() -> auto() -> int; // expected-error{{function cannot return function}}
auto i() -> auto(*)() -> int;

Просмотреть файл

@ -0,0 +1,3 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
auto j() -> enum { e3 }; // expected-error{{can not be defined in a type specifier}}