]> granicus.if.org Git - clang/commitdiff
Tighten checking of the "overloadable" attribute. If any function by a
authorDouglas Gregor <dgregor@apple.com>
Fri, 13 Feb 2009 00:26:38 +0000 (00:26 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 13 Feb 2009 00:26:38 +0000 (00:26 +0000)
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 <math.h>

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
include/clang/Basic/DiagnosticSemaKinds.def
lib/Sema/SemaDecl.cpp
test/Sema/overloadable.c

index 328ba5764ad994cd8d322bc579e9d2a0fb26ea32..60b84f43c3a577df64c733025af8e120a4a2bbf7 100644 (file)
@@ -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; }
 };
index 0eddb39e7dd5d718090ca4cda87fb840d72e9201..1024377cd0782ca042a6817f42610d17f15d76ba 100644 (file)
@@ -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")
 
index de06ca610cf14c15a263a76349390191b024b517..0dbd6d3804e1ec7da7e38b5f1f812aef96a5198b 100644 (file)
@@ -446,15 +446,15 @@ static void MergeAttributes(Decl *New, Decl *Old) {
   Attr *attr = const_cast<Attr*>(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<OverloadableAttr>())
-      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);
index 5118e40ab08a1cb9d0250675d5ee3fe8465c5173..040b7faf7cf468342a05a32d39f73fc9e7b123f2 100644 (file)
@@ -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'}}
+
+