diff options
-rw-r--r-- | include/clang/AST/DeclBase.h | 6 | ||||
-rw-r--r-- | lib/AST/DeclBase.cpp | 6 | ||||
-rw-r--r-- | lib/Frontend/PCHWriterDecl.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 4 | ||||
-rw-r--r-- | test/SemaTemplate/instantiate-function-2.cpp | 11 |
8 files changed, 35 insertions, 17 deletions
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index f6478d9ea6..fe091ad17b 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -330,7 +330,11 @@ public: /// \brief Whether this declaration was used, meaning that a definition /// is required. - bool isUsed() const; + /// + /// \param CheckUsedAttr When true, also consider the "used" attribute + /// (in addition to the "used" bit set by \c setUsed()) when determining + /// whether the function is used. + bool isUsed(bool CheckUsedAttr = true) const; void setUsed(bool U = true) { Used = U; } diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index f1b78e40fc..104df7ae84 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -212,17 +212,17 @@ ASTContext &Decl::getASTContext() const { return getTranslationUnitDecl()->getASTContext(); } -bool Decl::isUsed() const { +bool Decl::isUsed(bool CheckUsedAttr) const { if (Used) return true; // Check for used attribute. - if (hasAttr<UsedAttr>()) + if (CheckUsedAttr && hasAttr<UsedAttr>()) return true; // Check redeclarations for used attribute. for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { - if (I->hasAttr<UsedAttr>() || I->Used) + if ((CheckUsedAttr && I->hasAttr<UsedAttr>()) || I->Used) return true; } diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index 6b88dfcae4..36ce5c047f 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -118,7 +118,7 @@ void PCHDeclWriter::VisitDecl(Decl *D) { Record.push_back(D->isInvalidDecl()); Record.push_back(D->hasAttrs()); Record.push_back(D->isImplicit()); - Record.push_back(D->isUsed()); + Record.push_back(D->isUsed(false)); Record.push_back(D->getAccess()); Record.push_back(D->getPCHLevel()); } @@ -443,7 +443,7 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { if (!D->getTypeSourceInfo() && !D->hasAttrs() && !D->isImplicit() && - !D->isUsed() && + !D->isUsed(false) && D->getAccess() == AS_none && D->getPCHLevel() == 0 && D->getStorageClass() == 0 && diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 8bdf971d96..eadc2ad253 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -226,7 +226,8 @@ void Sema::ActOnEndOfTranslationUnit() { // Remove functions that turned out to be used. UnusedStaticFuncs.erase(std::remove_if(UnusedStaticFuncs.begin(), UnusedStaticFuncs.end(), - std::mem_fun(&FunctionDecl::isUsed)), + std::bind2nd(std::mem_fun(&FunctionDecl::isUsed), + true)), UnusedStaticFuncs.end()); // Check for #pragma weak identifiers that were never declared diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 2a881ff434..c6f149e8fe 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4216,7 +4216,7 @@ namespace { void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor) { assert((Constructor->isImplicit() && Constructor->isDefaultConstructor() && - !Constructor->isUsed()) && + !Constructor->isUsed(false)) && "DefineImplicitDefaultConstructor - call it for implicit default ctor"); CXXRecordDecl *ClassDecl = Constructor->getParent(); @@ -4237,7 +4237,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, CXXDestructorDecl *Destructor) { - assert((Destructor->isImplicit() && !Destructor->isUsed()) && + assert((Destructor->isImplicit() && !Destructor->isUsed(false)) && "DefineImplicitDestructor - call it for implicit default dtor"); CXXRecordDecl *ClassDecl = Destructor->getParent(); assert(ClassDecl && "DefineImplicitDestructor - invalid destructor"); @@ -4466,7 +4466,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, assert((CopyAssignOperator->isImplicit() && CopyAssignOperator->isOverloadedOperator() && CopyAssignOperator->getOverloadedOperator() == OO_Equal && - !CopyAssignOperator->isUsed()) && + !CopyAssignOperator->isUsed(false)) && "DefineImplicitCopyAssignment called for wrong function"); CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent(); @@ -4766,7 +4766,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, unsigned TypeQuals) { assert((CopyConstructor->isImplicit() && CopyConstructor->isCopyConstructor(TypeQuals) && - !CopyConstructor->isUsed()) && + !CopyConstructor->isUsed(false)) && "DefineImplicitCopyConstructor - call it for implicit copy ctor"); CXXRecordDecl *ClassDecl = CopyConstructor->getParent(); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index fa403c78d0..5882381e22 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -7500,7 +7500,7 @@ Sema::PopExpressionEvaluationContext() { void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { assert(D && "No declaration?"); - if (D->isUsed()) + if (D->isUsed(false)) return; // Mark a parameter or variable declaration "used", regardless of whether we're in a @@ -7543,24 +7543,24 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { unsigned TypeQuals; if (Constructor->isImplicit() && Constructor->isDefaultConstructor()) { - if (!Constructor->isUsed()) + if (!Constructor->isUsed(false)) DefineImplicitDefaultConstructor(Loc, Constructor); } else if (Constructor->isImplicit() && Constructor->isCopyConstructor(TypeQuals)) { - if (!Constructor->isUsed()) + if (!Constructor->isUsed(false)) DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals); } MarkVTableUsed(Loc, Constructor->getParent()); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { - if (Destructor->isImplicit() && !Destructor->isUsed()) + if (Destructor->isImplicit() && !Destructor->isUsed(false)) DefineImplicitDestructor(Loc, Destructor); if (Destructor->isVirtual()) MarkVTableUsed(Loc, Destructor->getParent()); } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) { if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() && MethodDecl->getOverloadedOperator() == OO_Equal) { - if (!MethodDecl->isUsed()) + if (!MethodDecl->isUsed(false)) DefineImplicitCopyAssignment(Loc, MethodDecl); } else if (MethodDecl->isVirtual()) MarkVTableUsed(Loc, MethodDecl->getParent()); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index b7059e5752..1b28579e61 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -361,7 +361,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { Var->setLexicalDeclContext(D->getLexicalDeclContext()); Var->setAccess(D->getAccess()); - Var->setUsed(D->isUsed()); + + if (!D->isStaticDataMember()) + Var->setUsed(D->isUsed(false)); // FIXME: In theory, we could have a previous declaration for variables that // are not static data members. diff --git a/test/SemaTemplate/instantiate-function-2.cpp b/test/SemaTemplate/instantiate-function-2.cpp index afca358784..ebc0ef3a9f 100644 --- a/test/SemaTemplate/instantiate-function-2.cpp +++ b/test/SemaTemplate/instantiate-function-2.cpp @@ -20,3 +20,14 @@ namespace PR7184 { template void f<int>(); } + +namespace UsedAttr { + template<typename T> + void __attribute__((used)) foo() { + T *x = 1; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} + } + + void bar() { + foo<int>(); // expected-note{{instantiation of}} + } +} |