From: Richard Smith Date: Tue, 22 Feb 2011 00:36:53 +0000 (+0000) Subject: Fix a few auto-related issues: X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e7397c6a1bb2b205c5fe678e26199eb26d22e38e;p=clang 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 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 30a35af8a9..e29547c661 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 8051b56034..9468b9c74a 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -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,21 +1623,6 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // of the type, otherwise the argument list is (). const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; - // 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()) && - (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId)) { - unsigned diagID = diag::err_func_returning_array_function; - // Last processing chunk in block context means this function chunk - // represents the block. - if (chunkIndex == 0 && - D.getContext() == Declarator::BlockLiteralContext) - diagID = diag::err_block_returning_array_function; - Diag(DeclType.Loc, diagID) << T->isFunctionType() << T; - T = Context.IntTy; - D.setInvalidType(true); - } - // Check for auto functions and trailing return type and adjust the // return type accordingly. if (!D.isInvalidType()) { @@ -1630,8 +1635,13 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, T = Context.IntTy; D.setInvalidType(true); } else if (FTI.TrailingReturnType) { - if (T.hasQualifiers() || !isa(T)) { - // T must be exactly 'auto' at this point. See CWG issue 681. + // T must be exactly 'auto' at this point. See CWG issue 681. + if (isa(T)) { + Diag(D.getDeclSpec().getTypeSpecTypeLoc(), + diag::err_trailing_return_in_parens) + << T << D.getDeclSpec().getSourceRange(); + D.setInvalidType(true); + } else if (T.hasQualifiers() || !isa(T)) { Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_trailing_return_without_auto) << T << D.getDeclSpec().getSourceRange(); @@ -1644,6 +1654,21 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } } + // 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()) && + (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId)) { + unsigned diagID = diag::err_func_returning_array_function; + // Last processing chunk in block context means this function chunk + // represents the block. + if (chunkIndex == 0 && + D.getContext() == Declarator::BlockLiteralContext) + diagID = diag::err_block_returning_array_function; + Diag(DeclType.Loc, diagID) << T->isFunctionType() << T; + T = Context.IntTy; + D.setInvalidType(true); + } + // 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()) diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp new file mode 100644 index 0000000000..18a0cf169d --- /dev/null +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp @@ -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 struct U {}; + +void j() { + (void)typeid(auto(*)()->void); + (void)sizeof(auto(*)()->void); + (void)__alignof(auto(*)()->void); + + Uvoid> v; + + int n; + (void)static_castvoid>(&j); + auto p = reinterpret_castint>(&j); + (void)const_castint>(&p); + (void)(auto(*)()->void)(&j); +} + +template void = &j> class C { }; +struct F : auto(*)()->int {}; // expected-error{{expected class name}} +templateint> 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. diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp index 20dd6343ce..fec53c941e 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp @@ -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 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}} diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p2-cxx0x.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p2-cxx0x.cpp index 4dc393da9f..70c9aeb488 100644 --- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p2-cxx0x.cpp +++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p2-cxx0x.cpp @@ -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())())(); diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p8-0x.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p8-0x.cpp new file mode 100644 index 0000000000..21efbfff1a --- /dev/null +++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p8-0x.cpp @@ -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; diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp new file mode 100644 index 0000000000..ca4701554b --- /dev/null +++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp @@ -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}}