summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaDecl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaDecl.cpp')
-rw-r--r--clang/lib/Sema/SemaDecl.cpp44
1 files changed, 41 insertions, 3 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index a3e0232987c..de06ca610cf 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -113,6 +113,25 @@ void Sema::PopDeclContext() {
CurContext = getContainingDC(CurContext);
}
+/// \brief Determine whether we allow overloading of the function
+/// PrevDecl with another declaration.
+///
+/// This routine determines whether overloading is possible, not
+/// whether some new function is actually an overload. It will return
+/// true in C++ (where we can always provide overloads) or, as an
+/// extension, in C when the previous function is already an
+/// overloaded function declaration or has the "overloadable"
+/// attribute.
+static bool AllowOverloadingOfFunction(Decl *PrevDecl, ASTContext &Context) {
+ if (Context.getLangOptions().CPlusPlus)
+ return true;
+
+ if (isa<OverloadedFunctionDecl>(PrevDecl))
+ return true;
+
+ return PrevDecl->getAttr<OverloadableAttr>() != 0;
+}
+
/// Add this decl to the scope shadowed decl chains.
void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) {
// Move up the scope chain until we find the nearest enclosing
@@ -173,7 +192,8 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) {
return;
}
}
- } else if (getLangOptions().CPlusPlus && isa<FunctionDecl>(D)) {
+ } else if (isa<FunctionDecl>(D) &&
+ AllowOverloadingOfFunction(D, Context)) {
// We are pushing the name of a function, which might be an
// overloaded name.
FunctionDecl *FD = cast<FunctionDecl>(D);
@@ -1637,15 +1657,16 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Merge the decl with the existing one if appropriate. Since C functions
// are in a flat namespace, make sure we consider decls in outer scopes.
+ bool OverloadableAttrRequired = false;
bool Redeclaration = false;
if (PrevDecl &&
(!getLangOptions().CPlusPlus||isDeclInScope(PrevDecl, DC, S))) {
- // If C++, determine whether NewFD is an overload of PrevDecl or
+ // Determine whether NewFD is an overload of PrevDecl or
// a declaration that requires merging. If it's an overload,
// 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 ||
+ if (!AllowOverloadingOfFunction(PrevDecl, Context) ||
!IsOverload(NewFD, PrevDecl, MatchedDecl)) {
Decl *OldDecl = PrevDecl;
@@ -1672,6 +1693,12 @@ 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() &&
@@ -1712,6 +1739,17 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// (for example to check for conflicts, etc).
ProcessDeclAttributes(NewFD, D);
+ if (OverloadableAttrRequired && !NewFD->getAttr<OverloadableAttr>()) {
+ // 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;
+ if (PrevDecl)
+ Diag(PrevDecl->getLocation(),
+ diag::note_attribute_overloadable_prev_overload);
+ NewFD->addAttr(new OverloadableAttr);
+ }
+
if (getLangOptions().CPlusPlus) {
// In C++, check default arguments now that we have merged decls. Unless
// the lexical context is the class, because in this case this is done
OpenPOWER on IntegriCloud