aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDeclCXX.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-10-04 22:13:39 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-10-04 22:13:39 +0000
commitd1a55a6631b11b6c5364772023451c547eafedee (patch)
tree67552a6ac38ebde3c3ffd7af81febb69d82c0297 /lib/Sema/SemaDeclCXX.cpp
parent59c0a818a79be850f7ae8fdafd57a1710e5b809a (diff)
Egriegious hack to support libstdc++4.6's broken <atomic> header, which defines
a non-inline namespace, then reopens it as inline to try to add its symbols to the surrounding namespace. In this one special case, permit the namespace to be reopened as inline, and patch up the name lookup tables to match. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@165263 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDeclCXX.cpp')
-rw-r--r--lib/Sema/SemaDeclCXX.cpp65
1 files changed, 41 insertions, 24 deletions
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index b3836a2602..e989fd541f 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -5399,7 +5399,42 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
// Namespace Handling
//===----------------------------------------------------------------------===//
+/// \brief Diagnose a mismatch in 'inline' qualifiers when a namespace is
+/// reopened.
+static void DiagnoseNamespaceInlineMismatch(Sema &S, SourceLocation KeywordLoc,
+ SourceLocation Loc,
+ IdentifierInfo *II, bool *IsInline,
+ NamespaceDecl *PrevNS) {
+ assert(*IsInline != PrevNS->isInline());
+
+ if (*IsInline && II && II->getName().startswith("__atomic") &&
+ S.getSourceManager().isInSystemHeader(Loc)) {
+ // libstdc++4.6's <atomic> reopens a non-inline namespace as inline, and
+ // expects that to affect the earlier declaration.
+ for (NamespaceDecl *NS = PrevNS->getMostRecentDecl(); NS;
+ NS = NS->getPreviousDecl())
+ NS->setInline(*IsInline);
+ // Patch up the lookup table for the containing namespace. This isn't really
+ // correct, but it's good enough for this particular case.
+ for (DeclContext::decl_iterator I = PrevNS->decls_begin(),
+ E = PrevNS->decls_end(); I != E; ++I)
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(*I))
+ PrevNS->getParent()->makeDeclVisibleInContext(ND);
+ return;
+ }
+ if (PrevNS->isInline())
+ // The user probably just forgot the 'inline', so suggest that it
+ // be added back.
+ S.Diag(Loc, diag::warn_inline_namespace_reopened_noninline)
+ << FixItHint::CreateInsertion(KeywordLoc, "inline ");
+ else
+ S.Diag(Loc, diag::err_inline_namespace_mismatch)
+ << IsInline;
+
+ S.Diag(PrevNS->getLocation(), diag::note_previous_definition);
+ *IsInline = PrevNS->isInline();
+}
/// ActOnStartNamespaceDef - This is called at the start of a namespace
/// definition.
@@ -5449,21 +5484,9 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
if (PrevNS) {
// This is an extended namespace definition.
- if (IsInline != PrevNS->isInline()) {
- // inline-ness must match
- if (PrevNS->isInline()) {
- // The user probably just forgot the 'inline', so suggest that it
- // be added back.
- Diag(Loc, diag::warn_inline_namespace_reopened_noninline)
- << FixItHint::CreateInsertion(NamespaceLoc, "inline ");
- } else {
- Diag(Loc, diag::err_inline_namespace_mismatch)
- << IsInline;
- }
- Diag(PrevNS->getLocation(), diag::note_previous_definition);
-
- IsInline = PrevNS->isInline();
- }
+ if (IsInline != PrevNS->isInline())
+ DiagnoseNamespaceInlineMismatch(*this, NamespaceLoc, Loc, II,
+ &IsInline, PrevNS);
} else if (PrevDecl) {
// This is an invalid name redefinition.
Diag(Loc, diag::err_redefinition_different_kind)
@@ -5494,15 +5517,9 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
PrevNS = ND->getAnonymousNamespace();
}
- if (PrevNS && IsInline != PrevNS->isInline()) {
- // inline-ness must match
- Diag(Loc, diag::err_inline_namespace_mismatch)
- << IsInline;
- Diag(PrevNS->getLocation(), diag::note_previous_definition);
-
- // Recover by ignoring the new namespace's inline status.
- IsInline = PrevNS->isInline();
- }
+ if (PrevNS && IsInline != PrevNS->isInline())
+ DiagnoseNamespaceInlineMismatch(*this, NamespaceLoc, NamespaceLoc, II,
+ &IsInline, PrevNS);
}
NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, IsInline,