diff options
| author | Vassil Vassilev <v.g.vassilev@gmail.com> | 2016-02-28 19:08:24 +0000 |
|---|---|---|
| committer | Vassil Vassilev <v.g.vassilev@gmail.com> | 2016-02-28 19:08:24 +0000 |
| commit | 4d75e8d6761cb950b410d99fc09319bad51b14cb (patch) | |
| tree | 375687cdc2021ffa691c12380c7e6c8351fdc3e3 /clang/lib/Sema | |
| parent | df0cd72657c898b1ed2b67c55b41459bc3ab5ab0 (diff) | |
| download | bcm5719-llvm-4d75e8d6761cb950b410d99fc09319bad51b14cb.tar.gz bcm5719-llvm-4d75e8d6761cb950b410d99fc09319bad51b14cb.zip | |
[modules] Prefer more complete array types.
If we import a module that has a complete array type and one that has an
incomplete array type, the declaration found by name lookup might be the one with
the incomplete type, possibly resulting in rejects-valid.
Now, the name lookup prefers decls with a complete array types. Also,
diagnose cases when the redecl chain has array bound, different from the merge
candidate.
Reviewed by Richard Smith.
llvm-svn: 262189
Diffstat (limited to 'clang/lib/Sema')
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 83 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 12 |
2 files changed, 61 insertions, 34 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 61ec1a77529..4a1bbde271d 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3245,6 +3245,22 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod, CheckObjCMethodOverride(newMethod, oldMethod); } +static void diagnoseVarDeclTypeMismatch(Sema &S, VarDecl *New, VarDecl* Old) { + assert(!S.Context.hasSameType(New->getType(), Old->getType())); + + S.Diag(New->getLocation(), New->isThisDeclarationADefinition() + ? diag::err_redefinition_different_type + : diag::err_redeclaration_different_type) + << New->getDeclName() << New->getType() << Old->getType(); + + diag::kind PrevDiag; + SourceLocation OldLocation; + std::tie(PrevDiag, OldLocation) + = getNoteDiagForInvalidRedeclaration(Old, New); + S.Diag(OldLocation, PrevDiag); + New->setInvalidDecl(); +} + /// MergeVarDeclTypes - We parsed a variable 'New' which has the same name and /// scope as a previous declaration 'Old'. Figure out how to merge their types, /// emitting diagnostics as appropriate. @@ -3271,21 +3287,40 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, // object or function shall be identical, except that declarations for an // array object can specify array types that differ by the presence or // absence of a major array bound (8.3.4). - else if (Old->getType()->isIncompleteArrayType() && - New->getType()->isArrayType()) { + else if (Old->getType()->isArrayType() && New->getType()->isArrayType()) { const ArrayType *OldArray = Context.getAsArrayType(Old->getType()); const ArrayType *NewArray = Context.getAsArrayType(New->getType()); - if (Context.hasSameType(OldArray->getElementType(), - NewArray->getElementType())) - MergedT = New->getType(); - } else if (Old->getType()->isArrayType() && - New->getType()->isIncompleteArrayType()) { - const ArrayType *OldArray = Context.getAsArrayType(Old->getType()); - const ArrayType *NewArray = Context.getAsArrayType(New->getType()); - if (Context.hasSameType(OldArray->getElementType(), - NewArray->getElementType())) - MergedT = Old->getType(); - } else if (New->getType()->isObjCObjectPointerType() && + + // We are merging a variable declaration New into Old. If it has an array + // bound, and that bound differs from Old's bound, we should diagnose the + // mismatch. + if (!NewArray->isIncompleteArrayType()) { + for (VarDecl *PrevVD = Old->getMostRecentDecl(); PrevVD; + PrevVD = PrevVD->getPreviousDecl()) { + const ArrayType *PrevVDTy = Context.getAsArrayType(PrevVD->getType()); + if (PrevVDTy->isIncompleteArrayType()) + continue; + + if (!Context.hasSameType(NewArray, PrevVDTy)) + return diagnoseVarDeclTypeMismatch(*this, New, PrevVD); + } + } + + if (OldArray->isIncompleteArrayType() && NewArray->isArrayType()) { + if (Context.hasSameType(OldArray->getElementType(), + NewArray->getElementType())) + MergedT = New->getType(); + } + // FIXME: Check visibility. New is hidden but has a complete type. If New + // has no array bound, it should not inherit one from Old, if Old is not + // visible. + else if (OldArray->isArrayType() && NewArray->isIncompleteArrayType()) { + if (Context.hasSameType(OldArray->getElementType(), + NewArray->getElementType())) + MergedT = Old->getType(); + } + } + else if (New->getType()->isObjCObjectPointerType() && Old->getType()->isObjCObjectPointerType()) { MergedT = Context.mergeObjCGCQualifiers(New->getType(), Old->getType()); @@ -3311,27 +3346,7 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, New->setType(Context.DependentTy); return; } - - // FIXME: Even if this merging succeeds, some other non-visible declaration - // of this variable might have an incompatible type. For instance: - // - // extern int arr[]; - // void f() { extern int arr[2]; } - // void g() { extern int arr[3]; } - // - // Neither C nor C++ requires a diagnostic for this, but we should still try - // to diagnose it. - Diag(New->getLocation(), New->isThisDeclarationADefinition() - ? diag::err_redefinition_different_type - : diag::err_redeclaration_different_type) - << New->getDeclName() << New->getType() << Old->getType(); - - diag::kind PrevDiag; - SourceLocation OldLocation; - std::tie(PrevDiag, OldLocation) = - getNoteDiagForInvalidRedeclaration(Old, New); - Diag(OldLocation, PrevDiag); - return New->setInvalidDecl(); + return diagnoseVarDeclTypeMismatch(*this, New, Old); } // Don't actually update the type on the new declaration if the old diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index a35c7600ab5..4baf6053359 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -419,6 +419,18 @@ static bool isPreferredLookupResult(Sema &S, Sema::LookupNameKind Kind, } } + // VarDecl can have incomplete array types, prefer the one with more complete + // array type. + if (VarDecl *DVD = dyn_cast<VarDecl>(DUnderlying)) { + VarDecl *EVD = cast<VarDecl>(EUnderlying); + if (EVD->getType()->isIncompleteType() && + !DVD->getType()->isIncompleteType()) { + // Prefer the decl with a more complete type if visible. + return S.isVisible(DVD); + } + return false; // Avoid picking up a newer decl, just because it was newer. + } + // For most kinds of declaration, it doesn't really matter which one we pick. if (!isa<FunctionDecl>(DUnderlying) && !isa<VarDecl>(DUnderlying)) { // If the existing declaration is hidden, prefer the new one. Otherwise, |

