From ae17094c001972a5949944a0a77ef6adf2a92c8f Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 13 Feb 2009 00:26:38 +0000 Subject: [PATCH] Tighten checking of the "overloadable" attribute. If any function by a given name in a given scope is marked as "overloadable", every function declaration and definition with that same name and in that same scope needs to have the "overloadable" attribute. Essentially, the "overloadable" attribute is not part of attribute merging, so it must be specified even for redeclarations. This keeps users from trying to be too sneaky for their own good: double sin(double) __attribute__((overloadable)); // too sneaky #include Previously, this would have made "sin" overloadable, and therefore given it a mangled name. Now, we get an error inside math.h when we see a (re)declaration of "sin" that doesn't have the "overloadable" attribute. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64414 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Attr.h | 6 +++++ include/clang/Basic/DiagnosticSemaKinds.def | 2 +- lib/Sema/SemaDecl.cpp | 27 ++++++++++----------- test/Sema/overloadable.c | 7 ++++-- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 328ba5764a..60b84f43c3 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -70,6 +70,10 @@ public: delete Next; } + /// \brief Whether this attribute should be merged to new + /// declarations. + virtual bool isMerged() const { return true; } + Kind getKind() const { return AttrKind; } Attr *getNext() { return Next; } @@ -449,6 +453,8 @@ class OverloadableAttr : public Attr { public: OverloadableAttr() : Attr(Overloadable) { } + virtual bool isMerged() const { return false; } + static bool classof(const Attr *A) { return A->getKind() == Overloadable; } static bool classof(const OverloadableAttr *) { return true; } }; diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def index 0eddb39e7d..1024377cd0 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.def +++ b/include/clang/Basic/DiagnosticSemaKinds.def @@ -396,7 +396,7 @@ DIAG(err_attribute_iboutlet_non_ivar, ERROR, DIAG(err_attribute_overloadable_not_function, ERROR, "'overloadable' attribute can only be applied to a function") DIAG(err_attribute_overloadable_missing, ERROR, - "overloaded function %0 must have the 'overloadable' attribute") + "%select{overloaded function|redeclaration of}0 %1 must have the 'overloadable' attribute") DIAG(note_attribute_overloadable_prev_overload, NOTE, "previous overload of function is here") diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index de06ca610c..0dbd6d3804 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -446,15 +446,15 @@ static void MergeAttributes(Decl *New, Decl *Old) { Attr *attr = const_cast(Old->getAttrs()), *tmp; while (attr) { - tmp = attr; - attr = attr->getNext(); + tmp = attr; + attr = attr->getNext(); - if (!DeclHasAttr(New, tmp)) { - tmp->setInherited(true); - New->addAttr(tmp); + if (!DeclHasAttr(New, tmp) && tmp->isMerged()) { + tmp->setInherited(true); + New->addAttr(tmp); } else { - tmp->setNext(0); - delete(tmp); + tmp->setNext(0); + delete(tmp); } } @@ -1666,6 +1666,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // there's no more work to do here; we'll just add the new // function to the scope. OverloadedFunctionDecl::function_iterator MatchedDecl; + + if (!getLangOptions().CPlusPlus && + AllowOverloadingOfFunction(PrevDecl, Context)) + OverloadableAttrRequired = true; + if (!AllowOverloadingOfFunction(PrevDecl, Context) || !IsOverload(NewFD, PrevDecl, MatchedDecl)) { Decl *OldDecl = PrevDecl; @@ -1693,12 +1698,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } } } - - // If we're in C, this new declaration better have the - // "overloadable" attribute on it. - if (!getLangOptions().CPlusPlus && - PrevDecl->getAttr()) - OverloadableAttrRequired = true; } if (D.getCXXScopeSpec().isSet() && @@ -1743,7 +1742,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // If a function name is overloadable in C, then every function // with that name must be marked "overloadable". Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing) - << NewFD; + << Redeclaration << NewFD; if (PrevDecl) Diag(PrevDecl->getLocation(), diag::note_attribute_overloadable_prev_overload); diff --git a/test/Sema/overloadable.c b/test/Sema/overloadable.c index 5118e40ab0..040b7faf7c 100644 --- a/test/Sema/overloadable.c +++ b/test/Sema/overloadable.c @@ -2,9 +2,10 @@ int var __attribute__((overloadable)); // expected-error{{'overloadable' attribute can only be applied to a function}} -int *f(int) __attribute__((overloadable)); // expected-note{{previous overload of function is here}} +int *f(int) __attribute__((overloadable)); // expected-note 2{{previous overload of function is here}} float *f(float); // expected-error{{overloaded function 'f' must have the 'overloadable' attribute}} -int *f(int); // expected-note{{previous declaration is here}} +int *f(int); // expected-error{{redeclaration of 'f' must have the 'overloadable' attribute}} \ + // expected-note{{previous declaration is here}} double *f(double) __attribute__((overloadable)); // okay, new void test_f(int iv, float fv, double dv) { @@ -35,3 +36,5 @@ void test_struct(struct X x, struct Y y) { } double *f(int) __attribute__((overloadable)); // expected-error{{conflicting types for 'f'}} + + -- 2.40.0