]> granicus.if.org Git - clang/commitdiff
Improve compatibility with GCC regarding inline semantics in GNU89
authorDouglas Gregor <dgregor@apple.com>
Tue, 28 Apr 2009 06:37:30 +0000 (06:37 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 28 Apr 2009 06:37:30 +0000 (06:37 +0000)
mode and in the presence of __gnu_inline__ attributes. This should fix
both PR3989 and PR4069.

As part of this, we now keep track of all of the attributes attached
to each declaration even after we've performed declaration
merging. This fixes PR3264.

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

include/clang/AST/ASTContext.h
include/clang/AST/Attr.h
include/clang/AST/Decl.h
lib/AST/Decl.cpp
lib/CodeGen/CodeGenModule.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclAttr.cpp
test/CodeGen/inline.c

index 4379854c768229ef75ddf95aba87d5f6d148725c..f4a01c4cf01b063ebe767f7cfbd76e6d7e0cc6ae 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/LangOptions.h"
+#include "clang/AST/Attr.h"
 #include "clang/AST/Builtins.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/NestedNameSpecifier.h"
@@ -768,7 +769,7 @@ private:
 ///                  allocator supports it).
 /// @return The allocated memory. Could be NULL.
 inline void *operator new(size_t Bytes, clang::ASTContext &C,
-                          size_t Alignment = 16) throw () {
+                          size_t Alignment) throw () {
   return C.Allocate(Bytes, Alignment);
 }
 /// @brief Placement delete companion to the new above.
index 91abcffdcdc35393b1821054ad233cc58e3a52e6..badab479113ad0403c8916fd34b91d913b20c061 100644 (file)
 
 namespace clang {
   class ASTContext;
+}
+
+
+// Defined in ASTContext.cpp
+void *operator new(size_t Bytes, clang::ASTContext &C,
+                   size_t Alignment = 16) throw ();
+
+namespace clang {
 
 /// Attr - This represents one attribute.
 class Attr {
@@ -116,10 +124,22 @@ public:
     Next = attr;
   }
   
+  // Clone this attribute.
+  virtual Attr* clone(ASTContext &C) const = 0;
+
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Attr *) { return true; }
 };
 
+#define DEF_SIMPLE_ATTR(ATTR)                                           \
+class ATTR##Attr : public Attr {                                        \
+public:                                                                 \
+  ATTR##Attr() : Attr(ATTR) {}                                          \
+  virtual Attr *clone(ASTContext &C) const { return ::new (C) ATTR##Attr; }                \
+  static bool classof(const Attr *A) { return A->getKind() == ATTR; }   \
+  static bool classof(const ATTR##Attr *A) { return true; }             \
+}
+
 class PackedAttr : public Attr {
   unsigned Alignment;
 
@@ -129,6 +149,10 @@ public:
   /// getAlignment - The specified alignment in bits.
   unsigned getAlignment() const { return Alignment; }
 
+  virtual Attr* clone(ASTContext &C) const { 
+    return ::new (C) PackedAttr(Alignment); 
+  }
+
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Attr *A) {
     return A->getKind() == Packed;
@@ -143,6 +167,8 @@ public:
 
   /// getAlignment - The specified alignment in bits.
   unsigned getAlignment() const { return Alignment; }
+
+  virtual Attr* clone(ASTContext &C) const { return ::new (C) AlignedAttr(Alignment); }
   
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Attr *A) {
@@ -157,6 +183,8 @@ public:
   AnnotateAttr(const std::string &ann) : Attr(Annotate), Annotation(ann) {}
   
   const std::string& getAnnotation() const { return Annotation; }
+
+  virtual Attr* clone(ASTContext &C) const { return ::new (C) AnnotateAttr(Annotation); }
   
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Attr *A) {
@@ -172,6 +200,8 @@ public:
   
   const std::string& getLabel() const { return Label; }
   
+  virtual Attr* clone(ASTContext &C) const { return ::new (C) AsmLabelAttr(Label); }
+  
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Attr *A) {
     return A->getKind() == AsmLabel;
@@ -179,15 +209,7 @@ public:
   static bool classof(const AsmLabelAttr *A) { return true; }
 };
 
-class AlwaysInlineAttr : public Attr {
-public:
-  AlwaysInlineAttr() : Attr(AlwaysInline) {}
-
-  // Implement isa/cast/dyncast/etc.
-
-  static bool classof(const Attr *A) { return A->getKind() == AlwaysInline; }
-  static bool classof(const AlwaysInlineAttr *A) { return true; }
-};
+DEF_SIMPLE_ATTR(AlwaysInline);
 
 class AliasAttr : public Attr {
   std::string Aliasee;
@@ -196,8 +218,9 @@ public:
 
   const std::string& getAliasee() const { return Aliasee; }
 
-  // Implement isa/cast/dyncast/etc.
+  virtual Attr *clone(ASTContext &C) const { return ::new (C) AliasAttr(Aliasee); }
 
+  // Implement isa/cast/dyncast/etc.
   static bool classof(const Attr *A) { return A->getKind() == Alias; }
   static bool classof(const AliasAttr *A) { return true; }
 };
@@ -209,6 +232,8 @@ public:
 
   int getPriority() const { return priority; }
   
+  virtual Attr *clone(ASTContext &C) const { return ::new (C) ConstructorAttr(priority); }
+
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Attr *A) { return A->getKind() == Constructor; }  
   static bool classof(const ConstructorAttr *A) { return true; }
@@ -221,25 +246,32 @@ public:
 
   int getPriority() const { return priority; }
   
+  virtual Attr *clone(ASTContext &C) const { return ::new (C) DestructorAttr(priority); }
+
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Attr *A) { return A->getKind() == Destructor; }  
   static bool classof(const DestructorAttr *A) { return true; }
 };  
     
-  
 class GNUInlineAttr : public Attr {
 public:
   GNUInlineAttr() : Attr(GNUInline) {}
-  
+
+  virtual Attr *clone(ASTContext &C) const { return ::new (C) GNUInlineAttr; }
+
   // Implement isa/cast/dyncast/etc.
-  static bool classof(const Attr *A) { return A->getKind() == GNUInline; }
+  static bool classof(const Attr *A) {
+    return A->getKind() == GNUInline;
+  }
   static bool classof(const GNUInlineAttr *A) { return true; }
 };
 
 class IBOutletAttr : public Attr {
 public:
   IBOutletAttr() : Attr(IBOutletKind) {}
-  
+
+  virtual Attr *clone(ASTContext &C) const { return ::new (C) IBOutletAttr; }
+
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Attr *A) {
     return A->getKind() == IBOutletKind;
@@ -247,34 +279,9 @@ public:
   static bool classof(const IBOutletAttr *A) { return true; }
 };
 
-class NoReturnAttr : public Attr {
-public:
-  NoReturnAttr() : Attr(NoReturn) {}
-  
-  // Implement isa/cast/dyncast/etc.
-  static bool classof(const Attr *A) { return A->getKind() == NoReturn; }  
-  static bool classof(const NoReturnAttr *A) { return true; }
-};
-  
-class AnalyzerNoReturnAttr : public Attr {
-public:
-  AnalyzerNoReturnAttr() : Attr(AnalyzerNoReturn) {}
-    
-  // Implement isa/cast/dyncast/etc.
-  static bool classof(const Attr *A) {
-    return A->getKind() == AnalyzerNoReturn;
-  }  
-  static bool classof(const AnalyzerNoReturnAttr *A) { return true; }
-};
-
-class DeprecatedAttr : public Attr {
-public:
-  DeprecatedAttr() : Attr(Deprecated) {}
-
-  // Implement isa/cast/dyncast/etc.
-  static bool classof(const Attr *A) { return A->getKind() == Deprecated; }
-  static bool classof(const DeprecatedAttr *A) { return true; }
-};
+DEF_SIMPLE_ATTR(NoReturn);
+DEF_SIMPLE_ATTR(AnalyzerNoReturn);  
+DEF_SIMPLE_ATTR(Deprecated);
 
 class SectionAttr : public Attr {
   std::string Name;
@@ -282,7 +289,9 @@ public:
   SectionAttr(const std::string &N) : Attr(Section), Name(N) {}
   
   const std::string& getName() const { return Name; }
-  
+
+  virtual Attr *clone(ASTContext &C) const { return ::new (C) SectionAttr(Name); }
+
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Attr *A) {
     return A->getKind() == Section;
@@ -290,80 +299,14 @@ public:
   static bool classof(const SectionAttr *A) { return true; }
 };
 
-class UnavailableAttr : public Attr {
-public:
-  UnavailableAttr() : Attr(Unavailable) {}
-
-  // Implement isa/cast/dyncast/etc.
-
-  static bool classof(const Attr *A) { return A->getKind() == Unavailable; }
-  static bool classof(const UnavailableAttr *A) { return true; }
-};
-
-class UnusedAttr : public Attr {
-public:
-  UnusedAttr() : Attr(Unused) {}
-  
-  // Implement isa/cast/dyncast/etc.
-  static bool classof(const Attr *A) { return A->getKind() == Unused; }  
-  static bool classof(const UnusedAttr *A) { return true; }
-};  
-  
-class UsedAttr : public Attr {
-public:
-  UsedAttr() : Attr(Used) {}
-  
-  // Implement isa/cast/dyncast/etc.
-  static bool classof(const Attr *A) { return A->getKind() == Used; }  
-  static bool classof(const UsedAttr *A) { return true; }
-};  
-  
-class WeakAttr : public Attr {
-public:
-  WeakAttr() : Attr(Weak) {}
-
-  // Implement isa/cast/dyncast/etc.
-
-  static bool classof(const Attr *A) { return A->getKind() == Weak; }
-  static bool classof(const WeakAttr *A) { return true; }
-};
-
-class WeakImportAttr : public Attr {
-public:
-  WeakImportAttr() : Attr(WeakImport) {}
-
-  // Implement isa/cast/dyncast/etc.
-
-  static bool classof(const Attr *A) { return A->getKind() == WeakImport; }
-  static bool classof(const WeakImportAttr *A) { return true; }
-};
-
-class NoThrowAttr : public Attr {
-public:
-  NoThrowAttr() : Attr(NoThrow) {}
-
-  // Implement isa/cast/dyncast/etc.
-  static bool classof(const Attr *A) { return A->getKind() == NoThrow; }
-  static bool classof(const NoThrowAttr *A) { return true; }
-};
-
-class ConstAttr : public Attr {
-public:
-  ConstAttr() : Attr(Const) {}
-
-  // Implement isa/cast/dyncast/etc.
-  static bool classof(const Attr *A) { return A->getKind() == Const; }
-  static bool classof(const ConstAttr *A) { return true; }
-};
-
-class PureAttr : public Attr {
-public:
-  PureAttr() : Attr(Pure) {}
-
-  // Implement isa/cast/dyncast/etc.
-  static bool classof(const Attr *A) { return A->getKind() == Pure; }
-  static bool classof(const PureAttr *A) { return true; }
-};
+DEF_SIMPLE_ATTR(Unavailable);
+DEF_SIMPLE_ATTR(Unused);
+DEF_SIMPLE_ATTR(Used);  
+DEF_SIMPLE_ATTR(Weak);  
+DEF_SIMPLE_ATTR(WeakImport);
+DEF_SIMPLE_ATTR(NoThrow);
+DEF_SIMPLE_ATTR(Const);
+DEF_SIMPLE_ATTR(Pure);
 
 class NonNullAttr : public Attr {
   unsigned* ArgNums;
@@ -391,7 +334,9 @@ public:
   bool isNonNull(unsigned arg) const {
     return ArgNums ? std::binary_search(ArgNums, ArgNums+Size, arg) : true;
   }  
-  
+
+  virtual Attr *clone(ASTContext &C) const { return ::new (C) NonNullAttr(ArgNums, Size); }
+
   static bool classof(const Attr *A) { return A->getKind() == NonNull; }
   static bool classof(const NonNullAttr *A) { return true; }
 };
@@ -408,8 +353,11 @@ public:
   int getFormatIdx() const { return formatIdx; }
   int getFirstArg() const { return firstArg; }
 
-  // Implement isa/cast/dyncast/etc.
+  virtual Attr *clone(ASTContext &C) const { 
+    return ::new (C) FormatAttr(Type, formatIdx, firstArg); 
+  }
 
+  // Implement isa/cast/dyncast/etc.
   static bool classof(const Attr *A) { return A->getKind() == Format; }
   static bool classof(const FormatAttr *A) { return true; }
 };
@@ -430,88 +378,29 @@ public:
 
   VisibilityTypes getVisibility() const { return VisibilityType; }
 
-  // Implement isa/cast/dyncast/etc.
+  virtual Attr *clone(ASTContext &C) const { return ::new (C) VisibilityAttr(VisibilityType); }
 
+  // Implement isa/cast/dyncast/etc.
   static bool classof(const Attr *A) { return A->getKind() == Visibility; }
   static bool classof(const VisibilityAttr *A) { return true; }
 };
 
-class DLLImportAttr : public Attr {
-public:
-  DLLImportAttr() : Attr(DLLImport) {}
-
-  // Implement isa/cast/dyncast/etc.
-
-  static bool classof(const Attr *A) { return A->getKind() == DLLImport; }
-  static bool classof(const DLLImportAttr *A) { return true; }
-};
-
-class DLLExportAttr : public Attr {
-public:
-  DLLExportAttr() : Attr(DLLExport) {}
-
-  // Implement isa/cast/dyncast/etc.
-
-  static bool classof(const Attr *A) { return A->getKind() == DLLExport; }
-  static bool classof(const DLLExportAttr *A) { return true; }
-};
-
-class FastCallAttr : public Attr {
-public:
-  FastCallAttr() : Attr(FastCall) {}
-
-  // Implement isa/cast/dyncast/etc.
-
-  static bool classof(const Attr *A) { return A->getKind() == FastCall; }
-  static bool classof(const FastCallAttr *A) { return true; }
-};
-
-class StdCallAttr : public Attr {
-public:
-  StdCallAttr() : Attr(StdCall) {}
-
-  // Implement isa/cast/dyncast/etc.
-
-  static bool classof(const Attr *A) { return A->getKind() == StdCall; }
-  static bool classof(const StdCallAttr *A) { return true; }
-};
-
-class TransparentUnionAttr : public Attr {
-public:
-  TransparentUnionAttr() : Attr(TransparentUnion) {}
-
-  // Implement isa/cast/dyncast/etc.
+DEF_SIMPLE_ATTR(DLLImport);
+DEF_SIMPLE_ATTR(DLLExport);
+DEF_SIMPLE_ATTR(FastCall);
+DEF_SIMPLE_ATTR(StdCall);
+DEF_SIMPLE_ATTR(TransparentUnion);
+DEF_SIMPLE_ATTR(ObjCNSObject);
+DEF_SIMPLE_ATTR(ObjCException);
 
-  static bool classof(const Attr *A) { return A->getKind() == TransparentUnion; }
-  static bool classof(const TransparentUnionAttr *A) { return true; }
-};
-
-class ObjCNSObjectAttr : public Attr {
-// Implement isa/cast/dyncast/etc.
-public:
-  ObjCNSObjectAttr() : Attr(ObjCNSObject) {}
-  
-static bool classof(const Attr *A) { return A->getKind() == ObjCNSObject; }
-static bool classof(const ObjCNSObjectAttr *A) { return true; }
-};
-  
-  
-class ObjCExceptionAttr : public Attr {
-public:
-  ObjCExceptionAttr() : Attr(ObjCException) {}
-  
-  // Implement isa/cast/dyncast/etc.
-  static bool classof(const Attr *A) { return A->getKind() == ObjCException; }
-  static bool classof(const ObjCExceptionAttr *A) { return true; }
-};
-  
-  
 class OverloadableAttr : public Attr {
 public:
   OverloadableAttr() : Attr(Overloadable) { }
 
   virtual bool isMerged() const { return false; }
 
+  virtual Attr *clone(ASTContext &C) const { return ::new (C) OverloadableAttr; }
+
   static bool classof(const Attr *A) { return A->getKind() == Overloadable; }
   static bool classof(const OverloadableAttr *) { return true; }
 };
@@ -528,8 +417,9 @@ public:
 
   BlocksAttrTypes getType() const { return BlocksAttrType; }
 
-  // Implement isa/cast/dyncast/etc.
+  virtual Attr *clone(ASTContext &C) const { return ::new (C) BlocksAttr(BlocksAttrType); }
 
+  // Implement isa/cast/dyncast/etc.
   static bool classof(const Attr *A) { return A->getKind() == Blocks; }
   static bool classof(const BlocksAttr *A) { return true; }
 };
@@ -544,40 +434,16 @@ public:
 
   const FunctionDecl *getFunctionDecl() const { return FD; }
   
-  // Implement isa/cast/dyncast/etc.
+  virtual Attr *clone(ASTContext &C) const { return ::new (C) CleanupAttr(FD); }
 
+  // Implement isa/cast/dyncast/etc.
   static bool classof(const Attr *A) { return A->getKind() == Cleanup; }
   static bool classof(const CleanupAttr *A) { return true; }
 };
 
-class NodebugAttr : public Attr {
-public:
-  NodebugAttr() : Attr(Nodebug) {}
-    
-  // Implement isa/cast/dyncast/etc.
-    
-  static bool classof(const Attr *A) { return A->getKind() == Nodebug; }
-  static bool classof(const NodebugAttr *A) { return true; }
-};
-  
-class WarnUnusedResultAttr : public Attr {
-public:
-  WarnUnusedResultAttr() : Attr(WarnUnusedResult) {}
-  
-  // Implement isa/cast/dyncast/etc.
-  static bool classof(const Attr *A) { return A->getKind() == WarnUnusedResult;}
-  static bool classof(const WarnUnusedResultAttr *A) { return true; }
-};
-
-class NoinlineAttr : public Attr {
-public:
-  NoinlineAttr() : Attr(Noinline) {}
-    
-  // Implement isa/cast/dyncast/etc.
-    
-  static bool classof(const Attr *A) { return A->getKind() == Noinline; }
-  static bool classof(const NoinlineAttr *A) { return true; }
-};
+DEF_SIMPLE_ATTR(Nodebug);
+DEF_SIMPLE_ATTR(WarnUnusedResult);  
+DEF_SIMPLE_ATTR(Noinline);
 
 class RegparmAttr : public Attr {
   unsigned NumParams;
@@ -587,27 +453,21 @@ public:
 
   unsigned getNumParams() const { return NumParams; }
 
-  // Implement isa/cast/dyncast/etc.
-    
+  virtual Attr *clone(ASTContext &C) const { 
+    return ::new (C) RegparmAttr(NumParams); 
+  }
+
+  // Implement isa/cast/dyncast/etc.    
   static bool classof(const Attr *A) { return A->getKind() == Regparm; }
   static bool classof(const RegparmAttr *A) { return true; }
 };
-  
-  
-#define DEF_SIMPLE_ATTR(ATTR)\
-class ATTR##Attr : public Attr {\
-public:\
-  ATTR##Attr() : Attr(ATTR) {}\
-  static bool classof(const Attr *A) { return A->getKind() == ATTR; }\
-  static bool classof(const ATTR##Attr *A) { return true; }\
-};
 
 // Checker-specific attributes.
-DEF_SIMPLE_ATTR(ObjCOwnershipCFRelease)
-DEF_SIMPLE_ATTR(ObjCOwnershipRelease)
-DEF_SIMPLE_ATTR(ObjCOwnershipCFRetain)
-DEF_SIMPLE_ATTR(ObjCOwnershipRetain)
-DEF_SIMPLE_ATTR(ObjCOwnershipReturns)
+DEF_SIMPLE_ATTR(ObjCOwnershipCFRelease);
+DEF_SIMPLE_ATTR(ObjCOwnershipRelease);
+DEF_SIMPLE_ATTR(ObjCOwnershipCFRetain);
+DEF_SIMPLE_ATTR(ObjCOwnershipRetain);
+DEF_SIMPLE_ATTR(ObjCOwnershipReturns);
 
 #undef DEF_SIMPLE_ATTR
   
index 9cd22eeb3bdc458012eec7569e499af50361e048..90d1328c3d8b26565da77e8d34d949ed41e56969 100644 (file)
@@ -690,6 +690,19 @@ public:
   bool isC99InlineDefinition() const { return C99InlineDefinition; }
   void setC99InlineDefinition(bool I) { C99InlineDefinition = I; }
 
+  /// \brief Determines whether this function has a gnu_inline
+  /// attribute that affects its semantics.
+  ///
+  /// The gnu_inline attribute only introduces GNU inline semantics
+  /// when all of the inline declarations of the function are marked
+  /// gnu_inline.
+  bool hasActiveGNUInlineAttribute() const;
+
+  /// \brief Determines whether this function is a GNU "extern
+  /// inline", which is roughly the opposite of a C99 "extern inline"
+  /// function.
+  bool isExternGNUInline() const;
+
   /// isOverloadedOperator - Whether this function declaration
   /// represents an C++ overloaded operator, e.g., "operator+".
   bool isOverloadedOperator() const { 
index aa0fc702a4e2357a146757f8fbc1a5f89696c113..9aba33c943497d7f7cb51391399cf8ecaa6694c9 100644 (file)
@@ -468,6 +468,30 @@ unsigned FunctionDecl::getMinRequiredArguments() const {
   return NumRequiredArgs;
 }
 
+bool FunctionDecl::hasActiveGNUInlineAttribute() const {
+  if (!isInline() || !hasAttr<GNUInlineAttr>())
+    return false;
+
+  for (const FunctionDecl *FD = getPreviousDeclaration(); FD; 
+       FD = FD->getPreviousDeclaration()) {
+    if (FD->isInline() && !FD->hasAttr<GNUInlineAttr>())
+      return false;
+  }
+
+  return true;
+}
+
+bool FunctionDecl::isExternGNUInline() const {
+  if (!hasActiveGNUInlineAttribute())
+    return false;
+
+  for (const FunctionDecl *FD = this; FD; FD = FD->getPreviousDeclaration())
+    if (FD->getStorageClass() == Extern && FD->hasAttr<GNUInlineAttr>())
+      return true;
+
+  return false;
+}
+
 /// getOverloadedOperator - Which C++ overloaded operator this
 /// function represents, if any.
 OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
index 378223e3a71bf9d48747cc11e9946647018b78a2..4e58d09360037a56d2c17ce58cdd82be39a434af 100644 (file)
@@ -240,9 +240,17 @@ GetLinkageForFunction(const FunctionDecl *FD, const LangOptions &Features) {
   
   // If the inline function explicitly has the GNU inline attribute on it, or if
   // this is C89 mode, we use to GNU semantics.
-  if (FD->hasAttr<GNUInlineAttr>() || (!Features.C99 && !Features.CPlusPlus)) {
+  if (!Features.C99 && !Features.CPlusPlus) {
     // extern inline in GNU mode is like C99 inline.
-    if (FD->isC99InlineDefinition())
+    if (FD->getStorageClass() == FunctionDecl::Extern)
+      return CodeGenModule::GVA_C99Inline;
+    // Normal inline is a strong symbol.
+    return CodeGenModule::GVA_StrongExternal;
+  } else if (FD->hasActiveGNUInlineAttribute()) {
+    // GCC in C99 mode seems to use a different decision-making
+    // process for extern inline, which factors in previous
+    // declarations.
+    if (FD->isExternGNUInline())
       return CodeGenModule::GVA_C99Inline;
     // Normal inline is a strong symbol.
     return CodeGenModule::GVA_StrongExternal;
index b46dd5547fecf90034e5ad83e29624ff6237d4c2..4427f0de1f28fdea6f985d78311ebb4901eaefc1 100644 (file)
@@ -584,22 +584,13 @@ static bool DeclHasAttr(const Decl *decl, const Attr *target) {
 
 /// MergeAttributes - append attributes from the Old decl to the New one.
 static void MergeAttributes(Decl *New, Decl *Old, ASTContext &C) {
-  Attr *attr = const_cast<Attr*>(Old->getAttrs());
-
-  while (attr) {
-    Attr *tmp = attr;
-    attr = attr->getNext();
-
-    if (!DeclHasAttr(New, tmp) && tmp->isMerged()) {
-      tmp->setInherited(true);
-      New->addAttr(tmp);
-    } else {
-      tmp->setNext(0);
-      tmp->Destroy(C);
+  for (const Attr *attr = Old->getAttrs(); attr; attr = attr->getNext()) {
+    if (!DeclHasAttr(New, attr) && attr->isMerged()) {
+      Attr *NewAttr = attr->clone(C);
+      NewAttr->setInherited(true);
+      New->addAttr(NewAttr);
     }
   }
-
-  Old->invalidateAttrs();
 }
 
 /// Used in MergeFunctionDecl to keep track of function parameters in
@@ -851,7 +842,8 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
   MergeAttributes(New, Old, Context);
 
   // Merge the storage class.
-  New->setStorageClass(Old->getStorageClass());
+  if (Old->getStorageClass() != FunctionDecl::Extern)
+    New->setStorageClass(Old->getStorageClass());
 
   // Merge "inline"
   if (Old->isInline())
@@ -2186,19 +2178,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
         isOutOfScopePreviousDeclaration(PrevDecl, DC, Context)))
     PrevDecl = 0;
 
-  // FIXME: We need to determine whether the GNU inline attribute will
-  // be applied to this function declaration, since it affects
-  // declaration merging. This hack will go away when the FIXME below
-  // is resolved, since we should be putting *all* attributes onto the
-  // declaration now.
-  for (const AttributeList *Attr = D.getDeclSpec().getAttributes();
-       Attr; Attr = Attr->getNext()) {
-    if (Attr->getKind() == AttributeList::AT_gnu_inline) {
-      NewFD->addAttr(::new (Context) GNUInlineAttr());
-      break;
-    }
-  }
-
   // Perform semantic checking on the function declaration.
   bool OverloadableAttrRequired = false; // FIXME: HACK!
   CheckFunctionDeclaration(NewFD, PrevDecl, Redeclaration,
@@ -2328,18 +2307,10 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
   // Here we determine whether this function, in isolation, would be a
   // C99 inline definition. MergeCompatibleFunctionDecls looks at
   // previous declarations.
-  if (NewFD->isInline() && 
-      NewFD->getDeclContext()->getLookupContext()->isTranslationUnit()) {
-    bool GNUInline = NewFD->hasAttr<GNUInlineAttr>() || 
-      (PrevDecl && PrevDecl->hasAttr<GNUInlineAttr>());
-    if (GNUInline || (!getLangOptions().CPlusPlus && !getLangOptions().C99)) {
-      // GNU "extern inline" is the same as "inline" in C99.
-      if (NewFD->getStorageClass() == FunctionDecl::Extern)
-        NewFD->setC99InlineDefinition(true);
-    } else if (getLangOptions().C99 && 
-               NewFD->getStorageClass() == FunctionDecl::None)
-      NewFD->setC99InlineDefinition(true);
-  }           
+  if (NewFD->isInline() && getLangOptions().C99 && 
+      NewFD->getStorageClass() == FunctionDecl::None &&
+      NewFD->getDeclContext()->getLookupContext()->isTranslationUnit())
+    NewFD->setC99InlineDefinition(true);
 
   // Check for a previous declaration of this name.
   if (!PrevDecl && NewFD->isExternC(Context)) {
index c72b7ad7e81387fa248b1eaaca98e104434692b1..09c627e42d1ea02194456caeb571a98411fc3184 100644 (file)
@@ -1474,11 +1474,7 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
     return;
   }
   
-  // FIXME: We only do this because of the hack in
-  // Sema::ActOnFunctionDeclarator, which needs to add the
-  // GNUInlineAttr early.
-  if (!d->hasAttr<GNUInlineAttr>())
-    d->addAttr(::new (S.Context) GNUInlineAttr());
+  d->addAttr(::new (S.Context) GNUInlineAttr());
 }
 
 static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) {
index 7bdf76de19b0fb69b63e09bd15d87d8a4aa1d673..234f1f8d93a807576aa320f2ed8cc604747d5bd5 100644 (file)
@@ -7,9 +7,11 @@
 // RUN: not grep unreferenced2 %t &&
 // RUN: grep "define void @gnu_inline()" %t &&
 // RUN: grep "define available_externally void @gnu_ei_inline()" %t &&
-// RUN: grep "define void @test3()" %t &&
 // RUN: grep "define i32 @test1" %t &&
 // RUN: grep "define i32 @test2" %t &&
+// RUN: grep "define void @test3()" %t &&
+// RUN: grep "define available_externally i32 @test4" %t &&
+// RUN: grep "define available_externally i32 @test5" %t &&
 
 // RUN: echo "\nC99 tests:" &&
 // RUN: clang %s -emit-llvm -S -o %t -std=c99 &&
@@ -22,6 +24,9 @@
 // RUN: grep "define available_externally void @gnu_ei_inline()" %t &&
 // RUN: grep "define i32 @test1" %t &&
 // RUN: grep "define i32 @test2" %t &&
+// RUN: grep "define available_externally void @test3" %t &&
+// RUN: grep "define available_externally i32 @test4" %t &&
+// RUN: grep "define i32 @test5" %t &&
 
 // RUN: echo "\nC++ tests:" &&
 // RUN: clang %s -emit-llvm -S -o %t -std=c++98 &&
@@ -62,4 +67,20 @@ void test_test2() { test2(); }
 
 // PR3989
 extern __inline void test3() __attribute__((gnu_inline));
-__inline void test3()  {}
+__inline void test3() {}
+
+void test_test3() { test3(); }
+
+extern int test4(void);
+extern __inline __attribute__ ((__gnu_inline__)) int test4(void)
+{
+}
+
+void test_test4() { test4(); }
+
+extern __inline int test5(void);
+extern __inline int __attribute__ ((__gnu_inline__)) test5(void)
+{
+}
+
+void test_test5() { test5(); }