Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -1881,6 +1881,10 @@ return getTypeDeclType(getBuiltinMSVaListDecl()); } + /// Return whether a declaration to a builtin is allowed to be + /// overloaded/redeclared. + bool canBuiltinBeRedeclared(const FunctionDecl *) const; + /// \brief Return a type with additional \c const, \c volatile, or /// \c restrict qualifiers. QualType getCVRQualifiedType(QualType T, unsigned CVR) const { Index: include/clang/Basic/Builtins.h =================================================================== --- include/clang/Basic/Builtins.h +++ include/clang/Basic/Builtins.h @@ -167,6 +167,13 @@ return strchr(getRecord(ID).Type, '*') != nullptr; } + /// \brief Return true if this builtin has a result or any arguments which are + /// reference types. + bool hasReferenceArgsOrResult(unsigned ID) const { + return strchr(getRecord(ID).Type, '&') != nullptr || + strchr(getRecord(ID).Type, 'A') != nullptr; + } + /// \brief Completely forget that the given ID was ever considered a builtin, /// e.g., because the user provided a conflicting signature. void forgetBuiltin(unsigned ID, IdentifierTable &Table); @@ -212,6 +219,10 @@ /// prefix. static bool isBuiltinFunc(const char *Name); + /// Returns true if this is a builtin that can be redeclared. Returns true + /// for non-builtins. + bool canBeRedeclared(unsigned ID) const; + private: const Info &getRecord(unsigned ID) const; Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -602,6 +602,7 @@ "incompatible redeclaration of library function %0">, InGroup>; def err_builtin_definition : Error<"definition of builtin function %0">; +def err_builtin_redeclare : Error<"cannot redeclare builtin function %0">; def err_arm_invalid_specialreg : Error<"invalid special register for builtin">; def err_invalid_cpu_supports : Error<"invalid cpu feature string for builtin">; def err_invalid_cpu_is : Error<"invalid cpu name for builtin">; Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -7244,6 +7244,10 @@ return BuiltinMSVaListDecl; } +bool ASTContext::canBuiltinBeRedeclared(const FunctionDecl *FD) const { + return BuiltinInfo.canBeRedeclared(FD->getBuiltinID()); +} + void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) { assert(ObjCConstantStringType.isNull() && "'NSConstantString' type already set!"); Index: lib/Basic/Builtins.cpp =================================================================== --- lib/Basic/Builtins.cpp +++ lib/Basic/Builtins.cpp @@ -139,3 +139,9 @@ bool &HasVAListArg) { return isLike(ID, FormatIdx, HasVAListArg, "sS"); } + +bool Builtin::Context::canBeRedeclared(unsigned ID) const { + return ID == Builtin::NotBuiltin || + (!hasReferenceArgsOrResult(ID) && + !hasCustomTypechecking(ID)); +} Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -3014,6 +3014,14 @@ if (Old->isInvalidDecl()) return true; + // Disallow redeclaration of some builtins. + if (!getASTContext().canBuiltinBeRedeclared(Old)) { + Diag(New->getLocation(), diag::err_builtin_redeclare) << Old->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_builtin_declaration) + << Old << Old->getType(); + return true; + } + diag::kind PrevDiag; SourceLocation OldLocation; std::tie(PrevDiag, OldLocation) = Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -998,6 +998,13 @@ Match = *I; return Ovl_Match; } + + // Builtins that have custom typechecking or have a reference should + // not be overloadable or redeclarable. + if (!getASTContext().canBuiltinBeRedeclared(OldF)) { + Match = *I; + return Ovl_NonFunction; + } } else if (isa(OldD) || isa(OldD)) { // We can overload with these, which can show up when doing // redeclaration checks for UsingDecls. Index: test/Sema/MicrosoftExtensions.c =================================================================== --- test/Sema/MicrosoftExtensions.c +++ test/Sema/MicrosoftExtensions.c @@ -166,7 +166,6 @@ T __ptr32 wrong10; // expected-error {{'__ptr32' attribute only applies to pointer arguments}} typedef char *my_va_list; -void __va_start(my_va_list *ap, ...); // expected-note {{passing argument to parameter 'ap' here}} void vmyprintf(const char *f, my_va_list ap); void myprintf(const char *f, ...) { my_va_list ap; Index: test/Sema/builtin-redecl.cpp =================================================================== --- test/Sema/builtin-redecl.cpp +++ test/Sema/builtin-redecl.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 %s -fsyntax-only -verify +// RUN: %clang_cc1 %s -fsyntax-only -verify -x c + +// Redeclaring library builtins is OK. +void exit(int); + +// expected-error@+2 {{cannot redeclare builtin function '__builtin_va_copy'}} +// expected-note@+1 {{'__builtin_va_copy' is a builtin with type}} +void __builtin_va_copy(double d); + +// expected-error@+2 {{cannot redeclare builtin function '__builtin_va_end'}} +// expected-note@+1 {{'__builtin_va_end' is a builtin with type}} +void __builtin_va_end(__builtin_va_list); Index: test/SemaCXX/microsoft-varargs.cpp =================================================================== --- test/SemaCXX/microsoft-varargs.cpp +++ test/SemaCXX/microsoft-varargs.cpp @@ -3,7 +3,6 @@ extern "C" { typedef char * va_list; -void __va_start(va_list *, ...); } int test___va_start(int i, ...) {