[llvm-branch-commits] [cfe-branch] r345409 - Merging r341775:
Tom Stellard via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Oct 26 10:32:52 PDT 2018
Author: tstellar
Date: Fri Oct 26 10:32:52 2018
New Revision: 345409
URL: http://llvm.org/viewvc/llvm-project?rev=345409&view=rev
Log:
Merging r341775:
------------------------------------------------------------------------
r341775 | rsmith | 2018-09-09 22:32:13 -0700 (Sun, 09 Sep 2018) | 2 lines
Part of PR33222: defer enforcing return type mismatch for dependent
friend function declarations of class templates.
------------------------------------------------------------------------
Modified:
cfe/branches/release_70/include/clang/Sema/Sema.h
cfe/branches/release_70/lib/Sema/SemaDecl.cpp
cfe/branches/release_70/test/SemaCXX/friend.cpp
Modified: cfe/branches/release_70/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_70/include/clang/Sema/Sema.h?rev=345409&r1=345408&r2=345409&view=diff
==============================================================================
--- cfe/branches/release_70/include/clang/Sema/Sema.h (original)
+++ cfe/branches/release_70/include/clang/Sema/Sema.h Fri Oct 26 10:32:52 2018
@@ -1950,6 +1950,8 @@ public:
FunctionDecl *NewFD, LookupResult &Previous,
bool IsMemberSpecialization);
bool shouldLinkDependentDeclWithPrevious(Decl *D, Decl *OldDecl);
+ bool canFullyTypeCheckRedeclaration(ValueDecl *NewD, ValueDecl *OldD,
+ QualType NewT, QualType OldT);
void CheckMain(FunctionDecl *FD, const DeclSpec &D);
void CheckMSVCRTEntryPoint(FunctionDecl *FD);
Attr *getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD, bool IsDefinition);
Modified: cfe/branches/release_70/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_70/lib/Sema/SemaDecl.cpp?rev=345409&r1=345408&r2=345409&view=diff
==============================================================================
--- cfe/branches/release_70/lib/Sema/SemaDecl.cpp (original)
+++ cfe/branches/release_70/lib/Sema/SemaDecl.cpp Fri Oct 26 10:32:52 2018
@@ -3258,8 +3258,8 @@ bool Sema::MergeFunctionDecl(FunctionDec
? New->getTypeSourceInfo()->getType()->castAs<FunctionType>()
: NewType)->getReturnType();
if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType) &&
- !((NewQType->isDependentType() || OldQType->isDependentType()) &&
- New->isLocalExternDecl())) {
+ canFullyTypeCheckRedeclaration(New, Old, NewDeclaredReturnType,
+ OldDeclaredReturnType)) {
QualType ResQT;
if (NewDeclaredReturnType->isObjCObjectPointerType() &&
OldDeclaredReturnType->isObjCObjectPointerType())
@@ -3427,13 +3427,11 @@ bool Sema::MergeFunctionDecl(FunctionDec
if (OldQTypeForComparison == NewQType)
return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld);
- if ((NewQType->isDependentType() || OldQType->isDependentType()) &&
- New->isLocalExternDecl()) {
- // It's OK if we couldn't merge types for a local function declaraton
- // if either the old or new type is dependent. We'll merge the types
- // when we instantiate the function.
+ // If the types are imprecise (due to dependent constructs in friends or
+ // local extern declarations), it's OK if they differ. We'll check again
+ // during instantiation.
+ if (!canFullyTypeCheckRedeclaration(New, Old, NewQType, OldQType))
return false;
- }
// Fall through for conflicting redeclarations and redefinitions.
}
@@ -9336,6 +9334,39 @@ Attr *Sema::getImplicitCodeSegOrSectionA
}
return nullptr;
}
+
+/// Determines if we can perform a correct type check for \p D as a
+/// redeclaration of \p PrevDecl. If not, we can generally still perform a
+/// best-effort check.
+///
+/// \param NewD The new declaration.
+/// \param OldD The old declaration.
+/// \param NewT The portion of the type of the new declaration to check.
+/// \param OldT The portion of the type of the old declaration to check.
+bool Sema::canFullyTypeCheckRedeclaration(ValueDecl *NewD, ValueDecl *OldD,
+ QualType NewT, QualType OldT) {
+ if (!NewD->getLexicalDeclContext()->isDependentContext())
+ return true;
+
+ // For dependently-typed local extern declarations and friends, we can't
+ // perform a correct type check in general until instantiation:
+ //
+ // int f();
+ // template<typename T> void g() { T f(); }
+ //
+ // (valid if g() is only instantiated with T = int).
+ if (NewT->isDependentType() &&
+ (NewD->isLocalExternDecl() || NewD->getFriendObjectKind()))
+ return false;
+
+ // Similarly, if the previous declaration was a dependent local extern
+ // declaration, we don't really know its type yet.
+ if (OldT->isDependentType() && OldD->isLocalExternDecl())
+ return false;
+
+ return true;
+}
+
/// Checks if the new declaration declared in dependent context must be
/// put in the same redeclaration chain as the specified declaration.
///
@@ -9346,20 +9377,30 @@ Attr *Sema::getImplicitCodeSegOrSectionA
/// belongs to.
///
bool Sema::shouldLinkDependentDeclWithPrevious(Decl *D, Decl *PrevDecl) {
- // Any declarations should be put into redeclaration chains except for
- // friend declaration in a dependent context that names a function in
- // namespace scope.
+ if (!D->getLexicalDeclContext()->isDependentContext())
+ return true;
+
+ // Don't chain dependent friend function definitions until instantiation, to
+ // permit cases like
//
- // This allows to compile code like:
+ // void func();
+ // template<typename T> class C1 { friend void func() {} };
+ // template<typename T> class C2 { friend void func() {} };
//
- // void func();
- // template<typename T> class C1 { friend void func() { } };
- // template<typename T> class C2 { friend void func() { } };
+ // ... which is valid if only one of C1 and C2 is ever instantiated.
//
- // This code snippet is a valid code unless both templates are instantiated.
- return !(D->getLexicalDeclContext()->isDependentContext() &&
- D->getDeclContext()->isFileContext() &&
- D->getFriendObjectKind() != Decl::FOK_None);
+ // FIXME: This need only apply to function definitions. For now, we proxy
+ // this by checking for a file-scope function. We do not want this to apply
+ // to friend declarations nominating member functions, because that gets in
+ // the way of access checks.
+ if (D->getFriendObjectKind() && D->getDeclContext()->isFileContext())
+ return false;
+
+ auto *VD = dyn_cast<ValueDecl>(D);
+ auto *PrevVD = dyn_cast<ValueDecl>(PrevDecl);
+ return !VD || !PrevVD ||
+ canFullyTypeCheckRedeclaration(VD, PrevVD, VD->getType(),
+ PrevVD->getType());
}
namespace MultiVersioning {
Modified: cfe/branches/release_70/test/SemaCXX/friend.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/release_70/test/SemaCXX/friend.cpp?rev=345409&r1=345408&r2=345409&view=diff
==============================================================================
--- cfe/branches/release_70/test/SemaCXX/friend.cpp (original)
+++ cfe/branches/release_70/test/SemaCXX/friend.cpp Fri Oct 26 10:32:52 2018
@@ -388,3 +388,26 @@ namespace default_arg {
friend void f(void *p = 0) {} // expected-error {{must be the only}}
};
}
+
+namespace PR33222 {
+ int f();
+ template<typename T> struct X {
+ friend T f();
+ };
+ X<int> xi;
+
+ int g(); // expected-note {{previous}}
+ template<typename T> struct Y {
+ friend T g(); // expected-error {{return type}}
+ };
+ Y<float> yf; // expected-note {{instantiation}}
+
+ int h();
+ template<typename T> struct Z {
+ // FIXME: The note here should point at the non-friend declaration, not the
+ // instantiation in Z<int>.
+ friend T h(); // expected-error {{return type}} expected-note {{previous}}
+ };
+ Z<int> zi;
+ Z<float> zf; // expected-note {{instantiation}}
+}
More information about the llvm-branch-commits
mailing list