diff options
| author | Richard Smith <richard-llvm@metafoo.co.uk> | 2017-01-13 02:22:01 +0000 |
|---|---|---|
| committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2017-01-13 02:22:01 +0000 |
| commit | 8210ed558662bd80f16bc96e482974120d2ca2bd (patch) | |
| tree | 8cf39a448668eefe9889917924585318c2ca93a2 /clang/lib/Sema/SemaDecl.cpp | |
| parent | 8515875e24831bda1ca3086da17163836100d30b (diff) | |
| download | bcm5719-llvm-8210ed558662bd80f16bc96e482974120d2ca2bd.tar.gz bcm5719-llvm-8210ed558662bd80f16bc96e482974120d2ca2bd.zip | |
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
Diffstat (limited to 'clang/lib/Sema/SemaDecl.cpp')
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 111 |
1 files changed, 61 insertions, 50 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index adcf2ee00e7..fe1775e1eb5 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -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; - - auto *Decomp = dyn_cast<DecompositionDecl>(D); - if (Decomp && !FirstDecompDeclaratorInGroup) - FirstDecompDeclaratorInGroup = Decomp; - - // 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; + // 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; + + 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 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; } } } |

