diff --git a/llvm/include/llvm/AsmParser/LLLexer.h b/llvm/include/llvm/AsmParser/LLLexer.h --- a/llvm/include/llvm/AsmParser/LLLexer.h +++ b/llvm/include/llvm/AsmParser/LLLexer.h @@ -37,7 +37,7 @@ lltok::Kind CurKind; std::string StrVal; unsigned UIntVal; - Type *TyVal; + Type *TyVal = nullptr; APFloat APFloatVal; APSInt APSIntVal; diff --git a/llvm/include/llvm/AsmParser/LLParser.h b/llvm/include/llvm/AsmParser/LLParser.h --- a/llvm/include/llvm/AsmParser/LLParser.h +++ b/llvm/include/llvm/AsmParser/LLParser.h @@ -95,6 +95,8 @@ typedef LLLexer::LocTy LocTy; private: LLVMContext &Context; + // Lexer to determine whether to use opaque pointers or not. + LLLexer OPLex; LLLexer Lex; // Module being parsed, null if we are only parsing summary index. Module *M; @@ -157,8 +159,9 @@ LLParser(StringRef F, SourceMgr &SM, SMDiagnostic &Err, Module *M, ModuleSummaryIndex *Index, LLVMContext &Context, SlotMapping *Slots = nullptr) - : Context(Context), Lex(F, SM, Err, Context), M(M), Index(Index), - Slots(Slots), BlockAddressPFS(nullptr) {} + : Context(Context), OPLex(F, SM, Err, Context), + Lex(F, SM, Err, Context), M(M), Index(Index), Slots(Slots), + BlockAddressPFS(nullptr) {} bool Run( bool UpgradeDebugInfo, DataLayoutCallbackTy DataLayoutCallback = [](StringRef) { return None; }); diff --git a/llvm/include/llvm/IR/LLVMContext.h b/llvm/include/llvm/IR/LLVMContext.h --- a/llvm/include/llvm/IR/LLVMContext.h +++ b/llvm/include/llvm/IR/LLVMContext.h @@ -305,6 +305,9 @@ /// LLVMContext is used by compilation. void setOptPassGate(OptPassGate&); + /// Whether we've decided on using opaque pointers or typed pointers yet. + bool hasSetOpaquePointersValue() const; + /// Enable opaque pointers. Can only be called before creating the first /// pointer type. void enableOpaquePointers() const; diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -860,7 +860,10 @@ TYPEKEYWORD("token", Type::getTokenTy(Context)); if (Keyword == "ptr") { - if (Context.supportsTypedPointers()) { + // enableOpaquePointers() must be called before creating any pointer types. + if (!Context.hasSetOpaquePointersValue()) { + Context.enableOpaquePointers(); + } else if (Context.supportsTypedPointers()) { Warning("ptr type is only supported in -opaque-pointers mode"); return lltok::Error; } diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -59,9 +59,29 @@ return Tmp.str(); } +static void setContextOpaquePointers(LLLexer &L, LLVMContext &C) { + while (true) { + lltok::Kind K = L.Lex(); + // LLLexer will set the opaque pointers option in LLVMContext if it sees an + // explicit "ptr". + if (K == lltok::star || K == lltok::Error || K == lltok::Eof || + isa_and_nonnull(L.getTyVal())) { + return; + } + } +} + /// Run: module ::= toplevelentity* bool LLParser::Run(bool UpgradeDebugInfo, DataLayoutCallbackTy DataLayoutCallback) { + // If we haven't decided on whether or not we're using opaque pointers, do a + // quick lex over the tokens to see if we explicitly construct any typed or + // opaque pointer types. + // Don't bail out on an error so we do the same work in the parsing below + // regardless of if --opaque-pointers is set. + if (!Context.hasSetOpaquePointersValue()) + setContextOpaquePointers(OPLex, Context); + // Prime the lexer. Lex.Lex(); diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp --- a/llvm/lib/IR/LLVMContext.cpp +++ b/llvm/lib/IR/LLVMContext.cpp @@ -351,6 +351,10 @@ return std::move(pImpl->DiagHandler); } +bool LLVMContext::hasSetOpaquePointersValue() const { + return pImpl->hasOpaquePointersValue(); +} + void LLVMContext::enableOpaquePointers() const { assert(pImpl->PointerTypes.empty() && pImpl->ASPointerTypes.empty() && "Must be called before creating any pointer types"); diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -1555,6 +1555,7 @@ // TODO: clean up the following after we no longer support non-opaque pointer // types. bool getOpaquePointers(); + bool hasOpaquePointersValue(); void setOpaquePointers(bool OP); private: diff --git a/llvm/lib/IR/LLVMContextImpl.cpp b/llvm/lib/IR/LLVMContextImpl.cpp --- a/llvm/lib/IR/LLVMContextImpl.cpp +++ b/llvm/lib/IR/LLVMContextImpl.cpp @@ -47,7 +47,11 @@ X86_FP80Ty(C, Type::X86_FP80TyID), FP128Ty(C, Type::FP128TyID), PPC_FP128Ty(C, Type::PPC_FP128TyID), X86_MMXTy(C, Type::X86_MMXTyID), X86_AMXTy(C, Type::X86_AMXTyID), Int1Ty(C, 1), Int8Ty(C, 8), - Int16Ty(C, 16), Int32Ty(C, 32), Int64Ty(C, 64), Int128Ty(C, 128) {} + Int16Ty(C, 16), Int32Ty(C, 32), Int64Ty(C, 64), Int128Ty(C, 128) { + if (OpaquePointersCL.getNumOccurrences()) { + OpaquePointers = OpaquePointersCL; + } +} LLVMContextImpl::~LLVMContextImpl() { // NOTE: We need to delete the contents of OwnedModules, but Module's dtor @@ -245,9 +249,13 @@ this->OPG = &OPG; } +bool LLVMContextImpl::hasOpaquePointersValue() { + return OpaquePointers.hasValue(); +} + bool LLVMContextImpl::getOpaquePointers() { if (LLVM_UNLIKELY(!(OpaquePointers.hasValue()))) - OpaquePointers = OpaquePointersCL; + OpaquePointers = false; return *OpaquePointers; } diff --git a/llvm/test/Assembler/ptr-outside-opaque-pointers-mode.ll b/llvm/test/Assembler/ptr-outside-opaque-pointers-mode.ll --- a/llvm/test/Assembler/ptr-outside-opaque-pointers-mode.ll +++ b/llvm/test/Assembler/ptr-outside-opaque-pointers-mode.ll @@ -1,4 +1,4 @@ -; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s +; RUN: not llvm-as < %s -disable-output --opaque-pointers=0 2>&1 | FileCheck %s ; CHECK: warning: ptr type is only supported in -opaque-pointers mode ; CHECK: error: expected type diff --git a/llvm/test/Other/force-opaque-ptrs-typed-dis.ll b/llvm/test/Bitcode/opaque-ptr.ll rename from llvm/test/Other/force-opaque-ptrs-typed-dis.ll rename to llvm/test/Bitcode/opaque-ptr.ll --- a/llvm/test/Other/force-opaque-ptrs-typed-dis.ll +++ b/llvm/test/Bitcode/opaque-ptr.ll @@ -1,4 +1,4 @@ -; RUN: llvm-as --opaque-pointers < %s | not llvm-dis 2>&1 | FileCheck %s +; RUN: llvm-as --opaque-pointers < %s | not llvm-dis --opaque-pointers=0 2>&1 | FileCheck %s ; CHECK: error: Opaque pointers are only supported in -opaque-pointers mode diff --git a/llvm/test/Other/mixed-opaque-ptrs-2.ll b/llvm/test/Other/mixed-opaque-ptrs-2.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Other/mixed-opaque-ptrs-2.ll @@ -0,0 +1,6 @@ +; RUN: llvm-as -disable-output %s 2>&1 +; FIXME: this should err out saying not to mix `ptr` and `foo*` +define void @f(ptr) { + %a = alloca i32* + ret void +} diff --git a/llvm/test/Other/mixed-opaque-ptrs.ll b/llvm/test/Other/mixed-opaque-ptrs.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Other/mixed-opaque-ptrs.ll @@ -0,0 +1,6 @@ +; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s +; CHECK: ptr type is only supported in -opaque-pointers mode +define void @f(i32*) { + %a = alloca ptr + ret void +}