diff options
author | Nick Lewycky <nicholas@mxc.ca> | 2013-02-02 00:25:55 +0000 |
---|---|---|
committer | Nick Lewycky <nicholas@mxc.ca> | 2013-02-02 00:25:55 +0000 |
commit | b7e5eec2f57bd82c6ddb762ca3dd7b7d8697e9d5 (patch) | |
tree | 7888570249ff2e98a75a4a6ec5ca6d4f6171e256 | |
parent | 0c4394c7f63008fbf4d335710b34f71afab362a3 (diff) |
This patch makes "&Cls::purevfn" not an odr use. This isn't what the standard
says, but that's a defect (to be filed). "Cls::purevfn()" is still an odr use.
Also fixes a bug that caused us to not mark the function referenced just
because we didn't want to mark it odr used.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@174242 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Sema/Sema.h | 2 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 43 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateVariadic.cpp | 2 | ||||
-rw-r--r-- | test/SemaCXX/address-of.cpp | 8 | ||||
-rw-r--r-- | test/SemaCXX/undefined-internal.cpp | 19 |
6 files changed, 58 insertions, 18 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index da80f0c8df..c8888a3275 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2863,7 +2863,7 @@ public: // for expressions referring to a decl; these exist because odr-use marking // needs to be delayed for some constant variables when we build one of the // named expressions. - void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D); + void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool OdrUse); void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func); void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var); void MarkDeclRefReferenced(DeclRefExpr *E); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 2167f01b63..0465707e7c 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2025,7 +2025,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, if (SelfExpr.isInvalid()) return ExprError(); - MarkAnyDeclReferenced(Loc, IV); + MarkAnyDeclReferenced(Loc, IV, true); ObjCMethodFamily MF = CurMethod->getMethodFamily(); if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize) @@ -11152,13 +11152,13 @@ void Sema::MarkVariableReferenced(SourceLocation Loc, VarDecl *Var) { } static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, - Decl *D, Expr *E) { + Decl *D, Expr *E, bool OdrUse) { if (VarDecl *Var = dyn_cast<VarDecl>(D)) { DoMarkVarDeclReferenced(SemaRef, Loc, Var, E); return; } - SemaRef.MarkAnyDeclReferenced(Loc, D); + SemaRef.MarkAnyDeclReferenced(Loc, D, OdrUse); // If this is a call to a method via a cast, also mark the method in the // derived class used in case codegen can devirtualize the call. @@ -11175,12 +11175,19 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, CXXMethodDecl *DM = MD->getCorrespondingMethodInClass(MostDerivedClassDecl); if (!DM) return; - SemaRef.MarkAnyDeclReferenced(Loc, DM); + SemaRef.MarkAnyDeclReferenced(Loc, DM, OdrUse); } /// \brief Perform reference-marking and odr-use handling for a DeclRefExpr. void Sema::MarkDeclRefReferenced(DeclRefExpr *E) { - MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E); + // TODO: update this with DR# once a defect report is filed. + // C++11 defect. The address of a pure member should not be an ODR use, even + // if it's a qualified reference. + bool OdrUse = true; + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getDecl())) + if (Method->isPure()) + OdrUse = false; + MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse); } /// \brief Perform reference-marking and odr-use handling for a MemberExpr. @@ -11191,25 +11198,31 @@ void Sema::MarkMemberReferenced(MemberExpr *E) { // overload resolution when referred to from a potentially-evaluated // expression, is odr-used, unless it is a pure virtual function and its // name is not explicitly qualified. + bool OdrUse = true; if (!E->hasQualifier()) { if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getMemberDecl())) if (Method->isPure()) - return; + OdrUse = false; } - MarkExprReferenced(*this, E->getMemberLoc(), E->getMemberDecl(), E); + MarkExprReferenced(*this, E->getMemberLoc(), E->getMemberDecl(), E, OdrUse); } /// \brief Perform marking for a reference to an arbitrary declaration. It /// marks the declaration referenced, and performs odr-use checking for functions /// and variables. This method should not be used when building an normal /// expression which refers to a variable. -void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D) { - if (VarDecl *VD = dyn_cast<VarDecl>(D)) - MarkVariableReferenced(Loc, VD); - else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - MarkFunctionReferenced(Loc, FD); - else - D->setReferenced(); +void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool OdrUse) { + if (OdrUse) { + if (VarDecl *VD = dyn_cast<VarDecl>(D)) { + MarkVariableReferenced(Loc, VD); + return; + } + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + MarkFunctionReferenced(Loc, FD); + return; + } + } + D->setReferenced(); } namespace { @@ -11234,7 +11247,7 @@ bool MarkReferencedDecls::TraverseTemplateArgument( const TemplateArgument &Arg) { if (Arg.getKind() == TemplateArgument::Declaration) { if (Decl *D = Arg.getAsDecl()) - S.MarkAnyDeclReferenced(Loc, D); + S.MarkAnyDeclReferenced(Loc, D, true); } return Inherited::TraverseTemplateArgument(Arg); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 9b56a204c0..86af8c3a23 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3950,7 +3950,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, // Create the template argument. Converted = TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()), ParamType->isReferenceType()); - S.MarkAnyDeclReferenced(Arg->getLocStart(), Entity); + S.MarkAnyDeclReferenced(Arg->getLocStart(), Entity, false); return false; } diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index bb20913dff..470896e0dd 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -844,7 +844,7 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S, return ExprError(); } - MarkAnyDeclReferenced(OpLoc, ParameterPack); + MarkAnyDeclReferenced(OpLoc, ParameterPack, true); return new (Context) SizeOfPackExpr(Context.getSizeType(), OpLoc, ParameterPack, NameLoc, RParenLoc); diff --git a/test/SemaCXX/address-of.cpp b/test/SemaCXX/address-of.cpp index 69fcaff8f1..677dc8966b 100644 --- a/test/SemaCXX/address-of.cpp +++ b/test/SemaCXX/address-of.cpp @@ -44,3 +44,11 @@ void PR11066::test() { int (PR11066::*ptr)(int) = & &PR11066::foo; // expected-error{{address expression must be an lvalue or a function designator}} } +namespace test3 { + // emit no error + template<typename T> struct S { + virtual void f() = 0; + }; + template<typename T> void S<T>::f() { T::error; } + void (S<int>::*p)() = &S<int>::f; +} diff --git a/test/SemaCXX/undefined-internal.cpp b/test/SemaCXX/undefined-internal.cpp index 62c6ff96ca..227e6b4a85 100644 --- a/test/SemaCXX/undefined-internal.cpp +++ b/test/SemaCXX/undefined-internal.cpp @@ -212,3 +212,22 @@ namespace test9 { x.X::used(); // expected-note {{used here}} } } + +namespace test10 { + namespace { + struct X { + virtual void notused() = 0; + virtual void used() = 0; // expected-warning {{function 'test10::<anonymous namespace>::X::used' has internal linkage but is not defined}} + + void test() { + notused(); + (void)&X::notused; + (this->*&X::notused)(); + X::used(); // expected-note {{used here}} + } + }; + struct Y : X { + using X::notused; + }; + } +} |