Add support for target-independent builtin functions (like __builtin_abs),
whose decl objects are lazily created the first time they are referenced.
Builtin functions are described by the clang/AST/Builtins.def file, which
makes it easy to add new ones.
This is missing two important pieces:
1. Support for the rest of the gcc builtins.
2. Support for target-specific builtins (e.g. __builtin_ia32_emms).
Just adding this builtins reduces the number of implicit function definitions
by 6, reducing the # diagnostics from 550 to 544 when parsing carbon.h.
I need to add all the i386-specific ones to eliminate several hundred more.
ugh.
llvm-svn: 39327
diff --git a/clang/AST/SemaDecl.cpp b/clang/AST/SemaDecl.cpp
index 133ee65..0d7e865 100644
--- a/clang/AST/SemaDecl.cpp
+++ b/clang/AST/SemaDecl.cpp
@@ -13,6 +13,7 @@
#include "Sema.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Builtins.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
@@ -20,6 +21,7 @@
#include "clang/Parse/Scope.h"
#include "clang/Lex/IdentifierTable.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallSet.h"
using namespace llvm;
using namespace clang;
@@ -69,7 +71,8 @@
/// LookupScopedDecl - Look up the inner-most declaration in the specified
/// namespace.
-Decl *Sema::LookupScopedDecl(IdentifierInfo *II, unsigned NSI) {
+Decl *Sema::LookupScopedDecl(IdentifierInfo *II, unsigned NSI,
+ SourceLocation IdLoc, Scope *S) {
if (II == 0) return 0;
Decl::IdentifierNamespace NS = (Decl::IdentifierNamespace)NSI;
@@ -80,10 +83,56 @@
if (D->getIdentifierNamespace() == NS)
return D;
+ // If we didn't find a use of this identifier, and if the identifier
+ // corresponds to a compiler builtin, create the decl object for the builtin
+ // now, injecting it into translation unit scope, and return it.
+ if (NS == Decl::IDNS_Ordinary) {
+ // If this is a builtin on some other target, or if this builtin varies
+ // across targets (e.g. in type), emit a diagnostic and mark the translation
+ // unit non-portable for using it.
+ if (II->isNonPortableBuiltin()) {
+ // Only emit this diagnostic once for this builtin.
+ II->setNonPortableBuiltin(false);
+ Context.Target.DiagnoseNonPortability(IdLoc,
+ diag::port_target_builtin_use);
+ }
+ // If this is a builtin on this (or all) targets, create the decl.
+ if (unsigned BuiltinID = II->getBuiltinID())
+ return LazilyCreateBuiltin(II, BuiltinID, S);
+ }
return 0;
}
+/// LazilyCreateBuiltin - The specified Builtin-ID was first used at file scope.
+/// lazily create a decl for it.
+Decl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, Scope *S) {
+ Builtin::ID BID = (Builtin::ID)bid;
+
+ TypeRef R = Builtin::GetBuiltinType(BID, Context);
+ FunctionDecl *New = new FunctionDecl(SourceLocation(), II, R);
+
+ // Find translation-unit scope to insert this function into.
+ while (S->getParent())
+ S = S->getParent();
+ S->AddDecl(New);
+
+ // Add this decl to the end of the identifier info.
+ if (Decl *LastDecl = II->getFETokenInfo<Decl>()) {
+ // Scan until we find the last (outermost) decl in the id chain.
+ while (LastDecl->getNext())
+ LastDecl = LastDecl->getNext();
+ // Insert before (outside) it.
+ LastDecl->setNext(New);
+ } else {
+ II->setFETokenInfo(New);
+ }
+ // Make sure clients iterating over decls see this.
+ LastInGroupList.push_back(New);
+
+ return New;
+}
+
/// MergeTypeDefDecl - We just parsed a typedef 'New' which has the same name
/// and scope as a previous declaration 'Old'. Figure out how to resolve this
/// situation, merging decls or emitting diagnostics as appropriate.
@@ -174,7 +223,8 @@
IdentifierInfo *II = D.getIdentifier();
// See if this is a redefinition of a variable in the same scope.
- Decl *PrevDecl = LookupScopedDecl(II, Decl::IDNS_Ordinary);
+ Decl *PrevDecl = LookupScopedDecl(II, Decl::IDNS_Ordinary,
+ D.getIdentifierLoc(), S);
if (!S->isDeclScope(PrevDecl))
PrevDecl = 0; // If in outer scope, it isn't the same thing.
@@ -239,7 +289,8 @@
// TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope.
// Can this happen for params? We already checked that they don't conflict
// among each other. Here they can only shadow globals, which is ok.
- if (Decl *PrevDecl = LookupScopedDecl(II, Decl::IDNS_Ordinary)) {
+ if (Decl *PrevDecl = LookupScopedDecl(II, Decl::IDNS_Ordinary,
+ PI.IdentLoc, FnScope)) {
}
@@ -382,7 +433,8 @@
// If this is a named struct, check to see if there was a previous forward
// declaration or definition.
if (TagDecl *PrevDecl =
- dyn_cast_or_null<TagDecl>(LookupScopedDecl(Name, Decl::IDNS_Tag))) {
+ dyn_cast_or_null<TagDecl>(LookupScopedDecl(Name, Decl::IDNS_Tag,
+ NameLoc, S))) {
// If this is a use of a previous tag, or if the tag is already declared in
// the same scope (so that the definition/declaration completes or
@@ -604,7 +656,7 @@
// Verify that there isn't already something declared with this name in this
// scope.
- if (Decl *PrevDecl = LookupScopedDecl(Id, Decl::IDNS_Ordinary)) {
+ if (Decl *PrevDecl = LookupScopedDecl(Id, Decl::IDNS_Ordinary, IdLoc, S)) {
if (S->isDeclScope(PrevDecl)) {
if (isa<EnumConstantDecl>(PrevDecl))
Diag(IdLoc, diag::err_redefinition_of_enumerator, Id->getName());