mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-09 01:29:52 +00:00
Implement DR1265 (wg21.link/cwg1265).
Diasllow a declaration using the 'auto' type specifier from using two different meanings of it at once, or from declaring multiple functions with deduced return types or introducing multiple trailing return types. The standard does not technically disallow the multiple trailing return types case if all the declarators declare variables (such as function pointers with trailing return types), but we disallow that too, following the clear intent. llvm-svn: 291880
This commit is contained in:
parent
8515875e24
commit
8210ed5586
@ -1867,6 +1867,11 @@ public:
|
||||
/// types, but not through decltype or typedefs.
|
||||
AutoType *getContainedAutoType() const;
|
||||
|
||||
/// Determine whether this type was written with a leading 'auto'
|
||||
/// corresponding to a trailing return type (possibly for a nested
|
||||
/// function type within a pointer to function type or similar).
|
||||
bool hasAutoForTrailingReturnType() const;
|
||||
|
||||
/// Member-template getAs<specific type>'. Look through sugar for
|
||||
/// an instance of \<specific type>. This scheme will eventually
|
||||
/// replace the specific getAsXXXX methods above.
|
||||
|
@ -1900,6 +1900,10 @@ def err_auto_new_deduction_failure : Error<
|
||||
def err_auto_different_deductions : Error<
|
||||
"'%select{auto|decltype(auto)|__auto_type}0' deduced as %1 in declaration "
|
||||
"of %2 and deduced as %3 in declaration of %4">;
|
||||
def err_auto_non_deduced_not_alone : Error<
|
||||
"%select{function with deduced return type|"
|
||||
"declaration with trailing return type}0 "
|
||||
"must be the only declaration in its group">;
|
||||
def err_implied_std_initializer_list_not_found : Error<
|
||||
"cannot deduce type of initializer list because std::initializer_list was "
|
||||
"not found; include <initializer_list>">;
|
||||
|
@ -1560,60 +1560,73 @@ TagDecl *Type::getAsTagDecl() const {
|
||||
|
||||
namespace {
|
||||
class GetContainedAutoVisitor :
|
||||
public TypeVisitor<GetContainedAutoVisitor, AutoType*> {
|
||||
public TypeVisitor<GetContainedAutoVisitor, Type*> {
|
||||
bool Syntactic;
|
||||
public:
|
||||
using TypeVisitor<GetContainedAutoVisitor, AutoType*>::Visit;
|
||||
AutoType *Visit(QualType T) {
|
||||
GetContainedAutoVisitor(bool Syntactic = false) : Syntactic(Syntactic) {}
|
||||
|
||||
using TypeVisitor<GetContainedAutoVisitor, Type*>::Visit;
|
||||
Type *Visit(QualType T) {
|
||||
if (T.isNull())
|
||||
return nullptr;
|
||||
return Visit(T.getTypePtr());
|
||||
}
|
||||
|
||||
// The 'auto' type itself.
|
||||
AutoType *VisitAutoType(const AutoType *AT) {
|
||||
Type *VisitAutoType(const AutoType *AT) {
|
||||
return const_cast<AutoType*>(AT);
|
||||
}
|
||||
|
||||
// Only these types can contain the desired 'auto' type.
|
||||
AutoType *VisitPointerType(const PointerType *T) {
|
||||
Type *VisitPointerType(const PointerType *T) {
|
||||
return Visit(T->getPointeeType());
|
||||
}
|
||||
AutoType *VisitBlockPointerType(const BlockPointerType *T) {
|
||||
Type *VisitBlockPointerType(const BlockPointerType *T) {
|
||||
return Visit(T->getPointeeType());
|
||||
}
|
||||
AutoType *VisitReferenceType(const ReferenceType *T) {
|
||||
Type *VisitReferenceType(const ReferenceType *T) {
|
||||
return Visit(T->getPointeeTypeAsWritten());
|
||||
}
|
||||
AutoType *VisitMemberPointerType(const MemberPointerType *T) {
|
||||
Type *VisitMemberPointerType(const MemberPointerType *T) {
|
||||
return Visit(T->getPointeeType());
|
||||
}
|
||||
AutoType *VisitArrayType(const ArrayType *T) {
|
||||
Type *VisitArrayType(const ArrayType *T) {
|
||||
return Visit(T->getElementType());
|
||||
}
|
||||
AutoType *VisitDependentSizedExtVectorType(
|
||||
Type *VisitDependentSizedExtVectorType(
|
||||
const DependentSizedExtVectorType *T) {
|
||||
return Visit(T->getElementType());
|
||||
}
|
||||
AutoType *VisitVectorType(const VectorType *T) {
|
||||
Type *VisitVectorType(const VectorType *T) {
|
||||
return Visit(T->getElementType());
|
||||
}
|
||||
AutoType *VisitFunctionType(const FunctionType *T) {
|
||||
Type *VisitFunctionProtoType(const FunctionProtoType *T) {
|
||||
if (Syntactic && T->hasTrailingReturn())
|
||||
return const_cast<FunctionProtoType*>(T);
|
||||
return VisitFunctionType(T);
|
||||
}
|
||||
Type *VisitFunctionType(const FunctionType *T) {
|
||||
return Visit(T->getReturnType());
|
||||
}
|
||||
AutoType *VisitParenType(const ParenType *T) {
|
||||
Type *VisitParenType(const ParenType *T) {
|
||||
return Visit(T->getInnerType());
|
||||
}
|
||||
AutoType *VisitAttributedType(const AttributedType *T) {
|
||||
Type *VisitAttributedType(const AttributedType *T) {
|
||||
return Visit(T->getModifiedType());
|
||||
}
|
||||
AutoType *VisitAdjustedType(const AdjustedType *T) {
|
||||
Type *VisitAdjustedType(const AdjustedType *T) {
|
||||
return Visit(T->getOriginalType());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
AutoType *Type::getContainedAutoType() const {
|
||||
return GetContainedAutoVisitor().Visit(this);
|
||||
return cast_or_null<AutoType>(GetContainedAutoVisitor().Visit(this));
|
||||
}
|
||||
|
||||
bool Type::hasAutoForTrailingReturnType() const {
|
||||
return dyn_cast_or_null<FunctionType>(
|
||||
GetContainedAutoVisitor(true).Visit(this));
|
||||
}
|
||||
|
||||
bool Type::hasIntegerRepresentation() const {
|
||||
|
@ -11045,6 +11045,11 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool hasDeducedAuto(DeclaratorDecl *DD) {
|
||||
auto *VD = dyn_cast<VarDecl>(DD);
|
||||
return VD && !VD->getType()->hasAutoForTrailingReturnType();
|
||||
}
|
||||
|
||||
Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
|
||||
ArrayRef<Decl *> Group) {
|
||||
SmallVector<Decl*, 8> Decls;
|
||||
@ -11055,29 +11060,46 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
|
||||
DeclaratorDecl *FirstDeclaratorInGroup = nullptr;
|
||||
DecompositionDecl *FirstDecompDeclaratorInGroup = nullptr;
|
||||
bool DiagnosedMultipleDecomps = false;
|
||||
DeclaratorDecl *FirstNonDeducedAutoInGroup = nullptr;
|
||||
bool DiagnosedNonDeducedAuto = false;
|
||||
|
||||
for (unsigned i = 0, e = Group.size(); i != e; ++i) {
|
||||
if (Decl *D = Group[i]) {
|
||||
auto *DD = dyn_cast<DeclaratorDecl>(D);
|
||||
if (DD && !FirstDeclaratorInGroup)
|
||||
FirstDeclaratorInGroup = DD;
|
||||
// For declarators, there are some additional syntactic-ish checks we need
|
||||
// to perform.
|
||||
if (auto *DD = dyn_cast<DeclaratorDecl>(D)) {
|
||||
if (!FirstDeclaratorInGroup)
|
||||
FirstDeclaratorInGroup = DD;
|
||||
if (!FirstDecompDeclaratorInGroup)
|
||||
FirstDecompDeclaratorInGroup = dyn_cast<DecompositionDecl>(D);
|
||||
if (!FirstNonDeducedAutoInGroup && DS.containsPlaceholderType() &&
|
||||
!hasDeducedAuto(DD))
|
||||
FirstNonDeducedAutoInGroup = DD;
|
||||
|
||||
auto *Decomp = dyn_cast<DecompositionDecl>(D);
|
||||
if (Decomp && !FirstDecompDeclaratorInGroup)
|
||||
FirstDecompDeclaratorInGroup = Decomp;
|
||||
if (FirstDeclaratorInGroup != DD) {
|
||||
// A decomposition declaration cannot be combined with any other
|
||||
// declaration in the same group.
|
||||
if (FirstDecompDeclaratorInGroup && !DiagnosedMultipleDecomps) {
|
||||
Diag(FirstDecompDeclaratorInGroup->getLocation(),
|
||||
diag::err_decomp_decl_not_alone)
|
||||
<< FirstDeclaratorInGroup->getSourceRange()
|
||||
<< DD->getSourceRange();
|
||||
DiagnosedMultipleDecomps = true;
|
||||
}
|
||||
|
||||
// A decomposition declaration cannot be combined with any other
|
||||
// declaration in the same group.
|
||||
auto *OtherDD = FirstDeclaratorInGroup;
|
||||
if (OtherDD == FirstDecompDeclaratorInGroup)
|
||||
OtherDD = DD;
|
||||
if (OtherDD && FirstDecompDeclaratorInGroup &&
|
||||
OtherDD != FirstDecompDeclaratorInGroup &&
|
||||
!DiagnosedMultipleDecomps) {
|
||||
Diag(FirstDecompDeclaratorInGroup->getLocation(),
|
||||
diag::err_decomp_decl_not_alone)
|
||||
<< OtherDD->getSourceRange();
|
||||
DiagnosedMultipleDecomps = true;
|
||||
// A declarator that uses 'auto' in any way other than to declare a
|
||||
// variable with a deduced type cannot be combined with any other
|
||||
// declarator in the same group.
|
||||
if (FirstNonDeducedAutoInGroup && !DiagnosedNonDeducedAuto) {
|
||||
Diag(FirstNonDeducedAutoInGroup->getLocation(),
|
||||
diag::err_auto_non_deduced_not_alone)
|
||||
<< FirstNonDeducedAutoInGroup->getType()
|
||||
->hasAutoForTrailingReturnType()
|
||||
<< FirstDeclaratorInGroup->getSourceRange()
|
||||
<< DD->getSourceRange();
|
||||
DiagnosedNonDeducedAuto = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Decls.push_back(D);
|
||||
@ -11105,38 +11127,27 @@ Sema::BuildDeclaratorGroup(MutableArrayRef<Decl *> Group) {
|
||||
// deduction, the program is ill-formed.
|
||||
if (Group.size() > 1) {
|
||||
QualType Deduced;
|
||||
CanQualType DeducedCanon;
|
||||
VarDecl *DeducedDecl = nullptr;
|
||||
for (unsigned i = 0, e = Group.size(); i != e; ++i) {
|
||||
if (VarDecl *D = dyn_cast<VarDecl>(Group[i])) {
|
||||
AutoType *AT = D->getType()->getContainedAutoType();
|
||||
// FIXME: DR1265: if we have a function pointer declaration, we can have
|
||||
// an 'auto' from a trailing return type. In that case, the return type
|
||||
// must match the various other uses of 'auto'.
|
||||
if (!AT)
|
||||
continue;
|
||||
// Don't reissue diagnostics when instantiating a template.
|
||||
if (D->isInvalidDecl())
|
||||
break;
|
||||
QualType U = AT->getDeducedType();
|
||||
if (!U.isNull()) {
|
||||
CanQualType UCanon = Context.getCanonicalType(U);
|
||||
if (Deduced.isNull()) {
|
||||
Deduced = U;
|
||||
DeducedCanon = UCanon;
|
||||
DeducedDecl = D;
|
||||
} else if (DeducedCanon != UCanon) {
|
||||
Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(),
|
||||
diag::err_auto_different_deductions)
|
||||
<< (unsigned)AT->getKeyword()
|
||||
<< Deduced << DeducedDecl->getDeclName()
|
||||
<< U << D->getDeclName()
|
||||
<< DeducedDecl->getInit()->getSourceRange()
|
||||
<< D->getInit()->getSourceRange();
|
||||
D->setInvalidDecl();
|
||||
break;
|
||||
}
|
||||
}
|
||||
VarDecl *D = dyn_cast<VarDecl>(Group[i]);
|
||||
if (!D || D->isInvalidDecl())
|
||||
break;
|
||||
AutoType *AT = D->getType()->getContainedAutoType();
|
||||
if (!AT || AT->getDeducedType().isNull())
|
||||
continue;
|
||||
if (Deduced.isNull()) {
|
||||
Deduced = AT->getDeducedType();
|
||||
DeducedDecl = D;
|
||||
} else if (!Context.hasSameType(AT->getDeducedType(), Deduced)) {
|
||||
Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(),
|
||||
diag::err_auto_different_deductions)
|
||||
<< (unsigned)AT->getKeyword()
|
||||
<< Deduced << DeducedDecl->getDeclName()
|
||||
<< AT->getDeducedType() << D->getDeclName()
|
||||
<< DeducedDecl->getInit()->getSourceRange()
|
||||
<< D->getInit()->getSourceRange();
|
||||
D->setInvalidDecl();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++14
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++11-extensions
|
||||
void f() {
|
||||
@ -19,22 +20,42 @@ void f() {
|
||||
}
|
||||
|
||||
void g() {
|
||||
#if __has_feature(cxx_trailing_return)
|
||||
auto a = 0,
|
||||
#if __has_feature(cxx_trailing_return)
|
||||
(*b)() -> void,
|
||||
#endif
|
||||
(*b)() -> void, // expected-error {{declaration with trailing return type must be the only declaration in its group}}
|
||||
c = 0;
|
||||
auto d = 0, // expected-error {{'auto' deduced as 'int' in declaration of 'd' and deduced as 'double' in declaration of 'f'}}
|
||||
#if __has_feature(cxx_trailing_return)
|
||||
(*e)() -> void,
|
||||
#endif
|
||||
auto d = 0,
|
||||
e() -> void, // expected-error {{declaration with trailing return type must be the only declaration in its group}}
|
||||
f = 0.0;
|
||||
auto x() -> void, // expected-error {{declaration with trailing return type must be the only declaration in its group}}
|
||||
y() -> void;
|
||||
#endif
|
||||
|
||||
#if __has_feature(cxx_decltype)
|
||||
auto g = 0ull, h = decltype(g)(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if __has_feature(cxx_trailing_return)
|
||||
int F();
|
||||
auto p = 0, (*q)() -> auto = F; // expected-error {{declaration with trailing return type must be the only declaration in its group}}
|
||||
#if __cplusplus < 201402L
|
||||
// expected-error@-2 {{'auto' not allowed in function return type}}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 201402L
|
||||
namespace DeducedReturnType {
|
||||
auto a = 0,
|
||||
b(), // expected-error {{function with deduced return type must be the only declaration in its group}}
|
||||
c = 0.0;
|
||||
auto d(), // expected-error {{function with deduced return type must be the only declaration in its group}}
|
||||
e = 1;
|
||||
auto f(), // expected-error {{function with deduced return type must be the only declaration in its group}}
|
||||
g();
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename T> void h() {
|
||||
auto a = T(), *b = &a;
|
||||
#if __has_feature(cxx_decltype)
|
||||
|
@ -14,7 +14,7 @@ namespace dr1213 { // dr1213: 4
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace dr1250 { // dr1250: 3.9
|
||||
namespace dr1250 { // dr1250: 3.9
|
||||
struct Incomplete;
|
||||
|
||||
struct Base {
|
||||
@ -24,9 +24,23 @@ struct Base {
|
||||
struct Derived : Base {
|
||||
virtual Incomplete *meow();
|
||||
};
|
||||
} // dr1250
|
||||
}
|
||||
|
||||
namespace dr1295 { // dr1295: 4
|
||||
namespace dr1265 { // dr1265: 5
|
||||
#if __cplusplus >= 201103L
|
||||
auto a = 0, b() -> int; // expected-error {{declaration with trailing return type must be the only declaration in its group}}
|
||||
auto b() -> int, d = 0; // expected-error {{declaration with trailing return type must be the only declaration in its group}}
|
||||
auto e() -> int, f() -> int; // expected-error {{declaration with trailing return type must be the only declaration in its group}}
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 201402L
|
||||
auto g(), h = 0; // expected-error {{function with deduced return type must be the only declaration in its group}}
|
||||
auto i = 0, j(); // expected-error {{function with deduced return type must be the only declaration in its group}}
|
||||
auto k(), l(); // expected-error {{function with deduced return type must be the only declaration in its group}}
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace dr1295 { // dr1295: 4
|
||||
struct X {
|
||||
unsigned bitfield : 4;
|
||||
};
|
||||
|
@ -3,6 +3,16 @@
|
||||
// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
|
||||
// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
|
||||
|
||||
__extension__ typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
namespace std {
|
||||
template<typename T> struct initializer_list {
|
||||
const T *ptr;
|
||||
size_t n;
|
||||
initializer_list(const T*, size_t);
|
||||
};
|
||||
}
|
||||
|
||||
namespace dr1315 { // dr1315: partial
|
||||
template <int I, int J> struct A {};
|
||||
template <int I> // expected-note {{non-deducible template parameter 'I'}}
|
||||
@ -159,6 +169,15 @@ namespace dr1346 { // dr1346: 3.5
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace dr1347 { // dr1347: yes
|
||||
auto x = 5, *y = &x; // expected-error 0-1{{extension}}
|
||||
auto z = y, *q = y; // expected-error {{'auto' deduced as 'int *' in declaration of 'z' and deduced as 'int' in declaration of 'q'}} expected-error 0-1{{extension}}
|
||||
#if __cplusplus >= 201103L
|
||||
auto a = 5, b = {1, 2}; // expected-error {{'auto' deduced as 'int' in declaration of 'a' and deduced as 'std::initializer_list<int>' in declaration of 'b'}}
|
||||
auto (*fp)(int) -> int, i = 0; // expected-error {{declaration with trailing return type must be the only declaration in its group}}
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace dr1359 { // dr1359: 3.5
|
||||
#if __cplusplus >= 201103L
|
||||
union A { constexpr A() = default; };
|
||||
|
@ -7405,7 +7405,7 @@ and <I>POD class</I></td>
|
||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1265">1265</a></td>
|
||||
<td>CD3</td>
|
||||
<td>Mixed use of the <TT>auto</TT> specifier</td>
|
||||
<td class="none" align="center">Unknown</td>
|
||||
<td class="svn" align="center">SVN</td>
|
||||
</tr>
|
||||
<tr class="open" id="1266">
|
||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1266">1266</a></td>
|
||||
@ -7897,7 +7897,7 @@ and <I>POD class</I></td>
|
||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1347">1347</a></td>
|
||||
<td>CD3</td>
|
||||
<td>Consistency of <TT>auto</TT> in multiple-declarator declarations</td>
|
||||
<td class="none" align="center">Unknown</td>
|
||||
<td class="full" align="center">Yes</td>
|
||||
</tr>
|
||||
<tr class="open" id="1348">
|
||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1348">1348</a></td>
|
||||
|
Loading…
Reference in New Issue
Block a user