]> granicus.if.org Git - clang/commitdiff
C99 DR #316 implies that the function parameter types that are known
authorDouglas Gregor <dgregor@apple.com>
Wed, 25 Feb 2009 16:33:18 +0000 (16:33 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 25 Feb 2009 16:33:18 +0000 (16:33 +0000)
only from a function definition (that does not have a prototype) are
only used to determine the compatible with other declarations of that
same function. In particular, when referencing the function we pretend
as if it does not have a prototype. Implement this behavior, which
fixes PR3626.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65460 91177308-0d34-0410-b5e6-96231b3b80d8

Driver/RewriteObjC.cpp
include/clang/AST/Decl.h
lib/AST/Decl.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
test/Sema/arg-duplicate.c
test/Sema/knr-def-call.c [new file with mode: 0644]

index 610e1c5106e3d19529e3f24e34772b2fe94205e1..bd95a3922ac644cd967cd4ffe3962e901c9f62ce 100644 (file)
@@ -4063,7 +4063,8 @@ FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(const char *name) {
   IdentifierInfo *ID = &Context->Idents.get(name);
   QualType FType = Context->getFunctionTypeNoProto(Context->VoidPtrTy);
   return FunctionDecl::Create(*Context, TUDecl,SourceLocation(), 
-                              ID, FType, FunctionDecl::Extern, false);
+                              ID, FType, FunctionDecl::Extern, false,
+                              false);
 }
 
 Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
index a8bd4b82119698247a5ea99721698aa7921ded65..aa009c8b4c0d9061a57049a7e9040cb5b3b5e5a8 100644 (file)
@@ -532,6 +532,7 @@ private:
   bool IsVirtual : 1;
   bool IsPure : 1;
   bool InheritedPrototype : 1;
+  bool HasPrototype : 1;
   bool IsDeleted : 1;
 
   // Move to DeclGroup when it is implemented.
@@ -545,7 +546,8 @@ protected:
       DeclContext(DK),
       ParamInfo(0), Body(0), PreviousDeclaration(0),
       SClass(S), IsInline(isInline), IsVirtual(false), IsPure(false),
-      InheritedPrototype(false), IsDeleted(false), TypeSpecStartLoc(TSSL) {}
+      InheritedPrototype(false), HasPrototype(true), IsDeleted(false), 
+      TypeSpecStartLoc(TSSL) {}
 
   virtual ~FunctionDecl() {}
   virtual void Destroy(ASTContext& C);
@@ -554,6 +556,7 @@ public:
   static FunctionDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
                               DeclarationName N, QualType T, 
                               StorageClass S = None, bool isInline = false,
+                              bool hasPrototype = true,
                               SourceLocation TSStartLoc = SourceLocation());  
   
   SourceLocation getTypeSpecStartLoc() const { return TypeSpecStartLoc; }
@@ -588,9 +591,15 @@ public:
   bool isPure() { return IsPure; }
   void setPure() { IsPure = true; }
 
+  /// \brief Whether this function has a prototype, either because one
+  /// was explicitly written or because it was "inherited" by merging
+  /// a declaration without a prototype with a declaration that has a
+  /// prototype.
+  bool hasPrototype() const { return HasPrototype || InheritedPrototype; }
+
   /// \brief Whether this function inherited its prototype from a
   /// previous declaration.
-  bool inheritedPrototype() { return InheritedPrototype; }
+  bool inheritedPrototype() const { return InheritedPrototype; }
   void setInheritedPrototype() { InheritedPrototype = true; }
 
   /// \brief Whether this function has been deleted.
index 9bf35ee83d6fd9c3f7b865fa847cddb7274786df..2732bf93c1864131219203eae8a93f03a164fe40 100644 (file)
@@ -75,9 +75,13 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
                                    SourceLocation L, 
                                    DeclarationName N, QualType T, 
                                    StorageClass S, bool isInline, 
+                                   bool hasPrototype,
                                    SourceLocation TypeSpecStartLoc) {
-  return new (C) FunctionDecl(Function, DC, L, N, T, S, isInline,
-                                TypeSpecStartLoc);
+  FunctionDecl *New 
+    = new (C) FunctionDecl(Function, DC, L, N, T, S, isInline, 
+                           TypeSpecStartLoc);
+  New->HasPrototype = hasPrototype;
+  return New;
 }
 
 BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
index abb5e40dd4a755fef85ca0d6f8a9bc72b04051ce..c31219597273248cb7cbd331e3a5e4fcb8d3a418 100644 (file)
@@ -334,7 +334,8 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
   FunctionDecl *New = FunctionDecl::Create(Context,
                                            Context.getTranslationUnitDecl(),
                                            Loc, II, R,
-                                           FunctionDecl::Extern, false);
+                                           FunctionDecl::Extern, false,
+                                           /*hasPrototype=*/true);
   New->setImplicit();
 
   // Create Decl objects for each parameter, adding them to the
@@ -1736,6 +1737,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
       // code path.
       NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(),
                                    Name, R, SC, isInline, 
+                                   /*hasPrototype=*/true,
                                    // FIXME: Move to DeclGroup...
                                    D.getDeclSpec().getSourceRange().getBegin());
       InvalidDecl = true;
@@ -1765,6 +1767,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
     NewFD = FunctionDecl::Create(Context, DC,
                                  D.getIdentifierLoc(),
                                  Name, R, SC, isInline, 
+                                 /*hasPrototype=*/
+                                   (getLangOptions().CPlusPlus ||
+                                    (D.getNumTypeObjects() &&
+                                     D.getTypeObject(0).Fun.hasPrototype)),
                                  // FIXME: Move to DeclGroup...
                                  D.getDeclSpec().getSourceRange().getBegin());
   }
index 174e408ead460ef613ca1605f45d575e9c08bd52..98d6b12b9c4a0ace84c5936b45ce56cb3efea5af 100644 (file)
@@ -873,6 +873,19 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
           CheckS = CheckS->getParent();
       }
     }
+  } else if (FunctionDecl *Func = dyn_cast<FunctionDecl>(VD)) {
+    if (!getLangOptions().CPlusPlus && !Func->hasPrototype()) {
+      // C99 DR 316 says that, if a function type comes from a
+      // function definition (without a prototype), that type is only
+      // used for checking compatibility. Therefore, when referencing
+      // the function, we pretend that we don't have the full function
+      // type.
+      QualType T = Func->getType();
+      QualType NoProtoType = T;
+      if (const FunctionTypeProto *Proto = T->getAsFunctionTypeProto())
+        NoProtoType = Context.getFunctionTypeNoProto(Proto->getResultType());
+      return Owned(BuildDeclRefExpr(VD, NoProtoType, Loc, false, false, SS));
+    }
   }
 
   // Only create DeclRefExpr's for valid Decl's.
index ea59b644c90d3e3516acedd156589efd1000ed28..c8671bc2e3a5f06039a5bce2bbb992bec2131b14 100644 (file)
@@ -543,7 +543,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
   QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0);
   FunctionDecl *Alloc =
     FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name,
-                         FnType, FunctionDecl::None, false,
+                         FnType, FunctionDecl::None, false, true,
                          SourceLocation());
   Alloc->setImplicit();
   ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
index 81cb8fd9c29f1ae640af5946e1b29ab2b92c319f..c5498a230916c01ea968b5ec7fe988ee70a743a3 100644 (file)
@@ -9,6 +9,6 @@ int f3(y, x,
 } 
 
 void f4(void) { 
-  f3 (1, 1, 2, 3, 4);   // expected-error {{too many arguments to function}}
+  f3 (1, 1, 2, 3, 4);
 }
 
diff --git a/test/Sema/knr-def-call.c b/test/Sema/knr-def-call.c
new file mode 100644 (file)
index 0000000..706f214
--- /dev/null
@@ -0,0 +1,14 @@
+// RUN: clang -fsyntax-only -verify %s
+
+// C DR #316, PR 3626.
+void f0(a, b, c, d) int a,b,c,d; {}
+void t0(void) { f0(1); }
+
+void f1(a, b) int a, b; {}
+void t1(void) { f1(1, 2, 3); }
+
+void f2(float); // expected-note{{previous declaration is here}}
+void f2(x) float x; { } // expected-error{{conflicting types for 'f2'}}
+
+typedef void (*f3)(void);
+f3 t3(int b) { return b? f0 : f1; } // okay