/// function-scope declarations.
void
Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S) {
- if (!getLangOpts().CPlusPlus &&
- ND->getLexicalDeclContext()->getRedeclContext()->isTranslationUnit())
- // Don't need to track declarations in the TU in C.
- return;
-
+ assert(
+ !ND->getLexicalDeclContext()->getRedeclContext()->isTranslationUnit() &&
+ "Decl is not a locally-scoped decl!");
// Note that we have a locally-scoped external with this name.
- // FIXME: There can be multiple such declarations if they are functions marked
- // __attribute__((overloadable)) declared in function scope in C.
LocallyScopedExternCDecls[ND->getDeclName()] = ND;
}
return isC99Inline;
}
-/// Determine whether a variable is extern "C" prior to attaching
-/// an initializer. We can't just call isExternC() here, because that
-/// will also compute and cache whether the declaration is externally
-/// visible, which might change when we attach the initializer.
-///
-/// This can only be used if the declaration is known to not be a
-/// redeclaration of an internal linkage declaration.
-///
-/// For instance:
-///
-/// auto x = []{};
-///
-/// Attaching the initializer here makes this declaration not externally
-/// visible, because its type has internal linkage.
-///
-/// FIXME: This is a hack.
-template<typename T>
-static bool isIncompleteDeclExternC(Sema &S, const T *D) {
- if (S.getLangOpts().CPlusPlus) {
- // In C++, the overloadable attribute negates the effects of extern "C".
- if (!D->isInExternCContext() || D->template hasAttr<OverloadableAttr>())
- return false;
- }
- return D->isExternC();
-}
-
static bool shouldConsiderLinkage(const VarDecl *VD) {
const DeclContext *DC = VD->getDeclContext()->getRedeclContext();
if (DC->isFunctionOrMethod())
ProcessPragmaWeak(S, NewVD);
checkAttributesAfterMerging(*this, *NewVD);
- // If this is the first declaration of an extern C variable, update
- // the map of such variables.
- if (!NewVD->getPreviousDecl() && !NewVD->isInvalidDecl() &&
- isIncompleteDeclExternC(*this, NewVD))
+ // If this is the first declaration of an extern C variable that is not
+ // declared directly in the translation unit, update the map of such
+ // variables.
+ if (!CurContext->getRedeclContext()->isTranslationUnit() &&
+ !NewVD->getPreviousDecl() && !NewVD->isInvalidDecl() &&
+ // FIXME: We only check isExternC if we're in an extern C context,
+ // to avoid computing and caching an 'externally visible' flag which
+ // could change if the variable's type is not visible.
+ (!getLangOpts().CPlusPlus || NewVD->isInExternCContext()) &&
+ NewVD->isExternC())
RegisterLocallyScopedExternCDecl(NewVD, S);
return NewVD;
CheckShadow(S, D, R);
}
-/// Check for conflict between this global or extern "C" declaration and
-/// previous global or extern "C" declarations. This is only used in C++.
template<typename T>
-static bool checkGlobalOrExternCConflict(
- Sema &S, const T *ND, bool IsGlobal, LookupResult &Previous) {
- assert(S.getLangOpts().CPlusPlus && "only C++ has extern \"C\"");
- NamedDecl *Prev = S.findLocallyScopedExternCDecl(ND->getDeclName());
-
- if (!Prev && IsGlobal && !isIncompleteDeclExternC(S, ND)) {
- // The common case: this global doesn't conflict with any extern "C"
- // declaration.
- return false;
- }
-
- if (Prev) {
- if (!IsGlobal || isIncompleteDeclExternC(S, ND)) {
- // Both the old and new declarations have C language linkage. This is a
- // redeclaration.
- Previous.clear();
- Previous.addDecl(Prev);
- return true;
- }
-
- // This is a global, non-extern "C" declaration, and there is a previous
- // non-global extern "C" declaration. Diagnose.
- } else {
- // The declaration is extern "C". Check for any declaration in the
- // translation unit which might conflict.
- if (IsGlobal) {
- // We have already performed the lookup into the translation unit.
- IsGlobal = false;
- for (LookupResult::iterator I = Previous.begin(), E = Previous.end();
- I != E; ++I) {
- if (isa<VarDecl>(*I) || isa<FunctionDecl>(*I)) {
- Prev = *I;
- break;
- }
- }
- } else {
- DeclContext::lookup_result R =
- S.Context.getTranslationUnitDecl()->lookup(ND->getDeclName());
- for (DeclContext::lookup_result::iterator I = R.begin(), E = R.end();
- I != E; ++I) {
- if (isa<VarDecl>(*I) || isa<FunctionDecl>(*I)) {
- Prev = *I;
- break;
- }
- // FIXME: If we have any other entity with this name in global scope,
- // the declaration is ill-formed, but that is a defect: it breaks the
- // 'stat' hack, for instance.
- }
- }
+static bool mayConflictWithNonVisibleExternC(const T *ND) {
+ const DeclContext *DC = ND->getDeclContext();
+ if (DC->getRedeclContext()->isTranslationUnit())
+ return true;
- if (!Prev)
+ // We know that is the first decl we see, other than function local
+ // extern C ones. If this is C++ and the decl is not in a extern C context
+ // it cannot have C language linkage. Avoid calling isExternC in that case.
+ // We need to this because of code like
+ //
+ // namespace { struct bar {}; }
+ // auto foo = bar();
+ //
+ // This code runs before the init of foo is set, and therefore before
+ // the type of foo is known. Not knowing the type we cannot know its linkage
+ // unless it is in an extern C block.
+ if (!ND->isInExternCContext()) {
+ const ASTContext &Context = ND->getASTContext();
+ if (Context.getLangOpts().CPlusPlus)
return false;
}
- // Use the first declaration's location to ensure we point at something which
- // is lexically inside an extern "C" linkage-spec.
- assert(Prev && "should have found a previous declaration to diagnose");
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Prev))
- Prev = FD->getFirstDeclaration();
- else
- Prev = cast<VarDecl>(Prev)->getFirstDeclaration();
-
- S.Diag(ND->getLocation(), diag::err_extern_c_global_conflict)
- << IsGlobal << ND;
- S.Diag(Prev->getLocation(), diag::note_extern_c_global_conflict)
- << IsGlobal;
- return false;
-}
-
-/// Apply special rules for handling extern "C" declarations. Returns \c true
-/// if we have found that this is a redeclaration of some prior entity.
-///
-/// Per C++ [dcl.link]p6:
-/// Two declarations [for a function or variable] with C language linkage
-/// with the same name that appear in different scopes refer to the same
-/// [entity]. An entity with C language linkage shall not be declared with
-/// the same name as an entity in global scope.
-template<typename T>
-static bool checkForConflictWithNonVisibleExternC(Sema &S, const T *ND,
- LookupResult &Previous) {
- if (!S.getLangOpts().CPlusPlus) {
- // In C, when declaring a global variable, look for a corresponding 'extern'
- // variable declared in function scope.
- //
- // FIXME: The corresponding case in C++ does not work. We should instead
- // set the semantic DC for an extern local variable to be the innermost
- // enclosing namespace, and ensure they are only found by redeclaration
- // lookup.
- if (ND->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
- if (NamedDecl *Prev = S.findLocallyScopedExternCDecl(ND->getDeclName())) {
- Previous.clear();
- Previous.addDecl(Prev);
- return true;
- }
- }
- return false;
- }
-
- // A declaration in the translation unit can conflict with an extern "C"
- // declaration.
- if (ND->getDeclContext()->getRedeclContext()->isTranslationUnit())
- return checkGlobalOrExternCConflict(S, ND, /*IsGlobal*/true, Previous);
-
- // An extern "C" declaration can conflict with a declaration in the
- // translation unit or can be a redeclaration of an extern "C" declaration
- // in another scope.
- if (isIncompleteDeclExternC(S,ND))
- return checkGlobalOrExternCConflict(S, ND, /*IsGlobal*/false, Previous);
-
- // Neither global nor extern "C": nothing to do.
- return false;
+ return ND->isExternC();
}
void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
// The most important point here is that we're not allowed to
// update our understanding of the type according to declarations
// not in scope.
- bool PreviousWasHidden =
- Previous.empty() &&
- checkForConflictWithNonVisibleExternC(*this, NewVD, Previous);
+ bool PreviousWasHidden = false;
+ if (Previous.empty() && mayConflictWithNonVisibleExternC(NewVD)) {
+ if (NamedDecl *ExternCPrev =
+ findLocallyScopedExternCDecl(NewVD->getDeclName())) {
+ Previous.addDecl(ExternCPrev);
+ PreviousWasHidden = true;
+ }
+ }
// Filter out any non-conflicting previous declarations.
filterNonConflictingPreviousDecls(Context, NewVD, Previous);
// marking the function.
AddCFAuditedAttribute(NewFD);
- // If this is the first declaration of an extern C variable, update
- // the map of such variables.
- if (!NewFD->getPreviousDecl() && !NewFD->isInvalidDecl() &&
- isIncompleteDeclExternC(*this, NewFD))
+ // If this is the first declaration of an extern C variable that is not
+ // declared directly in the translation unit, update the map of such
+ // variables.
+ if (!CurContext->getRedeclContext()->isTranslationUnit() &&
+ !NewFD->getPreviousDecl() && NewFD->isExternC() &&
+ !NewFD->isInvalidDecl())
RegisterLocallyScopedExternCDecl(NewFD, S);
// Set this FunctionDecl's range up to the right paren.
assert(!NewFD->getResultType()->isVariablyModifiedType()
&& "Variably modified return types are not handled here");
+ // Check for a previous declaration of this name.
+ if (Previous.empty() && mayConflictWithNonVisibleExternC(NewFD)) {
+ // Since we did not find anything by this name, look for a non-visible
+ // extern "C" declaration with the same name.
+ if (NamedDecl *ExternCPrev =
+ findLocallyScopedExternCDecl(NewFD->getDeclName()))
+ Previous.addDecl(ExternCPrev);
+ }
+
// Filter out any non-conflicting previous declarations.
filterNonConflictingPreviousDecls(Context, NewFD, Previous);
}
}
- // Check for a previous extern "C" declaration with this name.
- if (!Redeclaration &&
- checkForConflictWithNonVisibleExternC(*this, NewFD, Previous)) {
- filterNonConflictingPreviousDecls(Context, NewFD, Previous);
- if (!Previous.empty()) {
- // This is an extern "C" declaration with the same name as a previous
- // declaration, and thus redeclares that entity...
- Redeclaration = true;
- OldDecl = Previous.getFoundDecl();
-
- // ... except in the presence of __attribute__((overloadable)).
- if (OldDecl->hasAttr<OverloadableAttr>()) {
- if (!getLangOpts().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) {
- Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
- << Redeclaration << NewFD;
- Diag(Previous.getFoundDecl()->getLocation(),
- diag::note_attribute_overloadable_prev_overload);
- NewFD->addAttr(::new (Context) OverloadableAttr(SourceLocation(),
- Context));
- }
- if (IsOverload(NewFD, cast<FunctionDecl>(OldDecl), false)) {
- Redeclaration = false;
- OldDecl = 0;
- }
- }
- }
- }
-
// C++11 [dcl.constexpr]p8:
// A constexpr specifier for a non-static member function that is not
// a constructor declares that member function to be const.
return Ovl_Overload;
}
-bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
- bool UseUsingDeclRules) {
- // C++ [basic.start.main]p2: This function shall not be overloaded.
- if (New->isMain())
+static bool canBeOverloaded(const FunctionDecl &D) {
+ if (D.getAttr<OverloadableAttr>())
+ return true;
+ if (D.isExternC())
+ return false;
+
+ // Main cannot be overloaded (basic.start.main).
+ if (D.isMain())
return false;
+ return true;
+}
+
+static bool shouldTryToOverload(Sema &S, FunctionDecl *New, FunctionDecl *Old,
+ bool UseUsingDeclRules) {
FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate();
FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
return true;
// Is the function New an overload of the function Old?
- QualType OldQType = Context.getCanonicalType(Old->getType());
- QualType NewQType = Context.getCanonicalType(New->getType());
+ QualType OldQType = S.Context.getCanonicalType(Old->getType());
+ QualType NewQType = S.Context.getCanonicalType(New->getType());
// Compare the signatures (C++ 1.3.10) of the two functions to
// determine whether they are overloads. If we find any mismatch
if (OldQType != NewQType &&
(OldType->getNumArgs() != NewType->getNumArgs() ||
OldType->isVariadic() != NewType->isVariadic() ||
- !FunctionArgTypesAreEqual(OldType, NewType)))
+ !S.FunctionArgTypesAreEqual(OldType, NewType)))
return true;
// C++ [temp.over.link]p4:
// However, we don't consider either of these when deciding whether
// a member introduced by a shadow declaration is hidden.
if (!UseUsingDeclRules && NewTemplate &&
- (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
- OldTemplate->getTemplateParameters(),
- false, TPL_TemplateMatch) ||
+ (!S.TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
+ OldTemplate->getTemplateParameters(),
+ false, S.TPL_TemplateMatch) ||
OldType->getResultType() != NewType->getResultType()))
return true;
// declarations with the same name, the same parameter-type-list, and
// the same template parameter lists cannot be overloaded if any of
// them, but not all, have a ref-qualifier (8.3.5).
- Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload)
+ S.Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload)
<< NewMethod->getRefQualifier() << OldMethod->getRefQualifier();
- Diag(OldMethod->getLocation(), diag::note_previous_declaration);
+ S.Diag(OldMethod->getLocation(), diag::note_previous_declaration);
}
return true;
}
// or non-static member function). Add it now, on the assumption that this
// is a redeclaration of OldMethod.
unsigned NewQuals = NewMethod->getTypeQualifiers();
- if (!getLangOpts().CPlusPlus1y && NewMethod->isConstexpr() &&
+ if (!S.getLangOpts().CPlusPlus1y && NewMethod->isConstexpr() &&
!isa<CXXConstructorDecl>(NewMethod))
NewQuals |= Qualifiers::Const;
if (OldMethod->getTypeQualifiers() != NewQuals)
return false;
}
+bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
+ bool UseUsingDeclRules) {
+ if (!shouldTryToOverload(*this, New, Old, UseUsingDeclRules))
+ return false;
+
+ // If both of the functions are extern "C", then they are not
+ // overloads.
+ if (!canBeOverloaded(*Old) && !canBeOverloaded(*New))
+ return false;
+
+ return true;
+}
+
/// \brief Checks availability of the function depending on the current
/// function context. Inside an unavailable function, unavailability is ignored.
///
namespace test1 {
extern "C" {
void test1_f() {
- void test1_g(int); // expected-note {{declared with C language linkage here}}
+ void test1_g(int); // expected-note {{previous declaration is here}}
}
}
}
-int test1_g(int); // expected-error {{declaration of 'test1_g' in global scope conflicts with declaration with C language linkage}}
+int test1_g(int); // expected-error {{functions that differ only in their return type cannot be overloaded}}
namespace test2 {
extern "C" {
void test2_f() {
- extern int test2_x; // expected-note {{declared with C language linkage here}}
+ extern int test2_x; // expected-note {{previous definition is here}}
}
}
}
-float test2_x; // expected-error {{declaration of 'test2_x' in global scope conflicts with declaration with C language linkage}}
+float test2_x; // expected-error {{redefinition of 'test2_x' with a different type: 'float' vs 'int'}}
namespace test3 {
extern "C" {
extern "C" {
void test4_f() {
- extern int test4_b; // expected-note {{declared with C language linkage here}}
+ extern int test4_b; // expected-note {{previous definition is here}}
}
}
-static float test4_b; // expected-error {{declaration of 'test4_b' in global scope conflicts with declaration with C language linkage}}
+static float test4_b; // expected-error {{redefinition of 'test4_b' with a different type: 'float' vs 'int'}}
extern "C" {
void test5_f() {
- extern int test5_b; // expected-note {{declared with C language linkage here}}
+ extern int test5_b; // expected-note {{previous definition is here}}
}
}
extern "C" {
- static float test5_b; // expected-error {{declaration of 'test5_b' in global scope conflicts with declaration with C language linkage}}
+ static float test5_b; // expected-error {{redefinition of 'test5_b' with a different type: 'float' vs 'int'}}
}
extern "C" {
}
}
namespace from_outer {
- void linkage_from_outer_1(); // expected-note {{previous}}
+ void linkage_from_outer_1();
void linkage_from_outer_2(); // expected-note {{previous}}
extern "C" {
- void linkage_from_outer_1(int);
- void linkage_from_outer_1(); // expected-error {{different language linkage}}
+ void linkage_from_outer_1(int); // expected-note {{previous}}
+ void linkage_from_outer_1(); // expected-error {{conflicting types}}
void linkage_from_outer_2(); // expected-error {{different language linkage}}
}
}
}
}
-void lookup_in_global_f(); // expected-note {{here}}
+void lookup_in_global_f();
namespace lookup_in_global {
void lookup_in_global_f();
- void lookup_in_global_g();
extern "C" {
- void lookup_in_global_f(int); // expected-error {{conflicts with declaration in global scope}}
- void lookup_in_global_g(int); // expected-note {{here}}
+ // FIXME: We should reject this.
+ void lookup_in_global_f(int);
}
}
-void lookup_in_global_g(); // expected-error {{conflicts with declaration with C language linkage}}
-
-namespace N1 {
- extern "C" int different_kind_1; // expected-note {{here}}
- extern "C" void different_kind_2(); // expected-note {{here}}
-}
-namespace N2 {
- extern "C" void different_kind_1(); // expected-error {{different kind of symbol}}
- extern "C" int different_kind_2; // expected-error {{different kind of symbol}}
-}
-
-extern "C" {
- struct stat {};
- void stat(struct stat);
-}
-namespace X {
- extern "C" {
- void stat(struct ::stat);
- }
-}
-
-extern "C" void name_with_using_decl_1(int);
-namespace using_decl {
- void name_with_using_decl_1();
- void name_with_using_decl_2();
- void name_with_using_decl_3();
-}
-using using_decl::name_with_using_decl_1;
-using using_decl::name_with_using_decl_2;
-extern "C" void name_with_using_decl_2(int);
-extern "C" void name_with_using_decl_3(int);
-using using_decl::name_with_using_decl_3;