sepavloff updated this revision to Diff 101260.
sepavloff added a comment.
Do not call getCanonicalDecl for deleted functions
https://reviews.llvm.org/D30170
Files:
include/clang/AST/Decl.h
lib/AST/Decl.cpp
lib/Sema/SemaDecl.cpp
test/SemaCXX/cxx0x-cursory-default-delete.cpp
test/SemaCXX/friend2.cpp
Index: test/SemaCXX/friend2.cpp
===================================================================
--- test/SemaCXX/friend2.cpp
+++ test/SemaCXX/friend2.cpp
@@ -101,6 +101,34 @@
friend void func_12(int x = 0); // expected-error{{friend declaration specifying a default argument must be the only declaration}}
};
+// Friend function with uninstantiated body is still a definition.
+
+template<typename T> struct C20 {
+ friend void func_20() {} // expected-note{{previous definition is here}}
+};
+C20<int> c20i;
+void func_20() {} // expected-error{{redefinition of 'func_20'}}
+
+template<typename T> struct C21a {
+ friend void func_21() {} // expected-note{{previous definition is here}}
+};
+template<typename T> struct C21b {
+ friend void func_21() {} // expected-error{{redefinition of 'func_21'}}
+};
+C21a<int> c21ai;
+C21b<int> c21bi; // expected-note{{in instantiation of template class 'C21b<int>' requested here}}
+
+template<typename T> struct C22a {
+ friend void func_22() {} // expected-note{{previous definition is here}}
+};
+template<typename T> struct C22b {
+ friend void func_22();
+};
+C22a<int> c22ai;
+C22b<int> c22bi;
+void func_22() {} // expected-error{{redefinition of 'func_22'}}
+
+
namespace pr22307 {
Index: test/SemaCXX/cxx0x-cursory-default-delete.cpp
===================================================================
--- test/SemaCXX/cxx0x-cursory-default-delete.cpp
+++ test/SemaCXX/cxx0x-cursory-default-delete.cpp
@@ -136,13 +136,13 @@
};
struct DefaultDelete {
- DefaultDelete() = default; // expected-note {{previous declaration is here}}
+ DefaultDelete() = default; // expected-note {{previous definition is here}}
DefaultDelete() = delete; // expected-error {{constructor cannot be redeclared}}
- ~DefaultDelete() = default; // expected-note {{previous declaration is here}}
+ ~DefaultDelete() = default; // expected-note {{previous definition is here}}
~DefaultDelete() = delete; // expected-error {{destructor cannot be redeclared}}
- DefaultDelete &operator=(const DefaultDelete &) = default; // expected-note {{previous declaration is here}}
+ DefaultDelete &operator=(const DefaultDelete &) = default; // expected-note {{previous definition is here}}
DefaultDelete &operator=(const DefaultDelete &) = delete; // expected-error {{class member cannot be redeclared}}
};
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -11875,8 +11875,12 @@
SkipBodyInfo *SkipBody) {
const FunctionDecl *Definition = EffectiveDefinition;
if (!Definition)
- if (!FD->isDefined(Definition))
+ if (!FD->isOdrDefined(Definition))
return;
+ assert(Definition);
+
+ if (FD == Definition)
+ return;
if (canRedefineFunction(Definition, getLangOpts()))
return;
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -2534,16 +2534,45 @@
bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const {
for (auto I : redecls()) {
- if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed ||
- I->hasDefiningAttr()) {
- Definition = I->IsDeleted ? I->getCanonicalDecl() : I;
+ if (I->isThisDeclarationADefinition()) {
+ Definition = I;
return true;
}
}
return false;
}
+bool FunctionDecl::isOdrDefined(const FunctionDecl *&Definition) const {
+ // First try to find a declaration that has existing definition.
+ if (isDefined(Definition))
+ return true;
+
+ // If no existing definition exist, look for a definition which can be
+ // instantiated.
+ for (auto I : redecls()) {
+ if (I->getFriendObjectKind() != Decl::FOK_None) {
+ // If this is a friend function defined in a class template, it does not
+ // have a body until it is used, nevertheless it is a definition. The
+ // following code must produce redeclaration error:
+ //
+ // template<typename T> struct C20 { friend void func_20() {} };
+ // C20<int> c20i;
+ // void func_20() {}
+ //
+ if (FunctionDecl *Original = I->getInstantiatedFromMemberFunction()) {
+ const FunctionDecl *D;
+ if (Original->isOdrDefined(D)) {
+ Definition = I;
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
if (!hasBody(Definition))
return nullptr;
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -1778,11 +1778,26 @@
SourceRange getSourceRange() const override LLVM_READONLY;
- /// \brief Returns true if the function has a body (definition). The
- /// function body might be in any of the (re-)declarations of this
- /// function. The variant that accepts a FunctionDecl pointer will
- /// set that function declaration to the actual declaration
- /// containing the body (if there is one).
+ // Function definitions.
+ //
+ // A function declaration may be:
+ // - a non defining declaration,
+ // - a definition. A function may be defined because:
+ // - it has a body, or will have it in the case of late parsing.
+ // - it has an uninstantiated body. The body does not exist because the
+ // function is not used yet, but the declaration is considered a
+ // definition and does not allow other definition of this function.
+ // - it does not have a user specified body, but it does not allow
+ // redefinition, because it is deleted/defaulted or is defined through
+ // some other mechanism (alias, ifunc).
+
+ /// Returns true if the function has a body.
+ ///
+ /// The function body might be in any of the (re-)declarations of this
+ /// function. The variant that accepts a FunctionDecl pointer will set that
+ /// function declaration to the actual declaration containing the body (if
+ /// there is one).
+ ///
bool hasBody(const FunctionDecl *&Definition) const;
bool hasBody() const override {
@@ -1794,16 +1809,31 @@
/// not require any specific codegen.
bool hasTrivialBody() const;
- /// isDefined - Returns true if the function is defined at all, including
- /// a deleted definition. Except for the behavior when the function is
- /// deleted, behaves like hasBody.
+ /// Returns true if the function has a definition that does not need to be
+ /// instantiated.
+ ///
+ /// The variant that accepts a FunctionDecl pointer will set that function
+ /// declaration to the declaration that is a definition (if there is one).
+ ///
bool isDefined(const FunctionDecl *&Definition) const;
virtual bool isDefined() const {
const FunctionDecl* Definition;
return isDefined(Definition);
}
+ /// Returns true if there is a definition for this function in its
+ /// redeclaration chain and other definitions are not allowed.
+ ///
+ /// This function is proposed for function redefinition checks. In contrast to
+ /// isDefined it considers functions with uninstantiated bodies as
+ /// definitions.
+ ///
+ /// \param [out] Definition Is assigned defining declaration if the method
+ /// returns true.
+ ///
+ bool isOdrDefined(const FunctionDecl *&Definition) const;
+
/// \brief Get the definition for this declaration.
FunctionDecl *getDefinition() {
const FunctionDecl *Definition;
@@ -1829,19 +1859,19 @@
return getBody(Definition);
}
- /// isThisDeclarationADefinition - Returns whether this specific
- /// declaration of the function is also a definition. This does not
- /// determine whether the function has been defined (e.g., in a
- /// previous definition); for that information, use isDefined. Note
- /// that this returns false for a defaulted function unless that function
- /// has been implicitly defined (possibly as deleted).
+ /// Returns whether this specific declaration of the function is also a
+ /// definition that does not contain uninstantiated body.
+ ///
+ /// This does not determine whether the function has been defined (e.g., in a
+ /// previous definition); for that information, use isDefined.
+ ///
bool isThisDeclarationADefinition() const {
- return IsDeleted || Body || IsLateTemplateParsed;
+ return IsDeleted || IsDefaulted || Body || IsLateTemplateParsed ||
+ hasDefiningAttr();
}
- /// doesThisDeclarationHaveABody - Returns whether this specific
- /// declaration of the function has a body - that is, if it is a non-
- /// deleted definition.
+ /// Returns whether this specific declaration of the function has a body.
+ ///
bool doesThisDeclarationHaveABody() const {
return Body || IsLateTemplateParsed;
}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits